[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(¶ms);
+ }
+ 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<A>"
+(see <a href="../smbase/astlist.h">smbase/astlist.h</a>), then the
+constructor argument becomes "ASTList<A>*" and the field is
+"ASTList<A>". 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<A>" (see smbase/fakelist.h), then
+the constructor argument and class field are both "FakeList<A>*".
+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 <kind> { /* ...code... */ }
+</pre>
+
+<p>
+The <kind>, 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 <kind> 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>-></tt>" inside the superclass body. The syntax following "<tt>-></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 <name>;
+</pre>
+
+<p>
+Then a visitor implementation will be generated, and <name> 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(<name> &vis);
+</pre>
+where <name> is the visitor interface class name. You can start
+a visiting traversal by saying "<tt>node->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 <init>
+ 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 ⟨
+
+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 ⟨ // 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 ⟨
+
+ // 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 { -> 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 {
+ -> TOK_SELECT_FOO f:Foo { return f; }
+ -> TOK_SELECT_BAR b:Bar { return b; }
+ -> 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(¶ms);
+ 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>
+ <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> <i>num</i> <i>tok...</i> <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 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 3).
+<li><tt>sval</tt>: The semantic value, a value of the type given in the
+ Token Types specification (Section 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 {
+ -> e1:Exp "+" e2:Exp { return e1 + e2; }
+ -> 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 -> Exp "+"
+Exp</tt> and <tt>Exp -> TOK_NUMBER</tt>. The "<tt>-></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 -> B a c | b A a d
+ B -> b a a
+ A -> 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 -> A b | a b
+ A -> 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 {
+ -> A B C precedence("+") { /*...*/ }
+ }
+</pre>
+
+<p>
+This specification has the effect of assigning the rule
+"<tt>N -> 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 {
+ -> A B C forbid_next("+") forbid_next("*") { /*...*/ }
+ }
+</pre>
+
+<p>
+This specification means that the rule "<tt>N -> 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 {
+ -> A ;
+ }
+ nonterm(type) N {
+ -> B ;
+ }
+</pre>
+as equivalent to
+<pre>
+ nonterm(type) N {
+ -> A ;
+ -> 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 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 {
+ -> Expr "+" Expr ;
+ -> Expr "-" Expr ;
+ -> Expr "*" Expr ;
+ -> Expr "/" Expr ;
+ -> 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 -> 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>
+ * <-- top of stack
+ Expr(2)
+ +
+ Expr(1) <-- bottom of stack
+</pre>
+Then after one more shift, we have
+<pre>
+ Expr(3) <-- top of stack
+ *
+ Expr(2)
+ +
+ Expr(1) <-- bottom of stack
+</pre>
+and the only choice is to reduce via "<tt>Expr -> Expr * Expr</tt>", leading to
+the configuration
+<pre>
+ Expr(Expr(2)*Expr(3)) <-- top of stack
+ +
+ Expr(1) <-- bottom of stack
+</pre>
+and one more reduce yields
+<pre>
+ Expr( Expr(1) + Expr(Expr(2)*Expr(3)) ) <-- 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 -> 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 {
+ -> "if" "(" Expr ")" Stmt ;
+ -> "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 {
+ -> "if" "(" Expr ")" Stmt precedence("else");
+ -> "if" "(" Expr ")" Stmt "else" Stmt precedence("else");
+ ...
+ }
+</pre>
+At the crucial moment, the lookahead is "else" and the stack is
+<pre>
+ Stmt(a=b;) <-- top
+ ")"
+ Expr(Q)
+ "("
+ "if"
+ ")"
+ Expr(P)
+ "("
+ "if" <-- bottom
+</pre>
+The conflict is between shifting "else" and reducing via
+"<tt>Stmt -> 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;) <-- top
+ "else"
+ Stmt(a=b;)
+ ")"
+ Expr(Q)
+ "("
+ "if"
+ ")"
+ Expr(P)
+ "("
+ "if" <-- bottom
+</pre>
+Finally, the algorithm reduces via
+"<tt>Stmt -> if ( Expr ) Stmt else Stmt</tt>", yielding
+<pre>
+ If(Q, Stmt(a=b;), Stmt(c=d;)) <-- top
+ ")"
+ Expr(P)
+ "("
+ "if" <-- 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 < 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 -> 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 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 &Lexer::nextToken; }
+
+ // debugging assistance functions
+ string tokenDesc() const;
+ string tokenKindDesc(int kind) const;
+ };
+</pre>
+
+<a name="sec2.2"></a>
+<h3>2.2 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->type = TOK_EOF;
+ return;
+ }
+
+ // simple one-character tokens
+ switch (ch) {
+ case '+': lex->type = TOK_PLUS; return;
+ case '-': lex->type = TOK_MINUS; 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();
+ }
+</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(&map[kind-TOK_PLUS], 1);
+ }
+ }
+ }
+</pre>
+
+<a name="sec2.3"></a>
+<h3>2.3 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()(&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 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 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 <lexer.h >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 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>-></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 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(&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;
+ }
+</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] (
+ <noloc>:1:1: Parse error (state 4) at EOF
+ parse error
+
+ $ echo "2 + 3 + 5" | ./parser
+ <noloc>:1:1: WARNING: there is no action to merge nonterm AExp
+ result: 0
+
+ $ echo "2 + 3 + 5 +" | ./parser
+ <noloc>: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] (
+ <noloc>: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 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 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(&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);
+</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 -> AExp TOK_EOF
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_EOF
+
+ $ echo "2 + 3" | ./parser -tree
+ __EarlyStartSymbol -> AExp TOK_EOF
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_EOF
+
+ $ echo "2 + 3 + 4" | ./parser -tree
+ __EarlyStartSymbol -> AExp TOK_EOF
+ --------- ambiguous AExp: 1 of 2 ---------
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ --------- ambiguous AExp: 2 of 2 ---------
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> 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 -> 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 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 -> AExp TOK_EOF
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> 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 {
+ -> 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
+ }
+ }
+ }
+</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 <stdlib.h> // 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 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 &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);
+ }
+</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 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 {
+ -> 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); }
+ }
+</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 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 &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 -> value
+ TStringHash<Binding> 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 &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);
+ }
+ }
+</pre>
+
+<a name="#sec8.4"></a>
+<h3>8.4 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 && 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->debugPrint(cout, 0);
+ }
+
+ // evaluate
+ printf("evaluating...\n");
+ Env env;
+ top->eval(env);
+ printf("program terminated normally\n");
+
+ // recursively deallocate the tree
+ delete top;
+</pre>
+
+<a name="sec8.5"></a>
+<h3>8.5 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 <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 < 10 ->
+ print x;
+ x := x + 1
+ od;
+ print x
+
+ $ ./parser <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) ->
+ print x;
+ print y;
+ if x < y -> y := y - x #
+ y < x -> x := x - y fi
+ od;
+ print x
+
+ $ ./parser <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 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->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 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 -> (AExp+AExp)+AExp -> AExp+AExp -> AExp
+ 2+3+4 -> AExp+(AExp+AExp) -> AExp+AExp -> 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) < 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
+ }
+</pre>
+
+<p>This depends on the <tt>precedence</tt> function:
+
+<pre>
+ 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; } // +,-
+ }
+</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 -> Start TOK_EOF
+ Start -> Stmt
+ Stmt -> Stmt TOK_SEMI Stmt
+ Stmt -> TOK_IDENTIFIER TOK_ASSIGN AExp
+ TOK_IDENTIFIER
+ TOK_ASSIGN
+ --------- ambiguous AExp: 1 of 2 ---------
+ AExp -> AExp TOK_TIMES AExp
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_TIMES
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ --------- ambiguous AExp: 2 of 2 ---------
+ AExp -> AExp TOK_PLUS AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_PLUS
+ AExp -> AExp TOK_TIMES AExp
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ TOK_TIMES
+ AExp -> TOK_LITERAL
+ TOK_LITERAL
+ --------- end of ambiguous AExp ---------
+ TOK_SEMI
+ Stmt -> 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!
+<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> *¶ms);
+
+// 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 ⟨
+
+ // 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 ¶ms);
+ void deleteTemplateArgBindings(Scope *limit = NULL);
+
+ void mapPrimaryArgsToSpecArgs(
+ Variable *baseV,
+ ObjList<STemplateArgument> &partialSpecArgs,
+ ObjList<STemplateArgument> &primaryArgs);
+ void mapPrimaryArgsToSpecArgs_oneParamList(
+ SObjList<Variable> const ¶ms,
+ 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 ¶ms,
+ 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 ¶mList);
+ 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> ¶ms)
+ { return true; }
+void TypeVisitor::postvisitFunctionType_params(SObjList<Variable> ¶ms)
+ { }
+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 ¶ms)
+{
+ 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> ¶ms);
+ virtual void postvisitFunctionType_params(SObjList<Variable> ¶ms);
+ 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 ⟨ // 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 << f->nameAndParams->getDeclaratorId()->getName() << "\n";
+ }
+ };
+
+ void printFuncNames(TranslationUnit *unit)
+ {
+ FuncPrinter fp;
+ unit->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 <-- Declarator -> <-- Declarator -->
+
+ <---------------------- Declaration ----------------------->
+</pre>
+
+But they also have a recursive structure, represented in my
+AST as IDeclarators:
+<pre>
+ int * * y ;
+ |
+ D_name
+ <---- D_pointer ---->
+ <--------- D_pointer ---------->
+
+
+ int * * ( * func ) (int, int) ;
+ |
+ D_name
+ <-- D_pointer -->
+ <----- D_grouping ------->
+ <-------------- D_func ------------->
+ <------------- D_pointer ------------------>
+ <------------- D_pointer -------------------->
+</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> )
+
+<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 "&__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 <class T>
+ 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><class
+T></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 <template <class S> class T> /*...*/
+</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 </*...*/></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 <class T>
+ struct A;
+
+ template <class T>
+ struct B {
+ A<T> a;
+ };
+</pre>
+The B::a member has type <tt>A<T></tt>, but (in the context of
+the template B) <TT>T</TT> is abstract, so <tt>A<T></tt> is too.
+
+<p>
+Here is an example with an abstract template portion of an AbstractTemplateId:
+<pre>
+ template <template <class S> class T, class U>
+ struct A {
+ T<U> t;
+ };
+</pre>
+Here, A::t has type <tt>T<U></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 <class T>
+ 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 <int n>
+ struct A {
+ int foo(int (*p)[n]);
+ int foo(int (*p)[n+1]);
+ };
+
+ template <int n>
+ int A<n>::foo(int (*p)[n]) { /*...*/ }
+
+ template <int n>
+ int A<n>::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 <class S1>
+ struct A {
+ template <class T2>
+ struct B {
+ int f();
+ };
+ };
+
+ template <class S2>
+ template <class T2>
+ int A<S2>::B<T2>::f() { /*...*/ }
+</pre>
+the ClassMember for A::B::f will have enclosing parameter lists
+<tt><S2></tt> and <tt><T2></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 <----+
+ - 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 <----+
+ - QName |
+ | | rest -----+
+ | - QN_global
+ | - QN_nested
+ | qual -------+
+ - PQ_nameId <---+
+ | | 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>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+<center>This space left intentionally blank.</center>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <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&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&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&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 "<class T>" 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 -> 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&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<T*></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<Scope> &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->insertInto(b);
+
+ // now fold it in half
+ Polygon p = assembly.bisection();
+ xassert(p.closed());
+ FoldManager::singleton()->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 -->
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+<center>this space left intentionally blank</center>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <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 <class T>
+ class Base {
+ public:
+ int x;
+ };
+
+ template <class T>
+ class Derived : public Base<T> {
+ 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->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->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->traverse(cc);
+ cout << inputFname << ": found " << cc.count << " 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->decl->decl->loc;
+ }
+
+ bool CastCounter::visitExpression(Expression *obj)
+ {
+ if (obj->isE_cast()) {
+ count++;
+ E_cast *cast = obj->asE_cast();
+
+ cout << toString(locOfType(cast->ctype))
+ << ": C cast of `" << cast->expr->exprToString()
+ << "' to type `" << cast->ctype->getType()->toString() << "'\n";
+ }
+
+ else if (obj->isE_keywordCast()) {
+ count++;
+ E_keywordCast *cast = obj->asE_keywordCast();
+
+ cout << toString(locOfType(cast->ctype))
+ << ": " << toString(cast->key)
+ << " of `" << cast->expr->exprToString()
+ << "' to type `" << cast->ctype->getType()->toString() << "'\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>
+ << ": C cast of `" << trimWhitespace(cast->expr->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 <name> <line> 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> *¶ms) {
+ // 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&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&R extensions, in particular K&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> *¶ms);
+
+
+// -------------------- 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 ⟨ // 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 ↦
+ 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 ¶ms)
+{
+ 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 ¶ms);
+
+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 ¶mList)
+{
+ 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 ¶ms)
+{
+ // 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 ¶ms, // 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 ¶ms,
+ 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 ¶ms);
+
+
+// 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 ↦
+ 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 ↦
+ 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 ↦
+ 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 << "%%% weapons: " << "about to fire proton torpedo " << torpNum << 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 ↦ // 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 ↦
+ 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