From lattner at cs.uiuc.edu Mon Apr 5 11:03:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:03:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200404051602.LAA03561@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.178 -> 1.179 --- Log message: Fix a bug in yesterdays checkins which broke siod. siod is a great testcase! :) --- Diffs of the changes: (+1 -1) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.178 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.179 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.178 Sun Apr 4 21:10:19 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Mon Apr 5 11:02:41 2004 @@ -2422,10 +2422,10 @@ } Sum = BinaryOperator::create(Instruction::Add, SO1, GO1, GEP.getOperand(0)->getName()+".sum", &GEP); + WorkList.push_back(cast(Sum)); } GEP.setOperand(0, SrcGEPOperands[0]); GEP.setOperand(1, Sum); - WorkList.push_back(cast(Sum)); return &GEP; } else if (isa(*GEP.idx_begin()) && cast(*GEP.idx_begin())->isNullValue() && From lattner at cs.uiuc.edu Mon Apr 5 11:15:04 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:15:04 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/cscope.out Message-ID: <200404051614.LAA04963@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl: cscope.out (r1.1) removed --- Log message: This file doesn't belong here --- Diffs of the changes: (+0 -0) From lattner at cs.uiuc.edu Mon Apr 5 11:27:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:27:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c Message-ID: <200404051626.LAA05371@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl: toke.c updated: 1.1 -> 1.2 --- Log message: Add #include so that we get the prototype for atof. --- Diffs of the changes: (+5 -1) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c:1.1 Tue Feb 17 16:21:16 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/toke.c Mon Apr 5 11:26:44 2004 @@ -1,4 +1,4 @@ -/* $RCSfile: toke.c,v $$Revision: 1.1 $$Date: 2004/02/17 22:21:16 $ +/* $RCSfile: toke.c,v $$Revision: 1.2 $$Date: 2004/04/05 16:26:44 $ * * Copyright (c) 1989, Larry Wall * @@ -6,6 +6,9 @@ * as specified in the README file that comes with the perl 3.0 kit. * * $Log: toke.c,v $ + * Revision 1.2 2004/04/05 16:26:44 lattner + * Add #include so that we get the prototype for atof. + * * Revision 1.1 2004/02/17 22:21:16 criswell * Initial commit of the perl Malloc Benchmark. I've cheated a little by * generating the yacc output files and committing them directly, but it was @@ -29,6 +32,7 @@ #ifdef I_SYS_FILE #include #endif +#include /* which backslash sequences to keep in m// or s// */ From lattner at cs.uiuc.edu Mon Apr 5 11:27:04 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:27:04 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c Message-ID: <200404051627.LAA05376@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl: malloc.c updated: 1.1 -> 1.2 --- Log message: Disable the custom allocator that is really buggy --- Diffs of the changes: (+6 -2) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c:1.1 Tue Feb 17 16:21:16 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/malloc.c Mon Apr 5 11:26:28 2004 @@ -1,6 +1,9 @@ -/* $RCSfile: malloc.c,v $$Revision: 1.1 $$Date: 2004/02/17 22:21:16 $ +/* $RCSfile: malloc.c,v $$Revision: 1.2 $$Date: 2004/04/05 16:26:28 $ * * $Log: malloc.c,v $ + * Revision 1.2 2004/04/05 16:26:28 lattner + * Disable the custom allocator that is really buggy + * * Revision 1.1 2004/02/17 22:21:16 criswell * Initial commit of the perl Malloc Benchmark. I've cheated a little by * generating the yacc output files and committing them directly, but it was @@ -14,7 +17,7 @@ * */ -#ifndef lint +#if 0 static char sccsid[] = "@(#)malloc.c 4.3 (Berkeley) 9/16/83"; #ifdef DEBUGGING @@ -132,6 +135,7 @@ /* apart from this loop, this is O(1) */ while (shiftr >>= 1) bucket++; + printf("NB: %d %d\n", nbytes, bucket); /* * If nothing in hash bucket right now, * request more memory from the system. From lattner at cs.uiuc.edu Mon Apr 5 11:38:41 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:38:41 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h Message-ID: <200404051636.LAA06064@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl: handy.h updated: 1.1 -> 1.2 --- Log message: Finally, fix the last perl bug that prevented it from working with LLVM: No, memcpy is NOT allowed when the src & dest overlap! --- Diffs of the changes: (+6 -2) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h:1.1 Tue Feb 17 16:21:16 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h Mon Apr 5 11:35:52 2004 @@ -1,4 +1,4 @@ -/* $Header: /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h,v 1.1 2004/02/17 22:21:16 criswell Exp $ +/* $Header: /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Benchmarks/MallocBench/perl/handy.h,v 1.2 2004/04/05 16:35:52 lattner Exp $ * * Copyright (c) 1989, Larry Wall * @@ -6,6 +6,10 @@ * as specified in the README file that comes with the perl 3.0 kit. * * $Log: handy.h,v $ + * Revision 1.2 2004/04/05 16:35:52 lattner + * Finally, fix the last perl bug that prevented it from working with LLVM: + * No, memcpy is NOT allowed when the src & dest overlap! + * * Revision 1.1 2004/02/17 22:21:16 criswell * Initial commit of the perl Malloc Benchmark. I've cheated a little by * generating the yacc output files and committing them directly, but it was @@ -108,7 +112,7 @@ long xcount[MAXXCOUNT]; long lastxcount[MAXXCOUNT]; #endif /* LEAKTEST */ -#define Copy(s,d,n,t) (void)bcopy((char*)(s),(char*)(d), (n) * sizeof(t)) +#define Copy(s,d,n,t) (void)memmove((char*)(d),(char*)(s), (n) * sizeof(t)) #define Zero(d,n,t) (void)bzero((char*)(d), (n) * sizeof(t)) #else /* lint */ #define New(x,v,n,s) (v = Null(s *)) From lattner at cs.uiuc.edu Mon Apr 5 11:43:06 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 11:43:06 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c Message-ID: <200404051640.LAA06447@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make: main.c updated: 1.2 -> 1.3 --- Log message: Fix spurious testcase failures --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c:1.2 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c:1.3 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c:1.2 Fri Feb 20 13:28:17 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/make/main.c Mon Apr 5 11:39:53 2004 @@ -1362,7 +1362,7 @@ if (print_data_base_flag) fputs ("# ", stdout); - if (makelevel == 0) + if (1 || makelevel == 0) printf ("%s: %s ", "make", message); else printf ("%s[%u]: %s ", "make", makelevel, message); From brukman at cs.uiuc.edu Mon Apr 5 12:28:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 12:28:01 2004 Subject: [llvm-commits] CVS: llvm-www/status/index.html Message-ID: <200404051727.MAA06626@zion.cs.uiuc.edu> Changes in directory llvm-www/status: index.html updated: 1.40 -> 1.41 --- Log message: Some updates on compilation status (not all failures investigated). --- Diffs of the changes: (+39 -40) Index: llvm-www/status/index.html diff -u llvm-www/status/index.html:1.40 llvm-www/status/index.html:1.41 --- llvm-www/status/index.html:1.40 Mon Mar 15 17:59:53 2004 +++ llvm-www/status/index.html Mon Apr 5 12:27:24 2004 @@ -65,6 +65,44 @@ Status Notes + + + llvm + 1.1 + 5 Apr 2004 + FAILS + Linking VMcore fails because of instcombine bug + + + + ddd + 3.3.7 + 5 Apr 2004 + FAILS + Does not compile: ICE. + + + + pine + 4.58 + 5 Apr 2004 + FAILS + Build with: +
+./build CC=llvm-gcc lrh
+
+ lrh = Linux Red Hat, there are many such targets. + Compile fails: gccld fails on linking mtest (details later). + + + + ruby + 1.8.0 + 16 Mar 2004 + FAILS + Intermediate executable miniruby crashes + mutt @@ -119,14 +157,6 @@ FAILS Cannot compile: see bug 295. - - - llvm - 1.1 - 15 Mar 2004 - FAILS - bugpoint does not compile: bug 291. - hbd @@ -191,20 +221,6 @@ FAILS Running intermediate binary temacs results in a crash. - - - pine - 4.58 - 19 Nov 2003 - FAILS - Build with: -
-./build CC=llvm-gcc lrh
-
- lrh = Linux Red Hat, there are many such targets. - Compile fails: see bug 141 and - bug 82 for details. - xpdf @@ -250,15 +266,6 @@ WORKS passes its own regression test suite - - - ddd - 3.3.7 - 2 Nov 2003 - FAILS - Does not compile, see bug #82 - for details. - wget @@ -359,14 +366,6 @@ - - - ruby - 1.8.0 - 28 Aug 2003 - FAILS - miniruby: WARNING: cannot resolve `__builtin_frame_address' - @@ -393,7 +392,7 @@
Misha Brukman
The LLVM Compiler Infrastructure
- Last modified: $Date: 2004/03/15 23:59:53 $ + Last modified: $Date: 2004/04/05 17:27:24 $ From brukman at cs.uiuc.edu Mon Apr 5 12:30:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 12:30:02 2004 Subject: [llvm-commits] CVS: llvm-www/status/index.html Message-ID: <200404051729.MAA14923@zion.cs.uiuc.edu> Changes in directory llvm-www/status: index.html updated: 1.41 -> 1.42 --- Log message: Clarify failure of pine. --- Diffs of the changes: (+5 -4) Index: llvm-www/status/index.html diff -u llvm-www/status/index.html:1.41 llvm-www/status/index.html:1.42 --- llvm-www/status/index.html:1.41 Mon Apr 5 12:27:24 2004 +++ llvm-www/status/index.html Mon Apr 5 12:29:37 2004 @@ -71,8 +71,8 @@ 1.1 5 Apr 2004 FAILS - Linking VMcore fails because of instcombine bug + Linking VMcore fails: bug #311 + (instcombine). @@ -93,7 +93,8 @@ ./build CC=llvm-gcc lrh lrh = Linux Red Hat, there are many such targets. - Compile fails: gccld fails on linking mtest (details later). + Compile fails: gccld fails on linking mtest, see bug #311. @@ -392,7 +393,7 @@
Misha Brukman
The LLVM Compiler Infrastructure
- Last modified: $Date: 2004/04/05 17:27:24 $ + Last modified: $Date: 2004/04/05 17:29:37 $ From lattner at cs.uiuc.edu Mon Apr 5 13:23:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 13:23:02 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c utility.c Message-ID: <200404051822.NAA23771@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso: main.c updated: 1.1 -> 1.2 utility.c updated: 1.1 -> 1.2 --- Log message: Fix spurious diff failures due to printing argv[0] and timings --- Diffs of the changes: (+4 -3) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c:1.1 Tue Feb 17 12:13:40 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/main.c Mon Apr 5 13:22:14 2004 @@ -164,8 +164,8 @@ /* provide version information and summaries */ if (summary || trace) { /* echo command line and arguments */ - printf("#"); - for(i = 0; i < argc; i++) { + printf("# espresso"); + for(i = 1; i < argc; i++) { printf(" %s", argv[i]); } printf("\n"); @@ -570,6 +570,7 @@ for(i = 0; i < TIME_COUNT; i++) { if (total_calls[i] != 0) { temp = 100 * total_time[i]; + temp = 0; printf("# %s\t%2d call(s) for %s (%2ld.%01ld%%)\n", total_name[i], total_calls[i], print_time(total_time[i]), temp/total, (10 * (temp%total)) / total); Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/utility.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/utility.c:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/utility.c:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/utility.c:1.1 Tue Feb 17 12:13:41 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/utility.c Mon Apr 5 13:22:14 2004 @@ -124,7 +124,7 @@ long t; { static char s[40]; - + return ""; (void) sprintf(s, "%ld.%02ld sec", t/1000, (t%1000)/10); return s; } From lattner at cs.uiuc.edu Mon Apr 5 13:37:06 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 13:37:06 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c Message-ID: <200404051826.NAA23969@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso: cvrmisc.c updated: 1.1 -> 1.2 --- Log message: Don't print out the primes field, which is causing the diff to fail because of use of uninitialized memory. If someone can figure out how to FIX espresso, we could enable this, but my meager attempts were not enough. --- Diffs of the changes: (+4 -4) Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c diff -u llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c:1.1 llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c:1.2 --- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c:1.1 Tue Feb 17 12:13:40 2004 +++ llvm/test/Programs/MultiSource/Benchmarks/MallocBench/espresso/cvrmisc.c Mon Apr 5 13:25:56 2004 @@ -50,12 +50,12 @@ static char s[200]; if (cube.num_binary_vars == cube.num_vars - 1) - (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", - cost->cubes, cost->cubes - cost->primes, cost->in, + (void) sprintf(s, "c=%d in=%d out=%d tot=%d", + cost->cubes, cost->in, cost->out, cost->total); else - (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", - cost->cubes, cost->cubes - cost->primes, cost->in, + (void) sprintf(s, "c=%d in=%d mv=%d out=%d", + cost->cubes, cost->in, cost->mv, cost->out); return s; } From lattner at cs.uiuc.edu Mon Apr 5 13:47:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 13:47:01 2004 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/IndVarsSimplify/2004-04-05-InvokeCastCrash.llx Message-ID: <200404051846.NAA24829@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/IndVarsSimplify: 2004-04-05-InvokeCastCrash.llx added (r1.1) --- Log message: New testcase for PR312: http://llvm.cs.uiuc.edu/PR312 --- Diffs of the changes: (+286 -0) Index: llvm/test/Regression/Transforms/IndVarsSimplify/2004-04-05-InvokeCastCrash.llx diff -c /dev/null llvm/test/Regression/Transforms/IndVarsSimplify/2004-04-05-InvokeCastCrash.llx:1.1 *** /dev/null Mon Apr 5 13:46:44 2004 --- llvm/test/Regression/Transforms/IndVarsSimplify/2004-04-05-InvokeCastCrash.llx Mon Apr 5 13:46:33 2004 *************** *** 0 **** --- 1,286 ---- + ; RUN: llvm-as < %s | opt -indvars -disable-output + + %struct.__false_type = type { ubyte } + "struct.__gnu_cxx::_Hashtable_node" = type { "struct.__gnu_cxx::_Hashtable_node"*, "struct.llvm::Constant"* } + "struct.__gnu_cxx::_Hashtable_node >" = type { "struct.__gnu_cxx::_Hashtable_node >"*, "struct.std::pair" } + "struct.__gnu_cxx::hash_map,std::equal_to,std::allocator >" = type { "struct.__gnu_cxx::hashtable,const llvm::Value*,__gnu_cxx::hash,std::_Select1st >,std::equal_to,std::allocator >" } + "struct.__gnu_cxx::hash_set,std::equal_to,std::allocator >" = type { "struct.__gnu_cxx::hashtable,std::_Identity,std::equal_to,std::allocator >" } + "struct.__gnu_cxx::hashtable,std::_Identity,std::equal_to,std::allocator >" = type { %struct.__false_type, %struct.__false_type, %struct.__false_type, %struct.__false_type, "struct.std::vector<__gnu_cxx::_Hashtable_node*,std::allocator >", uint } + "struct.__gnu_cxx::hashtable,const llvm::Value*,__gnu_cxx::hash,std::_Select1st >,std::equal_to,std::allocator >" = type { %struct.__false_type, %struct.__false_type, %struct.__false_type, %struct.__false_type, "struct.std::vector<__gnu_cxx::_Hashtable_node >*,std::allocator >", uint } + "struct.llvm::AbstractTypeUser" = type { int (...)** } + "struct.llvm::Annotable" = type { int (...)**, "struct.llvm::Annotation"* } + "struct.llvm::Annotation" = type { int (...)**, "struct.llvm::AnnotationID", "struct.llvm::Annotation"* } + "struct.llvm::AnnotationID" = type { uint } + "struct.llvm::Argument" = type { "struct.llvm::Value", "struct.llvm::Function"*, "struct.llvm::Argument"*, "struct.llvm::Argument"* } + "struct.llvm::BasicBlock" = type { "struct.llvm::Value", "struct.llvm::iplist >", "struct.llvm::BasicBlock"*, "struct.llvm::BasicBlock"* } + "struct.llvm::Constant" = type opaque + "struct.llvm::DerivedType" = type { "struct.llvm::Type", "struct.llvm::AbstractTypeUser", "struct.std::vector >" } + "struct.llvm::Function" = type { "struct.llvm::GlobalValue", "struct.llvm::Annotable", "struct.llvm::iplist >", "struct.llvm::iplist >", "struct.llvm::SymbolTable"*, "struct.llvm::Function"*, "struct.llvm::Function"* } + "struct.llvm::FunctionPass" = type { "struct.llvm::Pass" } + "struct.llvm::FunctionType" = type { "struct.llvm::DerivedType", bool } + "struct.llvm::GlobalValue" = type { "struct.llvm::User", uint, "struct.llvm::Module"* } + "struct.llvm::Instruction" = type { "struct.llvm::User", "struct.llvm::Annotable", "struct.llvm::BasicBlock"*, "struct.llvm::Instruction"*, "struct.llvm::Instruction"*, uint } + "struct.llvm::IntrinsicLowering" = type opaque + "struct.llvm::MachineBasicBlock" = type { "struct.llvm::ilist", "struct.llvm::MachineBasicBlock"*, "struct.llvm::MachineBasicBlock"*, "struct.llvm::BasicBlock"* } + "struct.llvm::MachineConstantPool" = type opaque + "struct.llvm::MachineFrameInfo" = type opaque + "struct.llvm::MachineFunction" = type { "struct.llvm::Annotation", "struct.llvm::Function"*, "struct.llvm::TargetMachine"*, "struct.llvm::iplist >", "struct.llvm::SSARegMap"*, "struct.llvm::MachineFunctionInfo"*, "struct.llvm::MachineFrameInfo"*, "struct.llvm::MachineConstantPool"* } + "struct.llvm::MachineFunctionInfo" = type { "struct.__gnu_cxx::hash_set,std::equal_to,std::allocator >", "struct.__gnu_cxx::hash_map,std::equal_to,std::allocator >", uint, uint, uint, uint, uint, uint, uint, bool, bool, bool, "struct.llvm::MachineFunction"* } + "struct.llvm::MachineFunctionPass" = type { "struct.llvm::FunctionPass" } + "struct.llvm::MachineInstr" = type { short, ubyte, "struct.std::vector >", "struct.llvm::MachineInstr"*, "struct.llvm::MachineInstr"*, "struct.llvm::MachineBasicBlock"* } + "struct.llvm::MachineInstrBuilder" = type { "struct.llvm::MachineInstr"* } + "struct.llvm::MachineOperand" = type { "union.llvm::MachineOperand::._65", int, int } + "struct.llvm::Module" = type opaque + "struct.llvm::PATypeHandle" = type { "struct.llvm::Type"*, "struct.llvm::AbstractTypeUser"* } + "struct.llvm::PATypeHolder" = type { "struct.llvm::Type"* } + "struct.llvm::Pass" = type { int (...)**, "struct.llvm::AbstractTypeUser"*, "struct.llvm::PassInfo"*, "struct.std::vector,std::allocator > >" } + "struct.llvm::PassInfo" = type { sbyte*, sbyte*, "struct.std::type_info"*, ubyte, "struct.std::vector >", "struct.llvm::Pass"* ()*, "struct.llvm::Pass"* ("struct.llvm::TargetMachine"*)* } + "struct.llvm::SSARegMap" = type opaque + "struct.llvm::SymbolTable" = type opaque + "struct.llvm::SymbolTableListTraits >" = type { "struct.llvm::Function"*, "struct.llvm::Function"* } + "struct.llvm::SymbolTableListTraits >" = type { "struct.llvm::Function"*, "struct.llvm::BasicBlock"* } + "struct.llvm::TargetData" = type { "struct.llvm::FunctionPass", bool, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte } + "struct.llvm::TargetFrameInfo" = type { int (...)**, uint, uint, int } + "struct.llvm::TargetInstrDescriptor" = type { sbyte*, int, int, uint, bool, uint, uint, uint, uint, uint, uint*, uint* } + "struct.llvm::TargetInstrInfo" = type { int (...)**, "struct.llvm::TargetInstrDescriptor"*, uint, uint } + "struct.llvm::TargetMachine" = type { int (...)**, "struct.std::basic_string,std::allocator >", "struct.llvm::TargetData", "struct.llvm::IntrinsicLowering"* } + "struct.llvm::TargetRegClassInfo" = type { int (...)**, uint, uint, uint } + "struct.llvm::TargetRegInfo" = type { int (...)**, "struct.std::vector >", "struct.llvm::TargetMachine"* } + "struct.llvm::Type" = type { "struct.llvm::Value", uint, uint, bool, uint, "struct.llvm::Type"*, "struct.std::vector >" } + "struct.llvm::Use" = type { "struct.llvm::Value"*, "struct.llvm::User"*, "struct.llvm::Use"*, "struct.llvm::Use"* } + "struct.llvm::User" = type { "struct.llvm::Value", "struct.std::vector >" } + "struct.llvm::Value" = type { int (...)**, "struct.llvm::iplist >", "struct.std::basic_string,std::allocator >", "struct.llvm::PATypeHolder", uint } + "struct.llvm::_GLOBAL__N_::InsertPrologEpilogCode" = type { "struct.llvm::MachineFunctionPass" } + "struct.llvm::ilist" = type { "struct.llvm::iplist >" } + "struct.llvm::ilist_iterator" = type { "struct.llvm::MachineBasicBlock"* } + "struct.llvm::ilist_traits" = type { "struct.llvm::SymbolTableListTraits >" } + "struct.llvm::ilist_traits" = type { "struct.llvm::SymbolTableListTraits >" } + "struct.llvm::iplist >" = type { "struct.llvm::ilist_traits", "struct.llvm::Argument"*, "struct.llvm::Argument"* } + "struct.llvm::iplist >" = type { "struct.llvm::ilist_traits", "struct.llvm::BasicBlock"*, "struct.llvm::BasicBlock"* } + "struct.llvm::iplist >" = type { "struct.llvm::ilist_traits", "struct.llvm::Instruction"*, "struct.llvm::Instruction"* } + "struct.llvm::iplist >" = type { "struct.llvm::MachineBasicBlock"*, "struct.llvm::MachineBasicBlock"* } + "struct.llvm::iplist >" = type { "struct.llvm::ilist_iterator", "struct.llvm::MachineInstr"*, "struct.llvm::MachineInstr"* } + "struct.llvm::iplist >" = type { "struct.llvm::Use"*, "struct.llvm::Use"* } + "struct.std::_Vector_alloc_base<__gnu_cxx::_Hashtable_node*,std::allocator, true>" = type { "struct.__gnu_cxx::_Hashtable_node"**, "struct.__gnu_cxx::_Hashtable_node"**, "struct.__gnu_cxx::_Hashtable_node"** } + "struct.std::_Vector_alloc_base<__gnu_cxx::_Hashtable_node >*,std::allocator, true>" = type { "struct.__gnu_cxx::_Hashtable_node >"**, "struct.__gnu_cxx::_Hashtable_node >"**, "struct.__gnu_cxx::_Hashtable_node >"** } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::PassInfo"**, "struct.llvm::PassInfo"**, "struct.llvm::PassInfo"** } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::TargetRegClassInfo"**, "struct.llvm::TargetRegClassInfo"**, "struct.llvm::TargetRegClassInfo"** } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::AbstractTypeUser"**, "struct.llvm::AbstractTypeUser"**, "struct.llvm::AbstractTypeUser"** } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::MachineInstr"**, "struct.llvm::MachineInstr"**, "struct.llvm::MachineInstr"** } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::MachineOperand"*, "struct.llvm::MachineOperand"*, "struct.llvm::MachineOperand"* } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::PATypeHandle"*, "struct.llvm::PATypeHandle"*, "struct.llvm::PATypeHandle"* } + "struct.std::_Vector_alloc_base, true>" = type { "struct.llvm::Use"*, "struct.llvm::Use"*, "struct.llvm::Use"* } + "struct.std::_Vector_alloc_base,std::allocator >, true>" = type { "struct.std::pair"*, "struct.std::pair"*, "struct.std::pair"* } + "struct.std::_Vector_base<__gnu_cxx::_Hashtable_node*,std::allocator >" = type { "struct.std::_Vector_alloc_base<__gnu_cxx::_Hashtable_node*,std::allocator, true>" } + "struct.std::_Vector_base<__gnu_cxx::_Hashtable_node >*,std::allocator >" = type { "struct.std::_Vector_alloc_base<__gnu_cxx::_Hashtable_node >*,std::allocator, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base >" = type { "struct.std::_Vector_alloc_base, true>" } + "struct.std::_Vector_base,std::allocator > >" = type { "struct.std::_Vector_alloc_base,std::allocator >, true>" } + "struct.std::basic_string,std::allocator >" = type { "struct.std::basic_string,std::allocator >::_Alloc_hider" } + "struct.std::basic_string,std::allocator >::_Alloc_hider" = type { sbyte* } + "struct.std::pair" = type { "struct.llvm::PassInfo"*, "struct.llvm::Pass"* } + "struct.std::pair" = type { "struct.llvm::Value"*, int } + "struct.std::type_info" = type { int (...)**, sbyte* } + "struct.std::vector<__gnu_cxx::_Hashtable_node*,std::allocator >" = type { "struct.std::_Vector_base<__gnu_cxx::_Hashtable_node*,std::allocator >" } + "struct.std::vector<__gnu_cxx::_Hashtable_node >*,std::allocator >" = type { "struct.std::_Vector_base<__gnu_cxx::_Hashtable_node >*,std::allocator >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector >" = type { "struct.std::_Vector_base >" } + "struct.std::vector,std::allocator > >" = type { "struct.std::_Vector_base,std::allocator > >" } + "union.llvm::MachineOperand::._65" = type { "struct.std::basic_string,std::allocator >"* } + + implementation ; Functions: + + declare void %_Znwj() + + declare void %_ZN4llvm12MachineInstrC1Esjbb() + + declare void %_ZNSt6vectorIPN4llvm12MachineInstrESaIS2_EE9push_backERKS2_() + + declare void %_ZNK4llvm8Function15getFunctionTypeEv() + + declare void %_ZNK4llvm19MachineInstrBuilder7addMRegEiNS_14MachineOperand7UseTypeE() + + declare void %_ZNK4llvm19MachineInstrBuilder7addSImmEi() + + void %_ZN4llvm11_GLOBAL__N_22InsertPrologEpilogCode20runOnMachineFunctionERNS_15MachineFunctionE("struct.llvm::MachineFunction"* %F) { + entry: + %tmp.8.i = invoke "struct.llvm::TargetFrameInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.0.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetFrameInfo"*> [#uses=0] + + invoke_catch.0.i: ; preds = %entry, %invoke_cont.0.i, %tmp.7.i.noexc.i, %endif.0.i.i, %invoke_cont.1.i, %invoke_cont.2.i, %invoke_cont.3.i, %invoke_cont.4.i, %then.0.i, %invoke_cont.i.i, %invoke_cont.7.i, %invoke_cont.8.i, %invoke_cont.9.i, %endif.0.i, %then.1.i, %invoke_cont.34.i, %invoke_cont.35.i, %then.2.i, %invoke_cont.37.i, %invoke_cont.38.i, %invoke_cont.39.i, %invoke_cont.40.i, %invoke_cont.41.i, %invoke_cont.42.i, %invoke_cont.43.i, %invoke_cont.44.i, %no_exit.i, %invoke_cont.i53.i, %invoke_cont.47.i, %invoke_cont.48.i, %invoke_cont.49.i + ret void + + invoke_cont.0.i: ; preds = %entry + %tmp.7.i1.i = invoke "struct.llvm::TargetFrameInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %tmp.7.i.noexc.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetFrameInfo"*> [#uses=2] + + tmp.7.i.noexc.i: ; preds = %invoke_cont.0.i + %tmp.17.i2.i = invoke int null( "struct.llvm::TargetFrameInfo"* %tmp.7.i1.i ) + to label %endif.0.i.i unwind label %invoke_catch.0.i ; [#uses=0] + + endif.0.i.i: ; preds = %tmp.7.i.noexc.i + %tmp.38.i4.i = invoke int null( "struct.llvm::TargetFrameInfo"* %tmp.7.i1.i ) + to label %tmp.38.i.noexc.i unwind label %invoke_catch.0.i ; [#uses=0] + + tmp.38.i.noexc.i: ; preds = %endif.0.i.i + br bool false, label %invoke_cont.1.i, label %then.1.i.i + + then.1.i.i: ; preds = %tmp.38.i.noexc.i + ret void + + invoke_cont.1.i: ; preds = %tmp.38.i.noexc.i + %tmp.21.i = invoke "struct.llvm::TargetRegInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.2.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetRegInfo"*> [#uses=1] + + invoke_cont.2.i: ; preds = %invoke_cont.1.i + %tmp.28.i = invoke uint null( "struct.llvm::TargetRegInfo"* %tmp.21.i ) + to label %invoke_cont.3.i unwind label %invoke_catch.0.i ; [#uses=0] + + invoke_cont.3.i: ; preds = %invoke_cont.2.i + %tmp.36.i = invoke "struct.llvm::TargetInstrInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.4.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetInstrInfo"*> [#uses=1] + + invoke_cont.4.i: ; preds = %invoke_cont.3.i + %tmp.43.i = invoke bool null( "struct.llvm::TargetInstrInfo"* %tmp.36.i, short 383, long 0 ) + to label %invoke_cont.5.i unwind label %invoke_catch.0.i ; [#uses=1] + + invoke_cont.5.i: ; preds = %invoke_cont.4.i + br bool %tmp.43.i, label %then.0.i, label %else.i + + then.0.i: ; preds = %invoke_cont.5.i + invoke void %_Znwj( ) + to label %tmp.0.i.noexc.i unwind label %invoke_catch.0.i + + tmp.0.i.noexc.i: ; preds = %then.0.i + invoke void %_ZN4llvm12MachineInstrC1Esjbb( ) + to label %invoke_cont.i.i unwind label %cond_true.i.i + + cond_true.i.i: ; preds = %tmp.0.i.noexc.i + ret void + + invoke_cont.i.i: ; preds = %tmp.0.i.noexc.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addMRegEiNS_14MachineOperand7UseTypeE( ) + to label %invoke_cont.7.i unwind label %invoke_catch.0.i + + invoke_cont.7.i: ; preds = %invoke_cont.i.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addSImmEi( ) + to label %invoke_cont.8.i unwind label %invoke_catch.0.i + + invoke_cont.8.i: ; preds = %invoke_cont.7.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addMRegEiNS_14MachineOperand7UseTypeE( ) + to label %invoke_cont.9.i unwind label %invoke_catch.0.i + + invoke_cont.9.i: ; preds = %invoke_cont.8.i + invoke void %_ZNSt6vectorIPN4llvm12MachineInstrESaIS2_EE9push_backERKS2_( ) + to label %endif.0.i unwind label %invoke_catch.0.i + + else.i: ; preds = %invoke_cont.5.i + ret void + + endif.0.i: ; preds = %invoke_cont.9.i + invoke void %_ZNK4llvm8Function15getFunctionTypeEv( ) + to label %invoke_cont.33.i unwind label %invoke_catch.0.i + + invoke_cont.33.i: ; preds = %endif.0.i + br bool false, label %then.1.i, label %endif.1.i + + then.1.i: ; preds = %invoke_cont.33.i + invoke void %_ZNK4llvm8Function15getFunctionTypeEv( ) + to label %invoke_cont.34.i unwind label %invoke_catch.0.i + + invoke_cont.34.i: ; preds = %then.1.i + %tmp.121.i = invoke "struct.llvm::TargetRegInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.35.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetRegInfo"*> [#uses=1] + + invoke_cont.35.i: ; preds = %invoke_cont.34.i + %tmp.128.i = invoke uint null( "struct.llvm::TargetRegInfo"* %tmp.121.i ) + to label %invoke_cont.36.i unwind label %invoke_catch.0.i ; [#uses=0] + + invoke_cont.36.i: ; preds = %invoke_cont.35.i + br bool false, label %then.2.i, label %endif.1.i + + then.2.i: ; preds = %invoke_cont.36.i + %tmp.140.i = invoke "struct.llvm::TargetRegInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.37.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetRegInfo"*> [#uses=0] + + invoke_cont.37.i: ; preds = %then.2.i + %tmp.148.i = invoke "struct.llvm::TargetRegInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.38.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetRegInfo"*> [#uses=1] + + invoke_cont.38.i: ; preds = %invoke_cont.37.i + %tmp.155.i = invoke uint null( "struct.llvm::TargetRegInfo"* %tmp.148.i, "struct.llvm::Type"* null, bool false ) + to label %invoke_cont.39.i unwind label %invoke_catch.0.i ; [#uses=0] + + invoke_cont.39.i: ; preds = %invoke_cont.38.i + %tmp.163.i = invoke "struct.llvm::TargetFrameInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.40.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetFrameInfo"*> [#uses=1] + + invoke_cont.40.i: ; preds = %invoke_cont.39.i + %tmp.170.i = invoke int null( "struct.llvm::TargetFrameInfo"* %tmp.163.i ) + to label %invoke_cont.41.i unwind label %invoke_catch.0.i ; [#uses=0] + + invoke_cont.41.i: ; preds = %invoke_cont.40.i + %tmp.177.i = invoke "struct.llvm::TargetFrameInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.42.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetFrameInfo"*> [#uses=1] + + invoke_cont.42.i: ; preds = %invoke_cont.41.i + %tmp.184.i = invoke int null( "struct.llvm::TargetFrameInfo"* %tmp.177.i ) + to label %invoke_cont.43.i unwind label %invoke_catch.0.i ; [#uses=1] + + invoke_cont.43.i: ; preds = %invoke_cont.42.i + %tmp.191.i = invoke "struct.llvm::TargetFrameInfo"* null( "struct.llvm::TargetMachine"* null ) + to label %invoke_cont.44.i unwind label %invoke_catch.0.i ; <"struct.llvm::TargetFrameInfo"*> [#uses=1] + + invoke_cont.44.i: ; preds = %invoke_cont.43.i + %tmp.198.i = invoke int null( "struct.llvm::TargetFrameInfo"* %tmp.191.i, "struct.llvm::MachineFunction"* %F, bool* null ) + to label %invoke_cont.45.i unwind label %invoke_catch.0.i ; [#uses=0] + + invoke_cont.45.i: ; preds = %invoke_cont.44.i + br bool false, label %no_exit.i, label %endif.1.i + + no_exit.i: ; preds = %invoke_cont.45.i, %invoke_cont.50.i + %nextArgOffset.0.i.1 = phi int [ %tmp.221.i, %invoke_cont.50.i ], [ 0, %invoke_cont.45.i ] ; [#uses=1] + invoke void %_Znwj( ) + to label %tmp.0.i.noexc55.i unwind label %invoke_catch.0.i + + tmp.0.i.noexc55.i: ; preds = %no_exit.i + invoke void %_ZN4llvm12MachineInstrC1Esjbb( ) + to label %invoke_cont.i53.i unwind label %cond_true.i52.i + + cond_true.i52.i: ; preds = %tmp.0.i.noexc55.i + ret void + + invoke_cont.i53.i: ; preds = %tmp.0.i.noexc55.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addMRegEiNS_14MachineOperand7UseTypeE( ) + to label %invoke_cont.47.i unwind label %invoke_catch.0.i + + invoke_cont.47.i: ; preds = %invoke_cont.i53.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addMRegEiNS_14MachineOperand7UseTypeE( ) + to label %invoke_cont.48.i unwind label %invoke_catch.0.i + + invoke_cont.48.i: ; preds = %invoke_cont.47.i + invoke void %_ZNK4llvm19MachineInstrBuilder7addSImmEi( ) + to label %invoke_cont.49.i unwind label %invoke_catch.0.i + + invoke_cont.49.i: ; preds = %invoke_cont.48.i + invoke void %_ZNSt6vectorIPN4llvm12MachineInstrESaIS2_EE9push_backERKS2_( ) + to label %invoke_cont.50.i unwind label %invoke_catch.0.i + + invoke_cont.50.i: ; preds = %invoke_cont.49.i + %tmp.221.i = add int %nextArgOffset.0.i.1, %tmp.184.i ; [#uses=1] + br bool false, label %no_exit.i, label %endif.1.i + + endif.1.i: ; preds = %invoke_cont.33.i, %invoke_cont.36.i, %invoke_cont.45.i, %invoke_cont.50.i + ret void + } + From lattner at cs.uiuc.edu Mon Apr 5 13:47:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 13:47:07 2004 Subject: [llvm-commits] CVS: llvm/lib/Analysis/ScalarEvolution.cpp Message-ID: <200404051847.NAA24838@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis: ScalarEvolution.cpp updated: 1.3 -> 1.4 --- Log message: Fix PR312: http://llvm.cs.uiuc.edu/PR312 and IndVarsSimplify/2004-04-05-InvokeCastCrash.llx --- Diffs of the changes: (+2 -0) Index: llvm/lib/Analysis/ScalarEvolution.cpp diff -u llvm/lib/Analysis/ScalarEvolution.cpp:1.3 llvm/lib/Analysis/ScalarEvolution.cpp:1.4 --- llvm/lib/Analysis/ScalarEvolution.cpp:1.3 Fri Apr 2 18:43:03 2004 +++ llvm/lib/Analysis/ScalarEvolution.cpp Mon Apr 5 13:46:55 2004 @@ -2478,6 +2478,8 @@ else if (Instruction *I = dyn_cast(V)) { // FIXME: check to see if there is already a cast! BasicBlock::iterator IP = I; ++IP; + if (InvokeInst *II = dyn_cast(I)) + IP = II->getNormalDest()->begin(); while (isa(IP)) ++IP; return new CastInst(V, Ty, V->getName(), IP); } else { From brukman at cs.uiuc.edu Mon Apr 5 14:01:03 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 14:01:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Analysis/ScalarEvolution.cpp Message-ID: <200404051900.OAA30912@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis: ScalarEvolution.cpp updated: 1.4 -> 1.5 --- Log message: Kill warnings during an optimized compile where assert() disappears. --- Diffs of the changes: (+2 -0) Index: llvm/lib/Analysis/ScalarEvolution.cpp diff -u llvm/lib/Analysis/ScalarEvolution.cpp:1.4 llvm/lib/Analysis/ScalarEvolution.cpp:1.5 --- llvm/lib/Analysis/ScalarEvolution.cpp:1.4 Mon Apr 5 13:46:55 2004 +++ llvm/lib/Analysis/ScalarEvolution.cpp Mon Apr 5 14:00:46 2004 @@ -143,10 +143,12 @@ bool SCEVCouldNotCompute::isLoopInvariant(const Loop *L) const { assert(0 && "Attempt to use a SCEVCouldNotCompute object!"); + return false; } const Type *SCEVCouldNotCompute::getType() const { assert(0 && "Attempt to use a SCEVCouldNotCompute object!"); + return 0; } bool SCEVCouldNotCompute::hasComputableLoopEvolution(const Loop *L) const { From lattner at cs.uiuc.edu Mon Apr 5 14:06:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 14:06:02 2004 Subject: [llvm-commits] CVS: llvm/lib/Analysis/ScalarEvolution.cpp Message-ID: <200404051905.OAA03091@zion.cs.uiuc.edu> Changes in directory llvm/lib/Analysis: ScalarEvolution.cpp updated: 1.5 -> 1.6 --- Log message: Sparc don't got not "sqrtl", bum bum bum --- Diffs of the changes: (+1 -1) Index: llvm/lib/Analysis/ScalarEvolution.cpp diff -u llvm/lib/Analysis/ScalarEvolution.cpp:1.5 llvm/lib/Analysis/ScalarEvolution.cpp:1.6 --- llvm/lib/Analysis/ScalarEvolution.cpp:1.5 Mon Apr 5 14:00:46 2004 +++ llvm/lib/Analysis/ScalarEvolution.cpp Mon Apr 5 14:05:15 2004 @@ -2042,7 +2042,7 @@ cast(ConstantExpr::getCast(SqrtTerm, SqrtTerm->getType()->getUnsignedVersion())); uint64_t SqrtValV = SqrtVal->getValue(); - uint64_t SqrtValV2 = (uint64_t)sqrtl(SqrtValV); + uint64_t SqrtValV2 = (uint64_t)sqrt(SqrtValV); // The square root might not be precise for arbitrary 64-bit integer // values. Do some sanity checks to ensure it's correct. if (SqrtValV2*SqrtValV2 > SqrtValV || From lattner at cs.uiuc.edu Mon Apr 5 14:32:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 14:32:03 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/CodeGeneratorBug.cpp Message-ID: <200404051931.OAA15939@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: CodeGeneratorBug.cpp updated: 1.41 -> 1.42 --- Log message: Make full use of the Mangler interface to simplify code --- Diffs of the changes: (+9 -63) Index: llvm/tools/bugpoint/CodeGeneratorBug.cpp diff -u llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.41 llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.42 --- llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.41 Sun Apr 4 20:31:50 2004 +++ llvm/tools/bugpoint/CodeGeneratorBug.cpp Mon Apr 5 14:31:02 2004 @@ -30,8 +30,6 @@ #include "Support/Debug.h" #include "Support/StringExtras.h" #include "Support/FileUtilities.h" -#include -#include using namespace llvm; namespace llvm { @@ -255,71 +253,19 @@ return Result; } -namespace { - struct Disambiguator { - std::set SymbolNames; - std::set Symbols; - uint64_t uniqueCounter; - bool externalOnly; - public: - Disambiguator() : uniqueCounter(0), externalOnly(true) {} - void setExternalOnly(bool value) { externalOnly = value; } - void add(GlobalValue &V) { - // If we're only processing externals and this isn't external, bail - if (externalOnly && !V.isExternal()) return; - // If we're already processed this symbol, don't add it again - if (Symbols.count(&V) != 0) return; - // Ignore intrinsic functions - if (Function *F = dyn_cast(&V)) - if (F->getIntrinsicID() != 0) - return; - - std::string SymName = V.getName(); - - // Use the Mangler facility to make symbol names that will be valid in - // shared objects. - SymName = Mangler::makeNameProper(SymName); - V.setName(SymName); - - if (SymbolNames.count(SymName) == 0) { - DEBUG(std::cerr << "Disambiguator: adding " << SymName - << ", no conflicts.\n"); - SymbolNames.insert(SymName); - } else { - // Mangle name before adding - std::string newName; - do { - newName = SymName + "_" + utostr(uniqueCounter); - if (SymbolNames.count(newName) == 0) break; - else ++uniqueCounter; - } while (1); - //while (SymbolNames.count(V->getName()+utostr(uniqueCounter++))==0); - DEBUG(std::cerr << "Disambiguator: conflict: " << SymName - << ", adding: " << newName << "\n"); - V.setName(newName); - SymbolNames.insert(newName); - } - Symbols.insert(&V); - } - }; -} - static void DisambiguateGlobalSymbols(Module *M) { - // First, try not to cause collisions by minimizing chances of renaming an + // Try not to cause collisions by minimizing chances of renaming an // already-external symbol, so take in external globals and functions as-is. - Disambiguator D; + // The code should work correctly without disambiguation (assuming the same + // mangler is used by the two code generators), but having symbols with the + // same name causes warnings to be emitted by the code generator. + Mangler Mang(*M); DEBUG(std::cerr << "Disambiguating globals (external-only)\n"); - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) D.add(*I); + for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) + I->setName(Mang.getValueName(I)); DEBUG(std::cerr << "Disambiguating functions (external-only)\n"); - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) D.add(*I); - - // Now just rename functions and globals as necessary, keeping what's already - // in the set unique. - D.setExternalOnly(false); - DEBUG(std::cerr << "Disambiguating globals\n"); - for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) D.add(*I); - DEBUG(std::cerr << "Disambiguating globals\n"); - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) D.add(*I); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + I->setName(Mang.getValueName(I)); } From lattner at cs.uiuc.edu Mon Apr 5 15:18:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 15:18:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Support/Mangler.cpp Message-ID: <200404052018.PAA16198@zion.cs.uiuc.edu> Changes in directory llvm/lib/Support: Mangler.cpp updated: 1.10 -> 1.11 --- Log message: Do not mangle intrinsics in any way! --- Diffs of the changes: (+4 -1) Index: llvm/lib/Support/Mangler.cpp diff -u llvm/lib/Support/Mangler.cpp:1.10 llvm/lib/Support/Mangler.cpp:1.11 --- llvm/lib/Support/Mangler.cpp:1.10 Fri Feb 13 18:30:23 2004 +++ llvm/lib/Support/Mangler.cpp Mon Apr 5 15:17:53 2004 @@ -56,13 +56,16 @@ std::string name; if (V->hasName()) { // Print out the label if it exists... // Name mangling occurs as follows: + // - If V is an intrinsic function, do not change name at all // - If V is not a global, mangling always occurs. // - Otherwise, mangling occurs when any of the following are true: // 1) V has internal linkage // 2) V's name would collide if it is not mangled. // const GlobalValue* gv = dyn_cast(V); - if (gv && !gv->hasInternalLinkage() && !MangledGlobals.count(gv)) { + if (gv && isa(gv) && cast(gv)->getIntrinsicID()) { + name = gv->getName(); // Is an intrinsic function + } else if (gv && !gv->hasInternalLinkage() && !MangledGlobals.count(gv)) { name = makeNameProper(gv->getName()); if (AddUnderscorePrefix) name = "_" + name; } else { From lattner at cs.uiuc.edu Mon Apr 5 15:29:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 15:29:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Support/ToolRunner.cpp Message-ID: <200404052028.PAA18005@zion.cs.uiuc.edu> Changes in directory llvm/lib/Support: ToolRunner.cpp updated: 1.21 -> 1.22 --- Log message: lli no longer takes the -quiet option! --- Diffs of the changes: (+0 -2) Index: llvm/lib/Support/ToolRunner.cpp diff -u llvm/lib/Support/ToolRunner.cpp:1.21 llvm/lib/Support/ToolRunner.cpp:1.22 --- llvm/lib/Support/ToolRunner.cpp:1.21 Thu Feb 19 01:39:26 2004 +++ llvm/lib/Support/ToolRunner.cpp Mon Apr 5 15:28:41 2004 @@ -78,7 +78,6 @@ std::vector LLIArgs; LLIArgs.push_back(LLIPath.c_str()); - LLIArgs.push_back("-quiet"); LLIArgs.push_back("-force-interpreter=true"); LLIArgs.push_back(Bytecode.c_str()); // Add optional parameters to the running program from Argv @@ -195,7 +194,6 @@ // Construct a vector of parameters, incorporating those from the command-line std::vector JITArgs; JITArgs.push_back(LLIPath.c_str()); - JITArgs.push_back("-quiet"); JITArgs.push_back("-force-interpreter=false"); for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { From lattner at cs.uiuc.edu Mon Apr 5 16:38:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 16:38:01 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/CodeGeneratorBug.cpp Message-ID: <200404052138.QAA27767@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: CodeGeneratorBug.cpp updated: 1.42 -> 1.43 --- Log message: Minor cleanups, remove some old debug code --- Diffs of the changes: (+13 -43) Index: llvm/tools/bugpoint/CodeGeneratorBug.cpp diff -u llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.42 llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.43 --- llvm/tools/bugpoint/CodeGeneratorBug.cpp:1.42 Mon Apr 5 14:31:02 2004 +++ llvm/tools/bugpoint/CodeGeneratorBug.cpp Mon Apr 5 16:37:55 2004 @@ -100,16 +100,11 @@ !TestModule->getNamedFunction(F->getName())->isExternal()) { // If it has a non-zero use list, // 1. Add a string constant with its name to the global file - // The correct type is `const [ NUM x sbyte ]' where NUM is length of - // function name + 1 - const std::string &Name = F->getName(); + Constant *InitArray = ConstantArray::get(F->getName()); GlobalVariable *funcName = - new GlobalVariable(ArrayType::get(Type::SByteTy, Name.length()+1), - true /* isConstant */, - GlobalValue::InternalLinkage, - ConstantArray::get(Name), - Name + "_name", - SafeModule); + new GlobalVariable(InitArray->getType(), true /* isConstant */, + GlobalValue::InternalLinkage, InitArray, + F->getName() + "_name", SafeModule); // 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an // sbyte* so it matches the signature of the resolver function. @@ -156,30 +151,6 @@ abort(); } - DEBUG(std::cerr << "Safe module:\n"; - typedef Module::iterator MI; - typedef Module::giterator MGI; - - for (MI I = SafeModule->begin(), E = SafeModule->end(); I != E; ++I) - if (!I->isExternal()) std::cerr << "\t" << I->getName() << "\n"; - for (MGI I = SafeModule->gbegin(), E = SafeModule->gend(); I!=E; ++I) - if (!I->isExternal()) std::cerr << "\t" << I->getName() << "\n"; - - std::cerr << "Test module:\n"; - for (MI I = TestModule->begin(), E = TestModule->end(); I != E; ++I) - if (!I->isExternal()) std::cerr << "\t" << I->getName() << "\n"; - for (MGI I=TestModule->gbegin(),E = TestModule->gend(); I!= E; ++I) - if (!I->isExternal()) std::cerr << "\t" << I->getName() << "\n"; - ); - - // Write out the bytecode to be sent to CBE - std::string SafeModuleBC = getUniqueFilename("bugpoint.safe.bc"); - - if (BD.writeProgramToFile(SafeModuleBC, SafeModule)) { - std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting."; - exit(1); - } - // Remove all functions from the Test module EXCEPT for the ones specified in // Funcs. We know which ones these are because they are non-external in // ToOptimize, but external in ToNotOptimize. @@ -193,26 +164,25 @@ DeleteFunctionBody(I); } + // Clean up the modules, removing extra cruft that we don't need anymore... + TestModule = BD.performFinalCleanups(TestModule); + std::string TestModuleBC = getUniqueFilename("bugpoint.test.bc"); - if (verifyModule(*TestModule)) { - std::cerr << "Bytecode file corrupted!\n"; + if (BD.writeProgramToFile(TestModuleBC, TestModule)) { + std::cerr << "Error writing bytecode to `" << TestModuleBC << "'\nExiting."; exit(1); } + delete TestModule; - // Clean up the modules, removing extra cruft that we don't need anymore... - SafeModule = BD.performFinalCleanups(SafeModule); - TestModule = BD.performFinalCleanups(TestModule); + // Make the shared library + std::string SafeModuleBC = getUniqueFilename("bugpoint.safe.bc"); - if (BD.writeProgramToFile(TestModuleBC, TestModule)) { + if (BD.writeProgramToFile(SafeModuleBC, SafeModule)) { std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting."; exit(1); } - - // Make a shared library std::string SharedObject = BD.compileSharedObject(SafeModuleBC); - delete SafeModule; - delete TestModule; // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. From lattner at cs.uiuc.edu Mon Apr 5 16:39:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 16:39:01 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/Miscompilation.cpp Message-ID: <200404052138.QAA27772@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: Miscompilation.cpp updated: 1.35 -> 1.36 --- Log message: Refactor and genericize code --- Diffs of the changes: (+71 -55) Index: llvm/tools/bugpoint/Miscompilation.cpp diff -u llvm/tools/bugpoint/Miscompilation.cpp:1.35 llvm/tools/bugpoint/Miscompilation.cpp:1.36 --- llvm/tools/bugpoint/Miscompilation.cpp:1.35 Fri Apr 2 00:32:45 2004 +++ llvm/tools/bugpoint/Miscompilation.cpp Mon Apr 5 16:37:38 2004 @@ -124,8 +124,11 @@ namespace { class ReduceMiscompilingFunctions : public ListReducer { BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *, Module *); public: - ReduceMiscompilingFunctions(BugDriver &bd) : BD(bd) {} + ReduceMiscompilingFunctions(BugDriver &bd, + bool (*F)(BugDriver &, Module *, Module *)) + : BD(bd), TestFn(F) {} virtual TestResult doTest(std::vector &Prefix, std::vector &Suffix) { @@ -183,25 +186,15 @@ Module *ToNotOptimize = CloneModule(BD.getProgram()); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, Funcs); - // Run the optimization passes on ToOptimize, producing a transformed version - // of the functions being tested. - std::cout << " Optimizing functions being tested: "; - Module *Optimized = BD.runPassesOn(ToOptimize, BD.getPassesToRun(), - /*AutoDebugCrashes*/true); - std::cout << "done.\n"; - delete ToOptimize; - - - std::cout << " Checking to see if the merged program executes correctly: "; - bool Broken = TestMergedProgram(BD, Optimized, ToNotOptimize, true); - std::cout << (Broken ? " nope.\n" : " yup.\n"); - return Broken; + // Run the predicate, not that the predicate will delete both input modules. + return TestFn(BD, ToOptimize, ToNotOptimize); } /// ExtractLoops - Given a reduced list of functions that still exposed the bug, /// check to see if we can extract the loops in the region without obscuring the /// bug. If so, it reduces the amount of code identified. -static bool ExtractLoops(BugDriver &BD, +static bool ExtractLoops(BugDriver &BD, + bool (*TestFn)(BugDriver &, Module *, Module *), std::vector &MiscompiledFunctions) { bool MadeChange = false; while (1) { @@ -235,27 +228,22 @@ return MadeChange; } - // Okay, the loop extractor didn't break the program. Run the series of - // optimizations on the loop extracted portion and see if THEY still break - // the program. If so, it was safe to extract these loops! - std::cout << " Running optimizations on loop extracted portion: "; - Module *Optimized = BD.runPassesOn(ToOptimizeLoopExtracted, - BD.getPassesToRun(), - /*AutoDebugCrashes*/true); - std::cout << "done.\n"; - - std::cout << " Checking to see if the merged program executes correctly: "; - bool Broken = TestMergedProgram(BD, Optimized, ToNotOptimize, false); - delete Optimized; - if (!Broken) { - std::cout << "yup: loop extraction masked the problem. Undoing.\n"; + std::cout << " Testing after loop extraction:\n"; + // Clone modules, the tester function will free them. + Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); + Module *TNOBackup = CloneModule(ToNotOptimize); + if (!TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize)) { + std::cout << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. - delete ToNotOptimize; - delete ToOptimizeLoopExtracted; + delete TOLEBackup; + delete TNOBackup; return MadeChange; } - std::cout << "nope: loop extraction successful!\n"; + ToOptimizeLoopExtracted = TOLEBackup; + ToNotOptimize = TNOBackup; + + std::cout << "*** Loop extraction successful!\n"; // Okay, great! Now we know that we extracted a loop and that loop // extraction both didn't break the program, and didn't mask the problem. @@ -288,34 +276,23 @@ } } -/// debugMiscompilation - This method is used when the passes selected are not -/// crashing, but the generated output is semantically different from the -/// input. -/// -bool BugDriver::debugMiscompilation() { - // Make sure something was miscompiled... - if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { - std::cerr << "*** Optimized program matches reference output! No problem " - << "detected...\nbugpoint can't help you with your problem!\n"; - return false; - } - - std::cout << "\n*** Found miscompiling pass" - << (getPassesToRun().size() == 1 ? "" : "es") << ": " - << getPassesString(getPassesToRun()) << "\n"; - EmitProgressBytecode("passinput"); - +/// DebugAMiscompilation - This is a generic driver to narrow down +/// miscompilations, either in an optimization or a code generator. +static std::vector +DebugAMiscompilation(BugDriver &BD, + bool (*TestFn)(BugDriver &, Module *, Module *)) { // Okay, now that we have reduced the list of passes which are causing the // failure, see if we can pin down which functions are being // miscompiled... first build a list of all of the non-external functions in // the program. std::vector MiscompiledFunctions; - for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I) + Module *Prog = BD.getProgram(); + for (Module::iterator I = Prog->begin(), E = Prog->end(); I != E; ++I) if (!I->isExternal()) MiscompiledFunctions.push_back(I); // Do the reduction... - ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions); + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); std::cout << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -325,12 +302,12 @@ // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. - if (ExtractLoops(*this, MiscompiledFunctions)) { + if (ExtractLoops(BD, TestFn, MiscompiledFunctions)) { // Okay, we extracted some loops and the problem still appears. See if we // can eliminate some of the created functions from being candidates. // Do the reduction... - ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions); + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); std::cout << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -339,6 +316,45 @@ std::cout << "\n"; } + return MiscompiledFunctions; +} + +static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { + // Run the optimization passes on ToOptimize, producing a transformed version + // of the functions being tested. + std::cout << " Optimizing functions being tested: "; + Module *Optimized = BD.runPassesOn(Test, BD.getPassesToRun(), + /*AutoDebugCrashes*/true); + std::cout << "done.\n"; + delete Test; + + std::cout << " Checking to see if the merged program executes correctly: "; + bool Broken = TestMergedProgram(BD, Test, Safe, true); + std::cout << (Broken ? " nope.\n" : " yup.\n"); + return Broken; +} + + +/// debugMiscompilation - This method is used when the passes selected are not +/// crashing, but the generated output is semantically different from the +/// input. +/// +bool BugDriver::debugMiscompilation() { + // Make sure something was miscompiled... + if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { + std::cerr << "*** Optimized program matches reference output! No problem " + << "detected...\nbugpoint can't help you with your problem!\n"; + return false; + } + + std::cout << "\n*** Found miscompiling pass" + << (getPassesToRun().size() == 1 ? "" : "es") << ": " + << getPassesString(getPassesToRun()) << "\n"; + EmitProgressBytecode("passinput"); + + std::vector MiscompiledFunctions = + DebugAMiscompilation(*this, TestOptimizer); + // Output a bunch of bytecode files for the user... std::cout << "Outputting reduced bytecode files which expose the problem:\n"; Module *ToNotOptimize = CloneModule(getProgram()); @@ -346,12 +362,12 @@ MiscompiledFunctions); std::cout << " Non-optimized portion: "; - std::swap(Program, ToNotOptimize); + ToNotOptimize = swapProgramIn(ToNotOptimize); EmitProgressBytecode("tonotoptimize", true); setNewProgram(ToNotOptimize); // Delete hacked module. std::cout << " Portion that is input to optimizer: "; - std::swap(Program, ToOptimize); + ToOptimize = swapProgramIn(ToOptimize); EmitProgressBytecode("tooptimize"); setNewProgram(ToOptimize); // Delete hacked module. From lattner at cs.uiuc.edu Mon Apr 5 17:02:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 17:02:01 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/BugDriver.h Message-ID: <200404052201.RAA30849@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: BugDriver.h updated: 1.35 -> 1.36 --- Log message: Make a method public --- Diffs of the changes: (+2 -1) Index: llvm/tools/bugpoint/BugDriver.h diff -u llvm/tools/bugpoint/BugDriver.h:1.35 llvm/tools/bugpoint/BugDriver.h:1.36 --- llvm/tools/bugpoint/BugDriver.h:1.35 Sun Mar 14 15:21:57 2004 +++ llvm/tools/bugpoint/BugDriver.h Mon Apr 5 17:01:48 2004 @@ -209,12 +209,13 @@ bool runPasses(const std::vector &PassesToRun, std::string &OutputFilename, bool DeleteOutput = false, bool Quiet = false) const; -private: + /// writeProgramToFile - This writes the current "Program" to the named /// bytecode file. If an error occurs, true is returned. /// bool writeProgramToFile(const std::string &Filename, Module *M = 0) const; +private: /// runPasses - Just like the method above, but this just returns true or /// false indicating whether or not the optimizer crashed on the specified /// input (true = crashed). From lattner at cs.uiuc.edu Mon Apr 5 17:59:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 17:59:02 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/BugDriver.h Miscompilation.cpp CodeGeneratorBug.cpp Message-ID: <200404052258.RAA14662@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: BugDriver.h updated: 1.36 -> 1.37 Miscompilation.cpp updated: 1.36 -> 1.37 CodeGeneratorBug.cpp (r1.43) removed --- Log message: Merge the code generator miscompilation code into the optimizer miscompilation code. This "instantly" gives us loop-extractor power to assist with the debugment of our nasty codegen issues. :) --- Diffs of the changes: (+265 -1) Index: llvm/tools/bugpoint/BugDriver.h diff -u llvm/tools/bugpoint/BugDriver.h:1.36 llvm/tools/bugpoint/BugDriver.h:1.37 --- llvm/tools/bugpoint/BugDriver.h:1.36 Mon Apr 5 17:01:48 2004 +++ llvm/tools/bugpoint/BugDriver.h Mon Apr 5 17:58:16 2004 @@ -129,6 +129,16 @@ return OldProgram; } + AbstractInterpreter *switchToCBE() { + AbstractInterpreter *Old = Interpreter; + Interpreter = (AbstractInterpreter*)cbe; + return Old; + } + + void switchToInterpreter(AbstractInterpreter *AI) { + Interpreter = AI; + } + /// setNewProgram - If we reduce or update the program somehow, call this /// method to update bugdriver with it. This deletes the old module and sets /// the specified one as the current program. Index: llvm/tools/bugpoint/Miscompilation.cpp diff -u llvm/tools/bugpoint/Miscompilation.cpp:1.36 llvm/tools/bugpoint/Miscompilation.cpp:1.37 --- llvm/tools/bugpoint/Miscompilation.cpp:1.36 Mon Apr 5 16:37:38 2004 +++ llvm/tools/bugpoint/Miscompilation.cpp Mon Apr 5 17:58:16 2004 @@ -7,19 +7,30 @@ // //===----------------------------------------------------------------------===// // -// This file implements program miscompilation debugging support. +// This file implements optimizer and code generation miscompilation debugging +// support. // //===----------------------------------------------------------------------===// #include "BugDriver.h" #include "ListReducer.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Pass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/Mangler.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Linker.h" +#include "Support/CommandLine.h" #include "Support/FileUtilities.h" using namespace llvm; +namespace llvm { + extern cl::list InputArgv; +} + namespace { class ReduceMiscompilingPasses : public ListReducer { BugDriver &BD; @@ -218,7 +229,10 @@ // we're going to test the newly loop extracted program to make sure nothing // has broken. If something broke, then we'll inform the user and stop // extraction. + AbstractInterpreter *AI = BD.switchToCBE(); if (TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false)) { + BD.switchToInterpreter(AI); + // Merged program doesn't work anymore! std::cerr << " *** ERROR: Loop extraction broke the program. :(" << " Please report a bug!\n"; @@ -227,6 +241,7 @@ delete ToOptimizeLoopExtracted; return MadeChange; } + BD.switchToInterpreter(AI); std::cout << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. @@ -319,6 +334,9 @@ return MiscompiledFunctions; } +/// TestOptimizer - This is the predicate function used to check to see if the +/// "Test" portion of the program is misoptimized. If so, return true. In any +/// case, both module arguments are deleted. static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. @@ -374,3 +392,239 @@ return false; } +/// CleanupAndPrepareModules - Get the specified modules ready for code +/// generator testing. +static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, + Module *Safe) { + // Clean up the modules, removing extra cruft that we don't need anymore... + Test = BD.performFinalCleanups(Test); + + // If we are executing the JIT, we have several nasty issues to take care of. + if (!BD.isExecutingJIT()) return; + + // First, if the main function is in the Safe module, we must add a stub to + // the Test module to call into it. Thus, we create a new function `main' + // which just calls the old one. + if (Function *oldMain = Safe->getNamedFunction("main")) + if (!oldMain->isExternal()) { + // Rename it + oldMain->setName("llvm_bugpoint_old_main"); + // Create a NEW `main' function with same type in the test module. + Function *newMain = new Function(oldMain->getFunctionType(), + GlobalValue::ExternalLinkage, + "main", Test); + // Create an `oldmain' prototype in the test module, which will + // corresponds to the real main function in the same module. + Function *oldMainProto = new Function(oldMain->getFunctionType(), + GlobalValue::ExternalLinkage, + oldMain->getName(), Test); + // Set up and remember the argument list for the main function. + std::vector args; + for (Function::aiterator I = newMain->abegin(), E = newMain->aend(), + OI = oldMain->abegin(); I != E; ++I, ++OI) { + I->setName(OI->getName()); // Copy argument names from oldMain + args.push_back(I); + } + + // Call the old main function and return its result + BasicBlock *BB = new BasicBlock("entry", newMain); + CallInst *call = new CallInst(oldMainProto, args); + BB->getInstList().push_back(call); + + // If the type of old function wasn't void, return value of call + new ReturnInst(oldMain->getReturnType() != Type::VoidTy ? call : 0, BB); + } + + // The second nasty issue we must deal with in the JIT is that the Safe + // module cannot directly reference any functions defined in the test + // module. Instead, we use a JIT API call to dynamically resolve the + // symbol. + + // Add the resolver to the Safe module. + // Prototype: void *getPointerToNamedFunction(const char* Name) + Function *resolverFunc = + Safe->getOrInsertFunction("getPointerToNamedFunction", + PointerType::get(Type::SByteTy), + PointerType::get(Type::SByteTy), 0); + + // Use the function we just added to get addresses of functions we need. + for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F){ + if (F->isExternal() && !F->use_empty() && &*F != resolverFunc && + F->getIntrinsicID() == 0 /* ignore intrinsics */) { + Function *TestFn =Test->getFunction(F->getName(), F->getFunctionType()); + + // Don't forward functions which are external in the test module too. + if (TestFn && !TestFn->isExternal()) { + // 1. Add a string constant with its name to the global file + Constant *InitArray = ConstantArray::get(F->getName()); + GlobalVariable *funcName = + new GlobalVariable(InitArray->getType(), true /*isConstant*/, + GlobalValue::InternalLinkage, InitArray, + F->getName() + "_name", Safe); + + // 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an + // sbyte* so it matches the signature of the resolver function. + + // GetElementPtr *funcName, ulong 0, ulong 0 + std::vector GEPargs(2,Constant::getNullValue(Type::IntTy)); + Value *GEP = + ConstantExpr::getGetElementPtr(ConstantPointerRef::get(funcName), + GEPargs); + std::vector ResolverArgs; + ResolverArgs.push_back(GEP); + + // 3. Replace all uses of `func' with calls to resolver by: + // (a) Iterating through the list of uses of this function + // (b) Insert a cast instruction in front of each use + // (c) Replace use of old call with new call + + // Insert code at the beginning of the function + while (!F->use_empty()) + if (Instruction *Inst = dyn_cast(F->use_back())) { + // call resolver(GetElementPtr...) + CallInst *resolve = new CallInst(resolverFunc, ResolverArgs, + "resolver", Inst); + // cast the result from the resolver to correctly-typed function + CastInst *castResolver = + new CastInst(resolve, PointerType::get(F->getFunctionType()), + "resolverCast", Inst); + // actually use the resolved function + Inst->replaceUsesOfWith(F, castResolver); + } else { + // FIXME: need to take care of cases where a function is used by + // something other than an instruction; e.g., global variable + // initializers and constant expressions. + std::cerr << "UNSUPPORTED: Non-instruction is using an external " + << "function, " << F->getName() << "().\n"; + abort(); + } + } + } + } + + if (verifyModule(*Test) || verifyModule(*Safe)) { + std::cerr << "Bugpoint has a bug, which corrupted a module!!\n"; + abort(); + } +} + + + +/// TestCodeGenerator - This is the predicate function used to check to see if +/// the "Test" portion of the program is miscompiled by the code generator under +/// test. If so, return true. In any case, both module arguments are deleted. +static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { + CleanupAndPrepareModules(BD, Test, Safe); + + std::string TestModuleBC = getUniqueFilename("bugpoint.test.bc"); + if (BD.writeProgramToFile(TestModuleBC, Test)) { + std::cerr << "Error writing bytecode to `" << TestModuleBC << "'\nExiting."; + exit(1); + } + delete Test; + + // Make the shared library + std::string SafeModuleBC = getUniqueFilename("bugpoint.safe.bc"); + + if (BD.writeProgramToFile(SafeModuleBC, Safe)) { + std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting."; + exit(1); + } + std::string SharedObject = BD.compileSharedObject(SafeModuleBC); + delete Safe; + + // Run the code generator on the `Test' code, loading the shared library. + // The function returns whether or not the new output differs from reference. + int Result = BD.diffProgram(TestModuleBC, SharedObject, false); + + if (Result) + std::cerr << ": still failing!\n"; + else + std::cerr << ": didn't fail.\n"; + removeFile(TestModuleBC); + removeFile(SafeModuleBC); + removeFile(SharedObject); + + return Result; +} + + + +static void DisambiguateGlobalSymbols(Module *M) { + // Try not to cause collisions by minimizing chances of renaming an + // already-external symbol, so take in external globals and functions as-is. + // The code should work correctly without disambiguation (assuming the same + // mangler is used by the two code generators), but having symbols with the + // same name causes warnings to be emitted by the code generator. + Mangler Mang(*M); + for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I) + I->setName(Mang.getValueName(I)); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + I->setName(Mang.getValueName(I)); +} + + + +bool BugDriver::debugCodeGenerator() { + if ((void*)cbe == (void*)Interpreter) { + std::string Result = executeProgramWithCBE("bugpoint.cbe.out"); + std::cout << "\n*** The C backend cannot match the reference diff, but it " + << "is used as the 'known good'\n code generator, so I can't" + << " debug it. Perhaps you have a front-end problem?\n As a" + << " sanity check, I left the result of executing the program " + << "with the C backend\n in this file for you: '" + << Result << "'.\n"; + return true; + } + + DisambiguateGlobalSymbols(Program); + + std::vector Funcs = DebugAMiscompilation(*this, TestCodeGenerator); + + // Split the module into the two halves of the program we want. + Module *ToNotCodeGen = CloneModule(getProgram()); + Module *ToCodeGen = SplitFunctionsOutOfModule(ToNotCodeGen, Funcs); + + // Condition the modules + CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen); + + std::string TestModuleBC = getUniqueFilename("bugpoint.test.bc"); + if (writeProgramToFile(TestModuleBC, ToCodeGen)) { + std::cerr << "Error writing bytecode to `" << TestModuleBC << "'\nExiting."; + exit(1); + } + delete ToCodeGen; + + // Make the shared library + std::string SafeModuleBC = getUniqueFilename("bugpoint.safe.bc"); + if (writeProgramToFile(SafeModuleBC, ToNotCodeGen)) { + std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting."; + exit(1); + } + std::string SharedObject = compileSharedObject(SafeModuleBC); + delete ToNotCodeGen; + + std::cout << "You can reproduce the problem with the command line: \n"; + if (isExecutingJIT()) { + std::cout << " lli -load " << SharedObject << " " << TestModuleBC; + } else { + std::cout << " llc " << TestModuleBC << " -o " << TestModuleBC << ".s\n"; + std::cout << " gcc " << SharedObject << " " << TestModuleBC + << ".s -o " << TestModuleBC << ".exe -Wl,-R.\n"; + std::cout << " " << TestModuleBC << ".exe"; + } + for (unsigned i=0, e = InputArgv.size(); i != e; ++i) + std::cout << " " << InputArgv[i]; + std::cout << "\n"; + std::cout << "The shared object was created with:\n llc -march=c " + << SafeModuleBC << " -o temporary.c\n" + << " gcc -xc temporary.c -O2 -o " << SharedObject +#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) + << " -G" // Compile a shared library, `-G' for Sparc +#else + << " -shared" // `-shared' for Linux/X86, maybe others +#endif + << " -fno-strict-aliasing\n"; + + return false; +} From lattner at cs.uiuc.edu Mon Apr 5 20:21:28 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 20:21:28 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060121.UAA16947@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.204 -> 1.205 --- Log message: Two changes: * In promote32, if we can just promote a constant value, do so instead of promoting a constant dynamically. * In visitReturn inst, actually USE the promote32 argument that takes a Value* The end result of this is that we now generate this: test: mov %EAX, 0 ret instead of... test: mov %AX, 0 movzx %EAX, %AX ret for: ushort %test() { ret ushort 0 } --- Diffs of the changes: (+17 -6) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.204 llvm/lib/Target/X86/InstSelectSimple.cpp:1.205 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.204 Sun Apr 4 20:29:31 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 20:21:00 2004 @@ -1107,10 +1107,18 @@ void ISel::promote32(unsigned targetReg, const ValueRecord &VR) { bool isUnsigned = VR.Ty->isUnsigned(); + Value *Val = VR.Val; + const Type *Ty = VR.Ty; + if (Val) + if (Constant *C = dyn_cast(Val)) { + Val = ConstantExpr::getCast(C, Type::IntTy); + Ty = Type::IntTy; + } + // Make sure we have the register number for this value... - unsigned Reg = VR.Val ? getReg(VR.Val) : VR.Reg; + unsigned Reg = Val ? getReg(Val) : VR.Reg; - switch (getClassB(VR.Ty)) { + switch (getClassB(Ty)) { case cByte: // Extend value into target register (8->32) if (isUnsigned) @@ -1152,27 +1160,30 @@ } Value *RetVal = I.getOperand(0); - unsigned RetReg = getReg(RetVal); switch (getClassB(RetVal->getType())) { case cByte: // integral return values: extend or move into EAX and return case cShort: case cInt: - promote32(X86::EAX, ValueRecord(RetReg, RetVal->getType())); + promote32(X86::EAX, ValueRecord(RetVal)); // Declare that EAX is live on exit BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::EAX).addReg(X86::ESP); break; - case cFP: // Floats & Doubles: Return in ST(0) + case cFP: { // Floats & Doubles: Return in ST(0) + unsigned RetReg = getReg(RetVal); BuildMI(BB, X86::FpSETRESULT, 1).addReg(RetReg); // Declare that top-of-stack is live on exit BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::ST0).addReg(X86::ESP); break; - case cLong: + } + case cLong: { + unsigned RetReg = getReg(RetVal); BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(RetReg); BuildMI(BB, X86::MOV32rr, 1, X86::EDX).addReg(RetReg+1); // Declare that EAX & EDX are live on exit BuildMI(BB, X86::IMPLICIT_USE, 3).addReg(X86::EAX).addReg(X86::EDX) .addReg(X86::ESP); break; + } default: visitInstruction(I); } From lattner at cs.uiuc.edu Mon Apr 5 20:26:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 20:26:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060125.UAA17268@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.205 -> 1.206 --- Log message: Minor tweak to avoid an extra reg-reg copy that the register allocator has to eliminate --- Diffs of the changes: (+10 -1) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.205 llvm/lib/Target/X86/InstSelectSimple.cpp:1.206 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.205 Mon Apr 5 20:21:00 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 20:25:33 2004 @@ -1109,11 +1109,20 @@ Value *Val = VR.Val; const Type *Ty = VR.Ty; - if (Val) + if (Val) { if (Constant *C = dyn_cast(Val)) { Val = ConstantExpr::getCast(C, Type::IntTy); Ty = Type::IntTy; } + + // If this is a simple constant, just emit a MOVri directly to avoid the + // copy. + if (ConstantInt *CI = dyn_cast(Val)) { + int TheVal = CI->getRawValue() & 0xFFFFFFFF; + BuildMI(BB, X86::MOV32ri, 1, targetReg).addImm(TheVal); + return; + } + } // Make sure we have the register number for this value... unsigned Reg = Val ? getReg(Val) : VR.Reg; From lattner at cs.uiuc.edu Mon Apr 5 20:49:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 20:49:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060148.UAA17701@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.206 -> 1.207 --- Log message: Implement negation of longs efficiently. For this testcase: long %test(long %X) { %Y = sub long 0, %X ret long %Y } We used to generate: test: sub %ESP, 4 mov DWORD PTR [%ESP], %ESI mov %ECX, DWORD PTR [%ESP + 8] mov %ESI, DWORD PTR [%ESP + 12] mov %EAX, 0 mov %EDX, 0 sub %EAX, %ECX sbb %EDX, %ESI mov %ESI, DWORD PTR [%ESP] add %ESP, 4 ret Now we generate: test: mov %EAX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] neg %EAX adc %EDX, 0 neg %EDX ret --- Diffs of the changes: (+11 -2) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.206 llvm/lib/Target/X86/InstSelectSimple.cpp:1.207 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.206 Mon Apr 5 20:25:33 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 20:48:06 2004 @@ -1690,14 +1690,23 @@ unsigned Class = getClassB(Op0->getType()); // sub 0, X -> neg X - if (OperatorClass == 1 && Class != cLong) + if (OperatorClass == 1) if (ConstantInt *CI = dyn_cast(Op0)) { if (CI->isNullValue()) { unsigned op1Reg = getReg(Op1, MBB, IP); static unsigned const NEGTab[] = { - X86::NEG8r, X86::NEG16r, X86::NEG32r + X86::NEG8r, X86::NEG16r, X86::NEG32r, 0, X86::NEG32r }; BuildMI(*MBB, IP, NEGTab[Class], 1, DestReg).addReg(op1Reg); + + if (Class == cLong) { + // We just emitted: Dl = neg Sl + // Now emit : T = addc Sh, 0 + // : Dh = neg T + unsigned T = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, X86::ADC32ri, 2, T).addReg(op1Reg+1).addImm(0); + BuildMI(*MBB, IP, X86::NEG32r, 1, DestReg+1).addReg(T); + } return; } } else if (ConstantFP *CFP = dyn_cast(Op0)) From lattner at cs.uiuc.edu Mon Apr 5 21:03:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 21:03:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200404060202.VAA19453@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.66 -> 1.67 --- Log message: The sbb instructions really ARE sbb's, not adc's --- Diffs of the changes: (+4 -4) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.66 llvm/lib/Target/X86/X86InstrInfo.td:1.67 --- llvm/lib/Target/X86/X86InstrInfo.td:1.66 Fri Apr 2 10:02:50 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Mon Apr 5 21:02:11 2004 @@ -564,10 +564,10 @@ def SBB32rr : I <"sbb", 0x19, MRMDestReg>; // R32 -= R32+Borrow def SBB32rm : Im32 <"sbb", 0x19, MRMSrcMem >; // R32 -= [mem32]+Borrow def SBB32mr : Im32 <"sbb", 0x1B, MRMDestMem>; // [mem32] -= R32+Borrow -def SBB32ri : Ii32 <"adc", 0x81, MRM3r >; // R32 -= I32+Borrow -def SBB32ri8 : Ii8 <"adc", 0x83, MRM3r >; // R32 -= I8+Borrow -def SBB32mi : Im32i32<"adc", 0x81, MRM3m >; // [mem32] -= I32+Borrow -def SBB32mi8 : Im32i8 <"adc", 0x83, MRM3m >; // [mem32] -= I8+Borrow +def SBB32ri : Ii32 <"sbb", 0x81, MRM3r >; // R32 -= I32+Borrow +def SBB32ri8 : Ii8 <"sbb", 0x83, MRM3r >; // R32 -= I8+Borrow +def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Borrow +def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Borrow def IMUL16rr : I <"imul", 0xAF, MRMSrcReg>, TB, OpSize, Pattern<(set R16, (times R16, R16))>; def IMUL32rr : I <"imul", 0xAF, MRMSrcReg>, TB , Pattern<(set R32, (times R32, R32))>; From lattner at cs.uiuc.edu Mon Apr 5 21:12:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 21:12:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060211.VAA19767@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.207 -> 1.208 --- Log message: Add support for simple immediate handling to long instruction selection. This allows us to handle code like 'add long %X, 123456789012' more efficiently. --- Diffs of the changes: (+37 -25) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.207 llvm/lib/Target/X86/InstSelectSimple.cpp:1.208 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.207 Mon Apr 5 20:48:06 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 21:11:49 2004 @@ -1718,76 +1718,88 @@ } // Special case: op Reg, - if (Class != cLong && isa(Op1)) { + if (isa(Op1)) { ConstantInt *Op1C = cast(Op1); unsigned Op0r = getReg(Op0, MBB, IP); // xor X, -1 -> not X if (OperatorClass == 4 && Op1C->isAllOnesValue()) { - static unsigned const NOTTab[] = { X86::NOT8r, X86::NOT16r, X86::NOT32r }; + static unsigned const NOTTab[] = { + X86::NOT8r, X86::NOT16r, X86::NOT32r, 0, X86::NOT32r + }; BuildMI(*MBB, IP, NOTTab[Class], 1, DestReg).addReg(Op0r); + if (Class == cLong) // Invert the top part too + BuildMI(*MBB, IP, X86::NOT32r, 1, DestReg+1).addReg(Op0r+1); return; } // add X, -1 -> dec X if (OperatorClass == 0 && Op1C->isAllOnesValue()) { - static unsigned const DECTab[] = { X86::DEC8r, X86::DEC16r, X86::DEC32r }; + static unsigned const DECTab[] = { + X86::DEC8r, X86::DEC16r, X86::DEC32r, 0, X86::DEC32r + }; BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); + if (Class == cLong) // Dh = sbb Sh, 0 + BuildMI(*MBB, IP, X86::SBB32ri, 2, DestReg+1).addReg(Op0r+1).addImm(0); return; } // add X, 1 -> inc X if (OperatorClass == 0 && Op1C->equalsInt(1)) { - static unsigned const INCTab[] = { X86::INC8r, X86::INC16r, X86::INC32r }; + static unsigned const INCTab[] = { + X86::INC8r, X86::INC16r, X86::INC32r, 0, X86::INC32r + }; BuildMI(*MBB, IP, INCTab[Class], 1, DestReg).addReg(Op0r); + if (Class == cLong) // Dh = adc Sh, 0 + BuildMI(*MBB, IP, X86::ADC32ri, 2, DestReg+1).addReg(Op0r+1).addImm(0); return; } - static const unsigned OpcodeTab[][3] = { + static const unsigned OpcodeTab[][5] = { // Arithmetic operators - { X86::ADD8ri, X86::ADD16ri, X86::ADD32ri }, // ADD - { X86::SUB8ri, X86::SUB16ri, X86::SUB32ri }, // SUB + { X86::ADD8ri, X86::ADD16ri, X86::ADD32ri, 0, X86::ADD32ri }, // ADD + { X86::SUB8ri, X86::SUB16ri, X86::SUB32ri, 0, X86::SUB32ri }, // SUB // Bitwise operators - { X86::AND8ri, X86::AND16ri, X86::AND32ri }, // AND - { X86:: OR8ri, X86:: OR16ri, X86:: OR32ri }, // OR - { X86::XOR8ri, X86::XOR16ri, X86::XOR32ri }, // XOR + { X86::AND8ri, X86::AND16ri, X86::AND32ri, 0, X86::AND32ri }, // AND + { X86:: OR8ri, X86:: OR16ri, X86:: OR32ri, 0, X86::OR32ri }, // OR + { X86::XOR8ri, X86::XOR16ri, X86::XOR32ri, 0, X86::XOR32ri }, // XOR }; - assert(Class < cFP && "General code handles 64-bit integer types!"); unsigned Opcode = OpcodeTab[OperatorClass][Class]; - uint64_t Op1v = cast(Op1C)->getRawValue(); - BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1v); + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1v &0xFFFFFFFF); + + if (Class == cLong) { + static const unsigned TopTab[] = { + X86::ADC32ri, X86::SBB32ri, X86::AND32ri, X86::OR32ri, X86::XOR32ri + }; + BuildMI(*MBB, IP, TopTab[OperatorClass], 2, DestReg+1) + .addReg(Op0r+1).addImm(uint64_t(Op1v) >> 32); + } return; } // Finally, handle the general case now. static const unsigned OpcodeTab[][4] = { // Arithmetic operators - { X86::ADD8rr, X86::ADD16rr, X86::ADD32rr, X86::FpADD }, // ADD - { X86::SUB8rr, X86::SUB16rr, X86::SUB32rr, X86::FpSUB }, // SUB + { X86::ADD8rr, X86::ADD16rr, X86::ADD32rr, X86::FpADD, X86::ADD32rr },// ADD + { X86::SUB8rr, X86::SUB16rr, X86::SUB32rr, X86::FpSUB, X86::SUB32rr },// SUB // Bitwise operators - { X86::AND8rr, X86::AND16rr, X86::AND32rr, 0 }, // AND - { X86:: OR8rr, X86:: OR16rr, X86:: OR32rr, 0 }, // OR - { X86::XOR8rr, X86::XOR16rr, X86::XOR32rr, 0 }, // XOR + { X86::AND8rr, X86::AND16rr, X86::AND32rr, 0, X86::AND32rr }, // AND + { X86:: OR8rr, X86:: OR16rr, X86:: OR32rr, 0, X86:: OR32rr }, // OR + { X86::XOR8rr, X86::XOR16rr, X86::XOR32rr, 0, X86::XOR32rr }, // XOR }; - bool isLong = false; - if (Class == cLong) { - isLong = true; - Class = cInt; // Bottom 32 bits are handled just like ints - } - unsigned Opcode = OpcodeTab[OperatorClass][Class]; assert(Opcode && "Floating point arguments to logical inst?"); unsigned Op0r = getReg(Op0, MBB, IP); unsigned Op1r = getReg(Op1, MBB, IP); BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); - if (isLong) { // Handle the upper 32 bits of long values... + if (Class == cLong) { // Handle the upper 32 bits of long values... static const unsigned TopTab[] = { X86::ADC32rr, X86::SBB32rr, X86::AND32rr, X86::OR32rr, X86::XOR32rr }; From lattner at cs.uiuc.edu Mon Apr 5 21:14:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 21:14:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060213.VAA20080@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.208 -> 1.209 --- Log message: Fix typeo --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.208 llvm/lib/Target/X86/InstSelectSimple.cpp:1.209 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.208 Mon Apr 5 21:11:49 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 21:13:25 2004 @@ -1782,7 +1782,7 @@ } // Finally, handle the general case now. - static const unsigned OpcodeTab[][4] = { + static const unsigned OpcodeTab[][5] = { // Arithmetic operators { X86::ADD8rr, X86::ADD16rr, X86::ADD32rr, X86::FpADD, X86::ADD32rr },// ADD { X86::SUB8rr, X86::SUB16rr, X86::SUB32rr, X86::FpSUB, X86::SUB32rr },// SUB From lattner at cs.uiuc.edu Mon Apr 5 22:16:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 22:16:02 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060316.WAA21102@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.209 -> 1.210 --- Log message: Emit more efficient 64-bit operations when the RHS is a constant, and one of the words of the constant is zeros. For example: Y = and long X, 1234 now generates: Yl = and Xl, 1234 Yh = 0 instead of: Yl = and Xl, 1234 Yh = and Xh, 0 --- Diffs of the changes: (+41 -5) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.209 llvm/lib/Target/X86/InstSelectSimple.cpp:1.210 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.209 Mon Apr 5 21:13:25 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 22:15:53 2004 @@ -1767,18 +1767,54 @@ }; unsigned Opcode = OpcodeTab[OperatorClass][Class]; + unsigned Op1l = cast(Op1C)->getRawValue(); - uint64_t Op1v = cast(Op1C)->getRawValue(); - BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1v &0xFFFFFFFF); + if (Class != cLong) { + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1l); + return; + } else { + // If this is a long value and the high or low bits have a special + // property, emit some special cases. + unsigned Op1h = cast(Op1C)->getRawValue() >> 32LL; - if (Class == cLong) { + // If the constant is zero in the low 32-bits, just copy the low part + // across and apply the normal 32-bit operation to the high parts. There + // will be no carry or borrow into the top. + if (Op1l == 0) { + if (OperatorClass != 2) // All but and... + BuildMI(*MBB, IP, X86::MOV32rr, 1, DestReg).addReg(Op0r); + else + BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg).addImm(0); + BuildMI(*MBB, IP, OpcodeTab[OperatorClass][cLong], 2, DestReg+1) + .addReg(Op0r+1).addImm(Op1h); + return; + } + + // If this is a logical operation and the top 32-bits are zero, just + // operate on the lower 32. + if (Op1h == 0 && OperatorClass > 1) { + BuildMI(*MBB, IP, OpcodeTab[OperatorClass][cLong], 2, DestReg) + .addReg(Op0r).addImm(Op1l); + if (OperatorClass != 2) // All but and + BuildMI(*MBB, IP, X86::MOV32rr, 1, DestReg+1).addReg(Op0r+1); + else + BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); + return; + } + + // TODO: We could handle lots of other special cases here, such as AND'ing + // with 0xFFFFFFFF00000000 -> noop, etc. + + // Otherwise, code generate the full operation with a constant. static const unsigned TopTab[] = { X86::ADC32ri, X86::SBB32ri, X86::AND32ri, X86::OR32ri, X86::XOR32ri }; + + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addImm(Op1l); BuildMI(*MBB, IP, TopTab[OperatorClass], 2, DestReg+1) - .addReg(Op0r+1).addImm(uint64_t(Op1v) >> 32); + .addReg(Op0r+1).addImm(Op1h); + return; } - return; } // Finally, handle the general case now. From lattner at cs.uiuc.edu Mon Apr 5 22:23:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 22:23:02 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060323.WAA21438@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.210 -> 1.211 --- Log message: Improve code for passing constant longs as arguments to function calls. For example, on this instruction: call void %test(long 1234) Instead of this: mov %EAX, 1234 mov %ECX, 0 mov DWORD PTR [%ESP], %EAX mov DWORD PTR [%ESP + 4], %ECX call test We now emit this: mov DWORD PTR [%ESP], 1234 mov DWORD PTR [%ESP + 4], 0 call test --- Diffs of the changes: (+13 -5) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.210 llvm/lib/Target/X86/InstSelectSimple.cpp:1.211 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.210 Mon Apr 5 22:15:53 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 22:23:00 2004 @@ -1339,11 +1339,19 @@ } break; case cLong: - ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; - addRegOffset(BuildMI(BB, X86::MOV32mr, 5), - X86::ESP, ArgOffset).addReg(ArgReg); - addRegOffset(BuildMI(BB, X86::MOV32mr, 5), - X86::ESP, ArgOffset+4).addReg(ArgReg+1); + if (Args[i].Val && isa(Args[i].Val)) { + uint64_t Val = cast(Args[i].Val)->getRawValue(); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), + X86::ESP, ArgOffset).addImm(Val & ~0U); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), + X86::ESP, ArgOffset+4).addImm(Val >> 32ULL); + } else { + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset+4).addReg(ArgReg+1); + } ArgOffset += 4; // 8 byte entry, not 4. break; From lattner at cs.uiuc.edu Mon Apr 5 22:37:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 22:37:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060337.WAA24073@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.211 -> 1.212 --- Log message: Bugfixes: inc/dec don't set the carry flag! --- Diffs of the changes: (+8 -12) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.211 llvm/lib/Target/X86/InstSelectSimple.cpp:1.212 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.211 Mon Apr 5 22:23:00 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 22:36:57 2004 @@ -1742,24 +1742,20 @@ } // add X, -1 -> dec X - if (OperatorClass == 0 && Op1C->isAllOnesValue()) { - static unsigned const DECTab[] = { - X86::DEC8r, X86::DEC16r, X86::DEC32r, 0, X86::DEC32r - }; + if (OperatorClass == 0 && Op1C->isAllOnesValue() && Class != cLong) { + // Note that we can't use dec for 64-bit decrements, because it does not + // set the carry flag! + static unsigned const DECTab[] = { X86::DEC8r, X86::DEC16r, X86::DEC32r }; BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); - if (Class == cLong) // Dh = sbb Sh, 0 - BuildMI(*MBB, IP, X86::SBB32ri, 2, DestReg+1).addReg(Op0r+1).addImm(0); return; } // add X, 1 -> inc X - if (OperatorClass == 0 && Op1C->equalsInt(1)) { - static unsigned const INCTab[] = { - X86::INC8r, X86::INC16r, X86::INC32r, 0, X86::INC32r - }; + if (OperatorClass == 0 && Op1C->equalsInt(1) && Class != cLong) { + // Note that we can't use inc for 64-bit increments, because it does not + // set the carry flag! + static unsigned const INCTab[] = { X86::INC8r, X86::INC16r, X86::INC32r }; BuildMI(*MBB, IP, INCTab[Class], 1, DestReg).addReg(Op0r); - if (Class == cLong) // Dh = adc Sh, 0 - BuildMI(*MBB, IP, X86::ADC32ri, 2, DestReg+1).addReg(Op0r+1).addImm(0); return; } From lattner at cs.uiuc.edu Mon Apr 5 22:43:04 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 22:43:04 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060342.WAA24973@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.212 -> 1.213 --- Log message: Improve code generation of long shifts by 32. On this testcase: long %test(long %X) { %Y = shr long %X, ubyte 32 ret long %Y } instead of: t: mov %EAX, DWORD PTR [%ESP + 4] mov %EAX, DWORD PTR [%ESP + 8] sar %EAX, 0 mov %EDX, 0 ret we now emit: test: mov %EAX, DWORD PTR [%ESP + 4] mov %EAX, DWORD PTR [%ESP + 8] mov %EDX, 0 ret --- Diffs of the changes: (+13 -6) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.212 llvm/lib/Target/X86/InstSelectSimple.cpp:1.213 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.212 Mon Apr 5 22:36:57 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 22:42:38 2004 @@ -2128,13 +2128,20 @@ } else { // Shifting more than 32 bits Amount -= 32; if (isLeftShift) { - BuildMI(*MBB, IP, X86::SHL32ri, 2, - DestReg + 1).addReg(SrcReg).addImm(Amount); - BuildMI(*MBB, IP, X86::MOV32ri, 1, - DestReg).addImm(0); + if (Amount != 0) { + BuildMI(*MBB, IP, X86::SHL32ri, 2, + DestReg + 1).addReg(SrcReg).addImm(Amount); + } else { + BuildMI(*MBB, IP, X86::MOV32rr, 1, DestReg+1).addReg(SrcReg); + } + BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg).addImm(0); } else { - unsigned Opcode = isSigned ? X86::SAR32ri : X86::SHR32ri; - BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(SrcReg+1).addImm(Amount); + if (Amount != 0) { + BuildMI(*MBB, IP, isSigned ? X86::SAR32ri : X86::SHR32ri, 2, + DestReg).addReg(SrcReg+1).addImm(Amount); + } else { + BuildMI(*MBB, IP, X86::MOV32rr, 1, DestReg).addReg(SrcReg+1); + } BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); } } From brukman at cs.uiuc.edu Mon Apr 5 22:54:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 22:54:01 2004 Subject: [llvm-commits] CVS: llvm/docs/ExtendingLLVM.html llvm.css Message-ID: <200404060353.WAA28748@zion.cs.uiuc.edu> Changes in directory llvm/docs: ExtendingLLVM.html added (r1.1) llvm.css updated: 1.11 -> 1.12 --- Log message: Added notes on extending LLVM with new instructions, intrinsics, types, etc. --- Diffs of the changes: (+214 -0) Index: llvm/docs/ExtendingLLVM.html diff -c /dev/null llvm/docs/ExtendingLLVM.html:1.1 *** /dev/null Mon Apr 5 22:53:59 2004 --- llvm/docs/ExtendingLLVM.html Mon Apr 5 22:53:49 2004 *************** *** 0 **** --- 1,213 ---- + + + + Extending LLVM: Adding instructions, intrinsics, types, etc. + + + + + +
+ Extending LLVM: Adding instructions, intrinsics, types, etc. +
+ +
    +
  1. Introduction and Warning
  2. +
  3. Adding a new instruction
  4. +
  5. Adding a new intrinsic function
  6. +
  7. Adding a new type +
      +
    1. Adding a new fundamental type
    2. +
    3. Adding a new derived type
    4. +
  8. +
+ +
+

Written by Misha Brukman

+
+ + + + + +
+ +

During the course of using LLVM, you may wish to customize it for your + research project or for experimentation. At this point, you may realize that + you need to add something to LLVM, whether it be a new fundamental type, a new + intrinsic function, or a whole new instruction.

+ +

When you come to this realization, stop and think. Do you really need to + extend LLVM? Is it a new fundamental capability that LLVM does not support at + its current incarnation or can it be synthesized from already pre-existing LLVM + elements? If you are not sure, ask on the LLVM-dev list. The + reason is that extending LLVM will get involved as you need to update all the + different passes that you intend to use with your extension, and there are + many LLVM analyses and transformations, so it may be quite a bit of + work.

+ +

Before you invest a significant amount of effort into a non-trivial + extension, ask on the list if what you are + looking to do can be done with already-existing infrastructure, or if maybe + someone else is already working on it. You will save yourself a lot of time and + effort by doing so.

+ +

Finally, these are my notes, and since my extensions are not complete, I may + be missing steps. If you find some omissions, please let me know directly or post on LLVM-dev.

+ +
+ + + + + +
+ +

WARNING: adding instructions changes the bytecode + format, and will break compatibility with currently-existing LLVM + installations. Only add an instruction if it is absolutely + necessary.

+ +
    +
  1. llvm/include/llvm/Instruction.def: + add a number for your instruction and an enum name
  2. + +
  3. llvm/include/llvm/i*.h: + add a definition for the class that will represent your instruction
  4. + +
  5. llvm/include/llvm/Support/InstVisitor.h: + add a prototype for a visitor to your new instruction type
  6. + +
  7. llvm/lib/AsmParser/Lexer.l: + add a new token to parse your instruction from assembly text file
  8. + +
  9. llvm/lib/AsmParser/llvmAsmParser.y: + add the grammar on how your instruction can be read and what it will + construct as a result
  10. + +
  11. llvm/lib/Bytecode/Reader/InstructionReader.cpp: + add a case for your instruction and how it will be parsed from bytecode
  12. + +
  13. llvm/lib/VMCore/Instruction.cpp: + add a case for how your instruction will be printed out to assembly
  14. + +
  15. llvm/lib/VMCore/i*.cpp: + implement the class you defined in llvm/include/llvm/i*.h
  16. + +
+ +

Also, you need to implement (or modify) any analyses or passes that you want + to understand this new instruction.

+ +
+ + + + + +
+ +

Adding an intrinsic function is easier than adding an instruction, and is + transparent to optimization passes which treat it as an unanalyzable function. + If your added functionality can be expressed as a function call, an intrinsic + function is the method of choice for LLVM extension.

+ +
    + +
  1. llvm/include/llvm/Intrinsics.h: + add an enum in the llvm::Intrinsic namespace
  2. + +
  3. llvm/lib/VMCore/IntrinsicLowering.cpp: + implement the lowering for this intrinsic
  4. + +
  5. llvm/lib/VMCore/Verifier.cpp: + handle the new intrinsic
  6. + +
  7. llvm/lib/VMCore/Function.cpp: + handle the new intrinsic
  8. + +
+ +
+ + + + + +
+ +

WARNING: adding new types changes the bytecode + format, and will break compatibility with currently-existing LLVM + installations. Only add new types if it is absolutely necessary.

+ +
+ + + + +
+ +
    + +
  1. llvm/include/llvm/Type.def: + add enum for the type
  2. + +
  3. llvm/include/llvm/Type.h: + add ID number for the new type; add static Type* for this type
  4. + +
  5. llvm/lib/VMCore/Type.cpp: + add mapping from TypeID => Type*; + initialize the static Type*
  6. + +
  7. llvm/lib/AsmReader/Lexer.l: + add ability to parse in the type from text assembly
  8. + +
  9. llvm/lib/AsmReader/llvmAsmParser.y: + add a token for that type
  10. + +
+ +
+ + + + +
+ +

TODO

+ +
+ + + +
+
+ Valid CSS! + Valid HTML 4.01! + + Misha Brukman
+ The LLVM Compiler Infrastructure +
+ Last modified: $Date: 2004/04/06 03:53:49 $ +
+ + + Index: llvm/docs/llvm.css diff -u llvm/docs/llvm.css:1.11 llvm/docs/llvm.css:1.12 --- llvm/docs/llvm.css:1.11 Wed Jan 14 18:13:59 2004 +++ llvm/docs/llvm.css Mon Apr 5 22:53:49 2004 @@ -50,3 +50,4 @@ .doc_table { text-align: center; width: 90%; padding: 1px 1px 1px 1px; border: 1px; } +.doc_warning { color: red; font-weight: bold } From brukman at cs.uiuc.edu Mon Apr 5 23:18:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 23:18:01 2004 Subject: [llvm-commits] CVS: llvm/docs/ExtendingLLVM.html Message-ID: <200404060418.XAA05333@zion.cs.uiuc.edu> Changes in directory llvm/docs: ExtendingLLVM.html updated: 1.1 -> 1.2 --- Log message: Incorporated Chris' comments. --- Diffs of the changes: (+10 -8) Index: llvm/docs/ExtendingLLVM.html diff -u llvm/docs/ExtendingLLVM.html:1.1 llvm/docs/ExtendingLLVM.html:1.2 --- llvm/docs/ExtendingLLVM.html:1.1 Mon Apr 5 22:53:49 2004 +++ llvm/docs/ExtendingLLVM.html Mon Apr 5 23:17:51 2004 @@ -50,6 +50,12 @@ many LLVM analyses and transformations, so it may be quite a bit of work.

+

Adding an intrinsic function is easier than adding +an instruction, and is transparent to optimization passes which treat it as an +unanalyzable function. If your added functionality can be expressed as a +function call, an intrinsic function is the method of choice for LLVM +extension.

+

Before you invest a significant amount of effort into a non-trivial extension, ask on the list if what you are looking to do can be done with already-existing infrastructure, or if maybe @@ -72,11 +78,12 @@

WARNING: adding instructions changes the bytecode -format, and will break compatibility with currently-existing LLVM -installations. Only add an instruction if it is absolutely +format, and it will take some effort to maintain compatibility with +the previous version. Only add an instruction if it is absolutely necessary.

    +
  1. llvm/include/llvm/Instruction.def: add a number for your instruction and an enum name
  2. @@ -117,11 +124,6 @@
    -

    Adding an intrinsic function is easier than adding an instruction, and is -transparent to optimization passes which treat it as an unanalyzable function. -If your added functionality can be expressed as a function call, an intrinsic -function is the method of choice for LLVM extension.

    -
    1. llvm/include/llvm/Intrinsics.h: @@ -206,7 +208,7 @@ Misha Brukman
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/04/06 03:53:49 $ + Last modified: $Date: 2004/04/06 04:17:51 $ From brukman at cs.uiuc.edu Mon Apr 5 23:23:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon Apr 5 23:23:01 2004 Subject: [llvm-commits] CVS: llvm/docs/index.html Message-ID: <200404060422.XAA11886@zion.cs.uiuc.edu> Changes in directory llvm/docs: index.html updated: 1.10 -> 1.11 --- Log message: * Added link to newly written ExtendingLLVM.html document * Eliminated extraneous space in the HTML --- Diffs of the changes: (+32 -37) Index: llvm/docs/index.html diff -u llvm/docs/index.html:1.10 llvm/docs/index.html:1.11 --- llvm/docs/index.html:1.10 Mon Mar 8 11:59:31 2004 +++ llvm/docs/index.html Mon Apr 5 23:22:43 2004 @@ -1,8 +1,7 @@ - -The LLVM Compiler Infrastructure - - + + The LLVM Compiler Infrastructure +
      @@ -15,26 +14,18 @@
      -

      -Welcome to LLVM! -

      +

      Welcome to LLVM!

      + This file is intended to do four things:
        -
      1. - help you get started using LLVM; -
      2. - -
      3. - tell you how to get questions about LLVM answered; -
      4. - -
      5. - tell you where to find documentation for different kinds of questions; and -
      6. - -
      7. - tell you about three LLVM-related mailing lists. -
      8. +
      9. help you get started using LLVM;
      10. + +
      11. tell you how to get questions about LLVM answered;
      12. + +
      13. tell you where to find documentation for different kinds of questions; + and
      14. + +
      15. tell you about three LLVM-related mailing lists.
      @@ -167,32 +158,32 @@
      LLVM Programmers Manual:
      - llvm/docs/ProgrammersManual.html + llvm/docs/ProgrammersManual.html

      Writing an LLVM Pass:
      - llvm/docs/WritingAnLLVMPass.html + llvm/docs/WritingAnLLVMPass.html

      Alias Analysis in LLVM:
      - llvm/docs/AliasAnalysis.html + llvm/docs/AliasAnalysis.html

      Source Level Debugging with LLVM:
      - llvm/docs/SourceLevelDebugging.html + llvm/docs/SourceLevelDebugging.html

      TableGen Fundamentals:
      - llvm/docs/TableGenFundamentals.html + llvm/docs/TableGenFundamentals.html

      @@ -208,19 +199,23 @@

      Command Line Library:
      - llvm/docs/CommandLine.html + llvm/docs/CommandLine.html +

      + +

      + Extending LLVM: +
      + llvm/docs/ExtendingLLVM.html

      Coding Standards:
      - llvm/docs/CodingStandards.html + llvm/docs/CodingStandards.html

      -

      -Other LLVM Resources: -

      +

      Other LLVM Resources

      @@ -238,21 +233,20 @@
      Open Projects:
      - llvm/docs/OpenProjects.html + llvm/docs/OpenProjects.html

      Creating a new LLVM Project:
      - llvm/docs/Projects.html + llvm/docs/Projects.html


      -

      -Mailing Lists -

      +

      Mailing Lists

      + There are three mailing lists for providing LLVM users with information:
        @@ -288,6 +282,7 @@ volume.

      + From lattner at cs.uiuc.edu Mon Apr 5 23:30:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 23:30:02 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060429.XAA12007@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.213 -> 1.214 --- Log message: Efficiently handle a long multiplication by a constant. For this testcase: long %test(long %X) { %Y = mul long %X, 123 ret long %Y } we used to generate: test: sub %ESP, 12 mov DWORD PTR [%ESP + 8], %ESI mov DWORD PTR [%ESP + 4], %EDI mov DWORD PTR [%ESP], %EBX mov %ECX, DWORD PTR [%ESP + 16] mov %ESI, DWORD PTR [%ESP + 20] mov %EDI, 123 mov %EBX, 0 mov %EAX, %ECX mul %EDI imul %ESI, %EDI add %ESI, %EDX imul %ECX, %EBX add %ESI, %ECX mov %EDX, %ESI mov %EBX, DWORD PTR [%ESP] mov %EDI, DWORD PTR [%ESP + 4] mov %ESI, DWORD PTR [%ESP + 8] add %ESP, 12 ret Now we emit: test: mov %EAX, DWORD PTR [%ESP + 4] mov %ECX, DWORD PTR [%ESP + 8] mov %EDX, 123 mul %EDX imul %ECX, %ECX, 123 add %ECX, %EDX mov %EDX, %ECX ret Which, incidently, is substantially nicer than what GCC manages: T: sub %esp, 8 mov %eax, 123 mov DWORD PTR [%esp], %ebx mov %ebx, DWORD PTR [%esp+16] mov DWORD PTR [%esp+4], %esi mov %esi, DWORD PTR [%esp+12] imul %ecx, %ebx, 123 mov %ebx, DWORD PTR [%esp] mul %esi mov %esi, DWORD PTR [%esp+4] add %esp, 8 lea %edx, [%ecx+%edx] ret --- Diffs of the changes: (+57 -24) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.213 llvm/lib/Target/X86/InstSelectSimple.cpp:1.214 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.213 Mon Apr 5 22:42:38 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 23:29:36 2004 @@ -1940,7 +1940,7 @@ unsigned DestReg = getReg(I); // Simple scalar multiply? - if (I.getType() != Type::LongTy && I.getType() != Type::ULongTy) { + if (getClass(I.getType()) != cLong) { if (ConstantInt *CI = dyn_cast(I.getOperand(1))) { unsigned Val = (unsigned)CI->getRawValue(); // Cannot be 64-bit constant MachineBasicBlock::iterator MBBI = BB->end(); @@ -1951,31 +1951,64 @@ doMultiply(BB, MBBI, DestReg, I.getType(), Op0Reg, Op1Reg); } } else { - unsigned Op1Reg = getReg(I.getOperand(1)); - // Long value. We have to do things the hard way... - // Multiply the two low parts... capturing carry into EDX - BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); - BuildMI(BB, X86::MUL32r, 1).addReg(Op1Reg); // AL*BL - - unsigned OverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL - BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 - - MachineBasicBlock::iterator MBBI = BB->end(); - unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL - BuildMI(*BB, MBBI, X86::IMUL32rr,2,AHBLReg).addReg(Op0Reg+1).addReg(Op1Reg); + if (ConstantInt *CI = dyn_cast(I.getOperand(1))) { + unsigned CLow = CI->getRawValue(); + unsigned CHi = CI->getRawValue() >> 32; - unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) - AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); - - MBBI = BB->end(); - unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH - BuildMI(*BB, MBBI, X86::IMUL32rr,2,ALBHReg).addReg(Op0Reg).addReg(Op1Reg+1); - - BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) - DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); + // Multiply the two low parts... capturing carry into EDX + unsigned Op1RegL = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOV32ri, 1, Op1RegL).addImm(CLow); + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MUL32r, 1).addReg(Op1RegL); // AL*BL + + unsigned OverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + + unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL + BuildMI(BB, X86::IMUL32rri, 2, AHBLReg).addReg(Op0Reg+1).addImm(CLow); + + unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) + AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + + if (CHi != 0) { + unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH + BuildMI(BB, X86::IMUL32rri, 2, ALBHReg).addReg(Op0Reg).addImm(CHi); + + BuildMI(BB, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) + DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); + } else { + BuildMI(BB, X86::MOV32rr, 1, DestReg+1).addReg(AHBLplusOverflowReg); + } + } else { + unsigned Op1Reg = getReg(I.getOperand(1)); + // Multiply the two low parts... capturing carry into EDX + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MUL32r, 1).addReg(Op1Reg); // AL*BL + + unsigned OverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + + MachineBasicBlock::iterator MBBI = BB->end(); + unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL + BuildMI(*BB, MBBI, X86::IMUL32rr, 2, + AHBLReg).addReg(Op0Reg+1).addReg(Op1Reg); + + unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) + AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + + MBBI = BB->end(); + unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH + BuildMI(*BB, MBBI, X86::IMUL32rr, 2, + ALBHReg).addReg(Op0Reg).addReg(Op1Reg+1); + + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) + DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); + } } } From lattner at cs.uiuc.edu Mon Apr 5 23:56:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Apr 5 23:56:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404060455.XAA14133@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.214 -> 1.215 --- Log message: Handle various other important cases of multiplying a long constant immediate. For example, multiplying X*(1 + (1LL << 32)) now produces: test: mov %ECX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] mov %EAX, %ECX add %EDX, %ECX ret [[[Note to Alkis: why isn't linear scan generating this code?? This might be a problem with your intervals being too conservative: test: mov %EAX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] add %EDX, %EAX ret end note]]] Whereas GCC produces this: T: sub %esp, 12 mov %edx, DWORD PTR [%esp+16] mov DWORD PTR [%esp+8], %edi mov %ecx, DWORD PTR [%esp+20] xor %edi, %edi mov DWORD PTR [%esp], %ebx mov %ebx, %edi mov %eax, %edx mov DWORD PTR [%esp+4], %esi add %ebx, %edx mov %edi, DWORD PTR [%esp+8] lea %edx, [%ecx+%ebx] mov %esi, DWORD PTR [%esp+4] mov %ebx, DWORD PTR [%esp] add %esp, 12 ret I'm not sure example what GCC is smoking here, but it looks like it has just confused itself with a bunch of stack slots or something. The intel compiler is better, but still not good: T: movl 4(%esp), %edx #2.11 movl 8(%esp), %eax #2.11 lea (%eax,%edx), %ecx #3.12 movl $1, %eax #3.12 mull %edx #3.12 addl %ecx, %edx #3.12 ret #3.12 --- Diffs of the changes: (+43 -19) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.214 llvm/lib/Target/X86/InstSelectSimple.cpp:1.215 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.214 Mon Apr 5 23:29:36 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Apr 5 23:55:43 2004 @@ -1893,8 +1893,19 @@ MachineBasicBlock::iterator IP, unsigned DestReg, const Type *DestTy, unsigned op0Reg, unsigned ConstRHS) { + static const unsigned MOVrrTab[] = {X86::MOV8rr, X86::MOV16rr, X86::MOV32rr}; + static const unsigned MOVriTab[] = {X86::MOV8ri, X86::MOV16ri, X86::MOV32ri}; + unsigned Class = getClass(DestTy); + if (ConstRHS == 0) { + BuildMI(*MBB, IP, MOVriTab[Class], 1, DestReg).addImm(0); + return; + } else if (ConstRHS == 1) { + BuildMI(*MBB, IP, MOVrrTab[Class], 1, DestReg).addReg(op0Reg); + return; + } + // If the element size is exactly a power of 2, use a shift to get it. if (unsigned Shift = ExactLog2(ConstRHS)) { switch (Class) { @@ -1920,10 +1931,6 @@ } // Most general case, emit a normal multiply... - static const unsigned MOVriTab[] = { - X86::MOV8ri, X86::MOV16ri, X86::MOV32ri - }; - unsigned TmpReg = makeAnotherReg(DestTy); BuildMI(*MBB, IP, MOVriTab[Class], 1, TmpReg).addImm(ConstRHS); @@ -1956,31 +1963,48 @@ unsigned CLow = CI->getRawValue(); unsigned CHi = CI->getRawValue() >> 32; + if (CLow == 0) { + // If the low part of the constant is all zeros, things are simple. + BuildMI(BB, X86::MOV32ri, 1, DestReg).addImm(0); + doMultiplyConst(BB, BB->end(), DestReg+1, Type::UIntTy, Op0Reg, CHi); + return; + } + // Multiply the two low parts... capturing carry into EDX - unsigned Op1RegL = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::MOV32ri, 1, Op1RegL).addImm(CLow); - BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); - BuildMI(BB, X86::MUL32r, 1).addReg(Op1RegL); // AL*BL + unsigned OverflowReg = 0; + if (CLow == 1) { + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(Op0Reg); + } else { + unsigned Op1RegL = makeAnotherReg(Type::UIntTy); + OverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOV32ri, 1, Op1RegL).addImm(CLow); + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MUL32r, 1).addReg(Op1RegL); // AL*BL - unsigned OverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL - BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOV32rr, 1,OverflowReg).addReg(X86::EDX);// AL*BL >> 32 + } unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL - BuildMI(BB, X86::IMUL32rri, 2, AHBLReg).addReg(Op0Reg+1).addImm(CLow); + doMultiplyConst(BB, BB->end(), AHBLReg, Type::UIntTy, Op0Reg+1, CLow); - unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) - AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + unsigned AHBLplusOverflowReg; + if (OverflowReg) { + AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) + AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + } else { + AHBLplusOverflowReg = AHBLReg; + } - if (CHi != 0) { + if (CHi == 0) { + BuildMI(BB, X86::MOV32rr, 1, DestReg+1).addReg(AHBLplusOverflowReg); + } else { unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH - BuildMI(BB, X86::IMUL32rri, 2, ALBHReg).addReg(Op0Reg).addImm(CHi); + doMultiplyConst(BB, BB->end(), ALBHReg, Type::UIntTy, Op0Reg, CHi); BuildMI(BB, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); - } else { - BuildMI(BB, X86::MOV32rr, 1, DestReg+1).addReg(AHBLplusOverflowReg); } } else { unsigned Op1Reg = getReg(I.getOperand(1)); From lattner at cs.uiuc.edu Tue Apr 6 10:15:14 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 10:15:14 2004 Subject: [llvm-commits] CVS: llvm/docs/CommandGuide/bugpoint.html Message-ID: <200404061514.KAA25215@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: bugpoint.html updated: 1.25 -> 1.26 --- Log message: Remove some options that don't really have anything to do with bugpoint --- Diffs of the changes: (+0 -10) Index: llvm/docs/CommandGuide/bugpoint.html diff -u llvm/docs/CommandGuide/bugpoint.html:1.25 llvm/docs/CommandGuide/bugpoint.html:1.26 --- llvm/docs/CommandGuide/bugpoint.html:1.25 Mon Mar 29 14:21:45 2004 +++ llvm/docs/CommandGuide/bugpoint.html Tue Apr 6 10:14:10 2004 @@ -190,16 +190,6 @@ when attempting to reduce test programs. If you're trying to find a bug in one of these passes, bugpoint may crash.

      -

    2. -enable-correct-eh-support
      - Make the -lowerinvoke pass insert expensive, but correct, exception - handling code.

      - -

    3. -internalize-public-api-file <filename>
      - Preserve the symbols listed in the file filename.

      - -

    4. -internalize-public-api-list <list>
      - Preserve the symbols listed in list.

      -

    5. -help
      Print a summary of command line options.

      From lattner at cs.uiuc.edu Tue Apr 6 10:23:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 10:23:01 2004 Subject: [llvm-commits] CVS: llvm/docs/CommandGuide/bugpoint.html Message-ID: <200404061522.KAA25790@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: bugpoint.html updated: 1.26 -> 1.27 --- Log message: Update docs a bit --- Diffs of the changes: (+12 -10) Index: llvm/docs/CommandGuide/bugpoint.html diff -u llvm/docs/CommandGuide/bugpoint.html:1.26 llvm/docs/CommandGuide/bugpoint.html:1.27 --- llvm/docs/CommandGuide/bugpoint.html:1.26 Tue Apr 6 10:14:10 2004 +++ llvm/docs/CommandGuide/bugpoint.html Tue Apr 6 10:22:35 2004 @@ -17,9 +17,9 @@ The bugpoint tool narrows down the source of problems in LLVM tools and passes. It can be used to debug three types of -failures: optimizer crashes, miscompilations by optimizers, or invalid native -code generation. It aims to reduce large test cases to small, useful ones. -For example, +failures: optimizer crashes, miscompilations by optimizers, or bad native +code generation (including problems in the static and JIT compilers). It aims +to reduce large test cases to small, useful ones. For example, if gccas crashes while optimizing a file, it will identify the optimization (or combination of optimizations) that causes the crash, and reduce the file down to a small example which triggers the crash.

      @@ -30,11 +30,13 @@ bugpoint is designed to be a useful tool without requiring any hooks into the LLVM infrastructure at all. It works with any and all LLVM passes and code generators, and does not need to "know" how they work. Because -of this, it may appear to do a lot of stupid things or miss obvious +of this, it may appear to do stupid things or miss obvious simplifications. bugpoint is also designed to trade off programmer time for computer time in the compiler-debugging process; consequently, it may take a long period of (unattended) time to reduce a test case, but we feel it -is still worth it. :-)

      +is still worth it. Note that bugpoint is generally very quick unless +debugging a miscompilation where each test of the program (which requires +executing it) takes a long time.

      Automatic Debugger Selection

      @@ -43,7 +45,8 @@ specified on the command line and links them together into a single module, called the test program. If any LLVM passes are specified on the command line, it runs these passes on the test program. If -any of the passes crash, or if they produce malformed output, +any of the passes crash, or if they produce malformed output (which causes the +verifier to abort), bugpoint starts the crash debugger.

      Otherwise, if the -output option was not @@ -71,8 +74,7 @@ it can to reduce the list of passes (for optimizer crashes) and the size of the test program. First, bugpoint figures out which combination of optimizer passes triggers the bug. This is useful when debugging a problem -exposed by gccas, for example, because it runs over 25 -optimizations.

      +exposed by gccas, for example, because it runs over 38 passes.

      Next, bugpoint tries removing functions from the test program, to reduce its size. Usually it is able to reduce a test program to a single @@ -126,7 +128,7 @@

      1. In the code generator and miscompilation debuggers, bugpoint only works with programs that have deterministic output. Thus, if the program - outputs the date, time, or any other "random" data, bugpoint may + outputs argv[0], the date, time, or any other "random" data, bugpoint may misinterpret differences in these data, when output, as the result of a miscompilation. Programs should be temporarily modified to disable outputs that are likely to vary from run to run. @@ -148,7 +150,7 @@
        to get a copy of bugpoint's output in the file bugpoint.log, as well as on your terminal. -
      2. bugpoint cannot debug problems with the linker. If +
      3. bugpoint cannot debug problems with the LLVM linker. If bugpoint crashes before you see its "All input ok" message, you might try llvm-link -v on the same set of input files. If that also crashes, you may be experiencing a linker bug. From lattner at cs.uiuc.edu Tue Apr 6 11:03:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 11:03:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404061602.LAA26796@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.215 -> 1.216 --- Log message: Improve codegen of long == and != comparisons against constants. Before, comparing a long against zero got us this: sub %ESP, 8 mov DWORD PTR [%ESP + 4], %ESI mov DWORD PTR [%ESP], %EDI mov %EAX, DWORD PTR [%ESP + 12] mov %EDX, DWORD PTR [%ESP + 16] mov %ECX, 0 mov %ESI, 0 mov %EDI, %EAX xor %EDI, %ECX mov %ECX, %EDX xor %ECX, %ESI or %EDI, %ECX sete %CL test %CL, %CL je .LBB2 # PC rel: F Now it gets us this: mov %EAX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] mov %ECX, %EAX or %ECX, %EDX sete %CL test %CL, %CL je .LBB2 # PC rel: F --- Diffs of the changes: (+23 -3) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.215 llvm/lib/Target/X86/InstSelectSimple.cpp:1.216 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.215 Mon Apr 5 23:55:43 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Tue Apr 6 11:02:27 2004 @@ -806,9 +806,9 @@ unsigned Op0r = getReg(Op0, MBB, IP); // Special case handling of: cmp R, i - if (Class == cByte || Class == cShort || Class == cInt) - if (ConstantInt *CI = dyn_cast(Op1)) { - uint64_t Op1v = cast(CI)->getRawValue(); + if (ConstantInt *CI = dyn_cast(Op1)) { + if (Class == cByte || Class == cShort || Class == cInt) { + unsigned Op1v = CI->getRawValue(); // Mask off any upper bits of the constant, if there are any... Op1v &= (1ULL << (8 << Class)) - 1; @@ -833,7 +833,27 @@ BuildMI(*MBB, IP, CMPTab[Class], 2).addReg(Op0r).addImm(Op1v); return OpNum; + } else { + assert(Class == cLong && "Unknown integer class!"); + unsigned LowCst = CI->getRawValue(); + unsigned HiCst = CI->getRawValue() >> 32; + if (OpNum < 2) { // seteq, setne + unsigned LoTmp = Op0r; + if (LowCst != 0) { + LoTmp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, X86::XOR32ri, 2, LoTmp).addReg(Op0r).addImm(LowCst); + } + unsigned HiTmp = Op0r+1; + if (HiCst != 0) { + HiTmp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, X86::XOR32rr, 2,HiTmp).addReg(Op0r+1).addImm(HiCst); + } + unsigned FinalTmp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, X86::OR32rr, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + return OpNum; + } } + } // Special case handling of comparison against +/- 0.0 if (ConstantFP *CFP = dyn_cast(Op1)) From criswell at cs.uiuc.edu Tue Apr 6 11:04:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 11:04:02 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/Makefile Message-ID: <200404061603.LAA00403@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications: Makefile updated: 1.5 -> 1.6 --- Log message: Added hbd (Homebrew Decompiler) to the list of tests run on Linux. It should work on other platforms; I just haven't tested it yet. --- Diffs of the changes: (+3 -0) Index: llvm/test/Programs/MultiSource/Applications/Makefile diff -u llvm/test/Programs/MultiSource/Applications/Makefile:1.5 llvm/test/Programs/MultiSource/Applications/Makefile:1.6 --- llvm/test/Programs/MultiSource/Applications/Makefile:1.5 Tue Mar 9 13:33:09 2004 +++ llvm/test/Programs/MultiSource/Applications/Makefile Tue Apr 6 11:03:17 2004 @@ -5,5 +5,8 @@ include $(LEVEL)/Makefile.config PARALLEL_DIRS = Burg aha sgefa siod lambda-0.1.3 d +ifeq ($(OS),Linux) +PARALLEL_DIRS += hbd +endif include $(LEVEL)/test/Programs/Makefile.programs From lattner at cs.uiuc.edu Tue Apr 6 11:44:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 11:44:01 2004 Subject: [llvm-commits] CVS: llvm/tools/gccld/GenerateCode.cpp gccld.cpp gccld.h Message-ID: <200404061643.LAA14137@zion.cs.uiuc.edu> Changes in directory llvm/tools/gccld: GenerateCode.cpp updated: 1.21 -> 1.22 gccld.cpp updated: 1.69 -> 1.70 gccld.h updated: 1.7 -> 1.8 --- Log message: Add a new gccld -native-cbe option which causes gccld to generate native code for the application with the C backend instead of the native LLVM code generator --- Diffs of the changes: (+48 -1) Index: llvm/tools/gccld/GenerateCode.cpp diff -u llvm/tools/gccld/GenerateCode.cpp:1.21 llvm/tools/gccld/GenerateCode.cpp:1.22 --- llvm/tools/gccld/GenerateCode.cpp:1.21 Sun Mar 7 16:12:40 2004 +++ llvm/tools/gccld/GenerateCode.cpp Tue Apr 6 11:43:13 2004 @@ -25,7 +25,6 @@ #include "llvm/Transforms/Utils/Linker.h" #include "Support/SystemUtils.h" #include "Support/CommandLine.h" - using namespace llvm; namespace { @@ -182,6 +181,23 @@ return ExecWait(cmd, envp); } +/// GenerateAssembly - generates a native assembly language source file from the +/// specified bytecode file. +int GenerateCFile(const std::string &OutputFile, const std::string &InputFile, + const std::string &llc, char ** const envp) { + // Run LLC to convert the bytecode file into C. + const char *cmd[8]; + + cmd[0] = llc.c_str(); + cmd[1] = "-march=c"; + cmd[2] = "-f"; + cmd[3] = "-o"; + cmd[4] = OutputFile.c_str(); + cmd[5] = InputFile.c_str(); + cmd[6] = NULL; + return ExecWait(cmd, envp); +} + /// GenerateNative - generates a native assembly language source file from the /// specified assembly source file. /// @@ -230,6 +246,7 @@ // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. cmd.push_back(gcc.c_str()); + cmd.push_back("-O3"); cmd.push_back("-o"); cmd.push_back(OutputFilename.c_str()); cmd.push_back(InputFilename.c_str()); Index: llvm/tools/gccld/gccld.cpp diff -u llvm/tools/gccld/gccld.cpp:1.69 llvm/tools/gccld/gccld.cpp:1.70 --- llvm/tools/gccld/gccld.cpp:1.69 Thu Feb 19 14:32:39 2004 +++ llvm/tools/gccld/gccld.cpp Tue Apr 6 11:43:13 2004 @@ -78,6 +78,9 @@ cl::opt Native("native", cl::desc("Generate a native binary instead of a shell script")); + cl::opt + NativeCBE("native-cbe", + cl::desc("Generate a native binary with the C backend and GCC")); // Compatibility options that are ignored but supported by LD cl::opt @@ -276,6 +279,30 @@ // Remove the assembly language file. removeFile (AssemblyFile); + } else if (NativeCBE) { + std::string CFile = OutputFilename + ".cbe.c"; + + // Mark the output files for removal if we get an interrupt. + RemoveFileOnSignal(CFile); + RemoveFileOnSignal(OutputFilename); + + // Determine the locations of the llc and gcc programs. + std::string llc = FindExecutable("llc", argv[0]); + std::string gcc = FindExecutable("gcc", argv[0]); + if (llc.empty()) + return PrintAndReturn(argv[0], "Failed to find llc"); + if (gcc.empty()) + return PrintAndReturn(argv[0], "Failed to find gcc"); + + // Generate an assembly language file for the bytecode. + if (Verbose) std::cout << "Generating Assembly Code\n"; + GenerateCFile(CFile, RealBytecodeOutput, llc, envp); + if (Verbose) std::cout << "Generating Native Code\n"; + GenerateNative(OutputFilename, CFile, Libraries, LibPaths, gcc, envp); + + // Remove the assembly language file. + removeFile(CFile); + } else { // Output the script to start the program... std::ofstream Out2(OutputFilename.c_str()); Index: llvm/tools/gccld/gccld.h diff -u llvm/tools/gccld/gccld.h:1.7 llvm/tools/gccld/gccld.h:1.8 --- llvm/tools/gccld/gccld.h:1.7 Fri Nov 28 01:44:09 2003 +++ llvm/tools/gccld/gccld.h Tue Apr 6 11:43:13 2004 @@ -47,6 +47,9 @@ const std::string & InputFilename, const std::string & llc, char ** const envp); + +int GenerateCFile(const std::string &OutputFile, const std::string &InputFile, + const std::string &llc, char ** const envp); int GenerateNative (const std::string & OutputFilename, const std::string & InputFilename, From lattner at cs.uiuc.edu Tue Apr 6 11:47:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 11:47:02 2004 Subject: [llvm-commits] CVS: llvm/docs/CommandGuide/gccld.html Message-ID: <200404061646.LAA21465@zion.cs.uiuc.edu> Changes in directory llvm/docs/CommandGuide: gccld.html updated: 1.10 -> 1.11 --- Log message: Document new option --- Diffs of the changes: (+10 -1) Index: llvm/docs/CommandGuide/gccld.html diff -u llvm/docs/CommandGuide/gccld.html:1.10 llvm/docs/CommandGuide/gccld.html:1.11 --- llvm/docs/CommandGuide/gccld.html:1.10 Fri Mar 12 16:45:35 2004 +++ llvm/docs/CommandGuide/gccld.html Tue Apr 6 11:46:12 2004 @@ -80,7 +80,7 @@

        Native code generation

        The gccld program has limited support for native code generation, when -using the -native option. +using the -native or -native-cbe options.

        OPTIONS

        @@ -170,6 +170,15 @@ subsets of common libraries and then link in any part of the library that hasn't been converted to bytecode.

        + +

      4. -native-cbe +
        + Generate a native, machine code executable with the LLVM C backend. +

        + This option is identical to the -native option, but uses the + C backend to generate code for the program instead of an LLVM native + code generator. +

      5. -s
        From lattner at cs.uiuc.edu Tue Apr 6 11:55:05 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 11:55:05 2004 Subject: [llvm-commits] CVS: llvm/tools/gccld/GenerateCode.cpp Message-ID: <200404061654.LAA14112@zion.cs.uiuc.edu> Changes in directory llvm/tools/gccld: GenerateCode.cpp updated: 1.22 -> 1.23 --- Log message: Minor cleanups --- Diffs of the changes: (+18 -32) Index: llvm/tools/gccld/GenerateCode.cpp diff -u llvm/tools/gccld/GenerateCode.cpp:1.22 llvm/tools/gccld/GenerateCode.cpp:1.23 --- llvm/tools/gccld/GenerateCode.cpp:1.22 Tue Apr 6 11:43:13 2004 +++ llvm/tools/gccld/GenerateCode.cpp Tue Apr 6 11:54:04 2004 @@ -39,8 +39,6 @@ cl::desc("Do not run any optimization passes")); } -namespace llvm { - static inline void addPass(PassManager &PM, Pass *P) { // Add the pass to the pass manager... PM.add(P); @@ -57,13 +55,10 @@ /// Internalize - Flags whether all symbols should be marked internal. /// Out - Pointer to file stream to which to write the output. /// -/// Outputs: -/// None. -/// /// Returns non-zero value on error. /// -int -GenerateBytecode (Module *M, bool Strip, bool Internalize, std::ostream *Out) { +int llvm::GenerateBytecode(Module *M, bool Strip, bool Internalize, + std::ostream *Out) { // In addition to just linking the input from GCC, we also want to spiff it up // a little bit. Do this now. PassManager Passes; @@ -157,36 +152,31 @@ /// llc - The pathname to use for LLC. /// envp - The environment to use when running LLC. /// -/// Outputs: -/// None. -/// /// Return non-zero value on error. /// -int -GenerateAssembly(const std::string &OutputFilename, - const std::string &InputFilename, - const std::string &llc, - char ** const envp) -{ +int llvm::GenerateAssembly(const std::string &OutputFilename, + const std::string &InputFilename, + const std::string &llc, + char ** const envp) { // Run LLC to convert the bytecode file into assembly code. - const char *cmd[8]; - + const char *cmd[6]; cmd[0] = llc.c_str(); cmd[1] = "-f"; cmd[2] = "-o"; cmd[3] = OutputFilename.c_str(); cmd[4] = InputFilename.c_str(); - cmd[5] = NULL; + cmd[5] = 0; return ExecWait(cmd, envp); } /// GenerateAssembly - generates a native assembly language source file from the /// specified bytecode file. -int GenerateCFile(const std::string &OutputFile, const std::string &InputFile, - const std::string &llc, char ** const envp) { +int llvm::GenerateCFile(const std::string &OutputFile, + const std::string &InputFile, + const std::string &llc, char ** const envp) { // Run LLC to convert the bytecode file into C. - const char *cmd[8]; + const char *cmd[7]; cmd[0] = llc.c_str(); cmd[1] = "-march=c"; @@ -194,7 +184,7 @@ cmd[3] = "-o"; cmd[4] = OutputFile.c_str(); cmd[5] = InputFile.c_str(); - cmd[6] = NULL; + cmd[6] = 0; return ExecWait(cmd, envp); } @@ -214,13 +204,11 @@ /// /// Returns non-zero value on error. /// -int -GenerateNative(const std::string &OutputFilename, - const std::string &InputFilename, - const std::vector &Libraries, - const std::vector &LibPaths, - const std::string &gcc, - char ** const envp) { +int llvm::GenerateNative(const std::string &OutputFilename, + const std::string &InputFilename, + const std::vector &Libraries, + const std::vector &LibPaths, + const std::string &gcc, char ** const envp) { // Remove these environment variables from the environment of the // programs that we will execute. It appears that GCC sets these // environment variables so that the programs it uses can configure @@ -278,5 +266,3 @@ // Run the compiler to assembly and link together the program. return ExecWait(&(cmd[0]), clean_env); } - -} // End llvm namespace From brukman at cs.uiuc.edu Tue Apr 6 12:05:01 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue Apr 6 12:05:01 2004 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/BugDriver.cpp Message-ID: <200404061704.MAA25965@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: BugDriver.cpp updated: 1.31 -> 1.32 --- Log message: Wrap at 80 cols. --- Diffs of the changes: (+6 -7) Index: llvm/tools/bugpoint/BugDriver.cpp diff -u llvm/tools/bugpoint/BugDriver.cpp:1.31 llvm/tools/bugpoint/BugDriver.cpp:1.32 --- llvm/tools/bugpoint/BugDriver.cpp:1.31 Sun Mar 14 14:50:42 2004 +++ llvm/tools/bugpoint/BugDriver.cpp Tue Apr 6 12:04:30 2004 @@ -122,13 +122,12 @@ /// variables are set up from command line arguments. /// bool BugDriver::run() { - // The first thing that we must do is determine what the problem is. Does the - // optimization series crash the compiler, or does it produce illegal code? We - // make the top-level decision by trying to run all of the passes on the the - // input program, which should generate a bytecode file. If it does generate - // a bytecode file, then we know the compiler didn't crash, so try to diagnose - // a miscompilation. - // + // The first thing that we must do is determine what the problem is. Does the + // optimization series crash the compiler, or does it produce illegal code? + // We make the top-level decision by trying to run all of the passes on the + // the input program, which should generate a bytecode file. If it does + // generate a bytecode file, then we know the compiler didn't crash, so try + // to diagnose a miscompilation. if (!PassesToRun.empty()) { std::cout << "Running selected passes on program to test for crash: "; if (runPasses(PassesToRun)) From lattner at cs.uiuc.edu Tue Apr 6 12:35:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 12:35:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404061735.MAA30602@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.216 -> 1.217 --- Log message: Fix a minor bug in previous checking Enable folding of long seteq/setne comparisons into branches and select instructions Implement unfolded long relational comparisons against a constants a bit more efficiently Folding comparisons changes code that looks like this: mov %EAX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] mov %ECX, %EAX or %ECX, %EDX sete %CL test %CL, %CL je .LBB2 # PC rel: F into code that looks like this: mov %EAX, DWORD PTR [%ESP + 4] mov %EDX, DWORD PTR [%ESP + 8] mov %ECX, %EAX or %ECX, %EDX jne .LBB2 # PC rel: F This speeds up 186.crafty by 6% with llc-ls. --- Diffs of the changes: (+29 -2) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.216 llvm/lib/Target/X86/InstSelectSimple.cpp:1.217 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.216 Tue Apr 6 11:02:27 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Tue Apr 6 12:34:50 2004 @@ -756,7 +756,9 @@ Instruction *User = cast(SCI->use_back()); if ((isa(User) || isa(User)) && SCI->getParent() == User->getParent() && - getClassB(SCI->getOperand(0)->getType()) != cLong) + (getClassB(SCI->getOperand(0)->getType()) != cLong || + SCI->getOpcode() == Instruction::SetEQ || + SCI->getOpcode() == Instruction::SetNE)) return SCI; } return 0; @@ -846,10 +848,35 @@ unsigned HiTmp = Op0r+1; if (HiCst != 0) { HiTmp = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, X86::XOR32rr, 2,HiTmp).addReg(Op0r+1).addImm(HiCst); + BuildMI(*MBB, IP, X86::XOR32ri, 2,HiTmp).addReg(Op0r+1).addImm(HiCst); } unsigned FinalTmp = makeAnotherReg(Type::IntTy); BuildMI(*MBB, IP, X86::OR32rr, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + return OpNum; + } else { + // Emit a sequence of code which compares the high and low parts once + // each, then uses a conditional move to handle the overflow case. For + // example, a setlt for long would generate code like this: + // + // AL = lo(op1) < lo(op2) // Signedness depends on operands + // BL = hi(op1) < hi(op2) // Always unsigned comparison + // dest = hi(op1) == hi(op2) ? AL : BL; + // + + // FIXME: This would be much better if we had hierarchical register + // classes! Until then, hardcode registers so that we can deal with + // their aliases (because we don't have conditional byte moves). + // + BuildMI(*MBB, IP, X86::CMP32ri, 2).addReg(Op0r).addImm(LowCst); + BuildMI(*MBB, IP, SetCCOpcodeTab[0][OpNum], 0, X86::AL); + BuildMI(*MBB, IP, X86::CMP32ri, 2).addReg(Op0r+1).addImm(HiCst); + BuildMI(*MBB, IP, SetCCOpcodeTab[CompTy->isSigned()][OpNum], 0,X86::BL); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::BH); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::AH); + BuildMI(*MBB, IP, X86::CMOVE16rr, 2, X86::BX).addReg(X86::BX) + .addReg(X86::AX); + // NOTE: visitSetCondInst knows that the value is dumped into the BL + // register at this point for long values... return OpNum; } } From criswell at cs.uiuc.edu Tue Apr 6 12:52:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:52:01 2004 Subject: [llvm-commits] CVS: llvm/LICENSE.TXT Message-ID: <200404061751.MAA00962@choi.cs.uiuc.edu> Changes in directory llvm: LICENSE.TXT updated: 1.12 -> 1.13 --- Log message: Added licensing information for treecc. --- Diffs of the changes: (+1 -0) Index: llvm/LICENSE.TXT diff -u llvm/LICENSE.TXT:1.12 llvm/LICENSE.TXT:1.13 --- llvm/LICENSE.TXT:1.12 Fri Mar 12 11:29:20 2004 +++ llvm/LICENSE.TXT Tue Apr 6 12:51:10 2004 @@ -72,6 +72,7 @@ D: llvm/test/Programs/MultiSource/Applications/d Lambda: llvm/test/Programs/MultiSource/Applications/lambda-0.1.3 hbd: llvm/test/Programs/MultiSource/Applications/hbd +treecc: llvm/test/Programs/MultiSource/Applications/treecc Fhourstones: llvm/test/Programs/MultiSource/Benchmarks/Fhourstones McCat: llvm/test/Programs/MultiSource/Benchmarks/McCat Olden: llvm/test/Programs/MultiSource/Benchmarks/Olden From criswell at cs.uiuc.edu Tue Apr 6 12:52:07 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:52:07 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/ Message-ID: <200404061751.MAA00969@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/treecc added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 12:52:11 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:52:11 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/LICENSE.TXT Message-ID: <200404061751.MAA00983@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc: LICENSE.TXT added (r1.1) --- Log message: License file for treecc. --- Diffs of the changes: (+9 -0) Index: llvm/test/Programs/MultiSource/Applications/treecc/LICENSE.TXT diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/LICENSE.TXT:1.1 *** /dev/null Tue Apr 6 12:51:46 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/LICENSE.TXT Tue Apr 6 12:51:36 2004 *************** *** 0 **** --- 1,9 ---- + TreeCC + ------------------------------------------------------------------------------ + TreeCC is licensed under the GNU General Public License. Please see the file + COPYING for more information. It is copyright by Southern Storm Software, Pty + Ltd. + + Neither the original copyright holder nor the University of Illinois provide + any warranty; please see the llvm/LICENSE.TXT file for more details. + From criswell at cs.uiuc.edu Tue Apr 6 12:54:04 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:54:04 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/.cvsignore AUTHORS COPYING ChangeLog INSTALL Makefile NEWS README config.h context.c errors.c errors.h gen.c gen.h gen_c.c gen_cpp.c gen_cs.c gen_java.c gen_php.c gen_ruby.c info.h input.c input.h literal.c main.c node.c oper.c options.c options.h parse.c parse.h skeleton.c skels.c stream.c stream.h system.h Message-ID: <200404061753.MAA01082@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc: .cvsignore added (r1.1) AUTHORS added (r1.1) COPYING added (r1.1) ChangeLog added (r1.1) INSTALL added (r1.1) Makefile added (r1.1) NEWS added (r1.1) README added (r1.1) config.h added (r1.1) context.c added (r1.1) errors.c added (r1.1) errors.h added (r1.1) gen.c added (r1.1) gen.h added (r1.1) gen_c.c added (r1.1) gen_cpp.c added (r1.1) gen_cs.c added (r1.1) gen_java.c added (r1.1) gen_php.c added (r1.1) gen_ruby.c added (r1.1) info.h added (r1.1) input.c added (r1.1) input.h added (r1.1) literal.c added (r1.1) main.c added (r1.1) node.c added (r1.1) oper.c added (r1.1) options.c added (r1.1) options.h added (r1.1) parse.c added (r1.1) parse.h added (r1.1) skeleton.c added (r1.1) skels.c added (r1.1) stream.c added (r1.1) stream.h added (r1.1) system.h added (r1.1) --- Log message: Initial commit of treecc test program. --- Diffs of the changes: (+17512 -0) Index: llvm/test/Programs/MultiSource/Applications/treecc/.cvsignore diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/.cvsignore:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/.cvsignore Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,13 ---- + Makefile + Makefile.in + .deps + configure + config.log + config.cache + config.status + config.h + stamp-h + treecc + aclocal.m4 + config.h.in + skels.c Index: llvm/test/Programs/MultiSource/Applications/treecc/AUTHORS diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/AUTHORS:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/AUTHORS Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1 ---- + Southern Storm Software, Pty Ltd Index: llvm/test/Programs/MultiSource/Applications/treecc/COPYING diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/COPYING:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/COPYING Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,340 ---- + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + convey the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Also add information on how to contact you by electronic and paper mail. + + If the program is interactive, make it output a short notice like this + when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + + The hypothetical commands `show w' and `show c' should show the appropriate + parts of the General Public License. Of course, the commands you use may + be called something other than `show w' and `show c'; they could even be + mouse-clicks or menu items--whatever suits your program. + + You should also get your employer (if you work as a programmer) or your + school, if any, to sign a "copyright disclaimer" for the program, if + necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your program into + proprietary programs. If your program is a subroutine library, you may + consider it more useful to permit linking proprietary applications with the + library. If this is what you want to do, use the GNU Library General + Public License instead of this License. Index: llvm/test/Programs/MultiSource/Applications/treecc/ChangeLog diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/ChangeLog:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/ChangeLog Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,378 ---- + + 2004-01-03 Rhys Weatherley + + * configure.in, NEWS: update version for the 0.2.8 release. + + 2003-12-03 Rhys Weatherley + + * gen_c.c, tests/output15.out, tests/output7.out, tests/output8.out: + don't put a trailing comma on "enum" definitions, because strict ANSI + C compilers don't like them (thanks to Miroslaw Dobrzanski-Neumann). + + 2003-11-20 Gopal.V + + * context.c, gen_cpp.c, gen_cs.c, gen_java.c, info.h, options.c, + doc/treecc.texi: add the "base_type" option. + + 2003-07-17 Rhys Weatherley + + * configure.in, NEWS: update version for the 0.2.6 release. + + * configure.in: update working version to "0.2.7". + + 2003-07-05 Rhys Weatherley + + * gen_c.c, gen_cpp.c: fix some incorrect variable declarations + that gcc allowed through when it shouldn't have. + + 2003-07-04 Rhys Weatherley + + * README: minor change to the treecc README file. + + * Makefile.am, context.c, gen_c.c, gen_cpp.c, info.h, options.c, + doc/treecc.texi, etc/Makefile.am, etc/c_gc_skel.c, etc/c_gc_skel.h, + etc/cpp_gc_skel.cc, etc/cpp_gc_skel.h, tests/output17.out, + tests/output17.tst, tests/output18.out, tests/output18.tst, + tests/test_list: add the "gc_allocator" option to treecc, + to make the node allocator use libgc. + + 2003-02-29 Rhys Weatherley + + * tests/output5.out, tests/output6.out, tests/output9.out: + update test output files for one of jeyk's fixes. + + * configure.in, NEWS: update version for the 0.2.4 release. + + * configure.in: update working version to "0.2.5". + + 2003-02-29 Jeyasankar Kottalam + + * gen_cpp.cpp, etc/cpp_skel.cc: add namespace support for C++; + fix a bug in the C++ skeleton. + + 2003-02-08 Stephen Compall + + * treecc.spec.in: Removed $PREFIX/share/treecc from the install + search-path. + + 2003-02-08 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.2.2" release. + + * configure.in: update working version to "0.2.3". + + 2003-01-29 Rhys Weatherley + + * context.c, gen_c.c, gen_cpp.c, info.h, options.c, doc/treecc.texi, + etc/cpp_skel.cc, tests/output5.out, tests/output6.out, + tests/output9.out: add the "allocator" and "no_allocator" options, + which allow treecc's C/C++ node allocators to be replaced with + third party node allocators. + + * main.c, doc/treecc.1, doc/treecc.texi: add the "-O" option to + the treecc command-line, which allows "%option" commands to + be issued directly from the command-line. + + * tests/.cvsignore, tests/Makefile.am, tests/normalize.c, + tests/run_tests: replace the reference to "sed" in "run_tests" + with "normalize", to work around problems with CRLF's under cygwin. + + 2003-01-27 James Michael DuPont + + * context.c, info.h, options.c, stream.c: add the "print_lines" + and "no_print_lines" options to suppress #line directives. + + 2003-01-27 Rhys Weatherley + + * doc/treecc.texi: minor adjustment to direntry tag; only include + treecc once in the info directory. + + * doc/treecc.texi: document the "print_lines" and "no_print_lines" + options. + + 2003-01-26 Stephen Compall + + * doc/treecc.texi: Added info dir entries. + + 2003-01-15 Gopal.V + + * gen_php.c: Merge patch #942 for Php output and make a few cosmetic + changes to the file. + + 2003-01-11 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.2.0" release. + + * configure.in: update working version to "0.2.1". + + 2003-01-11 Alan Knowles + + * Makefile.am, gen.c, gen.h, gen_php.c, info.h, options.c: + add support for PHP output. + + 2003-01-09 Rhys Weatherley + + * stream.c (TreeCCStreamCreate): copy the "force" flag from + the configuration settings into newly created streams. + + 2002-12-31 Rhys Weatherley + + * gen_cs.c, gen_java.c, info.h, options.c, doc/treecc.texi, + tests/output16.out, tests/output16.tst, tests/test_list: + add the "internal_access" and "public_access" options, so that + treecc can output assembly-private node definitions. + + 2002-12-21 Rhys Weatherley + + * configure.in: remove AC_PROG_CXX from configure.in, because it + isn't necessary any more since expr_cpp was disabled. + + 2002-12-16 Rhys Weatherley + + * tests/run_tests: perform end of line conversion on the expected + test output files to prevent problems when diff'ing on MS-DOS systems. + + * configure.in: don't use "-mno-cygwin" with "mingw32" compilers. + + 2002-12-15 Rhys Weatherley + + * mkskel-sh, .cvsignore, Makefile.am, info.h, main.c, skeleton.c, + doc/treecc.1, doc/treecc.texi, etc/Makefile.am, tests/output1.out, + tests/output12.out, tests/output13.out, tests/output14.out, + tests/output15.out, tests/output2.out, tests/output3.out, + tests/output4.out, tests/output5.out, tests/output6.out, + tests/output7.out, tests/output8.out, tests/output9.out, + tests/test_output.c: bind the skeleton files into the "treecc" + binary so that we don't have any more skeleton path search problems. + + * README, configure.in: always turn off cygwin builds under Win32. + + * configure.in, config.guess, config.sub: set up for a canonical + build system, so that cygwin/mingw32 detection works correctly. + + * Makefile.am, configure.in, examples/Makefile.am, tests/Makefile.am: + remove TREECC_DATA_DIR and clean up the -Wall handling for gcc. + + * examples/Makefile.am: remove the unnecessary skeleton directory + specification. + + * make-zip.sh, doc/binary_readme.txt: add the "make-zip.sh" + script, to assist with building a Win32 binary .zip file package. + + * errors.c, main.c, examples/Makefile.am, examples/expr_c.tc, + tests/Makefile.am, tests/run_tests, tests/test_input.c, + tests/test_output.c, tests/test_parse.c: changes to support + out of tree builds properly. + + 2002-11-24 Gopal V + + * treecc.spec, configure.in, treecc.spec.in: Fix RPM builds + + 2002-11-23 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.1.8" release. + + * configure.in: update working version to "0.1.9". + + 2002-11-16 Peter Minten + + * doc/treecc.texi: Added Ruby output documentation. + + 2002-11-09 Peter Minten + + * gen_ruby.c: Modified to create code compliant with Ruby markup + conventions, also some little bug fixes. + + * examples/expr_ruby.tc: Improved example. + + * stream.h, stream.c: Overloaded TreeCCStreamCodeIndent + to support languages that don't use tabs for indenting. + + 2002-11-05 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.1.6" release. + + * configure.in: update working version to "0.1.7". + + 2002-11-03 Rhys Weatherley + + * doc/extending.txt, README: add a "quick and dirty" guide for + people who want to extend treecc with new output languages. + + 2002-10-26 Peter Minten + + * Makefile.am, gen.c, gen.h, gen_ruby.c, info.h, options.c, + examples/README, examples/expr_ruby.tc: add Ruby code generation + support to treecc. + + 2002-09-12 Rhys Weatherley + + * gen_cpp.c: extra comma where there shouldn't be in the + declaration of C++ virtual operations. + + 2002-09-02 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.1.4" release. + + * configure.in: update working version to "0.1.5". + + 2002-08-13 Rhys Weatherley + + * auto_gen.sh: slightly smarter script that also runs "aclocal". + + * aclocal.m4, config.h.in, missing, examples/Makefile.am, + examples/ylwrap: update build system to automake 1.6, and remove + "expr_cpp" from the build because cygwin's automake is busted. + + * auto_gen.sh, config.h.in: remove config.h.in from the CVS + tree and generate it from "auto_gen.sh" instead. + + 2002-06-27 Rhys Weatherley + + * NEWS, configure.in: update version for the "0.1.2" release. + + * configure.in: update working version to "0.1.3". + + 2002-06-14 Rhys Weatherley + + * auto_gen.sh, configure.in: make the system more friendly to + automake 1.5 systems. + + * tests/run_tests: work-around versions of "sed" that do not + recognise "-" to mean standard input. + + 2002-05-27 Rhys Weatherley + + * tests/Makefile.am, examples/Makefile.am: patches from + Stephen Compall to support out of tree builds. + + 2002-04-20 Rhys Weatherley + + * configure.in, NEWS: update version for the "0.1.0" release. + + * configure.in: update the working version to "0.1.1". + + 2002-04-01 Rhys Weatherley + + * configure.in, aclocal.m4: use "AM_MAINTAINER_MODE" in the + configure.in file to work around automake issues under Cygwin. + + * conf_fix.sh, README: remove "conf_fix.sh", as we don't + need it any more with maintainer mode. + + * auto_gen.sh: pass the "-a" option to "automake". + + 2002-03-27 Rhys Weatherley + + * conf_fix.sh, README: add a configuration script that can be + used to get around problems with automake 1.5 under Cygwin. + + * configure.in, NEWS: update version for the "0.0.8" release. + + * configure.in: update the working version to "0.0.9". + + 2002-03-23 Rhys Weatherley + + * doc/essay.html, README: add the treecc essay to the "doc" + subdirectory. + + 2002-03-17 Rhys Weatherley + + * context.c, gen_c.c, gen_cpp.c, gen_cs.c, gen_java.c, info.h, + options.c, skeleton.c, stream.c, stream.h, doc/treecc.texi: + implement the "strip_filenames" option to make it more likely + that treecc will generate constant output files regardless of + which directory it is executed in. + + * auto_gen.sh, README: add the "auto_gen.sh" script and some + instructions on its use. + + 2002-03-05 Rhys Weatherley + + * doc/treecc.texi: polish the text a little. + + * etc/cpp_skel.cc: declare the argument to "alloc" as "size_t", + to match the declaration in the common header file. + + * tests/output5.out, tests/output6.out, tests/output9.out: + modify test output files to match the change to "etc/cpp_skel.cc". + + 2002-01-10 Rhys Weatherley + + * configure.in, examples/Makefile.am: only build "expr_cpp" if + bison is being used, because it uses features that are not + compatible with byacc. + + 2002-01-07 Rhys Weatherley + + * input.c: add ';' after a goto label for correct ANSI C syntax. + + 2001-12-28 Rhys Weatherley + + * gen_c.c (ImplementCreateFuncs): insert a '*' into the return + cast when creating a singleton. + + * context.c, gen_c.c, info.h, options.c, doc/treecc.texi: + add the options "kind_in_vtable" and "kind_in_node". + + * skeleton.c (TreeCCIncludeSkeleton): replace all instances of + "yy" in a skeleton with "context->yy_replacement". + + * tests/output12.out, tests/output12.tst, tests/output13.out, + tests/output13.tst, tests/output14.out, tests/output14.tst, + tests/test_list: add new tests for singletons, vtable kinds, and + "yy" replacement. + + * ChangeLog: adjust the ChangeLog format to make it Emacs-friendly. + + * gen.c, gen.h, gen_c.c, gen_java.c, info.h, input.c, input.h, + parse.c, doc/treecc.texi, tests/output15.out, tests/output15.tst, + tests/test_input.c, tests/test_list: implement the "%split" flag + for non-virtual operations to split large "switch" statements + across multiple functions. + + * configure.in, NEWS: update the release version to 0.0.6. + + * configure.in: change the version to "0.0.7" for the new working + version. + + 2001-12-16 Rhys Weatherley + + * main.c: bug fix - create the default output files correctly; + defaults weren't working when the input didn't have "%output" + specified. + + 2001-12-11 Rhys Weatherley + + * etc/c_skel.c, etc/cpp_skel.cc: swap the order of "data__" and + "next__" in "YYNODESTATE_block" so that the start of the + "data__" buffer will be properly aligned on 64-bit platforms. + + * tests/output1.out, tests/output2.out, tests/output3.out, + tests/output4.out, tests/output5.out, tests/output6.out, + tests/output7.out, tests/output8.out, tests/output9.out: + new test output files that were affected by the skeleton change. + + 2001-11-08 Rhys Weatherley + + * etc/c_skel.c, etc/cpp_skel.cc: update the C and C++ skeleton + files with an alignment algorithm that should work better on + platforms such as 64-bit Solaris. + + * tests/output1.out, tests/output2.out, tests/output3.out, + tests/output4.out, tests/output5.out, tests/output6.out, + tests/output7.out, tests/output8.out, tests/output9.out: + new test output files that were affected by the skeleton change. + + * doc/treecc.texi: insert a "@page" command to force the index to + be formatted correctly when PDF documentation is generated. + + * configure.in, NEWS: version and news updates for the "0.0.4" release. + + * configure.in: change the version to "0.0.5" for the new working + version. + + 2001-08-14 Rhys Weatherley + + * treecc.spec: applied patch submitted by mdaniel to create + RPM spec file. Index: llvm/test/Programs/MultiSource/Applications/treecc/INSTALL diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/INSTALL:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/INSTALL Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,182 ---- + Basic Installation + ================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for + various system-dependent variables used during compilation. It uses + those values to create a `Makefile' in each directory of the package. + It may also create one or more `.h' files containing system-dependent + definitions. Finally, it creates a shell script `config.status' that + you can run in the future to recreate the current configuration, a file + `config.cache' that saves the results of its tests to speed up + reconfiguring, and a file `config.log' containing compiler output + (useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try + to figure out how `configure' could check whether to do them, and mail + diffs or instructions to the address given in the `README' so they can + be considered for the next release. If at some point `config.cache' + contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program + called `autoconf'. You only need `configure.in' if you want to change + it or regenerate `configure' using a newer version of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + Compilers and Options + ===================== + + Some systems require unusual options for compilation or linking that + the `configure' script does not know about. You can give `configure' + initial values for variables by setting them in the environment. Using + a Bourne-compatible shell, you can do that on the command line like + this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + + Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + + Compiling For Multiple Architectures + ==================================== + + You can compile the package for more than one kind of computer at the + same time, by placing the object files for each architecture in their + own directory. To do this, you must use a version of `make' that + supports the `VPATH' variable, such as GNU `make'. `cd' to the + directory where you want the object files and executables to go and run + the `configure' script. `configure' automatically checks for the + source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' + variable, you have to compile the package for one architecture at a time + in the source code directory. After you have installed the package for + one architecture, use `make distclean' before reconfiguring for another + architecture. + + Installation Names + ================== + + By default, `make install' will install the package's files in + `/usr/local/bin', `/usr/local/man', etc. You can specify an + installation prefix other than `/usr/local' by giving `configure' the + option `--prefix=PATH'. + + You can specify separate installation prefixes for + architecture-specific files and architecture-independent files. If you + give `configure' the option `--exec-prefix=PATH', the package will use + PATH as the prefix for installing programs and libraries. + Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give + options like `--bindir=PATH' to specify different values for particular + kinds of files. Run `configure --help' for a list of the directories + you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed + with an extra prefix or suffix on their names by giving `configure' the + option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Optional Features + ================= + + Some packages pay attention to `--enable-FEATURE' options to + `configure', where FEATURE indicates an optional part of the package. + They may also pay attention to `--with-PACKAGE' options, where PACKAGE + is something like `gnu-as' or `x' (for the X Window System). The + `README' should mention any `--enable-' and `--with-' options that the + package recognizes. + + For packages that use the X Window System, `configure' can usually + find the X include and library files automatically, but if it doesn't, + you can use the `configure' options `--x-includes=DIR' and + `--x-libraries=DIR' to specify their locations. + + Specifying the System Type + ========================== + + There may be some features `configure' can not figure out + automatically, but needs to determine by the type of host the package + will run on. Usually `configure' can figure that out, but if it prints + a message saying it can not guess the host type, give it the + `--host=TYPE' option. TYPE can either be a short name for the system + type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + + See the file `config.sub' for the possible values of each field. If + `config.sub' isn't included in this package, then this package doesn't + need to know the host type. + + If you are building compiler tools for cross-compiling, you can also + use the `--target=TYPE' option to select the type of system they will + produce code for and the `--build=TYPE' option to select the type of + system on which you are compiling the package. + + Sharing Defaults + ================ + + If you want to set default values for `configure' scripts to share, + you can create a site shell script called `config.site' that gives + default values for variables like `CC', `cache_file', and `prefix'. + `configure' looks for `PREFIX/share/config.site' if it exists, then + `PREFIX/etc/config.site' if it exists. Or, you can set the + `CONFIG_SITE' environment variable to the location of the site script. + A warning: not all `configure' scripts look for a site script. + + Operation Controls + ================== + + `configure' recognizes the following options to control how it + operates. + + `--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + + `--help' + Print a summary of the options to `configure', and exit. + + `--quiet' + `--silent' + `-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + + `--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + + `--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + + `configure' also accepts some other, not widely useful, options. Index: llvm/test/Programs/MultiSource/Applications/treecc/Makefile diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/Makefile:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/Makefile Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,6 ---- + LEVEL = ../../../../.. + PROG = treecc + #LDFLAGS += -lstdc++ + #LIBS += -lstdc++ + STDIN_FILENAME=$(BUILD_SRC_DIR)/tests/input3.tst + include ../../Makefile.multisrc Index: llvm/test/Programs/MultiSource/Applications/treecc/NEWS diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/NEWS:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/NEWS Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,105 ---- + + 0.2.8 (3 January 2004) + + * Add the "base_type" option (Gopal V). + * Don't put trailing commas on enums because strict ANSI C + does not allow trailing commas (Miroslaw Dobrzanski-Neumann). + + 0.2.6 (17 July 2003) + + * Add the "gc_allocator" option, so that node allocation can be + done using "libgc" if the programmer chooses to do so. + * Fix some non-ANSI variable declarations. + + 0.2.4 (29 March 2003) + + * Fixes to treecc.spec.in for RPM generation (Stephen Compall). + * Add support for namespaces in C++ (Jeyasankar Kottalam). + * Change "new.h" to "new" to comply with C++ standards + (Jeyasankar Kottalam). + * Fix the return type of YYNODESTATE::dealloc (Jeyasankar Kottalam). + + 0.2.2 (8 February 2003) + + * PHP back-end patches (Alan Knowles). + * Add directory entries to texinfo documentation (Stephen Compall). + * "print_lines" and "no_print_lines" options (James Michael DuPont). + * "allocator" and "no_allocator" options. + * Permit treecc "%name" options to be set from the command-line. + * Replace "sed" with "normalize" in "run_tests", to work around + problems on systems with CRLF end of line markers (e.g. cygwin. + + 0.2.0 (11 January 2003) + + * Bind the skeleton files directly into the "treecc" binary, + to solve problems with locating the skeletons at runtime. + * Always disable cygwin for Win32 builds. + * Better support for out of tree builds. + * Fix up end of line handling in the test suite so that the + tests don't fail because of CRLF vs LF issues. + * Add the "interal_access" and "public_access" options to + support creating private libraries of nodes in C#. + * Fix the "-f" (force) command-line flag. + * PHP back-end (Alan Knowles). + + 0.1.8 (23 November 2002) + + * Bug fixes and documentation for Ruby back-end (Peter Minten). + * Support languages that don't use tabs for indenting (Peter Minten). + + 0.1.6 (5 November 2002) + + * Fix C++ code generation in the declaration of virtual operations. + * Add Ruby code generation (Peter Minten). + * "Quick and Dirty" guide to extending treecc to new languages. + + 0.1.4 (2 September 2002) + + * Fixes to "auto_gen.sh" and autoconf/automake support scripts + to better support automake 1.6 systems. + + 0.1.2 (27 June 2002) + + * Add some patches to support out of tree builds (Stephen Compall). + * Make the build system more automake 1.5 friendly. + * Work around versions of "sed" that don't support "-" for stdin. + + 0.1.0 (20 April 2002) + + * Add maintainer mode to the autoconf system to work around + autotools version problems. + + 0.0.8 (27 March 2002) + + * ANSI C compatiblity fixes. + * Only build "expr_cpp" if bison is being used because "byacc" + does not understand the options used in the C++ grammar. + * Polish the Texinfo documentation a little. + * Fix the C++ skeleton to use "size_t" in the declaration of "alloc". + * Implement the "strip_filenames" option to improve the predictability + of code generation in Portable.NET's C# compiler. + * Add the "auto_gen.sh" and "conf_fix.sh" scripts. + * Add the "essay.html" file to the documentation directory. + + 0.0.6 (28 December 2001) + + * Swap the order of some fields in "YYNODESTATE" to align nodes + better on 64-bit platforms. + * Fix a bug which prevented treecc from creating default output + files if "%output" and "%header" were missing from the source. + * Bug fix in the singleton code: missing '*' in return case. + * Add an option for kind values in either the node or the vtable. + Vtable kinds can help reduce memory requirements. + * Bug fix to the skeleton expansion code: "yy" was not being + properly expanded to the specified prefix. + * Implement the "%split" flag for non-virtual operations to split + large "switch" statements across multiple functions. This should + help alleviate optimisation problems when compiling Portable.NET's + C# compiler with GCC 3.0. + + 0.0.4 (8 November 2001) + + * Modify the skeleton files so that tree nodes are aligned correctly + on 64-bit Solaris systems. + * Slight documentation and GNU-compliance updates. + * New version numbering scheme. Index: llvm/test/Programs/MultiSource/Applications/treecc/README diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/README:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/README Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,77 ---- + Tree Compiler-Compiler + ====================== + + The treecc program is designed to assist in the development of compilers + and other language-based tools. It manages the generation of code to handle + abstract syntax trees and operations upon the trees. + + A fuller account of why treecc exists and what it can be used for can + be found in the Texinfo documentation within the "doc" subdirectory, + and in the introductory article "doc/essay.html". + + Downloading and Building + ------------------------ + + The latest version of treecc can be obtained from the following Web site: + + http://www.southern-storm.com.au/treecc/ + + To build and install, unpack the ".tar.gz" file into a temporary directory + and execute the following commands: + + $ ./configure + $ make all + $ make check + $ make install + + The "make check" runs the treecc test suite to check for any problems + on your system. Report any such problems to the authors, together with + a script of the failed test output. + + If you obtained the treecc sources via CVS, you will need to run the + following before "./configure": + + $ ./auto_gen.sh + + If you wish to install treecc somewhere other than the default prefix + ("/usr/local"), use the following configuration command instead: + + $ ./configure --prefix=PREFIX + + where "PREFIX" is the full pathname of the directory where you want to + install the program. + + If you want to add a new output language, see "doc/extending.txt". + + Copyright Considerations + ------------------------ + + Treecc is distributed under the terms of the GNU General Public License. + A copy of this can be found in the "COPYING" file. + + However, it is not our intention to restrict the use of treecc to only + free software providers. Use by commercial software vendors is welcome. + + When you use treecc on your own input files to generate source code as + output, the resulting source code files are also owned by you. You may + re-distribute unmodified copies of these output source files, and any + binaries derived from them, in any way you see fit. + + If you modify treecc itself, and generate new output files as a result, + then you must release all modifications to treecc with your program so + that other users can benefit from your changes under the terms of the GPL. + + Contact the authors if you have any questions regarding the above. + It is our intention to allow the same amount of access to treecc output + files as is currently available using the GNU Bison and Flex programs. + + Contacting the Authors + ---------------------- + + The authors can be contacted via e-mail at the following address: + + treecc at southern-storm.com.au + + Also check our Web site for updates to treecc: + + http://www.southern-storm.com.au/treecc/ Index: llvm/test/Programs/MultiSource/Applications/treecc/config.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/config.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/config.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,72 ---- + /* config.h. Generated automatically by configure. */ + /* config.h.in. Generated automatically from configure.in by autoheader. */ + + /* Define to empty if the keyword does not work. */ + /* #undef const */ + + /* Define if you have the ANSI C header files. */ + #define STDC_HEADERS 1 + + /* Define if lex declares yytext as a char * by default, not a char[]. */ + #define YYTEXT_POINTER 1 + + /* Define if you have the _vsnprintf function. */ + /* #undef HAVE__VSNPRINTF */ + + /* Define if you have the access function. */ + #define HAVE_ACCESS 1 + + /* Define if you have the memcmp function. */ + #define HAVE_MEMCMP 1 + + /* Define if you have the memcpy function. */ + #define HAVE_MEMCPY 1 + + /* Define if you have the qsort function. */ + #define HAVE_QSORT 1 + + /* Define if you have the stat function. */ + #define HAVE_STAT 1 + + /* Define if you have the strchr function. */ + #define HAVE_STRCHR 1 + + /* Define if you have the vfprintf function. */ + #define HAVE_VFPRINTF 1 + + /* Define if you have the vsnprintf function. */ + #define HAVE_VSNPRINTF 1 + + /* Define if you have the vsprintf function. */ + #define HAVE_VSPRINTF 1 + + /* Define if you have the header file. */ + #define HAVE_STDARG_H 1 + + /* Define if you have the header file. */ + #define HAVE_STDLIB_H 1 + + /* Define if you have the header file. */ + #define HAVE_STRING_H 1 + + /* Define if you have the header file. */ + #define HAVE_STRINGS_H 1 + + /* Define if you have the header file. */ + #define HAVE_SYS_STAT_H 1 + + /* Define if you have the header file. */ + #define HAVE_SYS_TYPES_H 1 + + /* Define if you have the header file. */ + #define HAVE_UNISTD_H 1 + + /* Define if you have the header file. */ + /* #undef HAVE_VARARGS_H */ + + /* Name of package */ + #define PACKAGE "treecc" + + /* Version number of package */ + #define VERSION "0.2.8" + Index: llvm/test/Programs/MultiSource/Applications/treecc/context.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/context.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/context.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,111 ---- + /* + * context.c - Create or destroy "treecc" parsing contexts. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + TreeCCContext *TreeCCContextCreate(TreeCCInput *input) + { + TreeCCContext *context; + + /* Allocate space for the context */ + if((context = (TreeCCContext *)calloc(1, sizeof(TreeCCContext))) == 0) + { + TreeCCOutOfMemory(input); + } + + /* Initialize and return the context */ + context->input = input; + context->debugMode = 0; + context->track_lines = 1; + context->no_singletons = 0; + context->reentrant = 0; + context->force = 0; + context->virtual_factory = 0; + context->abstract_factory = 0; + context->kind_in_vtable = 0; + context->strip_filenames = 0; + context->print_lines = 1; + context->internal_access = 0; + context->use_allocator = 1; + context->use_gc_allocator = 0; + context->yy_replacement = "yy"; + context->state_type = "YYNODESTATE"; + context->namespace = 0; + context->language = TREECC_LANG_C; + context->block_size = 0; + context->nodeNumber = 1; + context->baseType = 0; + return context; + } + + void TreeCCContextDestroy(TreeCCContext *context) + { + unsigned int hash; + TreeCCNode *node, *nextNode; + TreeCCOperation *oper, *nextOper; + TreeCCStream *stream, *nextStream; + + /* Close the source streams */ + stream = context->streamList; + while(stream != 0) + { + nextStream = stream->nextStream; + TreeCCStreamDestroy(stream); + stream = nextStream; + } + + /* Free the contents of the node hash */ + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + node = context->nodeHash[hash]; + while(node != 0) + { + nextNode = node->nextHash; + TreeCCNodeFree(node); + node = nextNode; + } + } + + /* Free the contents of the operation hash */ + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + oper = context->operHash[hash]; + while(oper != 0) + { + nextOper = oper->nextHash; + TreeCCOperationFree(oper); + oper = nextOper; + } + } + + /* Free the context block itself */ + free(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/errors.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/errors.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/errors.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,124 ---- + /* + * errors.c - Error and message reporting for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + FILE *TreeCCErrorFile = NULL; + int TreeCCErrorStripPath = 0; + + static void ReportError(char *filename, long linenum, + const char *format, VA_LIST va) + { + if(!TreeCCErrorFile) + { + TreeCCErrorFile = stderr; + } + if(filename) + { + if(TreeCCErrorStripPath) + { + int len = strlen(filename); + while(len > 0 && filename[len - 1] != '/' && + filename[len - 1] != '\\') + { + --len; + } + filename += len; + } + fputs(filename, TreeCCErrorFile); + putc(':', TreeCCErrorFile); + } + fprintf(TreeCCErrorFile, "%ld: ", linenum); + #ifdef HAVE_VFPRINTF + vfprintf(TreeCCErrorFile, format, va); + #else + fputs(format, TreeCCErrorFile); + #endif + putc('\n', TreeCCErrorFile); + fflush(TreeCCErrorFile); + } + + void TreeCCError(TreeCCInput *input, const char *format, ...) + { + VA_START; + ReportError((input ? input->filename : 0), + (input ? input->linenum : 0), format, VA_GET_LIST); + VA_END; + if(input) + { + input->errors = 1; + } + } + + void TreeCCErrorOnLine(TreeCCInput *input, char *filename, long linenum, + const char *format, ...) + { + VA_START; + ReportError(filename, linenum, format, VA_GET_LIST); + VA_END; + if(input) + { + input->errors = 1; + } + } + + void TreeCCAbort(TreeCCInput *input, const char *format, ...) + { + VA_START; + ReportError((input ? input->filename : 0), + (input ? input->linenum : 0), format, VA_GET_LIST); + VA_END; + exit(1); + } + + void TreeCCDebug(long linenum, const char *format, ...) + { + VA_START; + printf("line %ld: ", linenum); + #ifdef HAVE_VFPRINTF + vfprintf(stdout, format, VA_GET_LIST); + #else + fputs(format, stdout); + #endif + putc('\n', stdout); + VA_END; + fflush(stdout); + } + + void TreeCCOutOfMemory(TreeCCInput *input) + { + if(input && input->progname) + { + fputs(input->progname, stderr); + fputs(": ", stderr); + } + fputs("virtual memory exhausted\n", stderr); + exit(1); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/errors.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/errors.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/errors.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,73 ---- + /* + * errors.h - Error and message reporting for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_ERRORS_H + #define _TREECC_ERRORS_H + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * If we are using GCC, then make it perform some extra + * error checking for printf-style formats. + */ + #ifdef __GNUC__ + #define TREECC_ERRFMT(n,m) \ + __attribute__ ((__format__ (__printf__, n, m))) + #else + #define TREECC_ERRFMT(n,m) + #endif + + /* + * Report an error on the current line of input. + */ + void TreeCCError(TreeCCInput *input, const char *format, ...) + TREECC_ERRFMT(2, 3); + + /* + * Report an error on a particular line of input. + */ + void TreeCCErrorOnLine(TreeCCInput *input, char *filename, long linenum, + const char *format, ...) + TREECC_ERRFMT(4, 5); + + /* + * Report an error on the current line of input and abort. + */ + void TreeCCAbort(TreeCCInput *input, const char *format, ...) + TREECC_ERRFMT(2, 3); + + /* + * Print a debugging message. + */ + void TreeCCDebug(long linenum, const char *format, ...) + TREECC_ERRFMT(2, 3); + + /* + * Abort the program due to out of memory. + */ + void TreeCCOutOfMemory(TreeCCInput *input); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_ERRORS_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/gen.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,664 ---- + /* + * gen.c - Generate code to "treecc" output files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + void TreeCCGenerate(TreeCCContext *context) + { + switch(context->language) + { + case TREECC_LANG_C: + { + TreeCCGenerateC(context); + } + break; + + case TREECC_LANG_CPP: + { + TreeCCGenerateCPP(context); + } + break; + + case TREECC_LANG_JAVA: + { + TreeCCGenerateJava(context); + } + break; + + case TREECC_LANG_CSHARP: + { + TreeCCGenerateCSharp(context); + } + break; + + case TREECC_LANG_RUBY: + { + TreeCCGenerateRuby(context); + } + break; + + case TREECC_LANG_PHP: + { + TreeCCGeneratePHP(context); + } + break; + + } + } + + /* + * Generate selectors for one case of a "switch" statement. + */ + static int GenerateSelectors(TreeCCContext *context, TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, TreeCCNode *node, + int markBit, int triggerNum) + { + /* If the mark bit is already set, then we've already handled this case */ + if((node->flags & markBit) != 0) + { + return 0; + } + + /* Mark the node as already visited */ + node->flags |= markBit; + + /* Generate a selector for this node */ + (*(nonVirt->genSelector))(context, stream, node, triggerNum); + + /* Generate selectors for the children */ + node = node->firstChild; + while(node != 0) + { + GenerateSelectors(context, stream, nonVirt, node, markBit, triggerNum); + node = node->nextSibling; + } + + /* We have done something non-trivial */ + return 1; + } + + /* + * Determine if the outer trigger levels of two operation cases match. + */ + static int LevelsMatch(TreeCCOperationCase *operCase1, + TreeCCOperationCase *operCase2, + int triggerNum) + { + TreeCCTrigger *trigger1 = operCase1->triggers; + TreeCCTrigger *trigger2 = operCase2->triggers; + while(triggerNum > 0) + { + if(trigger1->node != trigger2->node) + { + return 0; + } + trigger1 = trigger1->next; + trigger2 = trigger2->next; + } + return 1; + } + + /* + * Generate code for a "switch" on a trigger. + */ + static TreeCCOperationCase *GenerateSwitch + (TreeCCContext *context, TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, TreeCCOperation *oper, + TreeCCOperationCase *operCase, int triggerNum) + { + TreeCCParam *param; + int num, markBit; + int paramNum; + TreeCCOperationCase *firstCase; + TreeCCTrigger *trigger; + TreeCCNode *node; + int isEnum; + + /* Generate the head of the switch for this level */ + param = oper->params; + num = 0; + paramNum = 1; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(num == triggerNum) + { + break; + } + ++num; + } + if(!(param->name)) + { + ++paramNum; + } + param = param->next; + } + if(!param) + { + /* Output the code for the case */ + if((oper->flags & TREECC_OPER_INLINE) != 0) + { + (*(nonVirt->genCaseInline))(context, stream, operCase, + triggerNum - 1); + } + else + { + (*(nonVirt->genCaseCall))(context, stream, operCase, + operCase->number, triggerNum - 1); + } + return operCase->next; + } + node = TreeCCNodeFindByType(context, param->type); + isEnum = ((node->flags & TREECC_NODE_ENUM) != 0); + if(param->name) + { + (*(nonVirt->genSwitchHead))(context, stream, param->name, + triggerNum, isEnum); + } + else + { + char paramName[64]; + sprintf(paramName, "P%d__", paramNum); + (*(nonVirt->genSwitchHead))(context, stream, paramName, + triggerNum, isEnum); + } + + /* Recurse to handle the next-inner level of switch statements */ + markBit = TREECC_NODE_MARK(triggerNum); + TreeCCNodeClearMarking(context, markBit); + firstCase = operCase; + do + { + /* Output the "case" statements to match this operation case */ + trigger = operCase->triggers; + num = 0; + while(trigger != 0 && num < triggerNum) + { + ++num; + trigger = trigger->next; + } + if(trigger) + { + if(!GenerateSelectors(context, stream, nonVirt, + trigger->node, markBit, triggerNum)) + { + /* We already output code for this with another case */ + TreeCCErrorOnLine(context->input, operCase->filename, + operCase->linenum, + "this operation case duplicates another"); + } + } + (*(nonVirt->genEndSelectors))(context, stream, triggerNum); + + /* Generate the next level of "switch"'s */ + operCase = GenerateSwitch(context, stream, nonVirt, + oper, operCase, triggerNum + 1); + + /* Terminate the "case" statement */ + (*(nonVirt->genEndCase))(context, stream, triggerNum); + } + while(operCase != 0 && LevelsMatch(firstCase, operCase, triggerNum)); + + /* Generate the end of the switch for this level */ + (*(nonVirt->genEndSwitch))(context, stream, triggerNum); + + /* Return the next case to be handled to the caller */ + return operCase; + } + + /* + * Assign positions to the node types in a non-virtual operation. + */ + static void AssignTriggerPosns(TreeCCContext *context, TreeCCOperation *oper) + { + TreeCCParam *param; + TreeCCNode *type; + param = oper->params; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + type = TreeCCNodeFindByType(context, param->type); + if(type) + { + TreeCCNodeAssignPositions(type); + } + } + param = param->next; + } + } + + /* + * Forward declaration. + */ + static void GenerateMultiSwitch(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum); + + /* + * Scan down the hierarchy to generate cases for a multi-trigger operation. + */ + static void GenerateMultiScan(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum, + TreeCCNode *node) + { + /* Ignore abstract node types */ + if((node->flags & TREECC_NODE_ABSTRACT) == 0) + { + /* Generate a selector for this node */ + (*(nonVirt->genSelector))(context, stream, node, triggerNum); + (*(nonVirt->genEndSelectors))(context, stream, triggerNum); + + /* Go in one level for this node */ + GenerateMultiSwitch(context, stream, nonVirt, oper, sortedCases, + base + node->position * multiplier, + multiplier * nextParam->size, nextParam->next, + triggerNum + 1); + + /* Terminate the case for the above selector */ + (*(nonVirt->genEndCase))(context, stream, triggerNum); + } + + /* Scan all of the children */ + node = node->firstChild; + while(node != 0) + { + GenerateMultiScan(context, stream, nonVirt, oper, sortedCases, + base, multiplier, nextParam, triggerNum, node); + node = node->nextSibling; + } + } + + /* + * Generate code for a "switch" on a multi-trigger operation. + */ + static void GenerateMultiSwitch(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum) + { + TreeCCNode *type; + int isEnum; + + /* Scan for the next trigger parameter */ + while(nextParam != 0 && (nextParam->flags & TREECC_PARAM_TRIGGER) == 0) + { + nextParam = nextParam->next; + } + + /* If we are out of triggers, then we need to output the case code */ + if(!nextParam) + { + if((oper->flags & TREECC_OPER_INLINE) != 0) + { + (*(nonVirt->genCaseInline))(context, stream, sortedCases[base], + triggerNum - 1); + } + else + { + (*(nonVirt->genCaseCall))(context, stream, sortedCases[base], + sortedCases[base]->number, + triggerNum - 1); + } + return; + } + + /* Generate the head of the switch for this level */ + type = TreeCCNodeFindByType(context, nextParam->type); + isEnum = ((type->flags & TREECC_NODE_ENUM) != 0); + if(nextParam->name) + { + (*(nonVirt->genSwitchHead))(context, stream, nextParam->name, + triggerNum, isEnum); + } + else + { + char paramName[64]; + int paramNum = 0; + TreeCCParam *param = oper->params; + while(param != 0 && param != nextParam) + { + if(!(param->name)) + { + ++paramNum; + } + param = param->next; + } + sprintf(paramName, "P%d__", paramNum); + (*(nonVirt->genSwitchHead))(context, stream, paramName, + triggerNum, isEnum); + } + + /* Scan down the node type hierarchy for this trigger level */ + GenerateMultiScan(context, stream, nonVirt, oper, sortedCases, + base, multiplier, nextParam, triggerNum, type); + + /* Generate the end of the switch for this level */ + (*(nonVirt->genEndSwitch))(context, stream, triggerNum); + } + + /* + * Forward declaration. + */ + static void GenerateSplitMultiSwitch(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum); + + /* + * Scan down the hierarchy to generate cases for a multi-trigger operation + * that is split across multiple functions. + */ + static void GenerateSplitMultiScan(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum, + TreeCCNode *node) + { + int number; + + /* Ignore abstract node types */ + if((node->flags & TREECC_NODE_ABSTRACT) == 0) + { + /* Generate a selector for this node */ + (*(nonVirt->genSelector))(context, stream, node, 0); + (*(nonVirt->genEndSelectors))(context, stream, 0); + + /* Generate the code for the case */ + number = base + node->position * multiplier; + if(triggerNum == (oper->numTriggers - 1)) + { + /* We are at the inner-most level, so insert the case's code */ + if((oper->flags & TREECC_OPER_INLINE) != 0) + { + (*(nonVirt->genCaseInline))(context, stream, + sortedCases[number], 0); + } + else + { + (*(nonVirt->genCaseCall))(context, stream, + sortedCases[number], + sortedCases[number]->number, 0); + } + } + else + { + /* Generate a call to a split function */ + (*(nonVirt->genCaseSplit))(context, stream, + sortedCases[number], number, 0); + } + + /* Terminate the case for the above selector */ + (*(nonVirt->genEndCase))(context, stream, 0); + } + + /* Scan all of the children */ + node = node->firstChild; + while(node != 0) + { + GenerateSplitMultiScan(context, stream, nonVirt, oper, sortedCases, + base, multiplier, nextParam, triggerNum, node); + node = node->nextSibling; + } + } + + /* + * Scan down the hierarchy to generate split functions for + * a multi-trigger operation. + */ + static void GenerateSplitMultiScanFunc(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum, + TreeCCNode *node) + { + /* Ignore abstract node types */ + if((node->flags & TREECC_NODE_ABSTRACT) == 0) + { + /* Go in one level for this node */ + GenerateSplitMultiSwitch(context, stream, nonVirt, oper, sortedCases, + base + node->position * multiplier, + multiplier * nextParam->size, nextParam->next, + triggerNum + 1); + } + + /* Scan all of the children */ + node = node->firstChild; + while(node != 0) + { + GenerateSplitMultiScanFunc(context, stream, nonVirt, oper, + sortedCases, base, multiplier, + nextParam, triggerNum, node); + node = node->nextSibling; + } + } + + /* + * Generate code for a "switch" on a multi-trigger operation + * that is split across multiple functions. + */ + static void GenerateSplitMultiSwitch(TreeCCContext *context, + TreeCCStream *stream, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, + int base, int multiplier, + TreeCCParam *nextParam, + int triggerNum) + { + TreeCCNode *type; + int isEnum; + + /* Scan for the next trigger parameter */ + while(nextParam != 0 && (nextParam->flags & TREECC_PARAM_TRIGGER) == 0) + { + nextParam = nextParam->next; + } + + /* Generate the next level of split functions */ + type = TreeCCNodeFindByType(context, nextParam->type); + if(triggerNum != (oper->numTriggers - 1)) + { + GenerateSplitMultiScanFunc + (context, stream, nonVirt, oper, sortedCases, + base, multiplier, nextParam, triggerNum, type); + } + + /* Output the entry point for this switch function */ + if(triggerNum != 0) + { + (*(nonVirt->genSplitEntry))(context, stream, oper, base); + } + else + { + (*(nonVirt->genEntry))(context, stream, oper); + } + + /* Generate the head of the switch for this level */ + isEnum = ((type->flags & TREECC_NODE_ENUM) != 0); + if(nextParam->name) + { + (*(nonVirt->genSwitchHead))(context, stream, nextParam->name, + 0, isEnum); + } + else + { + char paramName[64]; + int paramNum = 0; + TreeCCParam *param = oper->params; + while(param != 0 && param != nextParam) + { + if(!(param->name)) + { + ++paramNum; + } + param = param->next; + } + sprintf(paramName, "P%d__", paramNum); + (*(nonVirt->genSwitchHead))(context, stream, paramName, 0, isEnum); + } + + /* Scan down the node type hierarchy for this trigger level */ + GenerateSplitMultiScan(context, stream, nonVirt, oper, sortedCases, + base, multiplier, nextParam, triggerNum, type); + + /* Generate the end of the switch for this level */ + (*(nonVirt->genEndSwitch))(context, stream, 0); + + /* Generate the exit point for this switch function */ + (*(nonVirt->genExit))(context, stream, oper); + } + + /* + * Generate code for a specific non-virtual operation. + */ + static void GenerateNonVirtual(TreeCCContext *context, + const TreeCCNonVirtual *nonVirt, + TreeCCOperation *oper) + { + TreeCCStream *stream; + TreeCCOperationCase *operCase; + int number; + + /* Determine which stream to write to */ + if(context->language == TREECC_LANG_JAVA) + { + if(oper->className) + { + stream = TreeCCStreamGetJava(context, oper->className); + } + else + { + stream = TreeCCStreamGetJava(context, oper->name); + } + } + else + { + stream = oper->source; + } + + /* Output start declarations for the operation */ + (*(nonVirt->genStart))(context, stream, oper); + + /* If the operation is not inline, then output functions for all cases */ + if((oper->flags & TREECC_OPER_INLINE) == 0) + { + number = 1; + operCase = oper->firstCase; + while(operCase != 0) + { + (*(nonVirt->genCaseFunc))(context, stream, operCase, number); + operCase->number = number++; + operCase = operCase->next; + } + } + + /* Process split non-virtuals */ + if(oper->numTriggers > 1 && (oper->flags & TREECC_OPER_SPLIT) != 0) + { + /* Split the switch statement over multiple levels of functions, + so that no single function grows too large */ + AssignTriggerPosns(context, oper); + GenerateSplitMultiSwitch(context, stream, nonVirt, oper, + oper->sortedCases, 0, 1, oper->params, 0); + (*(nonVirt->genEnd))(context, stream, oper); + return; + } + + /* Output the entry point for the operation */ + (*(nonVirt->genEntry))(context, stream, oper); + + /* Generate the switch statement for the outer-most level */ + if(oper->numTriggers <= 1) + { + GenerateSwitch(context, stream, nonVirt, oper, oper->firstCase, 0); + } + else + { + AssignTriggerPosns(context, oper); + GenerateMultiSwitch(context, stream, nonVirt, oper, + oper->sortedCases, 0, 1, oper->params, 0); + } + + /* Output the exit point for the operation */ + (*(nonVirt->genExit))(context, stream, oper); + + /* Output the end declarations for the operation */ + (*(nonVirt->genEnd))(context, stream, oper); + } + + void TreeCCGenerateNonVirtuals(TreeCCContext *context, + const TreeCCNonVirtual *nonVirt) + { + unsigned int hash; + TreeCCOperation *oper; + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + oper = context->operHash[hash]; + while(oper != 0) + { + if((oper->flags & TREECC_OPER_VIRTUAL) == 0) + { + GenerateNonVirtual(context, nonVirt, oper); + } + oper = oper->nextHash; + } + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,127 ---- + /* + * gen.h - Generate code to "treecc" output files. + * + * Copyright (C) 2001, 2002 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_GEN_H + #define _TREECC_GEN_H + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Generate the source code output. + */ + void TreeCCGenerate(TreeCCContext *context); + + /* + * Generate the source code output for specific languages. + */ + void TreeCCGenerateC(TreeCCContext *context); + void TreeCCGenerateCPP(TreeCCContext *context); + void TreeCCGenerateJava(TreeCCContext *context); + void TreeCCGenerateCSharp(TreeCCContext *context); + void TreeCCGenerateRuby(TreeCCContext *context); + void TreeCCGeneratePHP(TreeCCContext *context); + + /* + * Control structure for generating the code for + * non-virtual operations. + */ + typedef struct + { + /* Generate the start declarations for a non-virtual operation */ + void (*genStart)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper); + + /* Generate the entry point for a non-virtual operation */ + void (*genEntry)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper); + + /* Generate the entry point for a split-out function */ + void (*genSplitEntry)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number); + + /* Generate the head of a "switch" statement */ + void (*genSwitchHead)(TreeCCContext *context, TreeCCStream *stream, + char *paramName, int level, int isEnum); + + /* Generate a selector for a "switch" case */ + void (*genSelector)(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int level); + + /* Terminate the selectors and begin the body of a "switch" case */ + void (*genEndSelectors)(TreeCCContext *context, TreeCCStream *stream, + int level); + + /* Generate the code for a case within a function */ + void (*genCaseFunc)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number); + + /* Generate a call to a case function from within the "switch" */ + void (*genCaseCall)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, int level); + + /* Generate the code for a case inline within the "switch" */ + void (*genCaseInline)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int level); + + /* Generate the code for a call to a split function within the "switch" */ + void (*genCaseSplit)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, int level); + + /* Terminate a "switch" case */ + void (*genEndCase)(TreeCCContext *context, TreeCCStream *stream, + int level); + + /* Terminate the "switch" statement */ + void (*genEndSwitch)(TreeCCContext *context, TreeCCStream *stream, + int level); + + /* Generate the exit point for a non-virtual operation */ + void (*genExit)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper); + + /* Generate the end declarations for a non-virtual operation */ + void (*genEnd)(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper); + + } TreeCCNonVirtual; + + /* + * Generate the code for the non-virtual operations. + */ + void TreeCCGenerateNonVirtuals(TreeCCContext *context, + const TreeCCNonVirtual *nonVirt); + + /* + * Common non-virtual operations that are used for C and C++. + */ + extern TreeCCNonVirtual const TreeCCNonVirtualFuncsC; + + /* + * Common non-virtual operations that are used for Java and C#. + */ + extern TreeCCNonVirtual const TreeCCNonVirtualFuncsJava; + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_GEN_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_c.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_c.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_c.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1754 ---- + /* + * gen_c.c - Generate C source code from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Define the node numbers. + */ + static void DefineNodeNumbers(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) == 0) + { + TreeCCStreamPrint(stream, "#define %s_kind %d\n", + node->name, node->number); + } + } + + /* + * Declare the fields for a node type. + */ + static void DeclareFields(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCField *field; + if(node->parent) + { + DeclareFields(context, stream, node->parent); + } + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, "\t%s %s;\n", + field->type, field->name); + field = field->next; + } + } + + /* + * Declare the virtuals for a node type. + */ + static void DeclareVirtuals(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCVirtual *virt; + TreeCCParam *param; + int num; + if(node->parent) + { + DeclareVirtuals(context, stream, node->parent); + } + virt = node->virtuals; + while(virt != 0) + { + TreeCCStreamPrint(stream, "\t%s (*%s_v__)(%s *this__", + virt->returnType, virt->name, node->name); + param = virt->params; + num = 1; + while(param != 0) + { + if(param->name) + { + TreeCCStreamPrint(stream, ", %s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, ", %s P%d__", + param->type, num); + ++num; + } + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + virt = virt->next; + } + } + + /* + * Declare the macros for calling the virtuals for a node type. + */ + static void DeclareVirtualMacros(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCVirtual *virt; + TreeCCParam *param; + int num; + virt = node->virtuals; + while(virt != 0) + { + TreeCCStreamPrint(stream, "#define %s(this__", virt->name); + param = virt->params; + num = 1; + while(param != 0) + { + if(param->name) + { + TreeCCStreamPrint(stream, ",%s", param->name); + } + else + { + TreeCCStreamPrint(stream, ",P%d__", num); + ++num; + } + param = param->next; + } + TreeCCStreamPrint(stream, ") \\\n"); + TreeCCStreamPrint(stream, + "\t((*(((struct %s_vtable__ *)((this__)->vtable__))->%s_v__)) \\\n", + node->name, virt->name); + TreeCCStreamPrint(stream, "\t\t((%s *)(this__)", node->name); + param = virt->params; + num = 1; + while(param != 0) + { + if(param->name) + { + TreeCCStreamPrint(stream, ", (%s)", param->name); + } + else + { + TreeCCStreamPrint(stream, ", (P%d__)", num); + ++num; + } + param = param->next; + } + TreeCCStreamPrint(stream, "))\n\n"); + virt = virt->next; + } + } + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* Define an enumerated type */ + char const *sep = "\n"; + TreeCCNode *child; + TreeCCStreamPrint(stream, "typedef enum {"); + child = node->firstChild; + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, "%s\t%s", sep, child->name); + sep = ",\n"; + } + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "\n} %s;\n\n", node->name); + } + else if((node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + /* Define a regular node type */ + TreeCCStreamPrint(stream, "typedef struct %s__ %s;\n", + node->name, node->name); + } + } + + /* + * Declare the virtual method implementation functions for a node type. + */ + static int DeclareVirtualImpls(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + TreeCCOperation *oper; + int num; + int needComma; + int haveVirts = 0; + if(node->parent) + { + haveVirts = DeclareVirtualImpls(context, stream, + node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + /* We don't have a direct implementation in this class */ + virt = virt->next; + continue; + } + TreeCCStreamPrint(stream, "extern %s %s_%s__(", + virt->returnType, actualNode->name, virt->name); + oper = operCase->oper; + param = oper->params; + needComma = 0; + num = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + } + else + { + /* First argument must be declared with the actual type */ + if(param->name) + { + TreeCCStreamPrint(stream, "%s *%s", + actualNode->name, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s *P%d__", + actualNode->name, num); + ++num; + } + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + haveVirts = 1; + virt = virt->next; + } + return haveVirts; + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Output the structure header */ + TreeCCStreamPrint(stream, "struct %s__ {\n", node->name); + + /* Declare the vtable member variable */ + TreeCCStreamPrint(stream, "\tconst struct %s_vtable__ *vtable__;\n", + node->name); + + /* Declare the node kind member variable */ + if(!(context->kind_in_vtable)) + { + TreeCCStreamPrint(stream, "\tint kind__;\n"); + } + + /* Declare the filename and linenum fields if we are tracking lines */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, "\tchar *filename__;\n"); + TreeCCStreamPrint(stream, "\tlong linenum__;\n"); + } + + /* Declare the fields */ + DeclareFields(context, stream, node); + + /* Output the structure footer */ + TreeCCStreamPrint(stream, "};\n\n"); + + /* Output the vtable type header */ + TreeCCStreamPrint(stream, "struct %s_vtable__ {\n", node->name); + + /* Declare standard vtable members */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\tconst struct %s_vtable__ *parent__;\n", + node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "\tconst void *parent__;\n"); + } + TreeCCStreamPrint(stream, "\tint kind__;\n"); + TreeCCStreamPrint(stream, "\tconst char *name__;\n"); + + /* Declare the vtable function prototypes */ + DeclareVirtuals(context, stream, node); + + /* Output the vtable footer */ + TreeCCStreamPrint(stream, "};\n\n"); + + /* Declare the actual vtable for this node type */ + TreeCCStreamPrint(stream, "extern struct %s_vtable__ const %s_vt__;\n\n", + node->name, node->name); + + /* Declare the macros for calling the virtuals in this node type */ + DeclareVirtualMacros(context, stream, node); + + /* Declare the functions that implement all virtuals in this node type */ + if(DeclareVirtualImpls(context, stream, node, node)) + { + TreeCCStreamPrint(stream, "\n"); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", + field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Get the name of the "%typedef" type for a node. + */ + static const char *TypedefName(TreeCCNode *node) + { + while(node->parent != 0 && (node->flags & TREECC_NODE_TYPEDEF) == 0) + { + node = node->parent; + } + return node->name; + } + + /* + * Declare the prototypes for the node creation functions. + */ + static void DeclareCreateFuncs(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + int needComma; + + /* Don't need the create function if this node is abstract or enumerated */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0 || + (node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Output the return type and name */ + TreeCCStreamPrint(stream, "extern %s *%s_create(", + TypedefName(node), node->name); + + /* Add the state type if building a re-entrant compiler */ + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + + /* Output the field types and names as the create parameters */ + needComma = CreateParams(context, stream, node, needComma); + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + + /* Terminate the declaration */ + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Declare the prototypes for the non-virtual operations. + */ + static void DeclareNonVirtuals(TreeCCContext *context, + TreeCCOperation *oper) + { + TreeCCStream *stream = oper->header; + TreeCCParam *param; + int num; + int needComma; + + /* Bail out if the operation is virtual */ + if((oper->flags & TREECC_OPER_VIRTUAL) != 0) + { + return; + } + + /* Output the prototype */ + TreeCCStreamPrint(stream, "extern %s %s(", + oper->returnType, oper->name); + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + needComma = 1; + param = param->next; + } + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Output helper macros to the header stream. + */ + static void OutputHelpers(TreeCCContext *context) + { + TreeCCStream *stream; + + /* Determine which stream to write to */ + if(context->commonHeader) + { + stream = context->commonHeader; + } + else + { + stream = context->headerStream; + } + + /* yykind macro */ + TreeCCStreamPrint(stream, "#ifndef %skind\n", context->yy_replacement); + if(context->kind_in_vtable) + { + TreeCCStreamPrint(stream, + "#define %skind(node__) ((node__)->vtable__->kind__)\n", + context->yy_replacement); + } + else + { + TreeCCStreamPrint(stream, + "#define %skind(node__) ((node__)->kind__)\n", + context->yy_replacement); + } + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yykindname macro */ + TreeCCStreamPrint(stream, "#ifndef %skindname\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %skindname(node__) ((node__)->vtable__->name__)\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yykindof macro */ + TreeCCStreamPrint(stream, "#ifndef %skindof\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %skindof(type__) (type__##_kind)\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yyisa macro */ + TreeCCStreamPrint(stream, "#ifndef %sisa\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "extern int %sisa__(const void *vtable__, int kind__);\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %sisa(node__,type__) \\\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "\t(%sisa__((node__)->vtable__, (type__##_kind)))\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* Are we tracking line numbers? */ + if(context->track_lines) + { + /* yygetfilename macro */ + TreeCCStreamPrint(stream, + "#ifndef %sgetfilename\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %sgetfilename(node__) ((node__)->filename__)\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yygetlinenum macro */ + TreeCCStreamPrint(stream, + "#ifndef %sgetlinenum\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %sgetlinenum(node__) ((node__)->linenum__)\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yysetfilename macro */ + TreeCCStreamPrint(stream, + "#ifndef %ssetfilename\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %ssetfilename(node__, value__) \\\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "\t((node__)->filename__ = (value__))\n"); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yysetlinenum macro */ + TreeCCStreamPrint(stream, + "#ifndef %ssetlinenum\n", context->yy_replacement); + TreeCCStreamPrint(stream, + "#define %ssetlinenum(node__, value__) \\\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "\t((node__)->linenum__ = (value__))\n"); + TreeCCStreamPrint(stream, "#endif\n\n"); + + /* yycurrfilename and yycurrlinenum functions */ + TreeCCStreamPrint(stream, "#ifndef %stracklines_declared\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "extern char *%scurrfilename(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern long %scurrlinenum(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "#define %stracklines_declared 1\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + } + + /* Declare the "yynodealloc", "yynodepush", "yynodepop", and + "yynodeclear", and "yynodefailed" functions */ + TreeCCStreamPrint(stream, "#ifndef %snodeops_declared\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "extern void %snodeinit(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern void *%snodealloc(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__, ", context->state_type); + } + TreeCCStreamPrint(stream, "unsigned int size__"); + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern int %snodepush(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern void %snodepop(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern void %snodeclear(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "extern void %snodefailed(", + context->yy_replacement); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "#define %snodeops_declared 1\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "#endif\n\n"); + } + + /* + * Output the vtable function implementations for a node type. + */ + static void OutputVtableImpls(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + TreeCCOperation *oper; + int num; + int needComma; + if(node->parent) + { + OutputVtableImpls(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + /* We don't have a direct implementation in this class */ + virt = virt->next; + continue; + } + TreeCCStreamPrint(stream, "%s %s_%s__(", + virt->returnType, actualNode->name, virt->name); + oper = operCase->oper; + param = oper->params; + needComma = 0; + num = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(!needComma) + { + /* First argument must be declared with the actual type */ + if(param->name) + { + TreeCCStreamPrint(stream, "%s *%s", + actualNode->name, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s *P%d__", + actualNode->name, num); + ++num; + } + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + TreeCCStreamPrint(stream, "{"); + TreeCCStreamCode(stream, operCase->code); + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "\n"); + virt = virt->next; + } + } + + /* + * Output the vtable function references for a node type. + */ + static void OutputVtableFuncs(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + TreeCCNode *parent; + int num; + if(node->parent) + { + OutputVtableFuncs(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + TreeCCStreamPrint(stream, "\t(%s (*)(%s *this__", + virt->returnType, node->name); + param = virt->params; + num = 1; + while(param != 0) + { + if(param->name) + { + TreeCCStreamPrint(stream, ", %s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, ", %s P%d__", + param->type, num); + ++num; + } + param = param->next; + } + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + parent = actualNode; + while(!operCase) + { + parent = parent->parent; + if(!parent) + { + break; + } + operCase = TreeCCOperationFindCase(context, parent, virt->name); + } + if(operCase) + { + /* We are inheriting the implementation from "parent" */ + TreeCCStreamPrint(stream, "))%s_%s__,\n", + parent->name, virt->name); + } + else + { + /* No implementation for the method at all */ + TreeCCStreamPrint(stream, "))0,\n"); + } + virt = virt->next; + } + } + + /* + * Define a vtable for a node type. + */ + static void DefineVtables(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->source; + + /* Ignore this node if it is an enumerated type */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Output the implementations of the node vtable functions */ + OutputVtableImpls(context, stream, node, node); + + /* Output the vtable header */ + TreeCCStreamPrint(stream, "struct %s_vtable__ const %s_vt__ = {\n", + node->name, node->name); + if(node->parent) + { + TreeCCStreamPrint(stream, "\t&%s_vt__,\n", node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "\t0,\n"); + } + TreeCCStreamPrint(stream, "\t%s_kind,\n", node->name); + TreeCCStreamPrint(stream, "\t\"%s\",\n", node->name); + + /* Output the function references */ + OutputVtableFuncs(context, stream, node, node); + + /* Output the vtable footer */ + TreeCCStreamPrint(stream, "};\n\n"); + } + + /* + * Output a create function parameter list to the source stream. + */ + static int CreateParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Initialize a node's fields within a create function. + */ + static void InitFields(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node) + { + TreeCCField *field; + if(node->parent) + { + InitFields(context, stream, node->parent); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, "\tnode__->%s = %s;\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, "\tnode__->%s = %s;\n", + field->name, field->value); + } + field = field->next; + } + } + + /* + * Implement a create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->source; + const char *typedefName; + int needComma; + + /* Ignore this node if it is an enumerated type */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Don't need a create function if this node type is abstract */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Find the name of the "%typedef" node type for this node */ + typedefName = TypedefName(node); + + /* Output the create function header */ + TreeCCStreamPrint(stream, "%s *%s_create(", typedefName, node->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + needComma = CreateParamsSource(context, stream, node, needComma); + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "{\n"); + + /* Is the node type a singleton? */ + if(!(context->track_lines) && !(context->no_singletons) && + TreeCCNodeIsSingleton(node)) + { + /* This node type is a singleton, so create + a static node instance and always return it */ + TreeCCStreamPrint(stream, "\tstatic struct %s__ instance__ = {\n", + node->name); + TreeCCStreamPrint(stream, "\t\t&%s_vt__,\n", node->name); + if(!(context->kind_in_vtable)) + { + TreeCCStreamPrint(stream, "\t\t%s_kind\n", node->name); + } + TreeCCStreamPrint(stream, "\t};\n"); + TreeCCStreamPrint(stream, "\treturn (%s *)&instance__;\n", + typedefName); + } + else + { + /* Non-singleton node type */ + if(context->reentrant) + { + TreeCCStreamPrint(stream, + "\t%s *node__ = (%s *)%snodealloc(state__, " + "sizeof(struct %s__));\n", + node->name, node->name, context->yy_replacement, node->name); + } + else + { + TreeCCStreamPrint(stream, + "\t%s *node__ = (%s *)%snodealloc(sizeof(struct %s__));\n", + node->name, node->name, context->yy_replacement, node->name); + } + + /* Bail out to the caller if "yynodealloc" returned NULL */ + TreeCCStreamPrint(stream, "\tif(node__ == 0) return 0;\n"); + + /* Set the vtable and kind */ + TreeCCStreamPrint(stream, "\tnode__->vtable__ = &%s_vt__;\n", + node->name); + if(!(context->kind_in_vtable)) + { + TreeCCStreamPrint(stream, "\tnode__->kind__ = %s_kind;\n", + node->name); + } + + /* Track the filename and line number if necessary */ + if(context->track_lines) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + "\tnode__->filename__ = %scurrfilename(state__);\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "\tnode__->linenum__ = %scurrlinenum(state__);\n", + context->yy_replacement); + } + else + { + TreeCCStreamPrint(stream, + "\tnode__->filename__ = %scurrfilename();\n", + context->yy_replacement); + TreeCCStreamPrint(stream, + "\tnode__->linenum__ = %scurrlinenum();\n", + context->yy_replacement); + } + } + + /* Initialize the fields */ + InitFields(context, stream, node); + + /* Return the node to the caller */ + TreeCCStreamPrint(stream, "\treturn (%s *)node__;\n", typedefName); + } + + /* Output the create function footer */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Output the source code for the "yyisa__" helper function. + */ + static void OutputIsA(TreeCCContext *context) + { + TreeCCStream *stream; + + /* Determine which stream to write to */ + if(context->commonSource) + { + stream = context->commonSource; + } + else + { + stream = context->sourceStream; + } + + /* Declare a helper structure for walking vtable types */ + TreeCCStreamPrint(stream, "struct %s_vtable__ {\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "\tconst struct %s_vtable__ *parent__;\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "\tint kind__;\n"); + TreeCCStreamPrint(stream, "};\n\n"); + + /* Output the function header */ + TreeCCStreamPrint(stream, + "int %sisa__(const void *vtable__, int kind__)\n", + context->yy_replacement); + + /* Output the body of the function */ + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\tconst struct %s_vtable__ *vt;\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "\tvt = (const struct %s_vtable__ *)vtable__;\n", + context->yy_replacement); + TreeCCStreamPrint(stream, "\twhile(vt != 0) {\n"); + TreeCCStreamPrint(stream, "\t\tif(vt->kind__ == kind__)\n"); + TreeCCStreamPrint(stream, "\t\t\treturn 1;\n"); + TreeCCStreamPrint(stream, "\t\tvt = vt->parent__;\n"); + TreeCCStreamPrint(stream, "\t}\n"); + TreeCCStreamPrint(stream, "\treturn 0;\n"); + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Determine if a type name corresponds to an enumerated type. + */ + static int IsEnumType(TreeCCContext *context, const char *type) + { + TreeCCNode *node = TreeCCNodeFindByType(context, type); + if(node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + return 1; + } + } + return 0; + } + + /* + * Generate the start declarations for a non-virtual operation. + */ + static void C_GenStart(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + /* Nothing to do here for C and C++ */ + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void CGenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + TreeCCParam *param; + int num; + int needComma; + if(number != -1) + { + TreeCCStreamPrint(stream, "%s %s_split_%d__(", + oper->returnType, oper->name, number); + } + else if(context->language == TREECC_LANG_C || !(oper->className)) + { + TreeCCStreamPrint(stream, "%s %s(", + oper->returnType, oper->name); + } + else + { + TreeCCStreamPrint(stream, "%s %s::%s(", + oper->returnType, oper->className, oper->name); + } + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s ", param->type); + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(!IsEnumType(context, param->type)) + { + TreeCCStreamPrint(stream, "__"); + } + } + needComma = 1; + param = param->next; + } + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate the entry point for a split-out function. + */ + static void C_GenSplitEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + CGenEntry(context, stream, oper, number); + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void C_GenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + CGenEntry(context, stream, oper, -1); + } + + /* + * Output TAB's for a specific level of indenting. + */ + static void Indent(TreeCCStream *stream, int indent) + { + while(indent >= 4) + { + TreeCCStreamPrint(stream, "\t\t\t\t"); + indent -= 4; + } + if(indent == 1) + { + TreeCCStreamPrint(stream, "\t"); + } + else if(indent == 2) + { + TreeCCStreamPrint(stream, "\t\t"); + } + else if(indent == 3) + { + TreeCCStreamPrint(stream, "\t\t\t"); + } + } + + /* + * Generate the head of a "switch" statement. + */ + static void C_GenSwitchHead(TreeCCContext *context, TreeCCStream *stream, + char *paramName, int level, int isEnum) + { + Indent(stream, level * 2 + 1); + if(isEnum) + { + TreeCCStreamPrint(stream, "switch(%s)\n", paramName); + } + else if(context->language == TREECC_LANG_C) + { + if(context->kind_in_vtable) + { + TreeCCStreamPrint(stream, "switch(%s__->vtable__->kind__)\n", + paramName); + } + else + { + TreeCCStreamPrint(stream, "switch(%s__->kind__)\n", paramName); + } + } + else + { + TreeCCStreamPrint(stream, "switch(%s__->getKind())\n", paramName); + } + Indent(stream, level * 2 + 1); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate a selector for a "switch" case. + */ + static void C_GenSelector(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int level) + { + if((node->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "case %s:\n", node->name); + } + else if((node->flags & TREECC_NODE_ENUM) == 0) + { + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "case %s_kind:\n", node->name); + } + } + + /* + * Terminate the selectors and begin the body of a "switch" case. + */ + static void C_GenEndSelectors(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate the code for a case within a function. + */ + static void C_GenCaseFunc(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + char *type; + char *suffix; + + /* Output the header for the function */ + TreeCCStreamPrint(stream, "static %s %s_%d__(", + operCase->oper->returnType, + operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + type = trigger->node->name; + suffix = "*"; + } + else + { + type = param->type; + suffix = ""; + } + trigger = trigger->next; + } + else + { + type = param->type; + suffix = ""; + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s%s", + type, suffix, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s %sP%d__", + type, suffix, num); + ++num; + } + needComma = 1; + param = param->next; + } + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ")\n"); + + /* Output the code for the operation case */ + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + TreeCCStreamPrint(stream, "{"); + if(operCase->code) + { + TreeCCStreamCode(stream, operCase->code); + } + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a call to a case function from within the "switch". + */ + static void C_GenCaseCall(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, + int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 3); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s *)", trigger->node->name); + } + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Generate the code for a case inline within the "switch". + */ + static void C_GenCaseInline(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + + /* Copy the parameters to new variables of the correct types */ + param = operCase->oper->params; + trigger = operCase->triggers; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(param->name != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "%s *%s = (%s *)%s__;\n", + trigger->node->name, param->name, + trigger->node->name, param->name); + } + } + trigger = trigger->next; + } + param = param->next; + } + + /* Output the inline code for the case */ + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "{"); + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, level * 2 + 3); + } + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + } + + /* + * Generate the code for a call to a split function within the "switch". + */ + static void C_GenCaseSplit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, + int number, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 3); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_split_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s *)", trigger->node->name); + } + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Terminate a "switch" case. + */ + static void C_GenEndCase(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "}\n"); + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "break;\n\n"); + } + + /* + * Terminate the "switch" statement. + */ + static void C_GenEndSwitch(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "default: break;\n"); + Indent(stream, level * 2 + 1); + TreeCCStreamPrint(stream, "}\n"); + } + + /* + * Generate the exit point for a non-virtual operation. + */ + static void C_GenExit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(strcmp(oper->returnType, "void") != 0) + { + /* Generate a default return value for the function */ + if(oper->defValue) + { + TreeCCStreamPrint(stream, "\treturn (%s);\n", oper->defValue); + } + else + { + TreeCCStreamPrint(stream, "\treturn 0;\n"); + } + } + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Generate the end declarations for a non-virtual operation. + */ + static void C_GenEnd(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + /* Nothing to do here for C and C++ */ + } + + /* + * Table of non-virtual code generation functions. + */ + TreeCCNonVirtual const TreeCCNonVirtualFuncsC = { + C_GenStart, + C_GenEntry, + C_GenSplitEntry, + C_GenSwitchHead, + C_GenSelector, + C_GenEndSelectors, + C_GenCaseFunc, + C_GenCaseCall, + C_GenCaseInline, + C_GenCaseSplit, + C_GenEndCase, + C_GenEndSwitch, + C_GenExit, + C_GenEnd, + }; + + /* + * Write out header information for all streams. + */ + static void WriteHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->isHeader) + { + TreeCCStreamHeaderTop(stream); + TreeCCStreamPrint(stream, "\n"); + TreeCCStreamPrint(stream, "#ifdef __cplusplus\n"); + TreeCCStreamPrint(stream, "extern \"C\" {\n"); + TreeCCStreamPrint(stream, "#endif\n"); + TreeCCStreamPrint(stream, "\n"); + } + else + { + TreeCCStreamSourceTop(stream); + TreeCCStreamPrint(stream, "\n"); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WriteFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else if(stream->isHeader) + { + TreeCCStreamPrint(stream, "#ifdef __cplusplus\n"); + TreeCCStreamPrint(stream, "};\n"); + TreeCCStreamPrint(stream, "#endif\n"); + TreeCCStreamPrint(stream, "\n"); + TreeCCStreamHeaderBottom(stream); + } + else + { + TreeCCStreamSourceBottom(stream); + } + stream = stream->nextStream; + } + } + + /* + * Write the skeleton for the node memory manager to a source stream. + */ + static void WriteSourceSkeleton(TreeCCContext *context, TreeCCStream *stream) + { + if(context->block_size) + { + TreeCCStreamPrint(stream, "#define %s_BLKSIZ %d\n", + context->state_type, context->block_size); + } + if(context->reentrant) + { + TreeCCStreamPrint(stream, "#define %s_REENTRANT 1\n", + context->state_type); + } + if(context->track_lines) + { + TreeCCStreamPrint(stream, "#define %s_TRACK_LINES 1\n", + context->state_type); + } + if(context->use_gc_allocator) + { + TreeCCIncludeSkeleton(context, stream, "c_gc_skel.c"); + } + else + { + TreeCCIncludeSkeleton(context, stream, "c_skel.c"); + } + } + + void TreeCCGenerateC(TreeCCContext *context) + { + /* Write all stream headers */ + WriteHeaders(context); + + /* Generate the contents of the header stream */ + TreeCCNodeVisitAll(context, DefineNodeNumbers); + TreeCCStreamPrint(context->headerStream, "\n"); + TreeCCNodeVisitAll(context, DeclareTypeDefs); + TreeCCStreamPrint(context->headerStream, "\n"); + if(context->use_gc_allocator) + { + if(context->commonHeader) + { + TreeCCIncludeSkeleton + (context, context->commonHeader, "c_gc_skel.h"); + } + else + { + TreeCCIncludeSkeleton + (context, context->headerStream, "c_gc_skel.h"); + } + } + else + { + if(context->commonHeader) + { + TreeCCIncludeSkeleton(context, context->commonHeader, "c_skel.h"); + } + else + { + TreeCCIncludeSkeleton(context, context->headerStream, "c_skel.h"); + } + } + TreeCCNodeVisitAll(context, BuildTypeDecls); + TreeCCNodeVisitAll(context, DeclareCreateFuncs); + TreeCCStreamPrint(context->headerStream, "\n"); + TreeCCOperationVisitAll(context, DeclareNonVirtuals); + TreeCCStreamPrint(context->headerStream, "\n"); + OutputHelpers(context); + + /* Generate the contents of the source stream */ + if(context->use_allocator) + { + if(context->commonSource) + { + WriteSourceSkeleton(context, context->commonSource); + } + else + { + WriteSourceSkeleton(context, context->sourceStream); + } + } + TreeCCNodeVisitAll(context, DefineVtables); + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsC); + OutputIsA(context); + + /* Write all stream footers */ + WriteFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_cpp.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_cpp.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_cpp.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1107 ---- + /* + * gen_cpp.c - Generate C++ source code from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Define the node numbers. + */ + static void DefineNodeNumbers(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) == 0) + { + TreeCCStreamPrint(stream, "const int %s_kind = %d;\n", + node->name, node->number); + } + } + + /* + * Declare the fields for a node type. + */ + static void DeclareFields(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCField *field; + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, "\t%s %s;\n", field->type, field->name); + field = field->next; + } + } + + /* + * Declare the virtuals for a node type. + */ + static void DeclareVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + int num, needComma; + TreeCCOperationCase *operCase; + int declareCase, abstractCase; + TreeCCNode *tempNode; + if(node->parent) + { + DeclareVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + declareCase = abstractCase; + } + else + { + declareCase = 1; + abstractCase = 0; + } + if(declareCase) + { + TreeCCStreamPrint(stream, "\tvirtual %s %s(", + virt->returnType, virt->name); + param = virt->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + else + { + needComma = 1; + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + param = param->next; + } + if(abstractCase) + { + TreeCCStreamPrint(stream, ") = 0;\n"); + } + else + { + TreeCCStreamPrint(stream, ");\n"); + } + } + virt = virt->next; + } + } + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* Define an enumerated type */ + TreeCCNode *child; + TreeCCStreamPrint(stream, "typedef enum {\n"); + child = node->firstChild; + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, "\t%s,\n", child->name); + } + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "} %s;\n\n", node->name); + } + else if((node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + /* Define a regular node type */ + TreeCCStreamPrint(stream, "class %s;\n", node->name); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream = node->header; + int needComma; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Output the class header */ + if(node->parent) + { + /* Inherit from a specified parent type */ + TreeCCStreamPrint(stream, "class %s : public %s\n{\n", + node->name, node->parent->name); + } + else + { + /* This type is the base of a class hierarchy */ + if(context->baseType) + { + TreeCCStreamPrint(stream, "class %s : public %s\n{\n", node->name,context->baseType); + } + else + { + TreeCCStreamPrint(stream, "class %s\n{\n", node->name); + } + + /* The following fields have protected access */ + TreeCCStreamPrint(stream, "protected:\n\n"); + + /* Declare the node kind member variable */ + TreeCCStreamPrint(stream, "\tint kind__;\n"); + + /* Declare the filename and linenum fields if we are tracking lines */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, "\tchar *filename__;\n"); + TreeCCStreamPrint(stream, "\tlong linenum__;\n"); + } + + /* Declare the public methods for access to the above fields */ + TreeCCStreamPrint(stream, "\npublic:\n\n"); + TreeCCStreamPrint(stream, "\tint getKind() const { return kind__; }\n"); + if(context->track_lines) + { + TreeCCStreamPrint(stream, + "\tconst char *getFilename() const { return filename__; }\n"); + TreeCCStreamPrint(stream, + "\tlong getLinenum() const { return linenum__; }\n"); + TreeCCStreamPrint(stream, + "\tvoid setFilename(char *filename) { filename__ = filename; }\n"); + TreeCCStreamPrint(stream, + "\tvoid setLinenum(long linenum) { linenum__ = linenum; }\n"); + } + TreeCCStreamPrint(stream, "\n"); + + /* Declare the overloaded "new" and "delete" operators */ + if(!(context->reentrant)) + { + TreeCCStreamPrint(stream, + "\tvoid *operator new(size_t);\n"); + TreeCCStreamPrint(stream, + "\tvoid operator delete(void *, size_t);\n\n"); + } + } + + /* Declare the constructor for the node type */ + if(context->reentrant) + { + /* Re-entrant systems use a factory to create the nodes */ + if(context->virtual_factory || context->abstract_factory) + { + TreeCCStreamPrint(stream, "public: // for virtual factory\n\n"); + } + else + { + TreeCCStreamPrint(stream, "protected:\n\n"); + TreeCCStreamPrint(stream, "\tfriend class %s;\n\n", + context->state_type); + } + } + else + { + /* Non-reentrant systems can construct nodes directly, + unless the node happens to be abstract, in which + case we force the constructor to be protected */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + TreeCCStreamPrint(stream, "protected:\n\n"); + } + else + { + TreeCCStreamPrint(stream, "public:\n\n"); + } + } + TreeCCStreamPrint(stream, "\t%s(", node->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParams(context, stream, node, needComma); + TreeCCStreamPrint(stream, ");\n\n"); + + /* Declare the fields */ + TreeCCStreamPrint(stream, "public:\n\n"); + if(node->fields) + { + DeclareFields(context, stream, node); + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the virtual function prototypes */ + DeclareVirtuals(context, stream, node, node); + TreeCCStreamPrint(stream, "\n"); + + /* Declare the "isA" and "getKindName" helper methods */ + TreeCCStreamPrint(stream, "\tvirtual int isA(int kind) const;\n"); + TreeCCStreamPrint(stream, "\tvirtual const char *getKindName() const;\n\n"); + + /* Declare the protected destructor for the node type. + The destructor is never called, but we need it to + keep C++ compilers from whinging about classes with + virtuals, but no virtual destructor */ + TreeCCStreamPrint(stream, "protected:\n\n"); + TreeCCStreamPrint(stream, "\tvirtual ~%s();\n\n", node->name); + + /* Output the class footer */ + TreeCCStreamPrint(stream, "};\n\n"); + } + + /* + * Declare the prototypes for the non-virtual operations. + */ + static void DeclareNonVirtuals(TreeCCContext *context, + TreeCCOperation *oper) + { + TreeCCStream *stream = oper->header; + TreeCCParam *param; + int num; + int needComma; + + /* Bail out if the operation is virtual */ + if((oper->flags & TREECC_OPER_VIRTUAL) != 0) + { + return; + } + + /* Output a class header if the operation is inside a class */ + if(oper->className) + { + TreeCCStreamPrint(stream, "class %s\n", oper->className); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "public:\n\n"); + TreeCCStreamPrint(stream, "\tstatic "); + } + + /* Output the prototype */ + TreeCCStreamPrint(stream, "%s %s(", oper->returnType, oper->name); + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", param->type, num); + ++num; + } + needComma = 1; + param = param->next; + } + if(!needComma) + { + TreeCCStreamPrint(stream, "void"); + } + TreeCCStreamPrint(stream, ");\n"); + + /* Output a class footer if the operation is inside a class */ + if(oper->className) + { + TreeCCStreamPrint(stream, "};\n\n"); + } + } + + /* + * Output a constructor parameter list to the source stream. + */ + static int CreateParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the parameters to call an inherited constructor. + */ + static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = InheritParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the constructor implementation for a node type. + */ + static void ImplementConstructor(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node) + { + int needComma; + TreeCCField *field; + + /* Output the constructor function header */ + TreeCCStreamPrint(stream, "%s::%s(", node->name, node->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s *state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParamsSource(context, stream, node, needComma); + TreeCCStreamPrint(stream, ")\n"); + + /* Call the parent class constructor */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\t: %s(", node->parent->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "state__"); + needComma = 1; + } + else + { + needComma = 0; + } + InheritParamsSource(context, stream, node->parent, needComma); + TreeCCStreamPrint(stream, ")\n"); + } + + /* Output the beginning of the function body */ + TreeCCStreamPrint(stream, "{\n"); + + /* Set the node kind */ + TreeCCStreamPrint(stream, "\tthis->kind__ = %s_kind;\n", node->name); + + /* Track the filename and line number if necessary */ + if(context->track_lines && !(node->parent)) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + "\tthis->filename__ = state__->currFilename();\n"); + TreeCCStreamPrint(stream, + "\tthis->linenum__ = state__->currLinenum();\n"); + } + else + { + TreeCCStreamPrint(stream, + "\tthis->filename__ = %s::getState()->currFilename();\n", + context->state_type); + TreeCCStreamPrint(stream, + "\tthis->linenum__ = %s::getState()->currLinenum();\n", + context->state_type); + } + } + + /* Initialize the fields that are specific to this node type */ + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, "\tthis->%s = %s;\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, "\tthis->%s = %s;\n", + field->name, field->value); + } + field = field->next; + } + + /* Output the constructor function footer */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Implement the virtual methods that have implementations in a node type. + */ + static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + TreeCCOperation *oper; + int num, first; + int needComma; + if(node->parent) + { + ImplementVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + /* We don't have a direct implementation in this class */ + virt = virt->next; + continue; + } + TreeCCStreamPrint(stream, "%s %s::%s(", virt->returnType, + actualNode->name, virt->name); + oper = operCase->oper; + param = oper->params; + needComma = 0; + num = 1; + first = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(first) + { + /* Skip the first argument, which corresponds to "this" */ + if(!(param->name)) + { + ++num; + } + first = 0; + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + needComma = 1; + } + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + if(!(oper->params->name) || !strcmp(oper->params->name, "this")) + { + /* The first parameter is called "this", so we don't + need to declare it at the head of the function */ + TreeCCStreamLine(stream, operCase->codeLinenum, + operCase->codeFilename); + TreeCCStreamPrint(stream, "{"); + TreeCCStreamCode(stream, operCase->code); + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + } + else + { + /* The first parameter is called something else, + so create a temporary variable to hold "this" */ + TreeCCStreamPrint(stream, "{\n\t%s *%s = this;\n", + actualNode->name, oper->params->name); + TreeCCStreamLine(stream, operCase->codeLinenum, + operCase->codeFilename); + TreeCCStreamPrint(stream, "\t{"); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "}\n"); + } + TreeCCStreamPrint(stream, "\n"); + virt = virt->next; + } + } + + /* + * Implement a node type. + */ + static void ImplementNodeTypes(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream = node->source; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Implement the "new" and "delete" operators if this is a top-level node */ + if(!(node->parent) && !(context->reentrant)) + { + TreeCCStreamPrint(stream, "void *%s::operator new(size_t size__)\n", + node->name); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\treturn %s::getState()->alloc(size__);\n", + context->state_type); + TreeCCStreamPrint(stream, "}\n\n"); + TreeCCStreamPrint(stream, + "void %s::operator delete(void *ptr__, size_t size__)\n", + node->name); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\t%s::getState()->dealloc(ptr__, size__);\n", + context->state_type); + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* Implement the constructor */ + ImplementConstructor(context, stream, node); + + /* Implement the destructor */ + TreeCCStreamPrint(stream, "%s::~%s()\n", node->name, node->name); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\t// not used\n"); + TreeCCStreamPrint(stream, "}\n\n"); + + /* Implement the virtual methods that reside in this node type */ + ImplementVirtuals(context, stream, node, node); + + /* Implement the "isA" helper method */ + TreeCCStreamPrint(stream, "int %s::isA(int kind) const\n", node->name); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\tif(kind == %s_kind)\n", node->name); + TreeCCStreamPrint(stream, "\t\treturn 1;\n"); + TreeCCStreamPrint(stream, "\telse\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, "\t\treturn %s::isA(kind);\n", + node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "\t\treturn 0;\n"); + } + TreeCCStreamPrint(stream, "}\n\n"); + + /* Implement the "getKindName" helper method */ + TreeCCStreamPrint(stream, "const char *%s::getKindName() const\n", + node->name); + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\treturn \"%s\";\n", node->name); + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Declare the parameters for a factory method in the state type. + */ + static int FactoryCreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryCreateParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Declare the create function for a node type. + */ + static void DeclareCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + if(context->commonHeader) + { + stream = context->commonHeader; + } + else + { + stream = context->headerStream; + } + + /* Output the start of the function definition */ + if(context->virtual_factory || context->abstract_factory) + { + TreeCCStreamPrint(stream, "\tvirtual %s *%sCreate(", + node->name, node->name); + } + else + { + TreeCCStreamPrint(stream, "\t%s *%sCreate(", + node->name, node->name); + } + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + + /* Terminate the function definition */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, ") = 0;\n"); + } + else + { + TreeCCStreamPrint(stream, ");\n"); + } + } + + /* + * Declare the state type in the header stream. + */ + static void DeclareStateType(TreeCCContext *context, TreeCCStream *stream) + { + /* Declare the class header */ + TreeCCStreamPrint(stream, "class %s\n{\n", context->state_type); + + /* Declare the constructor and destructor */ + TreeCCStreamPrint(stream, "public:\n\n"); + TreeCCStreamPrint(stream, "\t%s();\n", context->state_type); + TreeCCStreamPrint(stream, "\tvirtual ~%s();\n\n", context->state_type); + + /* Include the header skeleton */ + if(context->use_gc_allocator) + { + TreeCCIncludeSkeleton(context, stream, "cpp_gc_skel.h"); + } + else + { + TreeCCIncludeSkeleton(context, stream, "cpp_skel.h"); + } + + /* Singleton handling for non-reentrant systems */ + if(!(context->reentrant)) + { + TreeCCStreamPrint(stream, "private:\n\n"); + TreeCCStreamPrint(stream, "\tstatic %s *state__;\n\n", + context->state_type); + TreeCCStreamPrint(stream, "public:\n\n"); + TreeCCStreamPrint(stream, "\tstatic %s *getState()\n", + context->state_type); + TreeCCStreamPrint(stream, "\t\t{\n"); + TreeCCStreamPrint(stream, "\t\t\tif(state__) return state__;\n"); + TreeCCStreamPrint(stream, "\t\t\tstate__ = new %s();\n", + context->state_type); + TreeCCStreamPrint(stream, "\t\t\treturn state__;\n"); + TreeCCStreamPrint(stream, "\t\t}\n\n"); + } + + /* Declare the create functions for all of the node types */ + if(context->reentrant) + { + TreeCCStreamPrint(stream, "public:\n\n"); + TreeCCNodeVisitAll(context, DeclareCreateFuncs); + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the node pool handling functions */ + TreeCCStreamPrint(stream, "public:\n\n"); + TreeCCStreamPrint(stream, "\tvoid *alloc(size_t);\n"); + TreeCCStreamPrint(stream, "\tvoid dealloc(void *, size_t);\n"); + TreeCCStreamPrint(stream, "\tint push();\n"); + TreeCCStreamPrint(stream, "\tvoid pop();\n"); + TreeCCStreamPrint(stream, "\tvoid clear();\n"); + + /* Declare the "failed" method for out of memory error reporting */ + TreeCCStreamPrint(stream, "\tvirtual void failed();\n"); + + /* Declare the line number tracking methods */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, "\tvirtual char *currFilename();\n"); + TreeCCStreamPrint(stream, "\tvirtual long currLinenum();\n"); + } + + /* Declare the end of the state type */ + TreeCCStreamPrint(stream, "\n};\n\n"); + } + + /* + * Output invocation parameters for a call to a constructor + * from within a factory method. + */ + static int FactoryInvokeParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryInvokeParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + if(context->commonSource) + { + stream = context->commonSource; + } + else + { + stream = context->sourceStream; + } + + /* Output the start of the function definition */ + TreeCCStreamPrint(stream, "%s *%s::%sCreate(", + node->name, context->state_type, node->name); + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + TreeCCStreamPrint(stream, ")\n"); + + /* Output the body of the creation function */ + TreeCCStreamPrint(stream, "{\n"); + TreeCCStreamPrint(stream, "\tvoid *buf__ = this->alloc(sizeof(%s));\n", + node->name); + + /* Bail out to the caller if "alloc" returned NULL */ + TreeCCStreamPrint(stream, "\tif(buf__ == 0) return 0;\n"); + + /* Invoke the constructor and return the node to the caller */ + TreeCCStreamPrint(stream, "\treturn new (buf__) %s(this", node->name); + FactoryInvokeParams(context, stream, node, 1); + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Implement the state type in the source stream. + */ + static void ImplementStateType(TreeCCContext *context, TreeCCStream *stream) + { + /* Include the common definitions from the skeleton */ + if(context->block_size) + { + TreeCCStreamPrint(stream, "#define %s_BLKSIZ %d\n", + context->state_type, context->block_size); + } + if(context->reentrant) + { + TreeCCStreamPrint(stream, "#define %s_REENTRANT 1\n", + context->state_type); + } + if(context->track_lines) + { + TreeCCStreamPrint(stream, "#define %s_TRACK_LINES 1\n", + context->state_type); + } + if(context->use_allocator) + { + TreeCCStreamPrint(stream, "#define %s_USE_ALLOCATOR 1\n", + context->state_type); + } + if(context->use_gc_allocator) + { + TreeCCIncludeSkeleton(context, stream, "cpp_gc_skel.cc"); + } + else + { + TreeCCIncludeSkeleton(context, stream, "cpp_skel.cc"); + } + + /* Implement the create functions for all of the node types */ + if(context->reentrant && !(context->abstract_factory)) + { + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + } + } + + /* + * Write out header information for all streams. + */ + static void WriteCPPHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->isHeader) + { + TreeCCStreamHeaderTop(stream); + TreeCCStreamPrint(stream, "\n"); + TreeCCStreamPrint(stream, "#include \n"); + TreeCCStreamPrint(stream, "\n"); + } + else + { + TreeCCStreamSourceTop(stream); + TreeCCStreamPrint(stream, "\n"); + } + if(context->namespace) + { + TreeCCStreamPrint(stream, "namespace %s\n{\n\n", + context->namespace); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WriteCPPFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else + { + if(context->namespace) + { + TreeCCStreamPrint(stream, "}\n"); + } + if(stream->isHeader) + { + TreeCCStreamHeaderBottom(stream); + } + else + { + TreeCCStreamSourceBottom(stream); + } + } + stream = stream->nextStream; + } + } + + void TreeCCGenerateCPP(TreeCCContext *context) + { + /* Write all stream headers */ + WriteCPPHeaders(context); + + /* Generate the contents of the header stream */ + TreeCCNodeVisitAll(context, DefineNodeNumbers); + TreeCCStreamPrint(context->headerStream, "\n"); + TreeCCNodeVisitAll(context, DeclareTypeDefs); + TreeCCStreamPrint(context->headerStream, "\n"); + if(context->commonHeader) + { + DeclareStateType(context, context->commonHeader); + } + else + { + DeclareStateType(context, context->headerStream); + } + TreeCCNodeVisitAll(context, BuildTypeDecls); + TreeCCStreamPrint(context->headerStream, "\n"); + TreeCCOperationVisitAll(context, DeclareNonVirtuals); + TreeCCStreamPrint(context->headerStream, "\n"); + + /* Implement the state type */ + if(context->commonSource) + { + ImplementStateType(context, context->commonSource); + } + else + { + ImplementStateType(context, context->sourceStream); + } + + /* Generate the contents of the source stream */ + TreeCCNodeVisitAll(context, ImplementNodeTypes); + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsC); + + /* Write all stream footers */ + WriteCPPFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_cs.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_cs.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_cs.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,830 ---- + /* + * gen_cs.c - Generate C# source code from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Declare the fields for a node type. + */ + static void DeclareFields(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCField *field; + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, "\tpublic %s %s;\n", + field->type, field->name); + field = field->next; + } + } + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* Define an enumerated type */ + TreeCCStream *stream = node->source; + TreeCCNode *child; + if(context->internal_access) + { + TreeCCStreamPrint(stream, "internal enum %s\n", node->name); + } + else + { + TreeCCStreamPrint(stream, "public enum %s\n", node->name); + } + TreeCCStreamPrint(stream, "{\n"); + child = node->firstChild; + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, "\t%s,\n", child->name); + } + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "}\n\n"); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the parameters to call an inherited constructor. + */ + static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = InheritParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the virtual methods that have implementations in a node type. + */ + static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + int declareCase, abstractCase; + TreeCCNode *tempNode; + int num, first; + int needComma; + if(node->parent) + { + ImplementVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + declareCase = abstractCase; + } + else + { + declareCase = 1; + abstractCase = 0; + } + if(declareCase) + { + if(abstractCase) + { + if(node == actualNode) + { + TreeCCStreamPrint(stream, + "\tpublic abstract %s %s(", + virt->returnType, virt->name); + } + else + { + /* Inherit the "abstract" definition from the parent */ + virt = virt->next; + continue; + } + } + else + { + if(node == actualNode) + { + TreeCCStreamPrint(stream, "\tpublic virtual %s %s(", + virt->returnType, virt->name); + } + else + { + TreeCCStreamPrint(stream, "\tpublic override %s %s(", + virt->returnType, virt->name); + } + } + param = virt->oper->params; + needComma = 0; + num = 1; + first = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(first) + { + /* Skip the first argument, which corresponds to "this" */ + if(!(param->name)) + { + ++num; + } + first = 0; + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + param->type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + param->type, num); + ++num; + } + needComma = 1; + } + param = param->next; + } + if(!abstractCase) + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamLine(stream, operCase->codeLinenum, + operCase->codeFilename); + TreeCCStreamPrint(stream, "\t{"); + if(!(virt->oper->params->name) || + !strcmp(virt->oper->params->name, "this")) + { + /* The first parameter is called "this", so we don't + need to declare it at the head of the function */ + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + else + { + /* The first parameter is called something else, + so create a temporary variable to hold "this" */ + TreeCCStreamPrint(stream, "\n\t\t%s %s = this;\n\t", + actualNode->name, + virt->oper->params->name); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "\n"); + } + else + { + TreeCCStreamPrint(stream, ");\n\n"); + } + } + virt = virt->next; + } + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream; + int needComma; + const char *constructorAccess; + TreeCCField *field; + int isAbstract; + const char *accessMode; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Determine if this class has abstract virtuals */ + isAbstract = TreeCCNodeHasAbstracts(context, node); + + /* Determine the access mode for the class */ + if(context->internal_access) + { + accessMode = "internal"; + } + else + { + accessMode = "public"; + } + + /* Output the class header */ + stream = node->source; + if(node->parent) + { + /* Inherit from a specified parent type */ + if(isAbstract) + { + TreeCCStreamPrint(stream, "%s abstract class %s : %s\n{\n", + accessMode, node->name, node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "%s class %s : %s\n{\n", + accessMode, node->name, node->parent->name); + } + } + else + { + /* This type is the base of a class hierarchy */ + if(isAbstract) + { + if(context->baseType) + { + TreeCCStreamPrint(stream, "%s abstract class %s : %s\n{\n", + accessMode, node->name, context->baseType); + } + else + { + TreeCCStreamPrint(stream, "%s abstract class %s\n{\n", + accessMode, node->name); + } + } + else + { + if(context->baseType) + { + TreeCCStreamPrint(stream, "%s class %s : %s\n{\n", + accessMode, node->name, context->baseType); + } + else + { + TreeCCStreamPrint(stream, "%s class %s\n{\n", + accessMode, node->name); + } + } + + /* Declare the node kind member variable */ + TreeCCStreamPrint(stream, "\tprotected int kind__;\n"); + + /* Declare the filename and linenum fields if we are tracking lines */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, "\tprotected String filename__;\n"); + TreeCCStreamPrint(stream, "\tprotected long linenum__;\n"); + } + TreeCCStreamPrint(stream, "\n"); + + /* Declare the public methods for access to the above fields */ + TreeCCStreamPrint(stream, + "\tpublic int getKind() { return kind__; }\n"); + if(context->track_lines) + { + TreeCCStreamPrint(stream, + "\tpublic String getFilename() { return filename__; }\n"); + TreeCCStreamPrint(stream, + "\tpublic long getLinenum() { return linenum__; }\n"); + TreeCCStreamPrint(stream, + "\tpublic void setFilename(String filename) " + "{ filename__ = filename; }\n"); + TreeCCStreamPrint(stream, + "\tpublic void setLinenum(long linenum) " + "{ linenum__ = linenum; }\n"); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the kind value */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\tpublic new const int KIND = %d;\n\n", + node->number); + } + else + { + TreeCCStreamPrint(stream, "\tpublic const int KIND = %d;\n\n", + node->number); + } + + /* Declare the fields */ + if(node->fields) + { + DeclareFields(context, stream, node); + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the constructor for the node type */ + if(context->reentrant) + { + /* Re-entrant systems use a factory to create the nodes. + C# doesn't have a notion of "access by members of + the namespace only". The closest is "internal", but + even that isn't quite right, so we always use "public" */ + constructorAccess = "public "; + } + else + { + /* Non-reentrant systems can construct nodes directly, + unless the node happens to be abstract, in which + case we force the constructor to be protected */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + constructorAccess = "protected "; + } + else + { + constructorAccess = "public "; + } + } + TreeCCStreamPrint(stream, "\t%s%s(", constructorAccess, node->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParams(context, stream, node, needComma); + TreeCCStreamPrint(stream, ")\n"); + + /* Call the parent class constructor */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\t\t: base("); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "state__"); + needComma = 1; + } + else + { + needComma = 0; + } + InheritParamsSource(context, stream, node->parent, needComma); + TreeCCStreamPrint(stream, ")\n"); + } + + /* Set the node kind */ + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\tthis.kind__ = KIND;\n"); + + /* Track the filename and line number if necessary */ + if(context->track_lines && !(node->parent)) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + "\t\tthis.filename__ = state__.currFilename();\n"); + TreeCCStreamPrint(stream, + "\t\tthis.linenum__ = state__.currLinenum();\n"); + } + else + { + TreeCCStreamPrint(stream, + "\t\tthis.filename__ = %s.getState().currFilename();\n", + context->state_type); + TreeCCStreamPrint(stream, + "\t\tthis.linenum__ = %s.getState().currLinenum();\n", + context->state_type); + } + } + + /* Initialize the fields that are specific to this node type */ + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, "\t\tthis.%s = %s;\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, "\t\tthis.%s = %s;\n", + field->name, field->value); + } + field = field->next; + } + TreeCCStreamPrint(stream, "\t}\n\n"); + + /* Implement the virtual functions */ + ImplementVirtuals(context, stream, node, node); + + /* Declare the "isA" and "getKindName" helper methods */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\tpublic override int isA(int kind)\n"); + } + else + { + TreeCCStreamPrint(stream, "\tpublic virtual int isA(int kind)\n"); + } + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\tif(kind == KIND)\n"); + TreeCCStreamPrint(stream, "\t\t\treturn 1;\n"); + TreeCCStreamPrint(stream, "\t\telse\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, "\t\t\treturn base.isA(kind);\n"); + } + else + { + TreeCCStreamPrint(stream, "\t\t\treturn 0;\n"); + } + TreeCCStreamPrint(stream, "\t}\n\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, "\tpublic override String getKindName()\n"); + } + else + { + TreeCCStreamPrint(stream, "\tpublic virtual String getKindName()\n"); + } + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\treturn \"%s\";\n", node->name); + TreeCCStreamPrint(stream, "\t}\n"); + + /* Output the class footer */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Declare the parameters for a factory method in the state type. + */ + static int FactoryCreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryCreateParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", + field->type, field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output invocation parameters for a call to a constructor + * from within a factory method. + */ + static int FactoryInvokeParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryInvokeParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + if(context->commonSource) + { + stream = context->commonSource; + } + else + { + stream = context->sourceStream; + } + + /* Output the start of the function definition */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, "\tpublic virtual abstract %s %sCreate(", + node->name, node->name); + } + else if(context->virtual_factory) + { + TreeCCStreamPrint(stream, "\tpublic virtual %s %sCreate(", + node->name, node->name); + } + else + { + TreeCCStreamPrint(stream, "\tpublic %s %sCreate(", + node->name, node->name); + } + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + + /* Output the body of the creation function */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, ");\n"); + } + else + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\treturn new %s(this", node->name); + FactoryInvokeParams(context, stream, node, 1); + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "\t}\n\n"); + } + } + + /* + * Implement the state type in the source stream. + */ + static void ImplementStateType(TreeCCContext *context, TreeCCStream *stream) + { + /* Declare the class header */ + if(context->reentrant && context->abstract_factory) + { + if(context->internal_access) + { + TreeCCStreamPrint(stream, "internal abstract class %s\n{\n\n", + context->state_type); + } + else + { + TreeCCStreamPrint(stream, "public abstract class %s\n{\n\n", + context->state_type); + } + } + else + { + if(context->internal_access) + { + TreeCCStreamPrint(stream, "internal class %s\n{\n\n", + context->state_type); + } + else + { + TreeCCStreamPrint(stream, "public class %s\n{\n\n", + context->state_type); + } + } + + /* Singleton handling for non-reentrant systems */ + if(!(context->reentrant)) + { + TreeCCStreamPrint(stream, "\tprivate static %s state__;\n\n", + context->state_type); + TreeCCStreamPrint(stream, "\tpublic static %s getState()\n", + context->state_type); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\tif(state__ != null) return state__;\n"); + TreeCCStreamPrint(stream, "\t\tstate__ = new %s();\n", + context->state_type); + TreeCCStreamPrint(stream, "\t\treturn state__;\n"); + TreeCCStreamPrint(stream, "\t}\n\n"); + } + + /* Implement the constructor */ + if(context->reentrant) + { + TreeCCStreamPrint(stream, "\tpublic %s() {}\n\n", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "\tpublic %s() { state__ = this; }\n\n", + context->state_type); + } + + /* Implement the create functions for all of the node types */ + if(context->reentrant) + { + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + } + + /* Implement the line number tracking methods */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, + "\tpublic virtual String currFilename() { return null; }\n"); + TreeCCStreamPrint(stream, + "\tpublic virtual long currLinenum() { return 0; }\n\n"); + } + + /* Declare the end of the state type */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Write out header information for all streams. + */ + static void WriteCSharpHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(!(stream->isHeader)) + { + TreeCCStreamPrint(stream, + "/* %s. Generated automatically by treecc */\n\n", + stream->embedName); + if(context->namespace) + { + TreeCCStreamPrint(stream, "namespace %s\n{\n\n", + context->namespace); + } + TreeCCStreamPrint(stream, "using System;\n\n"); + TreeCCStreamSourceTopCS(stream); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WriteCSharpFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else if(!(stream->isHeader)) + { + TreeCCStreamSourceBottom(stream); + if(context->namespace) + { + TreeCCStreamPrint(stream, "}\n"); + } + } + stream = stream->nextStream; + } + } + + void TreeCCGenerateCSharp(TreeCCContext *context) + { + /* Write all stream headers */ + WriteCSharpHeaders(context); + + /* Generate the contents of the source stream */ + TreeCCNodeVisitAll(context, DeclareTypeDefs); + if(context->commonSource) + { + ImplementStateType(context, context->commonSource); + } + else + { + ImplementStateType(context, context->sourceStream); + } + TreeCCNodeVisitAll(context, BuildTypeDecls); + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsJava); + + /* Write all stream footers */ + WriteCSharpFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_java.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_java.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_java.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1339 ---- + /* + * gen_java.c - Generate Java source code from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Convert enumerated types into "int", because Java + * doesn't support enumerations. + */ + static const char *ConvertType(TreeCCContext *context, char *type) + { + TreeCCNode *node = TreeCCNodeFind(context, type); + if(node && (node->flags & TREECC_NODE_ENUM) != 0) + { + return "int"; + } + else + { + return type; + } + } + + /* + * Declare the fields for a node type. + */ + static void DeclareFields(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCField *field; + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, "\tpublic %s %s;\n", + ConvertType(context, field->type), field->name); + field = field->next; + } + } + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* Define an enumerated type */ + TreeCCStream *stream = TreeCCStreamGetJava(context, node->name); + TreeCCNode *child; + int num; + TreeCCStreamPrint(stream, "public class %s\n", node->name); + TreeCCStreamPrint(stream, "{\n"); + child = node->firstChild; + num = 0; + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, + "\tpublic static final int %s = %d;\n", + child->name, num); + ++num; + } + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "}\n"); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", + ConvertType(context, field->type), + field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the parameters to call an inherited constructor. + */ + static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = InheritParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the virtual methods that have implementations in a node type. + */ + static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + int declareCase, abstractCase; + TreeCCNode *tempNode; + int num, first; + int needComma; + if(node->parent) + { + ImplementVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + declareCase = abstractCase; + } + else + { + declareCase = 1; + abstractCase = 0; + } + if(declareCase) + { + if(abstractCase) + { + TreeCCStreamPrint(stream, "\tpublic abstract %s %s(", + ConvertType(context, virt->returnType), + virt->name); + } + else + { + TreeCCStreamPrint(stream, "\tpublic %s %s(", + ConvertType(context, virt->returnType), + virt->name); + } + param = virt->oper->params; + needComma = 0; + num = 1; + first = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(first) + { + /* Skip the first argument, which corresponds to "this" */ + if(!(param->name)) + { + ++num; + } + first = 0; + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "%s %s", + ConvertType(context, param->type), + param->name); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + ConvertType(context, param->type), + num); + ++num; + } + needComma = 1; + } + param = param->next; + } + if(!abstractCase) + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "\t{\n"); + if(!(virt->oper->params->name) || + !strcmp(virt->oper->params->name, "this")) + { + /* The first parameter is called "this", so we don't + need to declare it at the head of the function */ + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + else + { + /* The first parameter is called something else, + so create a temporary variable to hold "this" */ + TreeCCStreamPrint(stream, "\t\t%s %s = this;\n", + actualNode->name, + virt->oper->params->name); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "}\n\n"); + } + else + { + TreeCCStreamPrint(stream, ");\n\n"); + } + } + virt = virt->next; + } + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream; + int needComma; + const char *constructorAccess; + TreeCCField *field; + int isAbstract; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Determine if this class has abstract virtuals */ + isAbstract = TreeCCNodeHasAbstracts(context, node); + + /* Output the class header */ + stream = TreeCCStreamGetJava(context, node->name); + if(node->parent) + { + /* Inherit from a specified parent type */ + if(isAbstract) + { + TreeCCStreamPrint(stream, + "public abstract class %s extends %s\n{\n", + node->name, node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "public class %s extends %s\n{\n", + node->name, node->parent->name); + } + } + else + { + /* This type is the base of a class hierarchy */ + if(isAbstract) + { + if(context->baseType) + { + TreeCCStreamPrint(stream, "public abstract class %s extends %s\n{\n", + node->name,context->baseType); + } + else + { + TreeCCStreamPrint(stream, "public abstract class %s\n{\n", + node->name); + } + } + else + { + if(context->baseType) + { + TreeCCStreamPrint(stream, "public class %s extends %s\n{\n", + node->name,context->baseType); + } + else + { + TreeCCStreamPrint(stream, "public class %s\n{\n", node->name); + } + } + + /* Declare the node kind member variable */ + TreeCCStreamPrint(stream, "\tprotected int kind__;\n"); + + /* Declare the filename and linenum fields if we are tracking lines */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, "\tprotected String filename__;\n"); + TreeCCStreamPrint(stream, "\tprotected long linenum__;\n"); + } + TreeCCStreamPrint(stream, "\n"); + + /* Declare the public methods for access to the above fields */ + TreeCCStreamPrint(stream, + "\tpublic int getKind() { return kind__; }\n"); + if(context->track_lines) + { + TreeCCStreamPrint(stream, + "\tpublic String getFilename() { return filename__; }\n"); + TreeCCStreamPrint(stream, + "\tpublic long getLinenum() { return linenum__; }\n"); + TreeCCStreamPrint(stream, + "\tpublic void setFilename(String filename) " + "{ filename__ = filename; }\n"); + TreeCCStreamPrint(stream, + "\tpublic void setLinenum(long linenum) " + "{ linenum__ = linenum; }\n"); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the kind value */ + TreeCCStreamPrint(stream, "\tpublic static final int KIND = %d;\n\n", + node->number); + + /* Declare the fields */ + if(node->fields) + { + DeclareFields(context, stream, node); + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the constructor for the node type */ + if(context->reentrant) + { + /* Re-entrant systems use a factory to create the nodes */ + if(context->virtual_factory || context->abstract_factory) + { + /* Subclasses need to be able to construct the node */ + constructorAccess = "public "; + } + else + { + /* Only the state type needs to be able to construct the node */ + constructorAccess = ""; + } + } + else + { + /* Non-reentrant systems can construct nodes directly, + unless the node happens to be abstract, in which + case we force the constructor to be protected */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + constructorAccess = "protected "; + } + else + { + constructorAccess = "public "; + } + } + TreeCCStreamPrint(stream, "\t%s%s(", constructorAccess, node->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "%s state__", context->state_type); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParams(context, stream, node, needComma); + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "\t{\n"); + + /* Call the parent class constructor */ + if(node->parent) + { + TreeCCStreamPrint(stream, "\t\tsuper("); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "state__"); + needComma = 1; + } + else + { + needComma = 0; + } + InheritParamsSource(context, stream, node->parent, needComma); + TreeCCStreamPrint(stream, ");\n"); + } + + /* Set the node kind */ + TreeCCStreamPrint(stream, "\t\tthis.kind__ = KIND;\n"); + + /* Track the filename and line number if necessary */ + if(context->track_lines && !(node->parent)) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + "\t\tthis.filename__ = state__.currFilename();\n"); + TreeCCStreamPrint(stream, + "\t\tthis.linenum__ = state__.currLinenum();\n"); + } + else + { + TreeCCStreamPrint(stream, + "\t\tthis.filename__ = %s.getState().currFilename();\n", + context->state_type); + TreeCCStreamPrint(stream, + "\t\tthis.linenum__ = %s.getState().currLinenum();\n", + context->state_type); + } + } + + /* Initialize the fields that are specific to this node type */ + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, "\t\tthis.%s = %s;\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, "\t\tthis.%s = %s;\n", + field->name, field->value); + } + field = field->next; + } + TreeCCStreamPrint(stream, "\t}\n\n"); + + /* Implement the virtual functions */ + ImplementVirtuals(context, stream, node, node); + + /* Declare the "isA" and "getKindName" helper methods */ + TreeCCStreamPrint(stream, "\tpublic int isA(int kind)\n"); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\tif(kind == KIND)\n"); + TreeCCStreamPrint(stream, "\t\t\treturn 1;\n"); + TreeCCStreamPrint(stream, "\t\telse\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, "\t\t\treturn super.isA(kind);\n"); + } + else + { + TreeCCStreamPrint(stream, "\t\t\treturn 0;\n"); + } + TreeCCStreamPrint(stream, "\t}\n\n"); + TreeCCStreamPrint(stream, "\tpublic String getKindName()\n"); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\treturn \"%s\";\n", node->name); + TreeCCStreamPrint(stream, "\t}\n"); + + /* Output the class footer */ + TreeCCStreamPrint(stream, "}\n"); + } + + /* + * Declare the parameters for a factory method in the state type. + */ + static int FactoryCreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryCreateParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s %s", + ConvertType(context, field->type), + field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output invocation parameters for a call to a constructor + * from within a factory method. + */ + static int FactoryInvokeParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryInvokeParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + stream = TreeCCStreamGetJava(context, context->state_type); + + /* Output the start of the function definition */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, "\tpublic abstract %s %sCreate(", + node->name, node->name); + } + else + { + TreeCCStreamPrint(stream, "\tpublic %s %sCreate(", + node->name, node->name); + } + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + + /* Output the body of the creation function */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, ");\n"); + } + else + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\treturn new %s(this", node->name); + FactoryInvokeParams(context, stream, node, 1); + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, "\t}\n\n"); + } + } + + /* + * Implement the state type in the source stream. + */ + static void ImplementStateType(TreeCCContext *context, TreeCCStream *stream) + { + /* Declare the class header */ + if(context->reentrant && context->abstract_factory) + { + TreeCCStreamPrint(stream, "public abstract class %s\n{\n\n", + context->state_type); + } + else + { + TreeCCStreamPrint(stream, "public class %s\n{\n\n", + context->state_type); + } + + /* Singleton handling for non-reentrant systems */ + if(!(context->reentrant)) + { + TreeCCStreamPrint(stream, "\tprivate static %s state__;\n\n", + context->state_type); + TreeCCStreamPrint(stream, "\tpublic static %s getState()\n", + context->state_type); + TreeCCStreamPrint(stream, "\t{\n"); + TreeCCStreamPrint(stream, "\t\tif(state__ != null) return state__;\n"); + TreeCCStreamPrint(stream, "\t\tstate__ = new %s();\n", + context->state_type); + TreeCCStreamPrint(stream, "\t\treturn state__;\n"); + TreeCCStreamPrint(stream, "\t}\n\n"); + } + + /* Implement the constructor */ + if(context->reentrant) + { + TreeCCStreamPrint(stream, "\tpublic %s() {}\n\n", context->state_type); + } + else + { + TreeCCStreamPrint(stream, "\tpublic %s() { state__ = this; }\n\n", + context->state_type); + } + + /* Implement the create functions for all of the node types */ + if(context->reentrant) + { + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + } + + /* Implement the line number tracking methods */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, + "\tpublic String currFilename() { return null; }\n"); + TreeCCStreamPrint(stream, + "\tpublic long currLinenum() { return 0; }\n\n"); + } + + /* Declare the end of the state type */ + TreeCCStreamPrint(stream, "}\n"); + } + + /* + * Determine if a type name corresponds to an enumerated type. + */ + static int IsEnumType(TreeCCContext *context, const char *type) + { + TreeCCNode *node = TreeCCNodeFindByType(context, type); + if(node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + return 1; + } + } + return 0; + } + + /* + * Generate the start declarations for a non-virtual operation. + */ + static void Java_GenStart(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + const char *accessMode; + if(context->internal_access && context->language == TREECC_LANG_CSHARP) + { + accessMode = "internal"; + } + else + { + accessMode = "public"; + } + if(oper->className) + { + TreeCCStreamPrint(stream, "%s class %s\n{\n", + accessMode, oper->className); + } + else + { + TreeCCStreamPrint(stream, "%s class %s\n{\n", + accessMode, oper->name); + } + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void JavaGenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + TreeCCParam *param; + int num; + int needComma; + if(number != -1) + { + TreeCCStreamPrint(stream, "\tprivate static %s %s_split_%d__(", + oper->returnType, oper->name, number); + } + else + { + TreeCCStreamPrint(stream, "\tpublic static %s %s(", + oper->returnType, oper->name); + } + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "%s ", param->type); + } + else + { + TreeCCStreamPrint(stream, "%s ", ConvertType(context, param->type)); + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(!IsEnumType(context, param->type)) + { + TreeCCStreamPrint(stream, "__"); + } + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "\t{\n"); + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void Java_GenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + JavaGenEntry(context, stream, oper, -1); + } + + /* + * Generate the entry point for a split-out function. + */ + static void Java_GenSplitEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + JavaGenEntry(context, stream, oper, number); + } + + /* + * Output TAB's for a specific level of indenting. + */ + static void Indent(TreeCCStream *stream, int indent) + { + while(indent >= 4) + { + TreeCCStreamPrint(stream, "\t\t\t\t"); + indent -= 4; + } + if(indent == 1) + { + TreeCCStreamPrint(stream, "\t"); + } + else if(indent == 2) + { + TreeCCStreamPrint(stream, "\t\t"); + } + else if(indent == 3) + { + TreeCCStreamPrint(stream, "\t\t\t"); + } + } + + /* + * Generate the head of a "switch" statement. + */ + static void Java_GenSwitchHead(TreeCCContext *context, TreeCCStream *stream, + char *paramName, int level, int isEnum) + { + Indent(stream, level * 2 + 2); + if(isEnum) + { + TreeCCStreamPrint(stream, "switch(%s)\n", paramName); + } + else + { + TreeCCStreamPrint(stream, "switch(%s__.getKind())\n", paramName); + } + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate a selector for a "switch" case. + */ + static void Java_GenSelector(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int level) + { + if((node->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "case %s.%s:\n", + node->parent->name, node->name); + } + else if((node->flags & TREECC_NODE_ENUM) == 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "case %s.KIND:\n", node->name); + } + } + + /* + * Terminate the selectors and begin the body of a "switch" case. + */ + static void Java_GenEndSelectors(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate the code for a case within a function. + */ + static void Java_GenCaseFunc(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + char *type; + + /* Output the header for the function */ + TreeCCStreamPrint(stream, "\tprivate static %s %s_%d__(", + ConvertType(context, operCase->oper->returnType), + operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + type = trigger->node->name; + } + else + { + type = param->type; + } + trigger = trigger->next; + } + else + { + type = param->type; + } + if(param->name) + { + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "%s %s", type, param->name); + } + else + { + TreeCCStreamPrint(stream, "%s %s", + ConvertType(context, type), param->name); + } + } + else + { + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "%s P%d__", type, num); + } + else + { + TreeCCStreamPrint(stream, "%s P%d__", + ConvertType(context, type), num); + } + ++num; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + + /* Output the code for the operation case */ + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + } + TreeCCStreamPrint(stream, "\t{"); + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamFixLine(stream); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a call to a case function from within the "switch". + */ + static void Java_GenCaseCall(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, + int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 4); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s)", trigger->node->name); + } + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Generate the code for a case inline within the "switch". + */ + static void Java_GenCaseInline(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + + /* Copy the parameters to new variables of the correct types */ + param = operCase->oper->params; + trigger = operCase->triggers; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(param->name != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + Indent(stream, level * 2 + 4); + TreeCCStreamPrint(stream, "%s %s = (%s)%s__;\n", + trigger->node->name, param->name, + trigger->node->name, param->name); + } + } + trigger = trigger->next; + } + param = param->next; + } + + /* Output the inline code for the case */ + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + } + Indent(stream, level * 2 + 4); + TreeCCStreamPrint(stream, "{"); + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, level * 2 + 4); + } + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamFixLine(stream); + } + } + + /* + * Generate a call to a split function from within the "switch". + */ + static void Java_GenCaseSplit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, + int number, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 4); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_split_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s)", trigger->node->name); + } + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Terminate a "switch" case. + */ + static void Java_GenEndCase(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "}\n"); + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "break;\n\n"); + } + + /* + * Terminate the "switch" statement. + */ + static void Java_GenEndSwitch(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "default: break;\n"); + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "}\n"); + } + + /* + * Generate the exit point for a non-virtual operation. + */ + static void Java_GenExit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(strcmp(oper->returnType, "void") != 0) + { + /* Generate a default return value for the function */ + if(oper->defValue) + { + TreeCCStreamPrint(stream, "\treturn (%s);\n", oper->defValue); + } + else + { + TreeCCStreamPrint(stream, "\treturn 0;\n"); + } + } + TreeCCStreamPrint(stream, "\t}\n"); + } + + /* + * Generate the end declarations for a non-virtual operation. + */ + static void Java_GenEnd(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "\n"); + } + } + + /* + * Table of non-virtual code generation functions. + */ + TreeCCNonVirtual const TreeCCNonVirtualFuncsJava = { + Java_GenStart, + Java_GenEntry, + Java_GenSplitEntry, + Java_GenSwitchHead, + Java_GenSelector, + Java_GenEndSelectors, + Java_GenCaseFunc, + Java_GenCaseCall, + Java_GenCaseInline, + Java_GenCaseSplit, + Java_GenEndCase, + Java_GenEndSwitch, + Java_GenExit, + Java_GenEnd, + }; + + /* + * Write out header information for all streams. + */ + static void WriteJavaHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(!(stream->isHeader)) + { + TreeCCStreamSourceTop(stream); + TreeCCStreamPrint(stream, "\n"); + if(context->namespace) + { + TreeCCStreamPrint(stream, "package %s;\n\n", + context->namespace); + } + TreeCCStreamPrint(stream, "import java.lang.*;\n\n"); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WriteJavaFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else if(!(stream->isHeader)) + { + TreeCCStreamSourceBottom(stream); + } + stream = stream->nextStream; + } + } + + /* + * Create streams for all of the node types. + */ + static void CreateNodeStreams(TreeCCContext *context, TreeCCNode *node) + { + if((node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamGetJava(context, node->name); + } + } + + /* + * Create streams for all of the non-virtual operations + */ + static void CreateNonVirtualStreams(TreeCCContext *context, + TreeCCOperation *oper) + { + if((oper->flags & TREECC_OPER_VIRTUAL) == 0) + { + if(oper->className) + { + TreeCCStreamGetJava(context, oper->className); + } + else + { + TreeCCStreamGetJava(context, oper->name); + } + } + } + + void TreeCCGenerateJava(TreeCCContext *context) + { + /* Create all streams that we will require later */ + TreeCCStreamGetJava(context, context->state_type); + TreeCCNodeVisitAll(context, CreateNodeStreams); + TreeCCOperationVisitAll(context, CreateNonVirtualStreams); + + /* Write all stream headers */ + WriteJavaHeaders(context); + + /* Generate the contents of the source stream */ + TreeCCNodeVisitAll(context, DeclareTypeDefs); + ImplementStateType(context, + TreeCCStreamGetJava(context, context->state_type)); + TreeCCNodeVisitAll(context, BuildTypeDecls); + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsJava); + + /* Write all stream footers */ + WriteJavaFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_php.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_php.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_php.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1366 ---- + /* + * gen_php.c - Generate Php source code from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Declare the fields for a node type. + */ + static void DeclareFields(TreeCCContext *context, + TreeCCStream *stream, TreeCCNode *node) + { + TreeCCField *field; + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, " var $%s;\n", + /*field->type, */ field->name); + field = field->next; + } + } + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* Define an enumerated type */ + /* since PHP doesnt have enums - we are going to have to create defines... + */ + int i=1; + + + TreeCCStream *stream = node->source; + TreeCCNode *child; + /* TreeCCStreamPrint(stream, "public enum %s\n", node->name); */ + /* TreeCCStreamPrint(stream, "{\n"); */ + child = node->firstChild; + + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, "define('%s_%s',%d);\n", node->name,child->name,i); + i++; + } + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "\n\n"); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, " $%s", /*field->type,*/ field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the parameters to call an inherited constructor. + */ + static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = InheritParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "$%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the virtual methods that have implementations in a node type. + */ + static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + int declareCase, abstractCase; + TreeCCNode *tempNode; + int num, first; + int needComma; + if(node->parent) + { + ImplementVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + declareCase = abstractCase; + } + else + { + declareCase = 1; + abstractCase = 0; + } + if(declareCase) + { + if(abstractCase) + { + if(node == actualNode) + { + /* TreeCCStreamPrint(stream, + " public abstract %s %s(", + virt->returnType, virt->name); */ + TreeCCStreamPrint(stream, " function %s(", virt->name); + } + else + { + /* Inherit the "abstract" definition from the parent */ + virt = virt->next; + continue; + } + } + else + { + /*if(node == actualNode) + { + TreeCCStreamPrint(stream, " public virtual %s %s(", + virt->returnType, virt->name); + } + else + { + TreeCCStreamPrint(stream, " public override %s %s(", + virt->returnType, virt->name); + }*/ + TreeCCStreamPrint(stream, " function %s(", virt->name); + + + } + param = virt->oper->params; + needComma = 0; + num = 1; + first = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(first) + { + /* Skip the first argument, which corresponds to "this" */ + if(!(param->name)) + { + ++num; + } + first = 0; + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "$%s ", + /* param->type, */ param->name); + } + else + { + TreeCCStreamPrint(stream, "$P%d__", + /* param->type, */ num); + ++num; + } + needComma = 1; + } + param = param->next; + } + if(!abstractCase) + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamLine(stream, operCase->codeLinenum, + operCase->codeFilename); + TreeCCStreamPrint(stream, " {"); + if(!(virt->oper->params->name) || + !strcmp(virt->oper->params->name, "this")) + { + /* The first parameter is called "this", so we don't + need to declare it at the head of the function */ + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + else + { + /* The first parameter is called something else, + so create a temporary variable to hold "this" */ + /* + TreeCCStreamPrint(stream, "\n %s %s = $this;\n ", + actualNode->name, + virt->oper->params->name); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + */ + TreeCCStreamPrint(stream, "\n $%s = &$this;\n ", virt->oper->params->name); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "}\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "\n"); + } + else + { + TreeCCStreamPrint(stream, ") {}\n\n"); + } + } + virt = virt->next; + } + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream; + int needComma; + const char *constructorAccess; + TreeCCField *field; + int isAbstract; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + /* Determine if this class has abstract virtuals */ + isAbstract = TreeCCNodeHasAbstracts(context, node); + + /* Output the class header */ + stream = node->source; + + if(node->parent) + { + /* + TreeCCStreamPrint(stream, " public new const int KIND = %d;\n\n", + node->number); + */ + TreeCCStreamPrint(stream, "define('%s_KIND',%d);\n", + node->name,node->number); + } + else + { + /* + TreeCCStreamPrint(stream, " public const int KIND = %d;\n\n", + node->number); + */ + TreeCCStreamPrint(stream, "define('%s_KIND', %d);\n", + node->name,node->number); + } + + if(node->parent) + { + /* Inherit from a specified parent type */ + if(isAbstract) + { + TreeCCStreamPrint(stream, "class %s extends %s\n{\n", + node->name, node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "class %s extends %s\n{\n", + node->name, node->parent->name); + } + } + else + { + /* This type is the base of a class hierarchy */ + if(isAbstract) + { + TreeCCStreamPrint(stream, "class %s\n{\n", + node->name); + } + else + { + TreeCCStreamPrint(stream, "class %s\n{\n", node->name); + } + + /* Declare the node kind member variable */ + TreeCCStreamPrint(stream, " var $kind__;\n"); + + /* Declare the filename and linenum fields if we are tracking lines */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, " var $filename__;\n"); + TreeCCStreamPrint(stream, " var $linenum__;\n"); + } + TreeCCStreamPrint(stream, "\n"); + + /* Declare the public methods for access to the above fields */ + TreeCCStreamPrint(stream, + " function getKind() { return $this->kind__; }\n"); + if(context->track_lines) + { + TreeCCStreamPrint(stream, + " function getFilename() { return $this->filename__; }\n"); + TreeCCStreamPrint(stream, + " function getLinenum() { return $this->linenum__; }\n"); + TreeCCStreamPrint(stream, + " function setFilename($filename) " + "{ $this->filename__ = $filename; }\n"); + TreeCCStreamPrint(stream, + " function setLinenum($linenum) " + "{ $this->linenum__ = $linenum; }\n"); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the kind value */ + + + /* Declare the fields */ + if(node->fields) + { + DeclareFields(context, stream, node); + TreeCCStreamPrint(stream, "\n"); + } + + /* Declare the constructor for the node type */ + if(context->reentrant) + { + /* Re-entrant systems use a factory to create the nodes. + C# doesn't have a notion of "access by members of + the namespace only". The closest is "internal", but + even that isn't quite right, so we always use "public" */ + /*constructorAccess = "public "; */ + constructorAccess = ""; + } + else + { + /* Non-reentrant systems can construct nodes directly, + unless the node happens to be abstract, in which + case we force the constructor to be protected */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + /* constructorAccess = "protected "; */ + constructorAccess = ""; + } + else + { + /* constructorAccess = "public "; */ + constructorAccess = ""; + } + } + TreeCCStreamPrint(stream, " function %s%s(", constructorAccess, node->name); + if(context->reentrant) + { + /* TreeCCStreamPrint(stream, "%s state__", context->state_type); */ + TreeCCStreamPrint(stream, "&$state__"); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParams(context, stream, node, needComma); + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, " {\n"); + /* Call the parent class constructor */ + if(node->parent) + { + TreeCCStreamPrint(stream, " parent::%s (",node->parent->name); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "&$state__"); + needComma = 1; + } + else + { + needComma = 0; + } + InheritParamsSource(context, stream, node->parent, needComma); + TreeCCStreamPrint(stream, ");\n"); + } + + /* Set the node kind */ + + TreeCCStreamPrint(stream, " $this->kind__ = %s_KIND;\n",node->name); + + /* Track the filename and line number if necessary */ + if(context->track_lines && !(node->parent)) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + " $this->filename__ = $state__->currFilename();\n"); + TreeCCStreamPrint(stream, + " $this->linenum__ = $state__->currLinenum();\n"); + } + else + { + TreeCCStreamPrint(stream, + " $_tmp = &%s::getState(); $this->filename__ = $_tmp->currFilename();\n", + context->state_type); + TreeCCStreamPrint(stream, + " $_tmp = &%s::getState(); $this->linenum__ = $_tmp->currLinenum();\n", + context->state_type); + } + } + + /* Initialize the fields that are specific to this node type */ + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, " $this->%s = $%s;\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, " $this->%s = $%s;\n", + field->name, field->value); + } + field = field->next; + } + TreeCCStreamPrint(stream, " }\n\n"); + + /* Implement the virtual functions */ + ImplementVirtuals(context, stream, node, node); + + /* Declare the "isA" and "getKindName" helper methods */ + if(node->parent) + { + TreeCCStreamPrint(stream, " function isA($kind)\n"); + } + else + { + TreeCCStreamPrint(stream, " function isA($kind)\n"); + } + TreeCCStreamPrint(stream, " {\n"); + TreeCCStreamPrint(stream, " if($kind == %s_KIND)\n",node->name); + TreeCCStreamPrint(stream, " return 1;\n"); + TreeCCStreamPrint(stream, " else\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, " return parent::isA($kind);\n"); + } + else + { + TreeCCStreamPrint(stream, " return 0;\n"); + } + TreeCCStreamPrint(stream, " }\n\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, " function getKindName()\n"); + } + else + { + TreeCCStreamPrint(stream, " function getKindName()\n"); + } + TreeCCStreamPrint(stream, " {\n"); + TreeCCStreamPrint(stream, " return \"%s\";\n", node->name); + TreeCCStreamPrint(stream, " }\n"); + + /* Output the class footer */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Declare the parameters for a factory method in the state type. + */ + static int FactoryCreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryCreateParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "$%s", + /* field->type, */ field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output invocation parameters for a call to a constructor + * from within a factory method. + */ + static int FactoryInvokeParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryInvokeParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "$%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + if(context->commonSource) + { + stream = context->commonSource; + } + else + { + stream = context->sourceStream; + } + + /* Output the start of the function definition */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, " function %sCreate(", + /* node->name, */ node->name); + } + else if(context->virtual_factory) + { + TreeCCStreamPrint(stream, " function %sCreate(", + /*node->name, */ node->name); + } + else + { + TreeCCStreamPrint(stream, " function %sCreate(", + /* node->name, */ node->name); + } + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + + /* Output the body of the creation function */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, ");\n"); + } + else + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, " {\n"); + TreeCCStreamPrint(stream, " return new %s($this", node->name); + FactoryInvokeParams(context, stream, node, 1); + TreeCCStreamPrint(stream, ");\n"); + TreeCCStreamPrint(stream, " }\n\n"); + } + } + + /* + * Implement the state type in the source stream. + */ + static void ImplementStateType(TreeCCContext *context, TreeCCStream *stream) + { + /* Declare the class header */ + if(context->reentrant && context->abstract_factory) + { + TreeCCStreamPrint(stream, "class %s\n{\n\n", + context->state_type); + } + else + { + TreeCCStreamPrint(stream, "class %s\n{\n\n", + context->state_type); + } + + /* Singleton handling for non-reentrant systems */ + if(!(context->reentrant)) + { + /* TreeCCStreamPrint(stream, " var $state;\n\n" , + context->state_type );*/ + TreeCCStreamPrint(stream, " function &getState()\n" /*, + context->state_type*/ ); + TreeCCStreamPrint(stream, " {\n"); + TreeCCStreamPrint(stream, " static $state = null;\n"); + TreeCCStreamPrint(stream, " if($state != null) return $state;\n"); + TreeCCStreamPrint(stream, " $state = new %s();\n", + context->state_type); + TreeCCStreamPrint(stream, " return $state;\n"); + TreeCCStreamPrint(stream, " }\n\n"); + } + + /* Implement the constructor */ + /* + -- we cant do constructor too well for this - (as $state is a static var in getState..) + if(context->reentrant) + { + TreeCCStreamPrint(stream, " function %s() {}\n\n", context->state_type); + } + else + { + TreeCCStreamPrint(stream, " function %s() { $this->state__ = $this; }\n\n", + context->state_type); + } + */ + /* Implement the create functions for all of the node types */ + if(context->reentrant) + { + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + } + + /* Implement the line number tracking methods */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, + " function currFilename() { return null; }\n"); + TreeCCStreamPrint(stream, + " function currLinenum() { return 0; }\n\n"); + } + + /* Declare the end of the state type */ + TreeCCStreamPrint(stream, "}\n\n"); + } + + /* + * Write out header information for all streams. + */ + static void WritePHPHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(!(stream->isHeader)) + { + TreeCCStreamPrint(stream, + "embedName); + /* if(context->namespace) + { + TreeCCStreamPrint(stream, "namespace %s\n{\n\n", + context->namespace); + } + + TreeCCStreamPrint(stream, "using System;\n\n"); + */ + TreeCCStreamSourceTopCS(stream); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WritePHPFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else if(!(stream->isHeader)) + { + TreeCCStreamSourceBottom(stream); + /* if(context->namespace) + { + TreeCCStreamPrint(stream, "}\n"); + } + */ + } + TreeCCStreamPrint(stream, "\n?>"); + stream = stream->nextStream; + } + } + + + static int IsEnumType(TreeCCContext *context, const char *type) + { + TreeCCNode *node = TreeCCNodeFindByType(context, type); + if(node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + return 1; + } + } + return 0; + } + + + /* + * Generate the start declarations for a non-virtual operation. + */ + static void PHP_GenStart(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(oper->className) + { + TreeCCStreamPrint(stream, "class %s\n{\n", oper->className); + } + else + { + TreeCCStreamPrint(stream, "class %s\n{\n", oper->name); + } + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void PHPGenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + TreeCCParam *param; + int num; + int needComma; + /* + if(number != -1) + { + TreeCCStreamPrint(stream, " private static %s %s_split_%d__(", + oper->returnType, oper->name, number); + } + else + { + TreeCCStreamPrint(stream, " public static %s %s(", + oper->returnType, oper->name); + } + */ + if(number != -1) + { + TreeCCStreamPrint(stream, " function %s_split_%d__(&", + oper->name, number); + } + else + { + TreeCCStreamPrint(stream, " function %s(&", oper->name); + } + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /* + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "%s ", param->type); + } + else + { + TreeCCStreamPrint(stream, "%s ", ConvertType(context, param->type)); + } + */ + if(param->name) + { + TreeCCStreamPrint(stream, "$%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "$P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(!IsEnumType(context, param->type)) + { + TreeCCStreamPrint(stream, "__"); + } + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, " {\n"); + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void PHP_GenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + PHPGenEntry(context, stream, oper, -1); + } + + /* + * Generate the entry point for a split-out function. + */ + static void PHP_GenSplitEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + PHPGenEntry(context, stream, oper, number); + } + + /* + * Output TAB's for a specific level of indenting. + */ + static void Indent(TreeCCStream *stream, int indent) + { + while(indent >= 4) + { + TreeCCStreamPrint(stream, " "); + indent -= 4; + } + if(indent == 1) + { + TreeCCStreamPrint(stream, " "); + } + else if(indent == 2) + { + TreeCCStreamPrint(stream, " "); + } + else if(indent == 3) + { + TreeCCStreamPrint(stream, " "); + } + } + + /* + * Generate the head of a "switch" statement. + */ + static void PHP_GenSwitchHead(TreeCCContext *context, TreeCCStream *stream, + char *paramName, int level, int isEnum) + { + Indent(stream, level * 2 + 2); + if(isEnum) + { + TreeCCStreamPrint(stream, "switch($%s)\n", paramName); + } + else + { + TreeCCStreamPrint(stream, "switch($%s__->getKind())\n", paramName); + } + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate a selector for a "switch" case. + */ + static void PHP_GenSelector(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int level) + { + if((node->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "case %s_%s:\n", + node->parent->name, node->name); + } + else if((node->flags & TREECC_NODE_ENUM) == 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "case %s_KIND:\n", node->name); + } + } + + /* + * Terminate the selectors and begin the body of a "switch" case. + */ + static void PHP_GenEndSelectors(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "{\n"); + } + + /* + * Generate the code for a case within a function. + */ + static void PHP_GenCaseFunc(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + char *type; + + /* Output the header for the function */ + /*TreeCCStreamPrint(stream, " private static %s %s_%d__(", + ConvertType(context, operCase->oper->returnType), + operCase->oper->name, number); + */ + TreeCCStreamPrint(stream, " function %s_%d__(&", + operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + type = trigger->node->name; + } + else + { + type = param->type; + } + trigger = trigger->next; + } + else + { + type = param->type; + } + if(param->name) + { + + TreeCCStreamPrint(stream, "$%s", param->name); + + } + else + { + + TreeCCStreamPrint(stream, "$P%d__", num); + + + ++num; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + + /* Output the code for the operation case */ + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + } + TreeCCStreamPrint(stream, " {"); + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamFixLine(stream); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a call to a case function from within the "switch". + */ + static void PHP_GenCaseCall(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, + int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 4); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + TreeCCStreamPrint(stream, "$_t = __CLASS__;$_t = new $_t; $_t->%s_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /* if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s)", trigger->node->name); + } + } + */ + if(param->name) + { + TreeCCStreamPrint(stream, "$%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "$P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Generate the code for a case inline within the "switch". + */ + static void PHP_GenCaseInline(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + + /* Copy the parameters to new variables of the correct types */ + param = operCase->oper->params; + trigger = operCase->triggers; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(param->name != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + Indent(stream, level * 2 + 4); + /* TreeCCStreamPrint(stream, "%s %s = (%s)%s__;\n", + trigger->node->name, param->name, + trigger->node->name, param->name); */ + TreeCCStreamPrint(stream, "$%s = %s__;\n", + param->name, param->name); + + + } + } + trigger = trigger->next; + } + param = param->next; + } + + /* Output the inline code for the case */ + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamLine(stream, operCase->codeLinenum, operCase->codeFilename); + } + Indent(stream, level * 2 + 4); + TreeCCStreamPrint(stream, "{"); + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, level * 2 + 4); + } + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamFixLine(stream); + } + } + + /* + * Generate a call to a split function from within the "switch". + */ + static void PHP_GenCaseSplit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, + int number, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 4); + + /* Add "return" to the front if the operation is non-void */ + if(strcmp(operCase->oper->returnType, "void") != 0) + { + TreeCCStreamPrint(stream, "return "); + } + + /* Print out the call */ + /* cheezy kludge, as self::method() doesnt working php4 (although it will in php5) */ + TreeCCStreamPrint(stream, "$_t = __CLASS__;$_t = new $_t; $_t->%s_split_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /*if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s)", trigger->node->name); + } + } + */ + if(param->name) + { + TreeCCStreamPrint(stream, "$%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ");\n"); + } + + /* + * Terminate a "switch" case. + */ + static void PHP_GenEndCase(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "}\n"); + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "break;\n\n"); + } + + /* + * Terminate the "switch" statement. + */ + static void PHP_GenEndSwitch(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "default: break;\n"); + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "}\n"); + } + + /* + * Generate the exit point for a non-virtual operation. + */ + static void PHP_GenExit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(strcmp(oper->returnType, "void") != 0) + { + /* Generate a default return value for the function */ + if(oper->defValue) + { + TreeCCStreamPrint(stream, " return (%s);\n", oper->defValue); + } + else + { + TreeCCStreamPrint(stream, " return 0;\n"); + } + } + TreeCCStreamPrint(stream, " }\n"); + } + + /* + * Generate the end declarations for a non-virtual operation. + */ + static void PHP_GenEnd(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + TreeCCStreamPrint(stream, "}\n"); + if(context->language == TREECC_LANG_CSHARP) + { + TreeCCStreamPrint(stream, "\n"); + } + } + + /* + * Table of non-virtual code generation functions. + */ + TreeCCNonVirtual const TreeCCNonVirtualFuncsPHP = { + PHP_GenStart, + PHP_GenEntry, + PHP_GenSplitEntry, + PHP_GenSwitchHead, + PHP_GenSelector, + PHP_GenEndSelectors, + PHP_GenCaseFunc, + PHP_GenCaseCall, + PHP_GenCaseInline, + PHP_GenCaseSplit, + PHP_GenEndCase, + PHP_GenEndSwitch, + PHP_GenExit, + PHP_GenEnd, + }; + + + + + + + + + + + + void TreeCCGeneratePHP(TreeCCContext *context) + { + /* Write all stream headers */ + WritePHPHeaders(context); + + /* Generate the contents of the source stream */ + TreeCCNodeVisitAll(context, DeclareTypeDefs); + if(context->commonSource) + { + ImplementStateType(context, context->commonSource); + } + else + { + ImplementStateType(context, context->sourceStream); + } + TreeCCNodeVisitAll(context, BuildTypeDecls); + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsPHP); + + /* Write all stream footers */ + WritePHPFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/gen_ruby.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/gen_ruby.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/gen_ruby.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1218 ---- + /* + * gen_ruby.c - Generate Ruby source code from "treecc" input files. + * + * Copyright (C) 2001, 2002 Southern Storm Software, Pty Ltd. + * + * Hacked by Peter Minten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "gen.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Declare the type definitions for a node type. + */ + static void DeclareTypeDefs(TreeCCContext *context, + TreeCCNode *node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + int counter = 0; + /* Define an enumerated type */ + TreeCCStream *stream = node->source; + TreeCCNode *child; + TreeCCStreamPrint(stream, "class %s \n", node->name); + child = node->firstChild; + while(child != 0) + { + if((child->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + TreeCCStreamPrint(stream, " %s = %i\n", child->name, counter++); + } + + child = child->nextSibling; + } + TreeCCStreamPrint(stream, "end\n\n"); + } + } + + /* + * Output the parameters for a node creation function. + */ + static int CreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = CreateParams(context, stream, node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /* Don't name the types, Ruby figures that out */ + TreeCCStreamPrint(stream, "%s", /*field->type,*/ field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output the parameters to call an inherited constructor. + */ + static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = InheritParamsSource(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the virtual methods that have implementations in a node type. + */ + static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCParam *param; + TreeCCOperationCase *operCase; + int declareCase, abstractCase; + TreeCCNode *tempNode; + int num, first; + int needComma; + if(node->parent) + { + ImplementVirtuals(context, stream, node->parent, actualNode); + } + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + declareCase = abstractCase; + } + else + { + declareCase = 1; + abstractCase = 0; + } + if(declareCase) + { + if(abstractCase) + { + if(node == actualNode) + { + TreeCCStreamPrint(stream, " def %s(", virt->name); + } + else + { + /* Inherit the "abstract" definition from the parent */ + virt = virt->next; + continue; + } + } + else + { + if(node == actualNode) + { + TreeCCStreamPrint(stream, " def %s(", virt->name); + } + else + { + TreeCCStreamPrint(stream, " def %s(", virt->name); + } + } + param = virt->oper->params; + needComma = 0; + num = 1; + first = 1; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(first) + { + /* Skip the first argument, which corresponds to "this" */ + if(!(param->name)) + { + ++num; + } + first = 0; + } + else + { + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "P%d__", num); + ++num; + } + needComma = 1; + } + param = param->next; + } + if(!abstractCase) + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamLine(stream, operCase->codeLinenum, + operCase->codeFilename); + TreeCCStreamPrint(stream, " "); + if(!(virt->oper->params->name) || + !strcmp(virt->oper->params->name, "self")) + { + /* The first parameter is called "this", so we don't + need to declare it at the head of the function */ + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + else + { + /* The first parameter is called something else, + so create a temporary variable to hold "this" */ + TreeCCStreamPrint(stream, "\n %s %s = self\n ", + actualNode->name, + virt->oper->params->name); + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, " end\n"); + TreeCCStreamFixLine(stream); + TreeCCStreamPrint(stream, "\n"); + } + else + { + TreeCCStreamPrint(stream, ")\n end\n"); + } + } + virt = virt->next; + } + } + + /* + * Build the type declarations for a node type. + */ + static void BuildTypeDecls(TreeCCContext *context, + TreeCCNode *node) + { + TreeCCStream *stream; + int needComma; + /*const char *constructorAccess; NOT USED*/ + TreeCCField *field; + int isAbstract; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Determine if this class has abstract virtuals */ + isAbstract = TreeCCNodeHasAbstracts(context, node); + + /* Output the class header */ + stream = node->source; + if(node->parent) + { + /* Inherit from a specified parent type */ + /* Ruby doesn't know abstract */ + /* + if(isAbstract) + { + TreeCCStreamPrint(stream, "public abstract class %s : %s\n{\n", + node->name, node->parent->name); + } + else + { + TreeCCStreamPrint(stream, "public class %s : %s\n{\n", + node->name, node->parent->name); + } + */ + TreeCCStreamPrint(stream, "class %s < %s\n", + node->name, node->parent->name); + } + else + { + /* This type is the base of a class hierarchy */ + /* Ruby doesn't know abstract */ + /* if(isAbstract) + { + TreeCCStreamPrint(stream, "public abstract class %s\n{\n", + node->name); + } + else + { + TreeCCStreamPrint(stream, "public class %s\n{\n", node->name); + }*/ + + TreeCCStreamPrint(stream, "class %s\n", node->name); + + /* Declare the node kind member variable */ + /* No declaration needed in Ruby */ + + /* Declare the filename and linenum fields if we are tracking lines */ + /* Not needed */ + + /* Declare the public methods for access to the above fields */ + /* Ruby has handy accessor creating stuff */ + /*TreeCCStreamPrint(stream, + " public int getKind() { return kind__; }\n");*/ + TreeCCStreamPrint(stream, + " protected\n attr_reader :kind\n public\n\n"); + + if(context->track_lines) + { + /* A same kind of hack here*/ + /*TreeCCStreamPrint(stream, + " public String getFilename() { return filename__; }\n"); + TreeCCStreamPrint(stream, + " public long getLinenum() { return linenum__; }\n"); + TreeCCStreamPrint(stream, + " public void setFilename(String filename) " + "{ filename__ = filename; }\n"); + TreeCCStreamPrint(stream, + " public void setLinenum(long linenum) " + "{ linenum__ = linenum; }\n");*/ + TreeCCStreamPrint(stream, + " attr_accessor :Linenum, :Filename\n"); + } + TreeCCStreamPrint(stream, "\n"); + } + + /* Add the attr_accessor stuff for nodes specific to this node type */ + field = node->fields; + while(field != 0) + { + TreeCCStreamPrint(stream, " attr_accessor :%s\n", field->name); + field = field->next; + } + /* End this section with an extra newline */ + TreeCCStreamPrint(stream, "\n"); + + /* Declare the kind value */ + /* Stick to the Ruby convention of constants, start with Uppercase, + continue with lowercase */ + /* The parent doesn't matter, so don't check it */ + TreeCCStreamPrint(stream, " KIND = %d\n\n", + node->number); + + /* Declare the constructor for the node type */ + /* A constructor is always public (I hope) anyway I don't expect + Ruby to cause troubles here */ + + /* The constructor is ALWAYS called initialize */ + TreeCCStreamPrint(stream, " def initialize("); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "state__"); + needComma = 1; + + } + else + { + needComma = 0; + } + + CreateParams(context, stream, node, needComma); + + TreeCCStreamPrint(stream, ")\n"); + + /* Enter the super call */ + /* Call the parent class constructor */ + if(node->parent) + { + /* Do not use base, Ruby uses super for that */ + /*TreeCCStreamPrint(stream, " : base(");*/ + TreeCCStreamPrint(stream, " super("); + if(context->reentrant) + { + TreeCCStreamPrint(stream, "@state"); + needComma = 1; + } + else + { + needComma = 0; + } + CreateParams(context, stream, node, needComma); + InheritParamsSource(context, stream, node->parent, needComma); + TreeCCStreamPrint(stream, ")\n"); + } + + /* Set the node kind */ + TreeCCStreamPrint(stream, " @kind = KIND\n"); + + /* Track the filename and line number if necessary */ + if(context->track_lines && !(node->parent)) + { + if(context->reentrant) + { + TreeCCStreamPrint(stream, + " @Filename = @state.currFilename\n"); + TreeCCStreamPrint(stream, + " @Finenum = @state.currLinenum\n"); + } + else + { + TreeCCStreamPrint(stream, + " @Filename = %s.state.currFilename()\n", + context->state_type); + TreeCCStreamPrint(stream, + " @Linenum = %s.state.currLinenum()\n", + context->state_type); + } + } + + /* Initialize the fields that are specific to this node type */ + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCStreamPrint(stream, " self.%s = %s\n", + field->name, field->name); + } + else if(field->value) + { + TreeCCStreamPrint(stream, " self.%s = %s\n", + field->name, field->value); + } + field = field->next; + } + TreeCCStreamPrint(stream, " end\n\n"); + + /* Implement the virtual functions */ + ImplementVirtuals(context, stream, node, node); + + /* Declare the "isA" and "getKindName" helper methods */ + + TreeCCStreamPrint(stream, " def isA(kind)\n"); + + TreeCCStreamPrint(stream, " if(@kind == KIND) then\n"); + TreeCCStreamPrint(stream, " return true\n"); + TreeCCStreamPrint(stream, " else\n"); + if(node->parent) + { + TreeCCStreamPrint(stream, " return super(kind)\n end\n"); + } + else + { + TreeCCStreamPrint(stream, " return 0\n end\n"); + } + TreeCCStreamPrint(stream, " end\n\n"); + + TreeCCStreamPrint(stream, " def KindName\n"); + + TreeCCStreamPrint(stream, " return \"%s\"\n", node->name); + TreeCCStreamPrint(stream, " end\n"); + + /* Output the class footer */ + TreeCCStreamPrint(stream, "end\n\n"); + } + + /* + * Declare the parameters for a factory method in the state type. + */ + static int FactoryCreateParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryCreateParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /* Delete the types */ + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Output invocation parameters for a call to a constructor + * from within a factory method. + */ + static int FactoryInvokeParams(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int needComma) + { + TreeCCField *field; + if(node->parent) + { + needComma = FactoryInvokeParams(context, stream, + node->parent, needComma); + } + field = node->fields; + while(field != 0) + { + if((field->flags & TREECC_FIELD_NOCREATE) == 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + TreeCCStreamPrint(stream, "%s", field->name); + needComma = 1; + } + field = field->next; + } + return needComma; + } + + /* + * Implement the create function for a node type. + */ + static void ImplementCreateFuncs(TreeCCContext *context, TreeCCNode *node) + { + TreeCCStream *stream; + + /* Ignore if this is an enumerated type node */ + if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0) + { + return; + } + + /* Ignore this if it is an abstract node */ + if((node->flags & TREECC_NODE_ABSTRACT) != 0) + { + return; + } + + /* Determine which stream to write to */ + if(context->commonSource) + { + stream = context->commonSource; + } + else + { + stream = context->sourceStream; + } + + /* Output the start of the function definition */ + TreeCCStreamPrint(stream, " def %s %sCreate(", + node->name, node->name); + + /* Output the parameters for the create function */ + FactoryCreateParams(context, stream, node, 0); + + /* Output the body of the creation function */ + if(context->abstract_factory) + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, "raise \"Abstract method called: %s\\n\"\n", node->name); + } + else + { + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, " return %s.new(this", node->name); + FactoryInvokeParams(context, stream, node, 1); + TreeCCStreamPrint(stream, ")\n"); + TreeCCStreamPrint(stream, " end\n\n"); + } + } + + /* + * Implement the state type in the source stream. + */ + static void ImplementStateType(TreeCCContext *context, TreeCCStream *stream) + { + TreeCCStreamPrint(stream, "class %s\n", + context->state_type); + + TreeCCStreamPrint(stream, " @@state = nil\n"); + + /* Singleton handling for non-reentrant systems */ + if(!(context->reentrant)) + { + TreeCCStreamPrint(stream, " def %s.state\n", context->state_type); + TreeCCStreamPrint(stream, " return @@state unless @@state.nil?\n"); + TreeCCStreamPrint(stream, " @@state = %s.new()\n", + context->state_type); + TreeCCStreamPrint(stream, " return @@state\n"); + TreeCCStreamPrint(stream, " end\n\n"); + } + + /* Implement the constructor */ + if(context->reentrant) + { + /* No constructor */ + } + else + { + TreeCCStreamPrint(stream, " def intialize \n @@state = self \n end\n\n"); + } + + /* Implement the create functions for all of the node types */ + if(context->reentrant) + { + TreeCCNodeVisitAll(context, ImplementCreateFuncs); + } + + /* Implement the line number tracking methods */ + if(context->track_lines) + { + TreeCCStreamPrint(stream, + " def currFilename \n return nil \n end\n\n"); + TreeCCStreamPrint(stream, + " def currLinenum \n return 0 \n end\n\n"); + } + + /* Declare the end of the state type */ + TreeCCStreamPrint(stream, "end\n\n"); + } + + /* + * Write out header information for all streams. + */ + static void WriteRubyHeaders(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(!(stream->isHeader)) + { + TreeCCStreamPrint(stream, + "# %s. Generated automatically by treecc \n\n", + stream->embedName); + if(context->namespace) + { + TreeCCStreamPrint(stream, "module %s\nbegin\n\n", + context->namespace); + } + /*Ruby doesn't require a System lib to be included*/ + /*TreeCCStreamPrint(stream, "using System;\n\n");*/ + TreeCCStreamSourceTopCS(stream); + } + if(stream->defaultFile) + { + /* Reset the dirty flag if this is a default stream, + because we don't want to write out the final file + if it isn't actually written to in practice */ + stream->dirty = 0; + } + stream = stream->nextStream; + } + } + + /* + * Write out footer information for all streams. + */ + static void WriteRubyFooters(TreeCCContext *context) + { + TreeCCStream *stream = context->streamList; + while(stream != 0) + { + if(stream->defaultFile && !(stream->dirty)) + { + /* Clear the default file's contents, which we don't need */ + TreeCCStreamClear(stream); + } + else if(!(stream->isHeader)) + { + TreeCCStreamSourceBottom(stream); + if(context->namespace) + { + TreeCCStreamPrint(stream, "end\n"); + } + } + stream = stream->nextStream; + } + } + + /* + * Determine if a type name corresponds to an enumerated type. + */ + static int IsEnumType(TreeCCContext *context, const char *type) + { + TreeCCNode *node = TreeCCNodeFindByType(context, type); + if(node) + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + return 1; + } + } + return 0; + } + + /* + * Output spaces's for a specific level of indenting. + */ + static void Indent(TreeCCStream *stream, int indent) + { + while(indent >= 4) + { + TreeCCStreamPrint(stream, " "); + indent -= 4; + } + if(indent == 1) + { + TreeCCStreamPrint(stream, " "); + } + else if(indent == 2) + { + TreeCCStreamPrint(stream, " "); + } + else if(indent == 3) + { + TreeCCStreamPrint(stream, " "); + } + } + + /* + * Non-virtual code generation functions start here + */ + + /* + * Generate the start declarations for a non-virtual operation. + */ + static void Ruby_GenStart(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(oper->className) + { + TreeCCStreamPrint(stream, "class %s\n", oper->className); + } + else + { + TreeCCStreamPrint(stream, "class %s\n", oper->name); + } + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void RubyGenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + TreeCCParam *param; + int num; + int needComma; + char *cname; + + if(oper->className) + { + cname = oper->className; + } + else + { + cname = oper->name; + } + + if(number != -1) + { + TreeCCStreamPrint(stream, " private \n def %s.%s_split_%d__(", + cname, oper->name, number); + } + else + { + TreeCCStreamPrint(stream, " public \n def %s.%s(", + cname, oper->name); + } + + param = oper->params; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "p%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(!IsEnumType(context, param->type)) + { + TreeCCStreamPrint(stream, "__"); + } + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + } + + /* + * Generate the entry point for a non-virtual operation. + */ + static void Ruby_GenEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + RubyGenEntry(context, stream, oper, -1); + } + + /* + * Generate the entry point for a split-out function. + */ + static void Ruby_GenSplitEntry(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper, int number) + { + RubyGenEntry(context, stream, oper, number); + } + + /* + * Generate the head of a "switch" statement. + */ + static void Ruby_GenSwitchHead(TreeCCContext *context, TreeCCStream *stream, + char *paramName, int level, int isEnum) + { + Indent(stream, level * 2 + 2); + if(isEnum) + { + TreeCCStreamPrint(stream, "case %s\n", paramName); + } + else + { + TreeCCStreamPrint(stream, "case %s__.type::KIND\n", paramName); + } + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a selector for a "switch" case. + */ + static void Ruby_GenSelector(TreeCCContext *context, TreeCCStream *stream, + TreeCCNode *node, int level) + { + if((node->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "when %s.%s\n", + node->parent->name, node->name); + } + else if((node->flags & TREECC_NODE_ENUM) == 0) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "when %s::KIND\n", node->name); + } + } + + /* + * Terminate the selectors and begin the body of a "switch" case. + */ + static void Ruby_GenEndSelectors(TreeCCContext *context, TreeCCStream *stream, + int level) + { + /* No use for this in Ruby */ + } + + /* + * Generate the code for a case within a function. + */ + static void Ruby_GenCaseFunc(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + char *type; + char *cname; + + if(operCase->oper->className) + { + cname = operCase->oper->className; + } + else + { + cname = operCase->oper->name; + } + + /* Output the header for the function */ + TreeCCStreamPrint(stream, " private \n def %s.%s_%d__(", + cname, operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + type = trigger->node->name; + } + else + { + type = param->type; + } + trigger = trigger->next; + } + else + { + type = param->type; + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "p%d__", num); + ++num; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + + /* Output the code for the operation case */ + if(operCase->code) + { + TreeCCStreamCodeIndent(stream, operCase->code, 1); + } + TreeCCStreamPrint(stream, "end\n"); + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a call to a case function from within the "switch". + */ + static void Ruby_GenCaseCall(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int number, + int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 1); + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + /* if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "(%s)", trigger->node->name); + } + }*/ + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "p%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + } + + /* + * Generate the code for a case inline within the "switch". + */ + static void Ruby_GenCaseInline(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + + /* Copy the parameters to new variables of the correct types */ + param = operCase->oper->params; + trigger = operCase->triggers; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if(param->name != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + Indent(stream, level * 2 + 4); + TreeCCStreamPrint(stream, "%s = %s__;\n", + param->name, param->name); + } + } + trigger = trigger->next; + } + param = param->next; + } + + /* Output the inline code for the case */ + Indent(stream, level * 2 + 4); + if(operCase->code) + { + /* Multiply the indent level by two because every ident is one space */ + TreeCCStreamCodeIndentCustom + (stream, operCase->code,' ',(level * 2 + 3) * 2); + } + Indent(stream, level * 2 + 4); + TreeCCStreamPrint(stream, "\n"); + } + + /* + * Generate a call to a split function from within the "switch". + */ + static void Ruby_GenCaseSplit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperationCase *operCase, + int number, int level) + { + TreeCCParam *param; + TreeCCTrigger *trigger; + int num; + int needComma; + + /* Indent to the correct level */ + Indent(stream, level * 2 + 2); + + /* Print out the call */ + TreeCCStreamPrint(stream, "%s_split_%d__(", operCase->oper->name, number); + param = operCase->oper->params; + trigger = operCase->triggers; + num = 1; + needComma = 0; + while(param != 0) + { + if(needComma) + { + TreeCCStreamPrint(stream, ", "); + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "%s", trigger->node->name); + } + } + if(param->name) + { + TreeCCStreamPrint(stream, "%s", param->name); + } + else + { + TreeCCStreamPrint(stream, "p%d__", num); + ++num; + } + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + if((trigger->node->flags & TREECC_NODE_ENUM) == 0 && + (trigger->node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + TreeCCStreamPrint(stream, "__"); + } + trigger = trigger->next; + } + needComma = 1; + param = param->next; + } + TreeCCStreamPrint(stream, ")\n"); + } + + /* + * Terminate a "switch" case. + */ + static void Ruby_GenEndCase(TreeCCContext *context, TreeCCStream *stream, + int level) + { + /*Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "\n");*/ + } + + /* + * Terminate the "switch" statement. + */ + static void Ruby_GenEndSwitch(TreeCCContext *context, TreeCCStream *stream, + int level) + { + Indent(stream, level * 2 + 3); + TreeCCStreamPrint(stream, "else\n"); + Indent(stream, level * 2 + 2); + TreeCCStreamPrint(stream, "end\n"); + } + + /* + * Generate the exit point for a non-virtual operation. + */ + static void Ruby_GenExit(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + if(strcmp(oper->returnType, "void") != 0) + { + /* Generate a default return value for the function */ + if(oper->defValue) + { + TreeCCStreamPrint(stream, " return %s\n", oper->defValue); + } + else + { + TreeCCStreamPrint(stream, " return 0\n"); + } + } + TreeCCStreamPrint(stream, " end\n"); + } + + /* + * Generate the end declarations for a non-virtual operation. + */ + static void Ruby_GenEnd(TreeCCContext *context, TreeCCStream *stream, + TreeCCOperation *oper) + { + TreeCCStreamPrint(stream, "end\n"); + } + + /* + * Table of non-virtual code generation functions. + */ + TreeCCNonVirtual const TreeCCNonVirtualFuncsRuby = { + Ruby_GenStart, + Ruby_GenEntry, + Ruby_GenSplitEntry, + Ruby_GenSwitchHead, + Ruby_GenSelector, + Ruby_GenEndSelectors, + Ruby_GenCaseFunc, + Ruby_GenCaseCall, + Ruby_GenCaseInline, + Ruby_GenCaseSplit, + Ruby_GenEndCase, + Ruby_GenEndSwitch, + Ruby_GenExit, + Ruby_GenEnd, + }; + + void TreeCCGenerateRuby(TreeCCContext *context) + { + /* Write all stream headers */ + WriteRubyHeaders(context); + + /* Generate the contents of the source stream */ + TreeCCNodeVisitAll(context, DeclareTypeDefs); + if(context->commonSource) + { + ImplementStateType(context, context->commonSource); + } + else + { + ImplementStateType(context, context->sourceStream); + } + TreeCCNodeVisitAll(context, BuildTypeDecls); + /* NO JAVA PLEASE */ + TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsRuby); + + + /* Write all stream footers */ + WriteRubyFooters(context); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/info.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/info.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/info.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,413 ---- + /* + * info.h - Store information about parsed "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_INFO_H + #define _TREECC_INFO_H + + #include "stream.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Forward declarations. + */ + typedef struct _tagTreeCCField TreeCCField; + typedef struct _tagTreeCCNode TreeCCNode; + typedef struct _tagTreeCCOperation TreeCCOperation; + typedef struct _tagTreeCCParam TreeCCParam; + typedef struct _tagTreeCCVirtual TreeCCVirtual; + typedef struct _tagTreeCCTrigger TreeCCTrigger; + typedef struct _tagTreeCCOperationCase TreeCCOperationCase; + + /* + * Field definition flags. + */ + #define TREECC_FIELD_NOCREATE 1 + + /* + * Node definition flags. + */ + #define TREECC_NODE_UNDEFINED 1 + #define TREECC_NODE_ABSTRACT 2 + #define TREECC_NODE_TYPEDEF 4 + #define TREECC_NODE_ENUM 8 + #define TREECC_NODE_ENUM_VALUE 16 + #define TREECC_NODE_MARK(n) (0x100 << (n)) + #define TREECC_NODE_MARK_BITS 0xFF00 + + /* + * Operation flags. + */ + #define TREECC_OPER_VIRTUAL 1 + #define TREECC_OPER_INLINE 2 + #define TREECC_OPER_SPLIT 4 + + /* + * Parameter flags. + */ + #define TREECC_PARAM_TRIGGER 1 + + /* + * Language values. + */ + #define TREECC_LANG_C 0 + #define TREECC_LANG_CPP 1 + #define TREECC_LANG_JAVA 2 + #define TREECC_LANG_CSHARP 3 + #define TREECC_LANG_RUBY 4 + #define TREECC_LANG_PHP 5 + + /* + * Information that is stored about a field. + */ + struct _tagTreeCCField + { + char *name; /* Name of the field */ + char *type; /* Type associated with the field */ + char *value; /* Default value for the field */ + int flags; /* Field flags */ + char *filename; /* File that defines the field */ + long linenum; /* Line where the field is defined */ + TreeCCField *next; /* Next field for the node type */ + + }; + + /* + * Information that is stored about a node type. + */ + struct _tagTreeCCNode + { + TreeCCNode *parent; /* Parent node type */ + TreeCCNode *firstChild; /* First child node type */ + TreeCCNode *lastChild; /* Last child node type */ + TreeCCNode *nextSibling;/* Next sibling node type under parent */ + char *name; /* Name of this node type */ + int flags; /* Node flags */ + int number; /* Number associated with this node type */ + int position; /* Position within the tree for operations */ + char *filename; /* File that defines the node type */ + long linenum; /* Line where the node type is defined */ + TreeCCField *fields; /* List of fields for this node type */ + TreeCCVirtual *virtuals; /* List of virtual methods for this node */ + TreeCCNode *nextHash; /* Next in the name hash table */ + TreeCCStream *header; /* Stream to write header to */ + TreeCCStream *source; /* Stream to write source to */ + + }; + + /* + * Information that is stored about an operation. + */ + struct _tagTreeCCOperation + { + char *name; /* Name of the operation */ + char *className; /* Name of the enclosing class */ + char *returnType; /* Return type for the operation */ + char *defValue; /* Default value for the operation */ + TreeCCParam *params; /* Parameters for the operation */ + int flags; /* Flags associated with the operation */ + int numTriggers;/* Number of trigger parameters */ + char *filename; /* File where the operation is declared */ + long linenum; /* Line where the operation is declared */ + TreeCCOperation *nextHash; /* Next in the operation hash table */ + TreeCCOperationCase *firstCase; /* First case associated with operation */ + TreeCCOperationCase *lastCase; /* Last case associated with operation */ + TreeCCOperationCase **sortedCases; /* Cases sorted for non-virtual ops */ + int numCases; /* Number of operation cases */ + TreeCCStream *header; /* Stream to write header to */ + TreeCCStream *source; /* Stream to write source to */ + + }; + + /* + * Information that is stored about an operation parameter. + */ + struct _tagTreeCCParam + { + char *name; /* Name of the parameter */ + char *type; /* Type for the parameter */ + int flags; /* Flags associated with the parameter */ + int size; /* Dimension size for non-virtual operations */ + TreeCCParam *next; /* Next parameter for the operation */ + + }; + + /* + * Information that is stored about a virtual method on a node type. + */ + struct _tagTreeCCVirtual + { + char *name; /* Name of the virtual method */ + char *returnType; /* Return type for the virtual method */ + TreeCCParam *params; /* Non-instance parameters */ + TreeCCOperation *oper; /* Operation block for the virtual */ + TreeCCVirtual *next; /* Next virtual method for the node type */ + + }; + + /* + * Information that is stored about a trigger match on an operation case. + */ + struct _tagTreeCCTrigger + { + TreeCCNode *node; /* Node type for the trigger */ + TreeCCTrigger *next; /* Next trigger for this case */ + + }; + + /* + * Information that is stored about an operation case. + */ + struct _tagTreeCCOperationCase + { + TreeCCTrigger *triggers; /* Trigger list for this case */ + char *code; /* Code associated with the case */ + TreeCCOperation *oper; /* Operation this case is associated with */ + int number; /* Reference number for code generation */ + char *filename; /* File that starts the case definition */ + long linenum; /* Line that starts the case definition */ + char *codeFilename;/* File that starts the code */ + long codeLinenum;/* Line that starts the code */ + TreeCCOperationCase *next; /* Next case for the operation */ + TreeCCOperationCase *nextHeader; /* Next header for same code block */ + + }; + + /* + * Context object that stores all definitions parsed from the input. + */ + #define TREECC_HASH_SIZE 512 + typedef struct _tagTreeCCContext + { + /* Hash table that allows quick lookup of node types */ + TreeCCNode *nodeHash[TREECC_HASH_SIZE]; + + /* Hash table that allows quick lookup of operation names */ + TreeCCOperation *operHash[TREECC_HASH_SIZE]; + + /* Current input stream */ + TreeCCInput *input; + + /* Output streams */ + TreeCCStream *streamList; /* List of all streams */ + TreeCCStream *headerStream; /* Current header stream */ + TreeCCStream *sourceStream; /* Current source stream */ + TreeCCStream *commonHeader; /* Stream for common definitions */ + TreeCCStream *commonSource; /* Stream for common source */ + + /* Flags that control the behaviour of the program */ + int debugMode : 1; /* Enable debug output */ + int track_lines : 1; /* Track node creation lines */ + int no_singletons : 1; /* Don't handle singletons specially */ + int reentrant : 1; /* Build a re-entrant system */ + int force : 1; /* Force the creation of files */ + int virtual_factory : 1;/* Allow overrides of factory methods */ + int abstract_factory : 1;/* Declare factory methods abstract */ + int kind_in_vtable : 1; /* Put kind value in vtable only */ + int strip_filenames : 1; /* Strip names in #line directives */ + int print_lines : 1; /* Dont emit #line directives */ + int internal_access : 1; /* Use "internal" classes in C# */ + int use_allocator : 1; /* Use the skeleton allocator */ + int use_gc_allocator : 1; /* Use the libgc allocator */ + + /* String to use to replace "yy" in output files */ + char *yy_replacement; + + /* Name of the type to use for re-entrant state */ + char *state_type; + + /* Namespace to store declarations within */ + char *namespace; + + /* Current node type number */ + int nodeNumber; + + /* Output source language to use */ + int language; + + /* Size of blocks to use in C/C++ memory alloction */ + int block_size; + + /* Name of the directory to output Java source files to */ + char *outputDirectory; + + /* name of the base type which is what %typedef expands to */ + char *baseType; + + } TreeCCContext; + + /* + * Create a context. + */ + TreeCCContext *TreeCCContextCreate(TreeCCInput *input); + + /* + * Destroy a context. + */ + void TreeCCContextDestroy(TreeCCContext *context); + + /* + * Hash a string. + */ + unsigned int TreeCCHashString(const char *str); + + /* + * Flags for "TreeCCAddLiteralDefn". + */ + #define TREECC_LITERAL_CODE 1 /* In source */ + #define TREECC_LITERAL_DECLS 2 /* In header */ + #define TREECC_LITERAL_END 4 /* Place at end */ + + /* + * Add a literal code definition block to the context. + */ + void TreeCCAddLiteralDefn(TreeCCContext *context, char *code, int flags); + + /* + * Free a node definition. + */ + void TreeCCNodeFree(TreeCCNode *node); + + /* + * Create a new node definition. + */ + TreeCCNode *TreeCCNodeCreate(TreeCCContext *context, long linenum, + char *name, char *parent, int flags); + + /* + * Find a node definition given its name. + */ + TreeCCNode *TreeCCNodeFind(TreeCCContext *context, const char *name); + + /* + * Find a node definition given a type name, which may be + * either "identifier" or "identifier *". + */ + TreeCCNode *TreeCCNodeFindByType(TreeCCContext *context, const char *name); + + /* + * Validate the node type hierarchy to ensure that everything is defined. + */ + void TreeCCNodeValidate(TreeCCContext *context); + + /* + * Visit every node type in a context's hierarchy. + */ + typedef void (*TreeCCNodeVisitor)(TreeCCContext *context, TreeCCNode *node); + void TreeCCNodeVisitAll(TreeCCContext *context, TreeCCNodeVisitor visitor); + + /* + * Determine if a node type is a singleton. i.e. no fields. + */ + int TreeCCNodeIsSingleton(TreeCCNode *node); + + /* + * Determine if a node type has abstract virtual operation cases. + */ + int TreeCCNodeHasAbstracts(TreeCCContext *context, TreeCCNode *node); + + /* + * Add a virtual operation to a node. + */ + void TreeCCNodeAddVirtual(TreeCCContext *context, TreeCCNode *node, + TreeCCOperation *oper); + + /* + * Determine if "nodea" inherits from "nodeb". + */ + int TreeCCNodeInheritsFrom(TreeCCNode *nodea, TreeCCNode *nodeb); + + /* + * Clear all marking bits that are used to track operation coverage. + */ + void TreeCCNodeClearMarking(TreeCCContext *context, int flags); + + /* + * Assign positions to all nodes started at a particular place + * in the node type hierarchy. Returns the number of positions. + */ + int TreeCCNodeAssignPositions(TreeCCNode *node); + + /* + * Create a new field definition and add it to a node. + */ + void TreeCCFieldCreate(TreeCCContext *context, TreeCCNode *node, + char *name, char *type, char *value, int flags); + + /* + * Free an operation. + */ + void TreeCCOperationFree(TreeCCOperation *oper); + + /* + * Create a new operation. + */ + TreeCCOperation *TreeCCOperationCreate(TreeCCContext *context, + char *returnType, char *name, + char *className, char *defValue, + TreeCCParam *params, int flags, + int numTriggers, char *filename, + long linenum); + + /* + * Find an operation with a specific name. + */ + TreeCCOperation *TreeCCOperationFind(TreeCCContext *context, char *name); + + /* + * Add a case definition to an operation. + */ + TreeCCOperationCase *TreeCCOperationAddCase + (TreeCCContext *context, TreeCCOperation *oper, + TreeCCTrigger *triggers, char *filename, long linenum); + + /* + * Validate all operations. + */ + void TreeCCOperationValidate(TreeCCContext *context); + + /* + * Find the operation case that corresponds to a virtual method. + * Returns NULL if the node does not have a virtual implementation. + */ + TreeCCOperationCase *TreeCCOperationFindCase + (TreeCCContext *context, TreeCCNode *node, char *name); + + /* + * Visit all operations declared by a context. + */ + typedef void (*TreeCCOperationVisitor)(TreeCCContext *context, + TreeCCOperation *oper); + void TreeCCOperationVisitAll(TreeCCContext *context, + TreeCCOperationVisitor visitor); + + /* + * Include the contents of a skeleton file in an output stream. + */ + void TreeCCIncludeSkeleton(TreeCCContext *context, TreeCCStream *stream, + const char *skeleton); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_INFO_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/input.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/input.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/input.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,990 ---- + /* + * input.c - Process input files for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + void TreeCCOpen(TreeCCInput *input, char *progname, + FILE *stream, char *filename) + { + input->token = TREECC_TOKEN_IDENTIFIER; + input->text = 0; + input->progname = progname; + input->stream = stream; + input->filename = filename; + input->linenum = 1; + input->nextline = 1; + input->errors = 0; + input->sawEOF = 0; + input->parseLiteral = 1; + input->readOnly = 0; + } + + void TreeCCClose(TreeCCInput *input, int closeRaw) + { + if(input->text && input->text != input->buffer) + { + free(input->text); + } + if(closeRaw) + { + fclose(input->stream); + } + } + + /* + * Determine if the next character looks like part of an identifier. + */ + #define IS_START_IDENT(ch) (((ch) >= 'A' && (ch) <= 'Z') || \ + ((ch) >= 'a' && (ch) <= 'z') || \ + (ch) == '_') + #define IS_IDENT(ch) (((ch) >= 'A' && (ch) <= 'Z') || \ + ((ch) >= 'a' && (ch) <= 'z') || \ + ((ch) >= '0' && (ch) <= '9') || \ + (ch) == '_') + + /* + * Report an invalid character error. + */ + static void InvalidChar(TreeCCInput *input, int ch) + { + if(ch >= ' ' && ch <= (char)0x7E) + { + TreeCCError(input, "invalid `%c' character in input", ch); + } + else + { + TreeCCError(input, "invalid `\\x%02X' character in input", ch); + } + } + + /* + * Report EOF inside a literal code block. + */ + static void LiteralEOF(TreeCCInput *input) + { + TreeCCError(input, "end of file inside literal code block"); + } + + /* + * Recognise an identifier from an input stream. + */ + static void RecogIdentifier(TreeCCInput *input, int ch, const char *name) + { + int len = 0; + int overflow = 0; + for(;;) + { + /* Add the character to the buffer */ + if(len < (TREECC_BUFSIZ - 1)) + { + input->buffer[len++] = ch; + } + else + { + overflow = 1; + } + + /* Get the next character */ + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + break; + } + else if(!IS_IDENT(ch)) + { + ungetc(ch, input->stream); + break; + } + } + if(overflow) + { + TreeCCError(input, "%s is too long", name); + } + input->buffer[len] = '\0'; + input->text = input->buffer; + } + + /* + * Flush a buffer of data to "input->text". + */ + static int FlushBuffer(TreeCCInput *input, int len, int currlen) + { + char *newText; + + /* Ignore the request if "len" is zero */ + if(!len) + { + return currlen; + } + + /* Reallocate the text buffer to the new length */ + if((newText = (char *)realloc(input->text, currlen + len + 1)) == 0) + { + TreeCCOutOfMemory(input); + } + input->text = newText; + + /* Copy the data to the buffer */ + strncpy(newText + currlen, input->buffer, len); + newText[currlen + len] = '\0'; + return currlen + len; + } + + /* + * Finalize the text buffer. + */ + static void FinalizeBuffer(TreeCCInput *input, int len, int currlen) + { + if(currlen != 0) + { + FlushBuffer(input, len, currlen); + } + else + { + input->buffer[len] = '\0'; + input->text = input->buffer; + } + } + + /* + * Recognise a literal code definition section. + */ + static void LiteralCodeDefn(TreeCCInput *input, int tillEnd) + { + int len = 0; + int currlen = 0; + int ch; + + /* Read characters until EOF or "%}" */ + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + if(!tillEnd) + { + LiteralEOF(input); + } + break; + } + else if(ch == '%' && !tillEnd) + { + /* Check for the "%}" terminating sequence */ + ch = getc(input->stream); + if(ch == '}') + { + break; + } + else if(ch == EOF) + { + input->buffer[len++] = '%'; + input->sawEOF = 1; + LiteralEOF(input); + break; + } + else + { + ungetc(ch, input->stream); + input->buffer[len++] = '%'; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + } + else + { + if(ch == '\n') + { + /* Unix-style end of line sequence */ + ++(input->nextline); + input->buffer[len++] = '\n'; + } + else if(ch == '\r') + { + /* MS-DOS or Mac-style end of line sequence */ + ++(input->nextline); + input->buffer[len++] = '\n'; + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + if(!tillEnd) + { + LiteralEOF(input); + } + break; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + } + else if(ch == '\0') + { + /* Strip out embedded NUL's */ + InvalidChar(input, ch); + } + else + { + /* Ordinary character */ + input->buffer[len++] = (char)ch; + } + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + } + + /* Finalize the text return buffer */ + FinalizeBuffer(input, len, currlen); + } + + /* + * Recognise a literal code section. This version is a little + * harder because we need to find a matching '}', while handling + * C-style and C++-style comments and strings. + */ + static void LiteralCode(TreeCCInput *input) + { + unsigned long level = 0; + int len = 0; + int currlen = 0; + int ch, quotech; + + /* Parse input until the next matching '}' */ + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + /* Premate end of file within the code block */ + input->sawEOF = 1; + LiteralEOF(input); + break; + } + else if(ch == '}') + { + /* Go out one code level */ + if(level == 0) + { + break; + } + --level; + input->buffer[len++] = '}'; + } + else if(ch == '{') + { + /* Go in one code level */ + ++level; + input->buffer[len++] = '{'; + } + else if(ch == '"' || ch == '\'') + { + /* Skip to the end of this string */ + quotech = ch; + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + while((ch = getc(input->stream)) != EOF && ch != quotech) + { + if(ch == '\\') + { + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + ch = getc(input->stream); + if(ch == EOF) + { + break; + } + } + if(ch == '\n' || ch == '\r') + { + TreeCCError(input, "end of line inside string"); + ungetc(ch, input->stream); + break; + } + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + if(ch == EOF) + { + input->sawEOF = 1; + TreeCCError(input, "end of file inside string"); + break; + } + else + { + input->buffer[len++] = (char)quotech; + } + } + else if(ch == '/') + { + /* May be the start of a comment */ + input->buffer[len++] = '/'; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + ch = getc(input->stream); + if(ch == EOF) + { + /* EOF in the middle of a code block */ + input->sawEOF = 1; + LiteralEOF(input); + break; + } + else if(ch == '/') + { + /* Single-line comment */ + input->buffer[len++] = '/'; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + while((ch = getc(input->stream)) != '\n' && + ch != '\r' && ch != EOF) + { + if(ch != '\0') + { + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + else + { + InvalidChar(input, ch); + } + } + if(ch == EOF) + { + input->sawEOF = 1; + LiteralEOF(input); + break; + } + ungetc(ch, input->stream); + } + else if(ch == '*') + { + /* Multi-line comment */ + input->buffer[len++] = '*'; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + /* EOF encountered in a comment */ + input->sawEOF = 1; + LiteralEOF(input); + goto finalize; + } + else if(ch == '*') + { + /* Check for the end of the comment */ + input->buffer[len++] = '*'; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + ch = getc(input->stream); + if(ch == '/') + { + input->buffer[len++] = '/'; + break; + } + else if(ch == EOF) + { + input->sawEOF = 1; + LiteralEOF(input); + goto finalize; + } + else + { + ungetc(ch, input->stream); + continue; + } + } + else if(ch == '\n') + { + /* Unix-style end of line in a comment */ + ++(input->nextline); + } + else if(ch == '\r') + { + /* MS-DOS or Mac-style end of line in a comment */ + ++(input->nextline); + ch = getc(input->stream); + if(ch == EOF) + { + input->buffer[len++] = '\n'; + input->sawEOF = 1; + LiteralEOF(input); + goto finalize; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + ch = '\n'; + } + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + } + else + { + /* Simple '/' character */ + ungetc(ch, input->stream); + } + } + else if(ch == '\n') + { + /* Unix-like end of line sequence */ + ++(input->nextline); + input->buffer[len++] = '\n'; + } + else if(ch == '\r') + { + /* MS-DOS or Mac-like end of line sequence */ + ++(input->nextline); + input->buffer[len++] = '\n'; + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + LiteralEOF(input); + break; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + } + else if(ch == '\0') + { + /* NUL characters are invalid in literal code blocks */ + InvalidChar(input, ch); + } + else + { + /* Normal character */ + input->buffer[len++] = (char)ch; + } + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + + /* Finalize the text return buffer */ + finalize: + FinalizeBuffer(input, len, currlen); + } + + /* + * Recognise a string from an input file. Escape sequences + * are not supported in this type of string. + */ + static void RecogString(TreeCCInput *input, int quotech) + { + int len = 0; + int currlen = 0; + int ch; + + /* Parse the contents of the string */ + for(;;) + { + ch = getc(input->stream); + if(ch == quotech) + { + /* Terminating quote for the string */ + break; + } + else if(ch == EOF) + { + /* EOF embedded in the string */ + input->sawEOF = 1; + TreeCCError(input, "end of file inside string"); + break; + } + else if(ch == '\n' || ch == '\r') + { + /* End of line embedding in the string */ + ungetc(ch, input->stream); + TreeCCError(input, "end of line inside string"); + break; + } + else if(ch == '\0') + { + /* NUL characters are invalid inside a string */ + InvalidChar(input, ch); + } + else + { + /* Ordinary character */ + input->buffer[len++] = (char)ch; + if(len >= (TREECC_BUFSIZ - 1)) + { + currlen = FlushBuffer(input, len, currlen); + len = 0; + } + } + } + + /* Finalize the text return buffer */ + FinalizeBuffer(input, len, currlen); + } + + /* + * Keyword table. Must be sorted into ascending order. + */ + static struct + { + const char *keyword; + TreeCCToken token; + + } const KeywordTable[] = { + {"abstract", TREECC_TOKEN_ABSTRACT}, + {"both", TREECC_TOKEN_BOTH}, + {"common", TREECC_TOKEN_COMMON}, + {"decls", TREECC_TOKEN_DECLS}, + {"end", TREECC_TOKEN_END}, + {"enum", TREECC_TOKEN_ENUM}, + {"header", TREECC_TOKEN_HEADER}, + {"include", TREECC_TOKEN_INCLUDE}, + {"inline", TREECC_TOKEN_INLINE}, + {"nocreate", TREECC_TOKEN_NOCREATE}, + {"node", TREECC_TOKEN_NODE}, + {"operation", TREECC_TOKEN_OPERATION}, + {"option", TREECC_TOKEN_OPTION}, + {"outdir", TREECC_TOKEN_OUTDIR}, + {"output", TREECC_TOKEN_OUTPUT}, + {"readonly", TREECC_TOKEN_READONLY}, + {"split", TREECC_TOKEN_SPLIT}, + {"typedef", TREECC_TOKEN_TYPEDEF}, + {"virtual", TREECC_TOKEN_VIRTUAL}, + }; + #define KeywordTableSize (sizeof(KeywordTable) / sizeof(KeywordTable[0])) + + int TreeCCNextToken(TreeCCInput *input) + { + int ch; + int low, middle, high; + + /* If we have seen EOF already, then bail out now */ + if(input->sawEOF) + { + input->linenum = input->nextline; + input->token = TREECC_TOKEN_EOF; + return 0; + } + + /* Free the text input buffer used by the previous token */ + if(input->text && input->text != input->buffer) + { + free(input->text); + } + input->text = 0; + + /* Determine what kind of token we have from the next character */ + for(;;) + { + input->linenum = input->nextline; + ch = getc(input->stream); + if(ch == EOF) + { + break; + } + else if(ch == '%') + { + ch = getc(input->stream); + if(ch == '{') + { + /* Start of a literal code definition section that + extends until the next occurrence of "%}" */ + LiteralCodeDefn(input, 0); + input->token = TREECC_TOKEN_LITERAL_DEFNS; + return 1; + } + else if(ch == '%') + { + /* Start of a literal code definition section that + extends until the end of the file */ + LiteralCodeDefn(input, 1); + input->token = TREECC_TOKEN_LITERAL_END; + return 1; + } + else if(IS_START_IDENT(ch)) + { + /* Start of a keyword */ + RecogIdentifier(input, ch, "keyword"); + low = 0; + high = KeywordTableSize - 1; + while(low <= high) + { + middle = ((low + high) / 2); + ch = strcmp(input->text, KeywordTable[middle].keyword); + if(!ch) + { + input->token = KeywordTable[middle].token; + return 1; + } + else if(ch < 0) + { + high = middle - 1; + } + else + { + low = middle + 1; + } + } + TreeCCError(input, "unknown keyword `%%%s'", input->text); + input->token = TREECC_TOKEN_UNKNOWN; + return 1; + } + else + { + TreeCCError(input, + "`%%' must be followed by a keyword, `{', or `%%'"); + if(ch == EOF) + { + break; + } + else + { + ungetc(ch, input->stream); + } + } + } + else if(IS_START_IDENT(ch)) + { + /* Start of an identifier */ + RecogIdentifier(input, ch, "identifier"); + input->token = TREECC_TOKEN_IDENTIFIER; + return 1; + } + else if(ch == '(') + { + input->token = TREECC_TOKEN_LPAREN; + return 1; + } + else if(ch == ')') + { + input->token = TREECC_TOKEN_RPAREN; + return 1; + } + else if(ch == '}') + { + input->token = TREECC_TOKEN_RBRACE; + return 1; + } + else if(ch == '[') + { + input->token = TREECC_TOKEN_LSQUARE; + return 1; + } + else if(ch == ']') + { + input->token = TREECC_TOKEN_RSQUARE; + return 1; + } + else if(ch == ',') + { + input->token = TREECC_TOKEN_COMMA; + return 1; + } + else if(ch == '=') + { + input->token = TREECC_TOKEN_EQUALS; + return 1; + } + else if(ch == '*') + { + input->token = TREECC_TOKEN_STAR; + return 1; + } + else if(ch == '&') + { + input->token = TREECC_TOKEN_REF; + return 1; + } + else if(ch == ';') + { + input->token = TREECC_TOKEN_SEMI; + return 1; + } + else if(ch == ':') + { + ch = getc(input->stream); + if(ch == ':') + { + input->token = TREECC_TOKEN_COLON_COLON; + return 1; + } + else if(ch == EOF) + { + InvalidChar(input, ':'); + input->sawEOF = 1; + input->linenum = input->nextline; + input->token = TREECC_TOKEN_EOF; + return 0; + } + else + { + ungetc(ch, input->stream); + InvalidChar(input, ':'); + } + } + else if(ch == '"' || ch == '\'') + { + RecogString(input, ch); + input->token = TREECC_TOKEN_STRING; + return 1; + } + else if(ch == '\n') + { + /* Unix-like end of line sequence */ + ++(input->nextline); + } + else if(ch == '\r') + { + /* MS-DOS or Mac-like end of line sequence */ + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + ++(input->nextline); + } + else if(ch == '{') + { + if(input->parseLiteral) + { + /* Start of a literal code block */ + LiteralCode(input); + input->token = TREECC_TOKEN_LITERAL_CODE; + return 1; + } + else + { + /* Probably a field definition block */ + input->token = TREECC_TOKEN_LBRACE; + return 1; + } + } + else if(ch == ' ' || ch == '\t' || ch == '\f' || ch == '\v') + { + /* Ignore white space on the current line */ + } + else if(ch == '/') + { + /* May be the start of a comment */ + ch = getc(input->stream); + if(ch == '*') + { + /* Multi-line comment */ + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + eofInComment: + TreeCCError(input, "end of file inside comment"); + input->sawEOF = 1; + input->linenum = input->nextline; + input->token = TREECC_TOKEN_EOF; + return 0; + } + else if(ch == '*') + { + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + goto eofInComment; + } + else if(ch == '/') + { + goto endComment; + } + else if(ch != '*') + { + ungetc(ch, input->stream); + break; + } + } + } + else if(ch == '\n') + { + ++(input->nextline); + } + else if(ch == '\r') + { + ++(input->nextline); + ch = getc(input->stream); + if(ch == EOF) + { + goto eofInComment; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + } + } + endComment: ; + } + else if(ch == '/') + { + /* Single-line comment */ + for(;;) + { + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + input->linenum = input->nextline; + input->token = TREECC_TOKEN_EOF; + return 0; + } + else if(ch == '\n') + { + break; + } + else if(ch == '\r') + { + ch = getc(input->stream); + if(ch == EOF) + { + input->sawEOF = 1; + } + else if(ch != '\n') + { + ungetc(ch, input->stream); + } + break; + } + } + ++(input->nextline); + } + else + { + /* Invalid comment sequence */ + InvalidChar(input, '/'); + if(ch == EOF) + { + break; + } + else + { + ungetc(ch, input->stream); + } + } + } + else + { + /* Invalid character in the input stream */ + InvalidChar(input, ch); + } + } + + /* If we get here, then we have reached EOF */ + input->linenum = input->nextline; + input->token = TREECC_TOKEN_EOF; + input->sawEOF = 1; + return 0; + } + + char *TreeCCValue(TreeCCInput *input) + { + char *result; + if(!(input->text)) + { + /* We don't have a text version of this token */ + TreeCCAbort(input, "no text for token type %d", input->token); + return 0; + } + else if(input->text != input->buffer) + { + /* The text is already malloc'ed, so return that */ + result = input->text; + input->text = 0; + return result; + } + else + { + /* Copy the text into a malloc'ed buffer */ + result = (char *)malloc(strlen(input->buffer) + 1); + if(!result) + { + TreeCCOutOfMemory(input); + } + strcpy(result, input->buffer); + input->text = 0; + return result; + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/input.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/input.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/input.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,121 ---- + /* + * input.h - Process input files for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_INPUT_H + #define _TREECC_INPUT_H + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Token types. + */ + typedef enum + { + TREECC_TOKEN_EOF, + TREECC_TOKEN_IDENTIFIER, + TREECC_TOKEN_LITERAL_DEFNS, + TREECC_TOKEN_LITERAL_CODE, + TREECC_TOKEN_LITERAL_END, + TREECC_TOKEN_LPAREN, + TREECC_TOKEN_RPAREN, + TREECC_TOKEN_LBRACE, + TREECC_TOKEN_RBRACE, + TREECC_TOKEN_LSQUARE, + TREECC_TOKEN_RSQUARE, + TREECC_TOKEN_COMMA, + TREECC_TOKEN_EQUALS, + TREECC_TOKEN_STAR, + TREECC_TOKEN_REF, + TREECC_TOKEN_SEMI, + TREECC_TOKEN_COLON_COLON, + TREECC_TOKEN_STRING, + TREECC_TOKEN_UNKNOWN, + TREECC_TOKEN_NODE, + TREECC_TOKEN_ABSTRACT, + TREECC_TOKEN_TYPEDEF, + TREECC_TOKEN_OPERATION, + TREECC_TOKEN_NOCREATE, + TREECC_TOKEN_VIRTUAL, + TREECC_TOKEN_INLINE, + TREECC_TOKEN_SPLIT, + TREECC_TOKEN_OPTION, + TREECC_TOKEN_HEADER, + TREECC_TOKEN_OUTPUT, + TREECC_TOKEN_OUTDIR, + TREECC_TOKEN_BOTH, + TREECC_TOKEN_DECLS, + TREECC_TOKEN_END, + TREECC_TOKEN_ENUM, + TREECC_TOKEN_COMMON, + TREECC_TOKEN_INCLUDE, + TREECC_TOKEN_READONLY, + + } TreeCCToken; + + /* + * Information structure for an input stream. + */ + #define TREECC_BUFSIZ 1024 + typedef struct + { + TreeCCToken token; + char *text; + char *progname; + FILE *stream; + char *filename; + long linenum; + long nextline; + int errors; + int sawEOF; + int parseLiteral; + int readOnly; + char buffer[TREECC_BUFSIZ]; + + } TreeCCInput; + + /* + * Open an input stream. + */ + void TreeCCOpen(TreeCCInput *input, char *progname, + FILE *stream, char *filename); + + /* + * Close an input stream. + */ + void TreeCCClose(TreeCCInput *input, int closeRaw); + + /* + * Get the next token from an input stream. + * Returns zero if at EOF, or non-zero if OK. + */ + int TreeCCNextToken(TreeCCInput *input); + + /* + * Copy the value of the current text token into a malloc'ed string. + */ + char *TreeCCValue(TreeCCInput *input); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_INPUT_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/literal.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/literal.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/literal.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,67 ---- + /* + * literal.c - Management node types for literal code blocks. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + void TreeCCAddLiteralDefn(TreeCCContext *context, char *code, int flags) + { + if(context->debugMode) + { + TreeCCDebug(context->input->linenum, "%%literal %d %s", + flags, code); + } + if((flags & TREECC_LITERAL_CODE) != 0 && + (flags & TREECC_LITERAL_DECLS) != 0) + { + TreeCCStreamAddLiteral(context->headerStream, code, + context->input->filename, + context->input->linenum, + (flags & TREECC_LITERAL_END) != 0, 0); + TreeCCStreamAddLiteral(context->sourceStream, code, + context->input->filename, + context->input->linenum, + (flags & TREECC_LITERAL_END) != 0, 1); + } + else if((flags & TREECC_LITERAL_CODE) != 0) + { + TreeCCStreamAddLiteral(context->sourceStream, code, + context->input->filename, + context->input->linenum, + (flags & TREECC_LITERAL_END) != 0, 0); + } + else + { + TreeCCStreamAddLiteral(context->headerStream, code, + context->input->filename, + context->input->linenum, + (flags & TREECC_LITERAL_END) != 0, 0); + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/main.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/main.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/main.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,590 ---- + /* + * main.c - Main program entry point for "treecc". + * + * Copyright (C) 2001, 2002 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "parse.h" + #include "errors.h" + #include "gen.h" + #include "options.h" + + #ifdef __cplusplus + extern "C" { + #endif + + static void Usage(char *progname); + static void Version(void); + static int ExtraOptions(TreeCCContext *context, char **options, int num); + static char *GetDefault(const char *filename, const char *extension); + + int main(int argc, char *argv[]) + { + char *progname = argv[0]; + char *opt; + char *outputFile = NULL; + char *headerFile = NULL; + char *extension = "c"; + char *outputDir = NULL; + int forceCreate = 0; + TreeCCInput input; + TreeCCContext *context; + int sawStdin = 0; + int generateOutput = 1; + FILE *file; + int len, result; + char **options = (char **)malloc(sizeof(char *) * argc); + int num_options = 0; + + /* Allocate the array for external "%option" values */ + options = (char **)malloc(sizeof(char *) * argc); + if(!options) + { + TreeCCOutOfMemory(0); + } + + /* Parse the command-line options */ + while(argc > 1 && argv[1][0] == '-') + { + if(argv[1][1] == '\0') + { + /* The input is stdin */ + break; + } + else if(argv[1][1] == '-') + { + /* The option begins with "--" */ + if(argv[1][2] == '\0') + { + /* End of options, and start of filenames */ + --argc; + ++argv; + break; + } + if(!strcmp(argv[1], "--output")) + { + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + outputFile = argv[1]; + } + else if(!strcmp(argv[1], "--header")) + { + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + headerFile = argv[1]; + } + else if(!strcmp(argv[1], "--output-dir")) + { + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + outputDir = argv[1]; + } + else if(!strcmp(argv[1], "--skeleton-dir")) + { + /* This option is obsolete: we still parse it just in + case there are older build systems that expect it */ + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + } + else if(!strcmp(argv[1], "--extension")) + { + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + extension = argv[1]; + } + else if(!strcmp(argv[1], "--option")) + { + --argc; + ++argv; + if(argc <= 1) + { + Usage(progname); + return 1; + } + options[num_options++] = argv[1]; + } + else if(!strcmp(argv[1], "--force-create")) + { + forceCreate = 1; + } + else if(!strcmp(argv[1], "--no-output")) + { + generateOutput = 0; + } + else if(!strcmp(argv[1], "--help")) + { + Usage(progname); + return 1; + } + else if(!strcmp(argv[1], "--version")) + { + Version(); + return 0; + } + else + { + Usage(progname); + return 1; + } + } + else + { + /* Single-character option */ + opt = argv[1] + 1; + while(*opt != '\0') + { + switch(*opt++) + { + case 'o': + { + if(*opt != '\0') + { + outputFile = opt; + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + outputFile = argv[1]; + } + } + break; + + case 'h': + { + if(*opt != '\0') + { + headerFile = opt; + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + headerFile = argv[1]; + } + } + break; + + case 'd': + { + if(*opt != '\0') + { + outputDir = opt; + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + outputDir = argv[1]; + } + } + break; + + case 's': + { + /* This option is obsolete: we still parse it just in + case there are older build systems that expect it */ + if(*opt != '\0') + { + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + } + } + break; + + case 'e': + { + if(*opt != '\0') + { + extension = opt; + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + extension = argv[1]; + } + } + break; + + case 'O': + { + if(*opt != '\0') + { + options[num_options++] = opt; + opt = ""; + } + else if(argc <= 2) + { + Usage(progname); + return 1; + } + else + { + --argc; + ++argv; + options[num_options++] = argv[1]; + } + } + break; + + case 'f': + { + forceCreate = 1; + } + break; + + case 'n': + { + generateOutput = 0; + } + break; + + case 'v': + { + Version(); + return 0; + } + /* Not reached */ + + default: + { + Usage(progname); + return 1; + } + /* Not reached */ + } + } + } + --argc; + ++argv; + } + if(argc <= 1) + { + Usage(progname); + return 1; + } + + /* Determine the default output and header filenames */ + if(!outputFile) + { + if(*extension == '.') + { + ++extension; + } + outputFile = GetDefault(argv[1], extension); + } + if(!headerFile) + { + headerFile = GetDefault(outputFile, "h"); + } + + /* Initialize the input routines */ + TreeCCOpen(&input, progname, NULL, NULL); + + /* Determine the default Java output directory */ + if(!outputDir) + { + len = strlen(argv[1]); + while(len > 0 && argv[1][len - 1] != '/' && argv[1][len - 1] != '\\') + { + --len; + } + if(len > 0) + { + --len; + } + if(len > 0) + { + outputDir = (char *)malloc(len + 1); + if(!outputDir) + { + TreeCCOutOfMemory(&input); + } + strncpy(outputDir, argv[1], len); + outputDir[len] = '\0'; + } + } + + /* Create the parsing context */ + context = TreeCCContextCreate(&input); + if(!context) + { + TreeCCOutOfMemory(&input); + } + context->force = forceCreate; + context->outputDirectory = outputDir; + + /* Process additional options from the command-line */ + if(!ExtraOptions(context, options, num_options)) + { + return 1; + } + free(options); + + /* Create the default source and header streams */ + context->sourceStream = TreeCCStreamCreate(context, outputFile, + NULL, 0); + context->sourceStream->defaultFile = 1; + context->headerStream = TreeCCStreamCreate(context, headerFile, + NULL, 1); + context->headerStream->defaultFile = 1; + + /* Process the input files */ + while(argc > 1) + { + if(!strcmp(argv[1], "-")) + { + /* Parse stdin, but only once */ + if(!sawStdin) + { + TreeCCOpen(&input, progname, stdin, "stdin"); + TreeCCParse(context); + TreeCCClose(&input, 0); + sawStdin = 1; + } + } + else + { + /* Parse some other file */ + if((file = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + input.errors = 1; + } + else + { + TreeCCOpen(&input, progname, file, argv[1]); + TreeCCParse(context); + TreeCCClose(&input, 1); + } + } + --argc; + ++argv; + } + + /* Validate node and operation coverage */ + TreeCCNodeValidate(context); + TreeCCOperationValidate(context); + + /* Abort if we encountered errors during parsing and validation */ + if(input.errors) + { + TreeCCContextDestroy(context); + return 1; + } + + /* Generate the output files */ + result = 0; + if(generateOutput) + { + TreeCCStream *stream; + TreeCCGenerate(context); + stream = context->streamList; + while(stream != 0) + { + if(!TreeCCStreamFlush(stream)) + { + result = 1; + } + stream = stream->nextStream; + } + } + + /* Done */ + TreeCCContextDestroy(context); + return result; + } + + static void Usage(char *progname) + { + fprintf(stderr, "TREECC " VERSION " - Tree Compiler-Compiler\n"); + fprintf(stderr, "Copyright (c) 2001, 2002 Southern Storm Software, Pty Ltd.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Usage: %s [options] input ...\n", progname); + fprintf(stderr, "\n"); + fprintf(stderr, " -o file, --output file\n"); + fprintf(stderr, " Set the name of the output file.\n"); + fprintf(stderr, " -h file, --header file\n"); + fprintf(stderr, " Set the name of the header output file.\n"); + fprintf(stderr, " -d dir, --output-dir file\n"); + fprintf(stderr, " Set the name of the Java output directory.\n"); + fprintf(stderr, " -e ext, --extension ext\n"); + fprintf(stderr, " Set the output file extension (default is \".c\").\n"); + fprintf(stderr, " -f, --force-create\n"); + fprintf(stderr, " Force the creation of unchanged output files.\n"); + fprintf(stderr, " -O opt, --option opt\n"); + fprintf(stderr, " Set a treecc source option value.\n"); + fprintf(stderr, " --help\n"); + fprintf(stderr, " Print this help message.\n"); + fprintf(stderr, " -v, --version\n"); + fprintf(stderr, " Print the program version.\n"); + } + + static void Version(void) + { + printf("TREECC " VERSION " - Tree Compiler-Compiler\n"); + printf("Copyright (c) 2001, 2002 Southern Storm Software, Pty Ltd.\n"); + printf("\n"); + printf("TREECC comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); + printf("and you are welcome to redistribute it under the terms of the\n"); + printf("GNU General Public License. See the file COPYING for further details.\n"); + printf("\n"); + printf("Use the `--help' option to get help on the command-line options.\n"); + } + + /* + * Process extra treecc "%option" values from the command-line. + */ + static int ExtraOptions(TreeCCContext *context, char **options, int num) + { + char *name; + char *value; + while(num-- > 0) + { + name = *options++; + value = name; + while(*value != '\0' && *value != '=') + { + ++value; + } + if(*value == '\0') + { + value = 0; + } + else + { + *value++ = '\0'; + } + if(TreeCCOptionProcess(context, name, value) != TREECC_OPT_OK) + { + fprintf(stderr, "%s: unknown option or invalid value\n", name); + return 0; + } + } + return 1; + } + + /* + * Get a default output or header filename from an input filename. + */ + static char *GetDefault(const char *filename, const char *extension) + { + int len; + char *name; + + /* USe a default filename pattern if we are reading from stdin */ + if(!strcmp(filename, "-")) + { + filename = "yy_tree.tc"; + } + + /* Find the end of the input filename, without its extension */ + len = strlen(filename); + while(len > 0 && filename[len - 1] != '/' && filename[len - 1] != '\\' && + filename[len - 1] != '.') + { + --len; + } + + /* Construct the new filename */ + if(len > 0 && filename[len - 1] == '.') + { + name = (char *)malloc(len + strlen(extension) + 1); + if(!name) + { + TreeCCOutOfMemory((TreeCCInput *)0); + } + strncpy(name, filename, len); + strcpy(name + len, extension); + } + else + { + len = strlen(filename); + name = (char *)malloc(len + strlen(extension) + 2); + if(!name) + { + TreeCCOutOfMemory((TreeCCInput *)0); + } + strcpy(name, filename); + name[len] = '.'; + strcpy(name + len + 1, extension); + } + return name; + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/node.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/node.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/node.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,682 ---- + /* + * node.c - Management for node types for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + unsigned int TreeCCHashString(const char *str) + { + unsigned int hash = 0; + while(*str != '\0') + { + hash = (hash << 5) + hash + (unsigned int)(*str++); + } + return hash; + } + + static unsigned int HashStringLen(const char *str, int len) + { + unsigned int hash = 0; + while(len > 0) + { + hash = (hash << 5) + hash + (unsigned int)(*str++); + --len; + } + return hash; + } + + void TreeCCNodeFree(TreeCCNode *node) + { + TreeCCField *field, *nextField; + TreeCCVirtual *virt, *nextVirt; + + /* Free the node's fields */ + field = node->fields; + while(field != 0) + { + nextField = field->next; + free(field->name); + free(field->type); + if(field->value) + { + free(field->value); + } + free(field); + field = nextField; + } + + /* Free the virtual member function references */ + virt = node->virtuals; + while(virt != 0) + { + nextVirt = virt->next; + free(virt); + virt = nextVirt; + } + + /* Free other members and the node itself */ + free(node->name); + free(node); + } + + /* + * Add a node to the hash table. + */ + static void AddToHash(TreeCCContext *context, TreeCCNode *node) + { + unsigned int hash = (TreeCCHashString(node->name) & (TREECC_HASH_SIZE - 1)); + node->nextHash = context->nodeHash[hash]; + context->nodeHash[hash] = node; + } + + TreeCCNode *TreeCCNodeCreate(TreeCCContext *context, long linenum, + char *name, char *parent, int flags) + { + TreeCCNode *parentNode; + TreeCCNode *node; + + /* Print debugging information if required */ + if(context->debugMode) + { + TreeCCDebug(linenum, "%%node %s %s %d", name, + (parent ? parent : "no_parent"), flags); + } + + /* Find or create the parent node */ + if(parent) + { + parentNode = TreeCCNodeFind(context, parent); + if(!parentNode) + { + /* Create an undefined placeholder for the parent */ + parentNode = (TreeCCNode *)malloc(sizeof(TreeCCNode)); + if(!parentNode) + { + TreeCCOutOfMemory(context->input); + } + parentNode->parent = 0; + parentNode->firstChild = 0; + parentNode->lastChild = 0; + parentNode->nextSibling = 0; + parentNode->name = parent; + parentNode->flags = TREECC_NODE_UNDEFINED; + parentNode->number = (context->nodeNumber)++; + parentNode->filename = context->input->filename; + parentNode->linenum = linenum; + parentNode->fields = 0; + parentNode->virtuals = 0; + parentNode->header = context->headerStream; + parentNode->source = context->sourceStream; + AddToHash(context, parentNode); + } + else + { + free(parent); + } + } + else + { + parentNode = 0; + } + + /* Find or create the current node */ + node = TreeCCNodeFind(context, name); + if(node) + { + if((node->flags & TREECC_NODE_UNDEFINED) == 0) + { + TreeCCErrorOnLine(context->input, context->input->filename, linenum, + "node type `%s' is already declared", name); + TreeCCErrorOnLine(context->input, node->filename, node->linenum, + "previous declaration here"); + free(name); + } + else + { + node->flags = flags; + node->parent = parentNode; + node->filename = context->input->filename; + node->linenum = linenum; + node->header = context->headerStream; + node->source = context->sourceStream; + node->nextSibling = 0; + if(parentNode) + { + if(parentNode->lastChild) + { + parentNode->lastChild->nextSibling = node; + } + else + { + parentNode->firstChild = node; + } + parentNode->lastChild = node; + } + } + } + else + { + node = (TreeCCNode *)malloc(sizeof(TreeCCNode)); + if(!node) + { + TreeCCOutOfMemory(context->input); + } + node->parent = parentNode; + node->firstChild = 0; + node->lastChild = 0; + node->name = name; + node->flags = flags; + node->number = (context->nodeNumber)++; + node->filename = context->input->filename; + node->linenum = linenum; + node->fields = 0; + node->virtuals = 0; + node->header = context->headerStream; + node->source = context->sourceStream; + node->nextSibling = 0; + if(parentNode) + { + if(parentNode->lastChild) + { + parentNode->lastChild->nextSibling = node; + } + else + { + parentNode->firstChild = node; + } + parentNode->lastChild = node; + } + AddToHash(context, node); + } + return node; + } + + TreeCCNode *TreeCCNodeFind(TreeCCContext *context, const char *name) + { + unsigned int hash = (TreeCCHashString(name) & (TREECC_HASH_SIZE - 1)); + TreeCCNode *node = context->nodeHash[hash]; + while(node != 0) + { + if(!strcmp(node->name, name)) + { + return node; + } + node = node->nextHash; + } + return 0; + } + + TreeCCNode *TreeCCNodeFindByType(TreeCCContext *context, const char *name) + { + unsigned int hash; + TreeCCNode *node; + int len; + int hasSuffix; + + /* Strip " *" from the end of the name, if present */ + len = strlen(name); + if(len >= 2 && name[len - 1] == '*' && name[len - 2] == ' ') + { + len -= 2; + hasSuffix = 1; + } + else + { + hasSuffix = 0; + } + + /* Look for the name */ + hash = (HashStringLen(name, len) & (TREECC_HASH_SIZE - 1)); + node = context->nodeHash[hash]; + while(node != 0) + { + if(!strncmp(node->name, name, len) && node->name[len] == '\0') + { + if((node->flags & TREECC_NODE_ENUM) != 0) + { + /* We can only use enumerations as types if no suffix */ + if(hasSuffix) + { + return 0; + } + else + { + return node; + } + } + else if((node->flags & TREECC_NODE_ENUM_VALUE) != 0) + { + /* Enumerated values cannot be used as types */ + return 0; + } + else + { + return node; + } + } + node = node->nextHash; + } + return 0; + } + + void TreeCCNodeValidate(TreeCCContext *context) + { + unsigned int hash; + TreeCCNode *node; + TreeCCNode *type; + TreeCCField *field; + int len; + int typeCheck = (context->language == TREECC_LANG_C || + context->language == TREECC_LANG_CPP); + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + node = context->nodeHash[hash]; + while(node != 0) + { + if((node->flags & TREECC_NODE_UNDEFINED) != 0) + { + TreeCCErrorOnLine(context->input, + node->filename, node->linenum, + "node type `%s' is not declared", + node->name); + } + if(!(node->parent) && + (node->flags & TREECC_NODE_UNDEFINED) == 0 && + (node->flags & TREECC_NODE_TYPEDEF) == 0) + { + TreeCCErrorOnLine(context->input, + node->filename, node->linenum, + "base node type `%s' must be declared with %%typedef", + node->name); + } + if(typeCheck) + { + /* In C or C++, fields that are declared as node + types must end in "*" */ + field = node->fields; + while(field != 0) + { + type = TreeCCNodeFindByType(context, field->type); + if(type != 0 && (type->flags & TREECC_NODE_ENUM) == 0) + { + len = strlen(field->type); + if(len < 2 || field->type[len - 1] != '*' || + field->type[len - 2] != ' ') + { + TreeCCErrorOnLine(context->input, + field->filename, field->linenum, + "field type does not end in `*'"); + } + } + field = field->next; + } + } + node = node->nextHash; + } + } + } + + /* + * Visit the children of a node in breadth-first order. + */ + static void Visit(TreeCCContext *context, TreeCCNode *node, + TreeCCNodeVisitor visitor) + { + TreeCCNode *child; + + /* Visit the children of the node */ + child = node->firstChild; + while(child != 0) + { + (*visitor)(context, child); + child = child->nextSibling; + } + + /* Visit their children */ + child = node->firstChild; + while(child != 0) + { + Visit(context, child, visitor); + child = child->nextSibling; + } + } + + void TreeCCNodeVisitAll(TreeCCContext *context, TreeCCNodeVisitor visitor) + { + unsigned int hash; + TreeCCNode *node; + + /* Find and visit all top-level nodes */ + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + node = context->nodeHash[hash]; + while(node != 0) + { + if(!(node->parent)) + { + (*visitor)(context, node); + Visit(context, node, visitor); + } + node = node->nextHash; + } + } + } + + int TreeCCNodeIsSingleton(TreeCCNode *node) + { + while(node != 0) + { + if(node->fields != 0) + { + return 0; + } + node = node->parent; + } + return 1; + } + + static int HasAbstracts(TreeCCContext *context, TreeCCNode *node, + TreeCCNode *actualNode) + { + TreeCCVirtual *virt; + TreeCCOperationCase *operCase; + TreeCCNode *tempNode; + int abstractCase; + + /* Check for abstracts in the parent node type */ + if(node->parent) + { + if(HasAbstracts(context, node->parent, actualNode)) + { + return 1; + } + } + + /* Check for abstracts in this node type */ + virt = node->virtuals; + while(virt != 0) + { + /* Determine if we need a definition for this virtual, + and whether the definition is real or abstract */ + operCase = TreeCCOperationFindCase(context, actualNode, virt->name); + if(!operCase) + { + tempNode = actualNode->parent; + abstractCase = 1; + while(tempNode != 0) + { + operCase = TreeCCOperationFindCase + (context, tempNode, virt->name); + if(operCase != 0) + { + abstractCase = 0; + break; + } + tempNode = tempNode->parent; + } + if(abstractCase) + { + return 1; + } + } + virt = virt->next; + } + return 0; + } + + int TreeCCNodeHasAbstracts(TreeCCContext *context, TreeCCNode *node) + { + return HasAbstracts(context, node, node); + } + + void TreeCCNodeAddVirtual(TreeCCContext *context, TreeCCNode *node, + TreeCCOperation *oper) + { + TreeCCVirtual *virt; + TreeCCVirtual *last; + + /* Print debugging information if required */ + if(context->debugMode) + { + TreeCCDebug(oper->linenum, "%%virtual %s %s", + node->name, oper->name); + } + + /* Allocate the virtual method block */ + if((virt = (TreeCCVirtual *)malloc(sizeof(TreeCCVirtual))) == 0) + { + TreeCCOutOfMemory(context->input); + } + + /* Initialise the virtual method fields */ + virt->name = oper->name; + virt->returnType = oper->returnType; + virt->params = oper->params->next; + virt->oper = oper; + virt->next = 0; + + /* Add the virtual method to the end of the node's virtual list */ + if(node->virtuals) + { + last = node->virtuals; + while(last->next != 0) + { + last = last->next; + } + last->next = virt; + } + else + { + node->virtuals = virt; + } + } + + int TreeCCNodeInheritsFrom(TreeCCNode *nodea, TreeCCNode *nodeb) + { + while(nodea != 0) + { + if(nodea == nodeb) + { + return 1; + } + nodea = nodea->parent; + } + return 0; + } + + void TreeCCNodeClearMarking(TreeCCContext *context, int flags) + { + unsigned int hash; + TreeCCNode *node; + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + node = context->nodeHash[hash]; + while(node != 0) + { + node->flags &= ~flags; + node = node->nextHash; + } + } + } + + /* + * Assign positions starting at a particular value. + */ + static int AssignPositions(TreeCCNode *node, int posn) + { + TreeCCNode *child; + + /* Assign positions to the children */ + child = node->firstChild; + while(child != 0) + { + posn = AssignPositions(child, posn); + child = child->nextSibling; + } + + /* Assign a position to this node */ + node->position = posn; + return posn + 1; + } + + int TreeCCNodeAssignPositions(TreeCCNode *node) + { + return AssignPositions(node, 0); + } + + /* + * Determine if a field name is already declared in a node type. + */ + static int IsDeclared(TreeCCContext *context, TreeCCNode *node, + char *name, int reverseError) + { + TreeCCField *field = node->fields; + while(field != 0) + { + if(!strcmp(field->name, name)) + { + if(reverseError) + { + /* We are attempting to declare a field already in a child */ + TreeCCErrorOnLine(context->input, + field->filename, field->linenum, + "field `%s' is already declared", name); + TreeCCError(context->input, "previous declaration here"); + } + else + { + /* We are attempting to declare a field already in a parent */ + TreeCCError(context->input, "field `%s' is already declared", + name); + TreeCCErrorOnLine(context->input, + field->filename, field->linenum, + "previous declaration here"); + } + return 1; + } + field = field->next; + } + return 0; + } + + /* + * Determine if a field name is already declared in child node types. + */ + static int IsDeclaredInChildren(TreeCCContext *context, TreeCCNode *node, + char *name) + { + TreeCCNode *child = node->firstChild; + while(child != 0) + { + if(IsDeclared(context, child, name, 1)) + { + return 1; + } + if(IsDeclaredInChildren(context, child, name)) + { + return 1; + } + child = child->nextSibling; + } + return 0; + } + + void TreeCCFieldCreate(TreeCCContext *context, TreeCCNode *node, + char *name, char *type, char *value, int flags) + { + TreeCCNode *current; + TreeCCField *field; + TreeCCField *prev; + + /* Print debugging information if required */ + if(context->debugMode) + { + TreeCCDebug(context->input->linenum, + "%%field %s %s %s %d", name, + (type ? type : "no_type"), + (value ? value : "no_value"), flags); + } + + /* Check to make sure that the field does not already exist + in this node type or any of its ancestor node types */ + current = node; + while(current != 0) + { + if(IsDeclared(context, current, name, 0)) + { + free(name); + free(type); + if(value) + { + free(value); + } + return; + } + current = current->parent; + } + + /* Check to make sure that the field does not already exist + in any of the child classes. This may happen if a child + class is declared before one of its ancestors */ + IsDeclaredInChildren(context, node, name); + + /* Find the end of the node's field list */ + field = node->fields; + prev = 0; + while(field != 0) + { + prev = field; + field = field->next; + } + + /* Create a new field block and fill it in */ + field = (TreeCCField *)malloc(sizeof(TreeCCField)); + if(!field) + { + TreeCCOutOfMemory(context->input); + } + field->name = name; + field->type = type; + field->value = value; + field->flags = flags; + field->filename = context->input->filename; + field->linenum = context->input->linenum; + field->next = 0; + + /* Add the field to the list */ + if(prev) + { + prev->next = field; + } + else + { + node->fields = field; + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/oper.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/oper.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/oper.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,835 ---- + /* + * oper.c - Management for operations for "treecc". + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + void TreeCCOperationFree(TreeCCOperation *oper) + { + TreeCCParam *param, *nextParam; + TreeCCOperationCase *operCase, *nextCase; + TreeCCTrigger *trigger, *nextTrigger; + + /* Free the name and return type */ + free(oper->name); + if(oper->className) + { + free(oper->className); + } + free(oper->returnType); + + /* Free the parameters */ + param = oper->params; + while(param != 0) + { + nextParam = param->next; + if(param->name) + { + free(param->name); + } + free(param->type); + param = nextParam; + } + + /* Free the operation cases */ + operCase = oper->firstCase; + while(operCase != 0) + { + nextCase = operCase->next; + if(operCase->code && !(operCase->nextHeader)) + { + free(operCase->code); + } + trigger = operCase->triggers; + while(trigger != 0) + { + nextTrigger = trigger->next; + free(trigger); + trigger = nextTrigger; + } + free(operCase); + operCase = nextCase; + } + + /* Free the array of sorted operation cases */ + if(oper->sortedCases) + { + free(oper->sortedCases); + } + + /* Free the operation block itself */ + free(oper); + } + + TreeCCOperation *TreeCCOperationCreate(TreeCCContext *context, + char *returnType, char *name, + char *className, char *defValue, + TreeCCParam *params, int flags, + int numTriggers, char *filename, + long linenum) + { + TreeCCOperation *oper; + unsigned int hash; + + /* Print debugging information if required */ + if(context->debugMode) + { + TreeCCParam *param; + TreeCCDebug(linenum, "%%operation %s %s%s%s %d", + returnType, + (className ? className : ""), + (className ? "::" : ""), + name, flags); + param = params; + while(param != 0) + { + TreeCCDebug(linenum, "%%param %s %s %d", + param->type, (param->name ? param->name : "no_name"), + param->flags); + param = param->next; + } + } + + /* Allocate the operation block */ + if((oper = (TreeCCOperation *)malloc(sizeof(TreeCCOperation))) == 0) + { + TreeCCOutOfMemory(context->input); + } + + /* Initialise the operation block */ + oper->name = name; + oper->className = className; + oper->returnType = returnType; + oper->defValue = defValue; + oper->params = params; + oper->flags = flags; + oper->numTriggers = numTriggers; + oper->filename = filename; + oper->linenum = linenum; + oper->firstCase = 0; + oper->lastCase = 0; + oper->sortedCases = 0; + oper->numCases = 0; + oper->header = context->headerStream; + oper->source = context->sourceStream; + + /* Add the operation to the hash table */ + hash = (TreeCCHashString(name) & (TREECC_HASH_SIZE - 1)); + oper->nextHash = context->operHash[hash]; + context->operHash[hash] = oper; + + /* Done */ + return oper; + } + + TreeCCOperation *TreeCCOperationFind(TreeCCContext *context, char *name) + { + unsigned int hash = (TreeCCHashString(name) & (TREECC_HASH_SIZE - 1)); + TreeCCOperation *oper = context->operHash[hash]; + while(oper != 0) + { + if(!strcmp(oper->name, name)) + { + return oper; + } + oper = oper->nextHash; + } + return 0; + } + + TreeCCOperationCase *TreeCCOperationAddCase + (TreeCCContext *context, TreeCCOperation *oper, + TreeCCTrigger *triggers, char *filename, long linenum) + { + TreeCCOperationCase *operCase; + + /* Print debugging information if required */ + if(context->debugMode) + { + if(!triggers) + { + TreeCCDebug(linenum, "%%case %s", oper->name); + } + else + { + TreeCCDebug(linenum, "%%case %s %s", triggers->node->name, + oper->name); + } + } + + /* Allocate the operation case block */ + if((operCase = (TreeCCOperationCase *)malloc(sizeof(TreeCCOperationCase))) + == 0) + { + TreeCCOutOfMemory(context->input); + } + + /* Initialise the operation case block */ + operCase->triggers = triggers; + operCase->code = 0; + operCase->oper = oper; + operCase->number = 0; + operCase->filename = filename; + operCase->linenum = linenum; + operCase->codeFilename = 0; + operCase->codeLinenum = 0; + operCase->next = 0; + operCase->nextHeader = 0; + + /* Add the case to the operation's case list */ + if(oper->lastCase) + { + oper->lastCase->next = operCase; + } + else + { + oper->firstCase = operCase; + } + oper->lastCase = operCase; + ++(oper->numCases); + + /* Return the case to the caller */ + return operCase; + } + + /* + * Verify the coverage of an operation over a node hierarchy. + */ + static void VerifyHierarchy(TreeCCContext *context, TreeCCOperation *oper, + TreeCCNode *node) + { + if((node->flags & TREECC_NODE_MARK(0)) != 0) + { + return; + } + if((node->flags & TREECC_NODE_ABSTRACT) == 0) + { + TreeCCErrorOnLine(context->input, oper->filename, oper->linenum, + "node type `%s' is not handled in operation `%s'", + node->name, oper->name); + return; + } + node = node->firstChild; + while(node != 0) + { + VerifyHierarchy(context, oper, node); + node = node->nextSibling; + } + } + + /* + * Append a parameter type name to a comma-separated string. + */ + static char *AppendParam(TreeCCContext *context, char *str, const char *type) + { + if(str) + { + int slen = strlen(str); + int tlen = strlen(type); + str = (char *)realloc(str, slen + tlen + 3); + if(!str) + { + TreeCCOutOfMemory(context->input); + } + strcpy(str + slen, ", "); + strcpy(str + slen + 2, type); + return str; + } + else + { + return TreeCCDupString((char *)type); + } + } + + /* + * Forward declaration. + */ + static void MarkMultiCase(TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCOperationCase *operCase, + TreeCCTrigger *nextTrigger); + + /* + * Scan down a node type hierarchy to mark all covered children. + */ + static void MarkMultiScan(TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCOperationCase *operCase, + TreeCCTrigger *nextTrigger, TreeCCNode *node) + { + /* Go in one level for this node */ + MarkMultiCase(sortedCases, base + node->position * multiplier, + multiplier * nextParam->size, nextParam->next, + operCase, nextTrigger->next); + + /* Scan all of the children */ + node = node->firstChild; + while(node != 0) + { + MarkMultiScan(sortedCases, base, multiplier, nextParam, + operCase, nextTrigger, node); + node = node->nextSibling; + } + } + + /* + * Mark all of the node types associated with an operation case. + */ + static void MarkMultiCase(TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCOperationCase *operCase, + TreeCCTrigger *nextTrigger) + { + /* Scan for the next trigger parameter */ + while(nextParam != 0 && (nextParam->flags & TREECC_PARAM_TRIGGER) == 0) + { + nextParam = nextParam->next; + } + + /* If we are out of triggers, then we need to set the current value */ + if(!nextParam) + { + if(sortedCases[base] == 0) + { + sortedCases[base] = operCase; + } + return; + } + + /* Scan down the node type hierarchy for this trigger level */ + MarkMultiScan(sortedCases, base, multiplier, nextParam, + operCase, nextTrigger, nextTrigger->node); + } + + /* + * Forward declaration. + */ + static void VerifyMultiCoverage(TreeCCContext *context, TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCNode **nodeStack, + TreeCCNode **nodeStackTop); + + /* + * Scan all children to verify a multi-coverage trigger. + */ + static void VerifyMultiScan(TreeCCContext *context, TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCNode *node, TreeCCNode **nodeStack, + TreeCCNode **nodeStackTop) + { + /* Go in one level for this node */ + *nodeStackTop = node; + VerifyMultiCoverage(context, oper, sortedCases, + base + node->position * multiplier, + multiplier * nextParam->size, + nextParam->next, nodeStack, nodeStackTop + 1); + + /* Scan all of the children */ + node = node->firstChild; + while(node != 0) + { + VerifyMultiScan(context, oper, sortedCases, base, multiplier, + nextParam, node, nodeStack, nodeStackTop); + node = node->nextSibling; + } + } + + /* + * Verify coverage of a multi-trigger operation. + */ + static void VerifyMultiCoverage(TreeCCContext *context, TreeCCOperation *oper, + TreeCCOperationCase **sortedCases, int base, + int multiplier, TreeCCParam *nextParam, + TreeCCNode **nodeStack, + TreeCCNode **nodeStackTop) + { + TreeCCNode *type; + + /* Scan for the next trigger */ + while(nextParam != 0 && (nextParam->flags & TREECC_PARAM_TRIGGER) == 0) + { + nextParam = nextParam->next; + } + + /* If we are out of triggers, then we need to do a test */ + if(!nextParam) + { + if(sortedCases[base] == 0) + { + /* No case: report an error if none of the node types + that led us here are abstract */ + int posn; + int isAbstract = 0; + for(posn = 0; posn < oper->numTriggers; ++posn) + { + if((nodeStack[posn]->flags & TREECC_NODE_ABSTRACT) != 0) + { + isAbstract = 1; + break; + } + } + if(!isAbstract) + { + char *str = 0; + for(posn = 0; posn < oper->numTriggers; ++posn) + { + str = AppendParam(context, str, nodeStack[posn]->name); + } + if(!str) + { + str = TreeCCDupString("?"); + } + TreeCCErrorOnLine(context->input, oper->filename, oper->linenum, + "case `%s' is missing from operation `%s'", + str, oper->name); + free(str); + } + } + return; + } + + /* Scan down the node type hierarchy for this parameter level */ + type = TreeCCNodeFindByType(context, nextParam->type); + if(!type) + { + return; + } + VerifyMultiScan(context, oper, sortedCases, base, + multiplier, nextParam, type, + nodeStack, nodeStackTop); + } + + /* + * Test the coverage of a multi-trigger operation. + */ + static void MultiCoverageTest(TreeCCContext *context, TreeCCOperation *oper) + { + TreeCCParam *param; + TreeCCParam *param2; + TreeCCNode *type; + TreeCCNode *type2; + int size; + TreeCCNode **nodeStack; + TreeCCOperationCase *operCase; + + /* Determine the size of the "sortedCases" array, and also + check to make sure there are no overlaps between triggers + that will cause position information to be inconsistent */ + size = 1; + param = oper->params; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + type = TreeCCNodeFindByType(context, param->type); + if(type) + { + param->size = TreeCCNodeAssignPositions(type); + size *= param->size; + param2 = oper->params; + while(param2 != 0) + { + if((param2->flags & TREECC_PARAM_TRIGGER) != 0 && + param2 != param) + { + type2 = TreeCCNodeFindByType(context, param2->type); + if(type2 && type2 != type) + { + if(TreeCCNodeInheritsFrom(type, type2) || + TreeCCNodeInheritsFrom(type2, type)) + { + TreeCCErrorOnLine(context->input, + oper->filename, oper->linenum, + "overlap between trigger types"); + return; + } + } + } + param2 = param2->next; + } + } + } + param = param->next; + } + + /* Create the "sortedCases" array */ + if((oper->sortedCases = (TreeCCOperationCase **)calloc + (size, sizeof(TreeCCOperationCase *))) == 0) + { + TreeCCOutOfMemory(context->input); + } + + /* Find the operation case to use for each combination of values */ + operCase = oper->firstCase; + while(operCase != 0) + { + MarkMultiCase(oper->sortedCases, 0, 1, oper->params, + operCase, operCase->triggers); + operCase = operCase->next; + } + + /* Verify that every combination of values has been handled */ + nodeStack = (TreeCCNode **)calloc(oper->numTriggers, sizeof(TreeCCNode *)); + if(!nodeStack) + { + TreeCCOutOfMemory(context->input); + } + VerifyMultiCoverage(context, oper, oper->sortedCases, 0, 1, + oper->params, nodeStack, nodeStack); + free(nodeStack); + } + + /* + * Test that an operation covers all relevant node type cases. + */ + static void OperationTest(TreeCCContext *context, TreeCCOperation *oper) + { + TreeCCOperationCase *operCase; + TreeCCTrigger *trigger; + TreeCCParam *param; + TreeCCNode *node; + + /* Clear the marking bits */ + TreeCCNodeClearMarking(context, TREECC_NODE_MARK_BITS); + + /* Print an error if the operation has no cases at all */ + if(!(oper->firstCase)) + { + TreeCCErrorOnLine(context->input, oper->filename, oper->linenum, + "operation `%s' has no cases", oper->name); + } + + /* Single or multiple triggers? */ + if(oper->numTriggers == 1) + { + /* Mark the coverage of all operation cases */ + operCase = oper->firstCase; + while(operCase != 0) + { + trigger = operCase->triggers; + if(trigger != 0) + { + if((trigger->node->flags & TREECC_NODE_MARK(0)) != 0) + { + TreeCCErrorOnLine(context->input, operCase->filename, + operCase->linenum, + "node type `%s' is handled multiple " + "times for operation `%s'", + trigger->node->name, oper->name); + } + else + { + trigger->node->flags |= TREECC_NODE_MARK(0); + } + } + operCase = operCase->next; + } + + /* Walk the node hierarchy to verify coverage */ + param = oper->params; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + node = TreeCCNodeFindByType(context, param->type); + if(node) + { + VerifyHierarchy(context, oper, node); + } + } + param = param->next; + } + } + else if(oper->numTriggers == 0) + { + /* Zero triggers: look for a single case definition */ + operCase = oper->firstCase; + if(operCase && operCase->next) + { + do + { + operCase = operCase->next; + TreeCCErrorOnLine(context->input, operCase->filename, + operCase->linenum, + "multiple definitions for operation `%s'", + oper->name); + } + while(operCase->next != 0); + TreeCCErrorOnLine(context->input, oper->firstCase->filename, + oper->firstCase->linenum, + "first definition here"); + } + } + else + { + /* Multiple triggers need a more complex algorithm to verify */ + if(oper->firstCase != 0) + { + MultiCoverageTest(context, oper); + } + } + } + + /* + * Compare two operation cases for a sort operation. + */ + static int CaseCompare(const void *e1, const void *e2) + { + TreeCCOperationCase *operCase1 = *((TreeCCOperationCase **)e1); + TreeCCOperationCase *operCase2 = *((TreeCCOperationCase **)e2); + TreeCCTrigger *trigger1 = operCase1->triggers; + TreeCCTrigger *trigger2 = operCase2->triggers; + TreeCCNode *ancestor1; + TreeCCNode *ancestor2; + while(trigger1 != 0 && trigger2 != 0) + { + if(trigger1->node != trigger2->node) + { + /* See if trigger1->node inherits from trigger2->node */ + ancestor1 = trigger1->node; + while(ancestor1->parent != 0) + { + if(ancestor1->parent == trigger2->node) + { + return -1; + } + ancestor1 = ancestor1->parent; + } + + /* See if trigger2->node inherits from trigger1->node */ + ancestor2 = trigger2->node; + while(ancestor2->parent != 0) + { + if(ancestor2->parent == trigger1->node) + { + return 1; + } + ancestor2 = ancestor2->parent; + } + + /* If the ancestors are separate, then use the node numbers + to order the separate trees. Note: this is highly unlikely + because operation definition forces all cases to inherit + from a declared common type. However, if we change this + requirement in the future, this code will be needed, so + we are being paranoid and including it now */ + if(ancestor1 != ancestor2) + { + if(ancestor1->number < ancestor2->number) + { + return -1; + } + else + { + return 1; + } + } + + /* This is the hard case: the two nodes are in separate + subtrees of the same ancestor, but we still need an + ordering between them. We need to find the lowest + common ancestor, and the nodes just below it */ + ancestor1 = trigger1->node; + while(ancestor1->parent != 0) + { + ancestor1 = ancestor1->parent; + ancestor1->flags |= TREECC_NODE_MARK(0); + } + ancestor2 = trigger2->node; + while(ancestor2->parent != 0) + { + if((ancestor2->parent->flags & TREECC_NODE_MARK(0)) != 0) + { + break; + } + ancestor2 = ancestor2->parent; + } + ancestor1 = trigger1->node; + while(ancestor1->parent != 0) + { + ancestor1 = ancestor1->parent; + ancestor1->flags &= ~(TREECC_NODE_MARK(0)); + } + ancestor1 = trigger1->node; + while(ancestor1->parent != ancestor2->parent) + { + ancestor1 = ancestor1->parent; + } + + /* ancestor1 and ancestor2 are now one step down + from the common ancestor that we found. Use + their node numbers to order the trees */ + if(ancestor1->number < ancestor2->number) + { + return -1; + } + else + { + return 1; + } + } + trigger1 = trigger1->next; + trigger2 = trigger2->next; + } + return 0; + } + + /* + * Sort a set of operation cases so that A precedes B + * if A inherits directly or indirectly from B. Operations + * with multiple triggers sort on the first, then the second, + * then the third, etc. + */ + static void SortCases(TreeCCContext *context, TreeCCOperation *oper) + { + TreeCCOperationCase **caseList; + TreeCCOperationCase *operCase; + int num; + + /* Bail out early if there are 0 or 1 cases, or no triggers */ + if(oper->numCases < 2 || !(oper->numTriggers)) + { + return; + } + + /* Clear the marking bits */ + TreeCCNodeClearMarking(context, TREECC_NODE_MARK_BITS); + + /* Build an array that contains all operation cases */ + if((caseList = (TreeCCOperationCase **)malloc + (sizeof(TreeCCOperationCase *) * oper->numCases)) == 0) + { + TreeCCOutOfMemory(context->input); + } + num = 0; + operCase = oper->firstCase; + while(operCase != 0) + { + caseList[num++] = operCase; + operCase = operCase->next; + } + + /* Sort the case list. There are probably more efficient + ways to do this (e.g. topological sorting), but this + version is perhaps easier to understand and maintain */ + #if HAVE_QSORT + qsort(caseList, oper->numCases, sizeof(TreeCCOperationCase *), CaseCompare); + #else + { + int i, j; + num = oper->numCases; + for(i = 0; i < (num - 1); ++i) + { + for(j = (i + 1); j < num; ++j) + { + if(CaseCompare(&(caseList[i]), &(caseList[j])) > 0) + { + operCase = caseList[i]; + caseList[i] = caseList[j]; + caseList[j] = operCase; + } + } + } + } + #endif + + /* Build a new case list from the sorted array */ + oper->firstCase = caseList[0]; + for(num = 1; num < oper->numCases; ++num) + { + caseList[num - 1]->next = caseList[num]; + } + oper->lastCase = caseList[oper->numCases - 1]; + caseList[oper->numCases - 1]->next = 0; + free(caseList); + } + + void TreeCCOperationValidate(TreeCCContext *context) + { + unsigned int hash; + TreeCCOperation *oper; + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + oper = context->operHash[hash]; + while(oper != 0) + { + if((oper->flags & TREECC_OPER_VIRTUAL) == 0) + { + /* Non-virtuals must be sorted for code generation, + and we also rely upon the sorted order to help us + test for operation coverage when multiple triggers + are used by the operation */ + SortCases(context, oper); + } + OperationTest(context, oper); + oper = oper->nextHash; + } + } + } + + TreeCCOperationCase *TreeCCOperationFindCase + (TreeCCContext *context, TreeCCNode *node, char *name) + { + TreeCCOperation *oper; + TreeCCOperationCase *operCase; + oper = TreeCCOperationFind(context, name); + if(!oper) + { + return 0; + } + operCase = oper->firstCase; + while(operCase != 0) + { + if(operCase->triggers && operCase->triggers->node == node) + { + return operCase; + } + operCase = operCase->next; + } + return 0; + } + + void TreeCCOperationVisitAll(TreeCCContext *context, + TreeCCOperationVisitor visitor) + { + unsigned int hash; + TreeCCOperation *oper; + for(hash = 0; hash < TREECC_HASH_SIZE; ++hash) + { + oper = context->operHash[hash]; + while(oper != 0) + { + (*visitor)(context, oper); + oper = oper->nextHash; + } + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/options.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/options.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/options.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,467 ---- + /* + * options.c - Process options from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "options.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * "track_lines": track line numbers when creating new nodes. + */ + static int TrackLinesOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->track_lines = flag; + return TREECC_OPT_OK; + } + } + + /* + * "no_singletons": suppress special create code for singletons. + */ + static int NoSingletonsOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->no_singletons = flag; + return TREECC_OPT_OK; + } + } + + /* + * "reentrant": generate re-entrant tree handling code. + */ + static int ReentrantOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->reentrant = flag; + return TREECC_OPT_OK; + } + } + + /* + * "force": force source files to be created even if unchanged. + */ + static int ForceOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->force = flag; + return TREECC_OPT_OK; + } + } + + /* + * "virtual_factory": use virtual factory methods. + */ + static int VirtualFactoryOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->virtual_factory = flag; + return TREECC_OPT_OK; + } + } + + /* + * "abstract_factory": use abstract factory methods. + */ + static int AbstractFactoryOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->abstract_factory = flag; + return TREECC_OPT_OK; + } + } + + /* + * "kind_in_vtable": put the kind value in the vtable, and not the node. + */ + static int KindInVtableOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->kind_in_vtable = flag; + return TREECC_OPT_OK; + } + } + + /* + * "prefix": specify the prefix to use instead of "yy". + */ + static int PrefixOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else + { + context->yy_replacement = value; + return TREECC_OPT_KEEP_VALUE; + } + } + + /* + * "state_type": specify the type name to use for re-entrant state. + */ + static int StateTypeOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else + { + context->state_type = value; + return TREECC_OPT_KEEP_VALUE; + } + } + + /* + * "namespace": specify the namespace to use for subsequent definitions. + */ + static int NamespaceOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else if(*value == '\0') + { + /* Put following declarations into the global namespace */ + context->namespace = 0; + return TREECC_OPT_OK; + } + else + { + context->namespace = value; + return TREECC_OPT_KEEP_VALUE; + } + } + + /* + * "base": specify a new base to use for node type identifiers. + */ + static int BaseOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else if(*value == '\0') + { + return TREECC_OPT_INVALID_VALUE; + } + else + { + int num = 0; + while(*value >= '0' && *value <= '9') + { + num = num * 10 + (int)(*value - '0'); + ++value; + } + if(*value != '\0') + { + return TREECC_OPT_INVALID_VALUE; + } + context->nodeNumber = num; + return TREECC_OPT_OK; + } + } + + /* + * "lang": specify the source language to use in the output files. + */ + static int LangOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else + { + if(!strcmp(value, "c") || !strcmp(value, "C")) + { + context->language = TREECC_LANG_C; + } + else if(!strcmp(value, "c++") || !strcmp(value, "C++")) + { + context->language = TREECC_LANG_CPP; + } + else if(!strcmp(value, "java") || !strcmp(value, "Java")) + { + context->language = TREECC_LANG_JAVA; + } + else if(!strcmp(value, "c#") || !strcmp(value, "C#") || + !strcmp(value, "csharp")) + { + context->language = TREECC_LANG_CSHARP; + } + else if(!strcmp(value, "ruby") || !strcmp(value, "Ruby")) + { + context->language = TREECC_LANG_RUBY; + } + else if(!strcmp(value, "php") || !strcmp(value, "PHP")) + { + context->language = TREECC_LANG_PHP; + } + else + { + return TREECC_OPT_INVALID_VALUE; + } + return TREECC_OPT_OK; + } + } + + /* + * "block_size": specify a new block size for C and C++ allocators. + */ + static int BlockSizeOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else if(*value == '\0') + { + return TREECC_OPT_INVALID_VALUE; + } + else + { + int num = 0; + while(*value >= '0' && *value <= '9') + { + num = num * 10 + (int)(*value - '0'); + ++value; + } + if(*value != '\0') + { + return TREECC_OPT_INVALID_VALUE; + } + context->block_size = num; + return TREECC_OPT_OK; + } + } + + + + /* + * "print_lines": print out line number directives. + */ + static int PrintLineNumberOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->print_lines = flag; + return TREECC_OPT_OK; + } + } + + /* + * "strip_filenames": strip filenames in #line directives down + * to their base name, with no directory information. + */ + static int StripFilenamesOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->strip_filenames = flag; + return TREECC_OPT_OK; + } + } + + /* + * "internal_access": use "internal" access on classes in C#, instead + * of using "public". "public_access" is used to select "public". + */ + static int InternalAccessOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->internal_access = flag; + return TREECC_OPT_OK; + } + } + + /* + * "allocator": use (or don't use) the standard treecc allocator for C/C++. + */ + static int AllocatorOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->use_allocator = flag; + return TREECC_OPT_OK; + } + } + + /* + * "gc_allocator": use (or don't use) the libgc treecc allocator for C/C++. + */ + static int GCAllocatorOption(TreeCCContext *context, char *value, int flag) + { + if(value) + { + return TREECC_OPT_NO_VALUE; + } + else + { + context->use_gc_allocator = flag; + return TREECC_OPT_OK; + } + } + + /* + * "base_type": use the type as the base type for the root treecc node + */ + static int BaseTypeOption(TreeCCContext *context, char *value, int flag) + { + if(!value) + { + return TREECC_OPT_NEED_VALUE; + } + else if(value == '\0') + { + context->baseType = 0; + return TREECC_OPT_OK; + } + else + { + context->baseType = value; + return TREECC_OPT_KEEP_VALUE; + } + } + + /* + * Table of option handlers. + */ + static struct + { + const char *name; + int (*func)(TreeCCContext *context, char *value, int flag); + int flag; + + } const OptionHandlers[] = { + {"track_lines", TrackLinesOption, 1}, + {"no_track_lines", TrackLinesOption, 0}, + {"no_singletons", NoSingletonsOption, 1}, + {"singletons", NoSingletonsOption, 0}, + {"reentrant", ReentrantOption, 1}, + {"no_reentrant", ReentrantOption, 0}, + {"force", ForceOption, 1}, + {"no_force", ForceOption, 0}, + {"virtual_factory", VirtualFactoryOption, 1}, + {"no_virtual_factory", VirtualFactoryOption, 0}, + {"abstract_factory", AbstractFactoryOption, 1}, + {"no_abstract_factory", AbstractFactoryOption, 0}, + {"kind_in_vtable", KindInVtableOption, 1}, + {"kind_in_node", KindInVtableOption, 0}, + {"prefix", PrefixOption, 0}, + {"state_type", StateTypeOption, 0}, + {"namespace", NamespaceOption, 0}, + {"package", NamespaceOption, 0}, + {"base", BaseOption, 0}, + {"lang", LangOption, 0}, + {"block_size", BlockSizeOption, 0}, + {"strip_filenames", StripFilenamesOption, 1}, + {"print_lines", PrintLineNumberOption, 1}, + {"no_print_lines", PrintLineNumberOption, 0}, + {"no_strip_filenames", StripFilenamesOption, 0}, + {"internal_access", InternalAccessOption, 1}, + {"public_access", InternalAccessOption, 0}, + {"allocator", AllocatorOption, 1}, + {"no_allocator", AllocatorOption, 0}, + {"gc_allocator", GCAllocatorOption, 1}, + {"no_gc_allocator", GCAllocatorOption, 0}, + {"base_type", BaseTypeOption, 0}, + {0, 0, 0}, + }; + + int TreeCCOptionProcess(TreeCCContext *context, char *name, char *value) + { + int opt = 0; + while(OptionHandlers[opt].name != 0) + { + if(!strcmp(name, OptionHandlers[opt].name)) + { + return (*(OptionHandlers[opt].func)) + (context, value, OptionHandlers[opt].flag); + } + ++opt; + } + return TREECC_OPT_UNKNOWN; + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/options.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/options.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/options.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,47 ---- + /* + * options.h - Process options from "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_OPTIONS_H + #define _TREECC_OPTIONS_H + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Return values from "TreeCCOptionProcess". + */ + #define TREECC_OPT_OK 0 + #define TREECC_OPT_KEEP_VALUE 1 + #define TREECC_OPT_UNKNOWN 2 + #define TREECC_OPT_INVALID_VALUE 3 + #define TREECC_OPT_NEED_VALUE 4 + #define TREECC_OPT_NO_VALUE 5 + + /* + * Process an option declaration. + */ + int TreeCCOptionProcess(TreeCCContext *context, char *name, char *value); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_OPTIONS_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/parse.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/parse.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/parse.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,1461 ---- + /* + * parse.c - Parse "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "parse.h" + #include "errors.h" + #include "options.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Append two strings and return a malloc'ed result. + */ + static char *AppendStrings(TreeCCInput *input, char *str1, + char *str2, int sep, int free2) + { + int len1 = strlen(str1); + int len2 = strlen(str2); + int len = len1 + len2 + sep + 1; + char *value = (char *)realloc(str1, len); + if(!value) + { + TreeCCOutOfMemory(input); + } + if(sep) + { + value[len1] = ' '; + strcpy(value + len1 + 1, str2); + value[len1 + len2 + 1] = '\0'; + } + else + { + strcpy(value + len1, str2); + value[len1 + len2] = '\0'; + } + if(free2) + { + free(str2); + } + return value; + } + + /* + * Parse a type specification and variable name using a + * simplified subset of C type syntax. + * + * TypeAndName ::= Type [IDENTIFIER] + * + * Type ::= TypeName + * | Type '*' + * | Type '&' + * | Type '[' ']' + * TypeName ::= IDENTIFIER { IDENTIFIER } + * + * Examples are "expression", "const char *", and "Item[]". + * Types that don't fit this pattern should use typedef'ed + * names from the underlying source language. + */ + static void ParseTypeAndName(TreeCCInput *input, char **type, char **name) + { + char *tempType; + char *last; + + /* Type names must begin with an identifier */ + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "type name expected"); + *type = 0; + *name = 0; + return; + } + + /* Collect up the identifiers within the type name. + We don't add the last to "tempType" until we've + seen what comes after it. This resolves the + ambiguity in the grammar */ + tempType = 0; + last = 0; + while(input->token == TREECC_TOKEN_IDENTIFIER) + { + if(!tempType) + { + /* This is the first identifier, which is + always part of the type */ + tempType = TreeCCValue(input); + } + else if(!last) + { + /* No last identifier yet, so just save this one */ + last = TreeCCValue(input); + } + else + { + /* Append "last" to "tempType" */ + tempType = AppendStrings(input, tempType, last, 1, 1); + + /* Save the new identifier as "last" */ + last = TreeCCValue(input); + } + TreeCCNextToken(input); + } + + /* If the next token is '*', '&', or '[', then "last" is + part of the type name, and not the variable name */ + if(last && (input->token == TREECC_TOKEN_STAR || + input->token == TREECC_TOKEN_REF || + input->token == TREECC_TOKEN_LSQUARE)) + { + tempType = AppendStrings(input, tempType, last, 1, 1); + last = 0; + } + + /* Parse the type suffixes */ + while(input->token == TREECC_TOKEN_STAR || + input->token == TREECC_TOKEN_REF || + input->token == TREECC_TOKEN_LSQUARE) + { + if(input->token == TREECC_TOKEN_STAR) + { + tempType = AppendStrings(input, tempType, "*", 1, 0); + } + else if(input->token == TREECC_TOKEN_REF) + { + tempType = AppendStrings(input, tempType, "&", 1, 0); + } + else + { + tempType = AppendStrings(input, tempType, "[]", 0, 0); + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_RSQUARE) + { + TreeCCError(input, "`]' expected"); + continue; + } + } + TreeCCNextToken(input); + } + + /* Parse the variable name, if necessary */ + if(!last && input->token == TREECC_TOKEN_IDENTIFIER) + { + last = TreeCCValue(input); + TreeCCNextToken(input); + } + + /* Return the values to the caller */ + *type = tempType; + *name = last; + } + + /* + * Parse a node definition. + * + * Node ::= %node IDENTIFIER [ IDENTIFIER ] { NodeFlag } [ "=" Fields ] + * NodeFlag ::= %abstract | %typedef + * Fields ::= "{" { Field } "}" + * Field ::= [ %nocreate ] TypeAndName [ "=" LITERAL_CODE ] ";" + */ + static void ParseNode(TreeCCContext *context) + { + TreeCCInput *input = context->input; + char *name; + char *parent; + int flags; + long linenum; + TreeCCNode *node; + char *fieldName; + char *fieldType; + char *fieldValue; + + /* Skip the "%node" keyword */ + TreeCCNextToken(input); + linenum = input->linenum; + + /* We need an identifier for the node that is being declared */ + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + /* Report an error for the identifier */ + TreeCCError(input, "identifier expected"); + return; + } + name = TreeCCValue(input); + TreeCCNextToken(input); + + /* Get the name of the parent */ + if(input->token == TREECC_TOKEN_IDENTIFIER) + { + parent = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + parent = 0; + } + + /* Parse the node definition flags */ + flags = 0; + for(;;) + { + if(input->token == TREECC_TOKEN_ABSTRACT) + { + flags |= TREECC_NODE_ABSTRACT; + TreeCCNextToken(input); + } + else if(input->token == TREECC_TOKEN_TYPEDEF) + { + flags |= TREECC_NODE_TYPEDEF; + TreeCCNextToken(input); + } + else + { + break; + } + } + + /* Create the node */ + node = TreeCCNodeCreate(context, linenum, name, parent, flags); + + /* If we have a field definition block, then read it */ + if(input->token == TREECC_TOKEN_EQUALS) + { + input->parseLiteral = 0; + TreeCCNextToken(input); + input->parseLiteral = 1; + if(input->token == TREECC_TOKEN_LBRACE) + { + /* Skip the "{" token */ + TreeCCNextToken(input); + + /* Process the field definitions */ + while(input->token != TREECC_TOKEN_RBRACE && + input->token != TREECC_TOKEN_EOF) + { + /* Skip spurious semi-colons in the field definition */ + if(input->token == TREECC_TOKEN_SEMI) + { + TreeCCNextToken(input); + continue; + } + + /* Process field definition flags */ + if(input->token == TREECC_TOKEN_NOCREATE) + { + flags = TREECC_FIELD_NOCREATE; + TreeCCNextToken(input); + } + else + { + flags = 0; + } + + /* Parse the field type and name */ + ParseTypeAndName(input, &fieldType, &fieldName); + if(fieldType && fieldName) + { + if(input->token == TREECC_TOKEN_EQUALS) + { + TreeCCNextToken(input); + if(input->token == TREECC_TOKEN_LITERAL_CODE) + { + fieldValue = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + TreeCCError + (input, "literal code constant expected"); + fieldValue = 0; + } + } + else + { + fieldValue = 0; + } + if(fieldValue && (flags & TREECC_FIELD_NOCREATE) == 0) + { + TreeCCError(input, + "default values can only be specified for " + "`%%nocreate' fields"); + } + TreeCCFieldCreate(context, node, fieldName, fieldType, + fieldValue, flags); + } + else + { + if(fieldType) + { + TreeCCError(input, "field name expected"); + } + else + { + TreeCCError(input, "field declaration expected"); + } + if(fieldType) + { + free(fieldType); + } + if(fieldName) + { + free(fieldName); + } + + /* Attempt to recover from the error */ + while(input->token != TREECC_TOKEN_SEMI && + input->token != TREECC_TOKEN_RBRACE && + input->token != TREECC_TOKEN_IDENTIFIER && + input->token != TREECC_TOKEN_EOF) + { + TreeCCNextToken(input); + } + } + + /* Recognize the ";" at the end of the field */ + if(input->token == TREECC_TOKEN_SEMI) + { + TreeCCNextToken(input); + } + else + { + /* Attempt to recover from the lack of a semi-colon */ + TreeCCError(input, "`;' expected"); + if(input->token != TREECC_TOKEN_IDENTIFIER && + input->token != TREECC_TOKEN_RBRACE) + { + TreeCCNextToken(input); + } + } + } + + /* Skip the "}" token */ + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "field definition block expected"); + } + } + } + + /* + * Validate trigger type suffixes against the language. + */ + static void ValidateSuffixes(TreeCCContext *context, const char *type, + TreeCCNode *node, char *filename, long linenum) + { + int len = strlen(type); + if(context->language == TREECC_LANG_C || + context->language == TREECC_LANG_CPP) + { + if((node->flags & TREECC_NODE_ENUM) == 0 && + (node->flags & TREECC_NODE_ENUM_VALUE) == 0) + { + if(len < 2 || type[len - 1] != '*' || + type[len - 2] != ' ') + { + TreeCCErrorOnLine(context->input, filename, linenum, + "trigger types must end in `*'"); + } + } + } + } + + /* + * Parse an operation definition. + * + * Operation ::= %operation { OperFlag } Type [ClassName ] IDENTIFIER + * '(' [ Params ] ')' [ '=' LITERAL_CODE ] [ ';' ] + * OperFlag ::= %virtual | %inline + * ClassName ::= IDENTIFIER "::" + * Params ::= Param { ',' Param } + * Param ::= TypeAndName | '[' TypeAndName ']' + */ + static void ParseOperation(TreeCCContext *context) + { + TreeCCInput *input = context->input; + int flags; + char *returnType; + char *name; + char *className; + char *defValue; + TreeCCParam *params = 0; + TreeCCParam *lastParam = 0; + TreeCCParam *newParam; + int numTriggers = 0; + char *paramType; + char *paramName; + int paramFlags; + TreeCCOperation *oper; + char *filename; + long linenum; + TreeCCNode *typeNode; + + /* Skip the "%operation" keyword */ + TreeCCNextToken(input); + + /* Parse the operation flags */ + flags = 0; + for(;;) + { + if(input->token == TREECC_TOKEN_VIRTUAL) + { + flags |= TREECC_OPER_VIRTUAL; + TreeCCNextToken(input); + } + else if(input->token == TREECC_TOKEN_INLINE) + { + flags |= TREECC_OPER_INLINE; + TreeCCNextToken(input); + } + else if(input->token == TREECC_TOKEN_SPLIT) + { + flags |= TREECC_OPER_SPLIT; + TreeCCNextToken(input); + } + else + { + break; + } + } + if((flags & TREECC_OPER_VIRTUAL) != 0 && + (flags & TREECC_OPER_INLINE) != 0) + { + TreeCCError(input, "`virtual' and `inline' cannot be used together"); + flags &= ~TREECC_OPER_INLINE; + } + + /* Parse the return type and name of the operation */ + ParseTypeAndName(input, &returnType, &name); + filename = input->filename; + linenum = input->linenum; + if(!returnType || !name) + { + if(returnType) + { + TreeCCError(input, "operation name expected"); + } + else + { + TreeCCError(input, "operation return type expected"); + } + if(returnType) + { + free(returnType); + } + if(name) + { + free(name); + } + return; + } + + /* If the next token is "::", then "name" is actually the + class name and we need to get the real operation name */ + if(input->token == TREECC_TOKEN_COLON_COLON) + { + className = name; + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "operation name expected"); + free(returnType); + free(className); + return; + } + name = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + className = 0; + } + + /* If the operation is non-virtual, and the language is C#, + then we must have a class name which is different from + the operation name. This is necessary because of a + "feature" in the design of C# and Microsoft's compilers */ + if((flags & TREECC_OPER_VIRTUAL) == 0 && + context->language == TREECC_LANG_CSHARP) + { + if(!className) + { + TreeCCErrorOnLine(input, filename, linenum, + "C# requires that a class name be specified"); + } + else if(!strcmp(className, name)) + { + TreeCCErrorOnLine(input, filename, linenum, + "C# requires different class and operation names"); + } + } + + /* Parse the parameter list for the operation */ + if(input->token == TREECC_TOKEN_LPAREN) + { + TreeCCNextToken(input); + while(input->token == TREECC_TOKEN_IDENTIFIER || + input->token == TREECC_TOKEN_LSQUARE) + { + /* Parse the parameter information */ + if(input->token == TREECC_TOKEN_IDENTIFIER) + { + paramFlags = 0; + ParseTypeAndName(input, ¶mType, ¶mName); + } + else + { + paramFlags = TREECC_PARAM_TRIGGER; + TreeCCNextToken(input); + ParseTypeAndName(input, ¶mType, ¶mName); + if(input->token == TREECC_TOKEN_RSQUARE) + { + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "`]' expected"); + } + ++numTriggers; + } + + /* Create the parameter block */ + if(!paramType) + { + TreeCCError(input, "parameter declaration expected"); + } + else if(!strcmp(paramType, "void")) + { + /* Ignore "void" parameters */ + free(paramType); + if(paramName) + { + free(paramName); + } + } + else + { + newParam = (TreeCCParam *)malloc(sizeof(TreeCCParam)); + if(!newParam) + { + TreeCCOutOfMemory(input); + } + newParam->name = paramName; + newParam->type = paramType; + newParam->flags = paramFlags; + newParam->size = 0; + newParam->next = 0; + if(lastParam) + { + lastParam->next = newParam; + } + else + { + params = newParam; + } + lastParam = newParam; + if((paramFlags & TREECC_PARAM_TRIGGER) != 0) + { + if((typeNode = TreeCCNodeFindByType(context, paramType)) + == 0) + { + TreeCCError(input, "`%s' is not a valid trigger type", + paramType); + } + else + { + ValidateSuffixes(context, paramType, typeNode, + input->filename, input->linenum); + } + } + } + + /* Skip the comma and go on to the next parameter */ + if(input->token == TREECC_TOKEN_COMMA) + { + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_IDENTIFIER && + input->token != TREECC_TOKEN_LSQUARE) + { + TreeCCError(input, "parameter declaration expected"); + } + } + else + { + break; + } + } + if(input->token == TREECC_TOKEN_RPAREN) + { + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "`)' expected"); + } + } + else + { + TreeCCError(input, "`(' expected"); + } + + /* Recognise the default value, if present */ + if(input->token == TREECC_TOKEN_EQUALS) + { + TreeCCNextToken(input); + if(input->token == TREECC_TOKEN_LITERAL_CODE) + { + defValue = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "default value expected"); + defValue = 0; + } + } + else + { + defValue = 0; + if((flags & TREECC_OPER_VIRTUAL) == 0 && + strcmp(returnType, "void") != 0) + { + TreeCCError(input, "default value required"); + } + } + + /* Recognise an optional semi-colon */ + if(input->token == TREECC_TOKEN_SEMI) + { + TreeCCNextToken(input); + } + + /* Set a default trigger parameter if necessary */ + if(numTriggers == 0 && params != 0) + { + numTriggers = 1; + params->flags |= TREECC_PARAM_TRIGGER; + if((typeNode = TreeCCNodeFindByType(context, params->type)) == 0) + { + TreeCCErrorOnLine(input, filename, linenum, + "`%s' is not a valid trigger type", + params->type); + } + else + { + ValidateSuffixes(context, params->type, typeNode, + filename, linenum); + } + } + + /* If the operation is virtual, then check that the first + parameter is the sole trigger for the operation */ + if((flags & TREECC_OPER_VIRTUAL) != 0) + { + if(!params || numTriggers != 1 || + (params->flags & TREECC_PARAM_TRIGGER) == 0) + { + if(!params) + { + TreeCCError(input, + "virtual operations must have at least one parameter"); + } + else + { + TreeCCError(input, + "the first parameter of a virtual must be the trigger"); + } + flags &= ~TREECC_OPER_VIRTUAL; + } + else if((typeNode = TreeCCNodeFindByType(context, params->type)) == 0) + { + flags &= ~TREECC_OPER_VIRTUAL; + } + else if((typeNode->flags & TREECC_NODE_ENUM) != 0) + { + TreeCCError(input, + "cannot use enumerated types as triggers for virtual operations"); + flags &= ~TREECC_OPER_VIRTUAL; + } + } + + /* See if we already have an operation with this name */ + oper = TreeCCOperationFind(context, name); + if(oper != 0) + { + TreeCCErrorOnLine(input, filename, linenum, + "operation `%s' is already declared", name); + TreeCCErrorOnLine(input, oper->filename, oper->linenum, + "previous declaration here"); + free(returnType); + free(name); + if(className) + { + free(className); + } + if(defValue) + { + free(defValue); + } + while(params != 0) + { + newParam = params->next; + if(params->name) + { + free(params->name); + } + if(params->type) + { + free(params->type); + } + free(params); + params = newParam; + } + return; + } + + /* Create the operation */ + oper = TreeCCOperationCreate(context, returnType, name, className, + defValue, params, flags, numTriggers, + filename, linenum); + + /* If the operation is virtual, then attach it to the node type */ + if((flags & TREECC_OPER_VIRTUAL) != 0) + { + TreeCCNodeAddVirtual + (context, TreeCCNodeFindByType(context, params->type), oper); + } + } + + /* + * Parse an operation case header. + * + * OperationHead ::= IDENTIFIER '(' [ TypeList ] ')' + * TypeList ::= IDENTIFIER { ',' IDENTIFIER } + */ + static TreeCCOperationCase *ParseOperationHeader(TreeCCContext *context) + { + TreeCCInput *input = context->input; + TreeCCTrigger *triggers = 0; + TreeCCTrigger *lastTrigger = 0; + TreeCCTrigger *newTrigger; + TreeCCOperation *oper; + TreeCCNode *node; + int fatalError = 0; + int numTriggers = 0; + char *filename; + long linenum; + + /* Look up the operation name */ + filename = input->filename; + linenum = input->linenum; + oper = TreeCCOperationFind(context, input->text); + if(!oper) + { + TreeCCError(input, "operation `%s' is not declared", input->text); + fatalError = 1; + } + TreeCCNextToken(input); + + /* Parse the type trigger list */ + if(input->token == TREECC_TOKEN_LPAREN) + { + TreeCCNextToken(input); + while(input->token == TREECC_TOKEN_IDENTIFIER) + { + ++numTriggers; + node = TreeCCNodeFind(context, input->text); + if(!node) + { + TreeCCError(input, "node type `%s' is not declared", + input->text); + fatalError = 1; + } + newTrigger = (TreeCCTrigger *)malloc(sizeof(TreeCCTrigger)); + if(!newTrigger) + { + TreeCCOutOfMemory(input); + } + newTrigger->node = node; + newTrigger->next = 0; + if(lastTrigger) + { + lastTrigger->next = newTrigger; + } + else + { + triggers = newTrigger; + } + lastTrigger = newTrigger; + TreeCCNextToken(input); + if(input->token == TREECC_TOKEN_COMMA) + { + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "type name expected"); + } + } + else + { + if(input->token != TREECC_TOKEN_RPAREN) + { + TreeCCError(input, "`,' expected"); + } + break; + } + } + if(input->token == TREECC_TOKEN_RPAREN) + { + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "`)' expected"); + } + } + else + { + TreeCCError(input, "`(' expected"); + } + + /* Check that we have a trigger match for the operation */ + if(oper) + { + if(oper->numTriggers != numTriggers) + { + TreeCCErrorOnLine(input, filename, linenum, + "incorrect number of triggers for operation"); + TreeCCErrorOnLine(input, oper->filename, oper->linenum, + "operation declared here"); + fatalError = 1; + } + else + { + TreeCCParam *param = oper->params; + int reportedError = 0; + newTrigger = triggers; + while(param != 0) + { + if((param->flags & TREECC_PARAM_TRIGGER) != 0) + { + node = TreeCCNodeFindByType(context, param->type); + if(node && !TreeCCNodeInheritsFrom(newTrigger->node, node)) + { + if(newTrigger->node) + { + TreeCCErrorOnLine(input, filename, linenum, + "node type `%s' does not inherit from `%s'", + newTrigger->node->name, node->name); + reportedError = 1; + fatalError = 1; + } + } + newTrigger = newTrigger->next; + } + param = param->next; + } + if(reportedError) + { + TreeCCErrorOnLine(input, oper->filename, oper->linenum, + "operation declared here"); + } + } + } + + /* Bail out if we've seen a fatal error */ + if(fatalError) + { + while(triggers != 0) + { + newTrigger = triggers->next; + free(triggers); + triggers = newTrigger; + } + return 0; + } + + /* Add the operation case to the operation */ + return TreeCCOperationAddCase(context, oper, triggers, filename, linenum); + } + + /* + * Parse an operation case definition. + * + * OperationCase ::= OperationHead { ',' OperationHead } LiteralCode + */ + static void ParseOperationCase(TreeCCContext *context) + { + TreeCCInput *input = context->input; + TreeCCOperationCase *operCase; + TreeCCOperationCase *caseList; + char *code; + char *codeFilename; + long codeLinenum; + + /* Parse the operation case headers */ + caseList = 0; + while(input->token == TREECC_TOKEN_IDENTIFIER) + { + operCase = ParseOperationHeader(context); + if(operCase) + { + operCase->nextHeader = caseList; + caseList = operCase; + } + if(input->token == TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "`,' expected"); + continue; + } + if(input->token != TREECC_TOKEN_COMMA) + { + break; + } + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "identifier expected"); + } + } + + /* Recognise the code for the operation case */ + codeFilename = input->filename; + codeLinenum = input->linenum; + if(input->token == TREECC_TOKEN_LITERAL_CODE) + { + code = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + code = 0; + TreeCCError(input, "code block expected"); + } + + /* Add the code to all of the operation cases */ + if(code) + { + operCase = caseList; + while(operCase != 0) + { + operCase->code = code; + operCase->codeFilename = codeFilename; + operCase->codeLinenum = codeLinenum; + operCase = operCase->nextHeader; + } + } + } + + /* + * Parse an option declaration. + * + * Option ::= %option IDENTIFIER [ '=' Value ] + * Value ::= IDENTIFIER | STRING + */ + static void ParseOption(TreeCCContext *context) + { + TreeCCInput *input = context->input; + char *name; + char *value; + char *filename; + long linenum; + int optValue; + + /* Skip the "%option" keyword */ + TreeCCNextToken(input); + + /* Recognise the option name */ + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "option name expected"); + return; + } + name = TreeCCValue(input); + filename = input->filename; + linenum = input->linenum; + TreeCCNextToken(input); + + /* Recognise the option value, if present */ + if(input->token == TREECC_TOKEN_EQUALS) + { + TreeCCNextToken(input); + if(input->token == TREECC_TOKEN_IDENTIFIER || + input->token == TREECC_TOKEN_STRING) + { + value = TreeCCValue(input); + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "identifier or string expected"); + value = 0; + } + } + else + { + value = 0; + } + + /* Dump the option to the debug stream if necessary */ + if(context->debugMode) + { + if(value) + { + TreeCCDebug(linenum, "%%option %s %s", name, value); + } + else + { + TreeCCDebug(linenum, "%%option %s", name); + } + } + + /* Process the option */ + optValue = TreeCCOptionProcess(context, name, value); + if(optValue == TREECC_OPT_UNKNOWN) + { + TreeCCErrorOnLine(input, filename, linenum, + "unknown option `%s'", name); + } + else if(optValue == TREECC_OPT_INVALID_VALUE) + { + TreeCCErrorOnLine(input, filename, linenum, + "invalid value for option `%s'", name); + } + else if(optValue == TREECC_OPT_NEED_VALUE) + { + TreeCCErrorOnLine(input, filename, linenum, + "option `%s' requires a value", name); + } + else if(optValue == TREECC_OPT_NO_VALUE) + { + TreeCCErrorOnLine(input, filename, linenum, + "option `%s' does not take a value", name); + } + + /* Clean up the memory that we used */ + free(name); + if(optValue != TREECC_OPT_KEEP_VALUE && value) + { + free(value); + } + } + + /* + * Parse an enumerated type declaration. + * + * Enum ::= %enum IDENTIFIER '=' EnumBody + * EnumBody ::= '{' IDENTIFIER { ',' IDENTIFIER } [ ',' ] '}' + */ + static void ParseEnum(TreeCCContext *context) + { + TreeCCInput *input = context->input; + char *name; + TreeCCNode *node; + int sawValue; + + /* Skip the "%enum" keyword */ + TreeCCNextToken(input); + + /* Get the name of the enumerated type */ + if(input->token != TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "enumerated type name expected"); + return; + } + name = TreeCCValue(input); + + /* Create a node for the enumerated type */ + node = TreeCCNodeCreate(context, input->linenum, name, 0, + TREECC_NODE_ABSTRACT | + TREECC_NODE_TYPEDEF | + TREECC_NODE_ENUM); + + /* Parse the start of the enumeration body */ + TreeCCNextToken(input); + if(input->token != TREECC_TOKEN_EQUALS) + { + TreeCCError(input, "`=' expected"); + return; + } + input->parseLiteral = 0; + TreeCCNextToken(input); + input->parseLiteral = 1; + if(input->token != TREECC_TOKEN_LBRACE) + { + TreeCCError(input, "`{' expected"); + return; + } + TreeCCNextToken(input); + + /* Parse the enumeration body */ + sawValue = 0; + while(input->token == TREECC_TOKEN_IDENTIFIER) + { + TreeCCNodeCreate(context, input->linenum, + TreeCCValue(input), + TreeCCDupString(node->name), + TREECC_NODE_ENUM_VALUE); + sawValue = 1; + TreeCCNextToken(input); + if(input->token == TREECC_TOKEN_COMMA) + { + TreeCCNextToken(input); + } + else if(input->token == TREECC_TOKEN_IDENTIFIER) + { + TreeCCError(input, "`,' expected"); + } + else + { + break; + } + } + if(input->token == TREECC_TOKEN_COMMA) + { + /* Permit an extra trailing comma */ + TreeCCNextToken(input); + } + if(!sawValue) + { + TreeCCError(input, "no values were specified for the enumeration"); + } + + /* Recognise the end of the enumeration body */ + if(input->token == TREECC_TOKEN_RBRACE) + { + TreeCCNextToken(input); + } + else + { + TreeCCError(input, "`}' expected"); + } + } + + /* + * Determine if a token is the start of a declaration. + */ + #define IsStartDecl(token) \ + ((token) == TREECC_TOKEN_EOF || \ + (token) == TREECC_TOKEN_IDENTIFIER || \ + (token) == TREECC_TOKEN_LITERAL_DEFNS || \ + (token) == TREECC_TOKEN_LITERAL_END || \ + (token) == TREECC_TOKEN_NODE || \ + (token) == TREECC_TOKEN_OPERATION || \ + (token) == TREECC_TOKEN_OPTION || \ + (token) == TREECC_TOKEN_HEADER || \ + (token) == TREECC_TOKEN_OUTPUT || \ + (token) == TREECC_TOKEN_BOTH || \ + (token) == TREECC_TOKEN_DECLS || \ + (token) == TREECC_TOKEN_END || \ + (token) == TREECC_TOKEN_ENUM || \ + (token) == TREECC_TOKEN_COMMON || \ + (token) == TREECC_TOKEN_INCLUDE) + + /* + * File ::= { Declaration } + * Declaration ::= Node + * | Operation + * | OperationCase + * | Option + * | Enum + * | Literal + * | Header + * | Output + * | Common + * | Include + * Literal ::= { LiteralFlag } ( LITERAL_DEFNS | LITERAL_END ) + * LiteralFlag ::= %both | %decls | %end + * Header ::= %header STRING + * Output ::= %output STRING + * Common ::= %common + * Include ::= %include [ %readonly ] STRING + */ + void TreeCCParse(TreeCCContext *context) + { + /* Fetch the first token from the input stream */ + if(!TreeCCNextToken(context->input)) + { + return; + } + + /* Parse lines of input until the input is exhausted */ + do + { + switch(context->input->token) + { + case TREECC_TOKEN_EOF: + { + /* Shouldn't happen, but ignore it if it does */ + } + break; + + case TREECC_TOKEN_IDENTIFIER: + { + /* Parse an operation case definition */ + ParseOperationCase(context); + } + continue; /* Skip the call to TreeCCNextToken */ + + case TREECC_TOKEN_LITERAL_DEFNS: + case TREECC_TOKEN_LITERAL_END: + case TREECC_TOKEN_BOTH: + case TREECC_TOKEN_DECLS: + case TREECC_TOKEN_END: + { + /* Parse a literal definition block for this file */ + int flags = 0; + while(context->input->token == TREECC_TOKEN_BOTH || + context->input->token == TREECC_TOKEN_DECLS || + context->input->token == TREECC_TOKEN_END) + { + if(context->input->token == TREECC_TOKEN_BOTH) + { + flags |= TREECC_LITERAL_CODE | + TREECC_LITERAL_DECLS; + } + else if(context->input->token == TREECC_TOKEN_DECLS) + { + flags |= TREECC_LITERAL_DECLS; + } + else + { + flags |= TREECC_LITERAL_END; + } + TreeCCNextToken(context->input); + } + if((flags & TREECC_LITERAL_DECLS) == 0) + { + flags |= TREECC_LITERAL_CODE; + } + if(context->input->token == TREECC_TOKEN_LITERAL_DEFNS) + { + TreeCCAddLiteralDefn(context, TreeCCValue(context->input), + flags); + } + else if(context->input->token == TREECC_TOKEN_LITERAL_END) + { + TreeCCAddLiteralDefn(context, TreeCCValue(context->input), + flags | TREECC_LITERAL_END); + } + else + { + TreeCCError(context->input, + "literal definition block expected"); + continue; + } + } + break; + + case TREECC_TOKEN_NODE: + { + /* Parse a node definition */ + ParseNode(context); + } + continue; /* Skip the call to TreeCCNextToken */ + + case TREECC_TOKEN_OPERATION: + { + /* Parse an operation definition */ + ParseOperation(context); + } + continue; /* Skip the call to TreeCCNextToken */ + + case TREECC_TOKEN_OPTION: + { + /* Parse an option declaration */ + ParseOption(context); + } + continue; /* Skip the call to TreeCCNextToken */ + + case TREECC_TOKEN_HEADER: + { + /* Parse a header filename specification */ + TreeCCNextToken(context->input); + if(context->input->token == TREECC_TOKEN_STRING) + { + TreeCCStream *stream = + TreeCCStreamCreate(context, context->input->text, + context->input->text, 1); + context->headerStream = stream; + stream->readOnly |= context->input->readOnly; + if(!(context->commonHeader)) + { + context->commonHeader = stream; + } + } + else + { + TreeCCError(context->input, "header filename expected"); + continue; + } + } + break; + + case TREECC_TOKEN_OUTPUT: + { + /* Parse an output filename specification */ + TreeCCNextToken(context->input); + if(context->input->token == TREECC_TOKEN_STRING) + { + TreeCCStream *stream = + TreeCCStreamCreate(context, context->input->text, + context->input->text, 0); + context->sourceStream = stream; + stream->readOnly |= context->input->readOnly; + if(!(context->commonSource)) + { + context->commonSource = stream; + } + } + else + { + TreeCCError(context->input, "output filename expected"); + continue; + } + } + break; + + case TREECC_TOKEN_OUTDIR: + { + /* Parse an output directory specification */ + TreeCCNextToken(context->input); + if(context->input->token == TREECC_TOKEN_STRING) + { + context->outputDirectory = + TreeCCResolvePathname(context->input->filename, + context->input->text); + } + else + { + TreeCCError(context->input, "output filename expected"); + continue; + } + } + break; + + case TREECC_TOKEN_ENUM: + { + /* Parse an enumerated type definition */ + ParseEnum(context); + } + continue; /* Skip the call to TreeCCNextToken */ + + case TREECC_TOKEN_COMMON: + { + /* Put the common housekeeping code in the + current header and source streams */ + context->commonHeader = context->headerStream; + context->commonSource = context->sourceStream; + } + break; + + case TREECC_TOKEN_INCLUDE: + { + /* Include another file at this point */ + int readOnly = context->input->readOnly; + TreeCCNextToken(context->input); + if(context->input->token == TREECC_TOKEN_READONLY) + { + readOnly = 1; + TreeCCNextToken(context->input); + } + if(context->input->token == TREECC_TOKEN_STRING) + { + char *includeFile = + TreeCCResolvePathname(context->input->filename, + context->input->text); + FILE *file = fopen(includeFile, "r"); + if(file != NULL) + { + /* Parse the contents of the included file */ + TreeCCInput *newInput = + (TreeCCInput *)malloc(sizeof(TreeCCInput)); + TreeCCInput *origInput = context->input; + if(!newInput) + { + TreeCCOutOfMemory(context->input); + } + TreeCCOpen(newInput, context->input->progname, + file, includeFile); + context->input = newInput; + TreeCCParse(context); + context->input = origInput; + TreeCCClose(newInput, 1); + free(newInput); + } + else + { + TreeCCError(context->input, "cannot open \"%s\"", + includeFile); + free(includeFile); + } + } + else + { + TreeCCError(context->input, "include filename expected"); + } + } + break; + + case TREECC_TOKEN_LITERAL_CODE: + case TREECC_TOKEN_LPAREN: + case TREECC_TOKEN_RPAREN: + case TREECC_TOKEN_LBRACE: + case TREECC_TOKEN_RBRACE: + case TREECC_TOKEN_LSQUARE: + case TREECC_TOKEN_RSQUARE: + case TREECC_TOKEN_COMMA: + case TREECC_TOKEN_EQUALS: + case TREECC_TOKEN_STAR: + case TREECC_TOKEN_REF: + case TREECC_TOKEN_SEMI: + case TREECC_TOKEN_COLON_COLON: + case TREECC_TOKEN_STRING: + case TREECC_TOKEN_UNKNOWN: + case TREECC_TOKEN_ABSTRACT: + case TREECC_TOKEN_TYPEDEF: + case TREECC_TOKEN_NOCREATE: + case TREECC_TOKEN_VIRTUAL: + case TREECC_TOKEN_INLINE: + case TREECC_TOKEN_SPLIT: + case TREECC_TOKEN_READONLY: + { + /* This token is not valid here */ + TreeCCError(context->input, "declaration expected"); + do + { + /* Attempt to re-synchronise on the next declaration */ + TreeCCNextToken(context->input); + } + while(!IsStartDecl(context->input->token)); + } + continue; /* Skip the call to TreeCCNextToken */ + } + + /* Get the next token from the input stream */ + TreeCCNextToken(context->input); + } + while(context->input->token != TREECC_TOKEN_EOF); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/parse.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/parse.h:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/parse.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,42 ---- + /* + * parse.h - Parse "treecc" input files. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_PARSE_H + #define _TREECC_PARSE_H + + #include "system.h" + #include "input.h" + #include "info.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Parse the contents of an input stream and populate "context" + * with the definitions that are found within it. + */ + void TreeCCParse(TreeCCContext *context); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_PARSE_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/skeleton.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/skeleton.c:1.1 *** /dev/null Tue Apr 6 12:53:41 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/skeleton.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,147 ---- + /* + * skeleton.c - Include skeleton code in an output stream. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Find a particular skeleton string within "skels.c". + */ + extern const char * const TreeCCSkelFiles[]; + static char *FindSkeletonString(const char *skeleton) + { + char **search = (char **)TreeCCSkelFiles; + while(*search != 0) + { + if(!strcmp(*search, skeleton)) + { + return search[1]; + } + search += 2; + } + return 0; + } + + /* + * Read a line from a skeleton buffer.. + */ + static int ReadSkeletonLine(char *buffer, int size, char **skel) + { + char *ptr = *skel; + if(*ptr == '\0') + { + return 0; + } + while(*ptr != '\0' && *ptr != '\n') + { + if(size > 2) + { + *buffer++ = *ptr; + --size; + } + ++ptr; + } + if(*ptr == '\n') + { + *buffer++ = *ptr++; + } + *buffer = '\0'; + *skel = ptr; + return 1; + } + + void TreeCCIncludeSkeleton(TreeCCContext *context, TreeCCStream *stream, + const char *skeleton) + { + char *skelstr = FindSkeletonString(skeleton); + char buffer[BUFSIZ]; + int posn, start; + if(!skelstr) + { + fprintf(stderr, + "treecc: internal error - could not find skeleton \"%s\"\n", + skeleton); + exit(1); + } + TreeCCStreamLine(stream, 1, skeleton); + while(ReadSkeletonLine(buffer, BUFSIZ, &skelstr)) + { + #if HAVE_STRCHR + if(strchr(buffer, 'Y') != 0 || strchr(buffer, 'y') != 0) + #endif + { + /* The line probably contains "YYNODESTATE" or "yy" */ + posn = 0; + start = 0; + while(buffer[posn] != '\0') + { + if(buffer[posn] == 'Y' && + !strncmp(buffer + posn, "YYNODESTATE", 11)) + { + buffer[posn] = '\0'; + if(start < posn) + { + TreeCCStreamCode(stream, buffer + start); + } + TreeCCStreamCode(stream, context->state_type); + posn += 11; + start = posn; + } + else if(buffer[posn] == 'y' && buffer[posn + 1] == 'y') + { + buffer[posn] = '\0'; + if(start < posn) + { + TreeCCStreamCode(stream, buffer + start); + } + TreeCCStreamCode(stream, context->yy_replacement); + posn += 2; + start = posn; + } + else + { + ++posn; + } + } + if(start < posn) + { + TreeCCStreamCode(stream, buffer + start); + } + } + #if HAVE_STRCHR + else + { + /* Ordinary line */ + TreeCCStreamCode(stream, buffer); + } + #endif + } + TreeCCStreamFixLine(stream); + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/skels.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/skels.c:1.1 *** /dev/null Tue Apr 6 12:53:42 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/skels.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,812 ---- + /* This file is automatically generated by mkskel-sh - do not edit */ + + #include "config.h" + + static char const TreeCCSkel_c_skel_c[] = + "/*\n" + " * treecc node allocation routines for C.\n" + " *\n" + " * Copyright (C) 2001 Southern Storm Software, Pty Ltd.\n" + " *\n" + " * This program is free software; you can redistribute it and/or modify\n" + " * it under the terms of the GNU General Public License as published by\n" + " * the Free Software Foundation; either version 2 of the License, or\n" + " * (at your option) any later version.\n" + " *\n" + " * This program is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " * GNU General Public License for more details.\n" + " *\n" + " * You should have received a copy of the GNU General Public License\n" + " * along with this program; if not, write to the Free Software\n" + " * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + " *\n" + " * As a special exception, when this file is copied by treecc into\n" + " * a treecc output file, you may use that output file without restriction.\n" + " */\n" + "\n" + "#include \n" + "\n" + "#ifndef YYNODESTATE_BLKSIZ\n" + "#define YYNODESTATE_BLKSIZ 2048\n" + "#endif\n" + "\n" + "/*\n" + " * Types used by the allocation routines.\n" + " */\n" + "struct YYNODESTATE_block\n" + "{\n" + " char data__[YYNODESTATE_BLKSIZ];\n" + " struct YYNODESTATE_block *next__;\n" + "\n" + "};\n" + "struct YYNODESTATE_push\n" + "{\n" + " struct YYNODESTATE_push *next__;\n" + " struct YYNODESTATE_block *saved_block__;\n" + " int saved_used__;\n" + "};\n" + "\n" + "/*\n" + " * The fixed global state to use for non-reentrant allocation.\n" + " */\n" + "#ifndef YYNODESTATE_REENTRANT\n" + "static YYNODESTATE fixed_state__;\n" + "#endif\n" + "\n" + "/*\n" + " * Some macro magic to determine the default alignment\n" + " * on this machine. This will compile down to a constant.\n" + " */\n" + "#define YYNODESTATE_ALIGN_CHECK_TYPE(type,name) \\\n" + " struct _YYNODESTATE_align_##name { \\\n" + " char pad; \\\n" + " type field; \\\n" + " }\n" + "#define YYNODESTATE_ALIGN_FOR_TYPE(type) \\\n" + " ((unsigned)(&(((struct _YYNODESTATE_align_##type *)0)->field)))\n" + "#define YYNODESTATE_ALIGN_MAX(a,b) \\\n" + " ((a) > (b) ? (a) : (b))\n" + "#define YYNODESTATE_ALIGN_MAX3(a,b,c) \\\n" + " (YYNODESTATE_ALIGN_MAX((a), YYNODESTATE_ALIGN_MAX((b), (c))))\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(int, int);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(long, long);\n" + "#if defined(WIN32) && !defined(__CYGWIN__)\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(__int64, long_long);\n" + "#else\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(long long, long_long);\n" + "#endif\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(void *, void_p);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(float, float);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(double, double);\n" + "#define YYNODESTATE_ALIGNMENT \\\n" + " YYNODESTATE_ALIGN_MAX( \\\n" + " YYNODESTATE_ALIGN_MAX3 \\\n" + " (YYNODESTATE_ALIGN_FOR_TYPE(int), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(long), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(long_long)), \\\n" + " YYNODESTATE_ALIGN_MAX3 \\\n" + " (YYNODESTATE_ALIGN_FOR_TYPE(void_p), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(float), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(double)))\n" + "\n" + "/*\n" + " * Initialize the node allocation pool.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodeinit(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodeinit()\n" + "{\n" + " YYNODESTATE *state__ = &fixed_state__;\n" + "#endif\n" + " state__->blocks__ = 0;\n" + " state__->push_stack__ = 0;\n" + " state__->used__ = 0;\n" + "}\n" + "\n" + "/*\n" + " * Allocate a block of memory.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void *yynodealloc(state__, size__)\n" + "YYNODESTATE *state__;\n" + "unsigned int size__;\n" + "{\n" + "#else\n" + "void *yynodealloc(size__)\n" + "unsigned int size__;\n" + "{\n" + " YYNODESTATE *state__ = &fixed_state__;\n" + "#endif\n" + " struct YYNODESTATE_block *block__;\n" + " void *result__;\n" + "\n" + " /* Round the size to the next alignment boundary */\n" + " size__ = (size__ + YYNODESTATE_ALIGNMENT - 1) &\n" + " ~(YYNODESTATE_ALIGNMENT - 1);\n" + "\n" + " /* Do we need to allocate a new block? */\n" + " block__ = state__->blocks__;\n" + " if(!block__ || (state__->used__ + size__) > YYNODESTATE_BLKSIZ)\n" + " {\n" + " if(size__ > YYNODESTATE_BLKSIZ)\n" + " {\n" + " /* The allocation is too big for the node pool */\n" + " return (void *)0;\n" + " }\n" + " block__ = (struct YYNODESTATE_block *)\n" + " malloc(sizeof(struct YYNODESTATE_block));\n" + " if(!block__)\n" + " {\n" + " /* The system is out of memory. The programmer can\n" + " supply the \"yynodefailed\" function to report the\n" + " out of memory state and/or abort the program */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + " yynodefailed(state__);\n" + "#else\n" + " yynodefailed();\n" + "#endif\n" + " return (void *)0;\n" + " }\n" + " block__->next__ = state__->blocks__;\n" + " state__->blocks__ = block__;\n" + " state__->used__ = 0;\n" + " }\n" + "\n" + " /* Allocate the memory and return it */\n" + " result__ = (void *)(block__->data__ + state__->used__);\n" + " state__->used__ += size__;\n" + " return result__;\n" + "}\n" + "\n" + "/*\n" + " * Push the node allocation state.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "int yynodepush(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "int yynodepush()\n" + "{\n" + " YYNODESTATE *state__ = &fixed_state__;\n" + "#endif\n" + " struct YYNODESTATE_block *saved_block__;\n" + " int saved_used__;\n" + " struct YYNODESTATE_push *push_item__;\n" + "\n" + " /* Save the current state of the node allocation pool */\n" + " saved_block__ = state__->blocks__;\n" + " saved_used__ = state__->used__;\n" + "\n" + " /* Allocate space for a push item */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + " push_item__ = (struct YYNODESTATE_push *)\n" + " yynodealloc(state__, sizeof(struct YYNODESTATE_push));\n" + "#else\n" + " push_item__ = (struct YYNODESTATE_push *)\n" + " yynodealloc(sizeof(struct YYNODESTATE_push));\n" + "#endif\n" + " if(!push_item__)\n" + " {\n" + " return 0;\n" + " }\n" + "\n" + " /* Copy the saved information to the push item */\n" + " push_item__->saved_block__ = saved_block__;\n" + " push_item__->saved_used__ = saved_used__;\n" + "\n" + " /* Add the push item to the push stack */\n" + " push_item__->next__ = state__->push_stack__;\n" + " state__->push_stack__ = push_item__;\n" + " return 1;\n" + "}\n" + "\n" + "/*\n" + " * Pop the node allocation state.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodepop(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodepop()\n" + "{\n" + " YYNODESTATE *state__ = &fixed_state__;\n" + "#endif\n" + " struct YYNODESTATE_push *push_item__;\n" + " struct YYNODESTATE_block *saved_block__;\n" + " struct YYNODESTATE_block *temp_block__;\n" + "\n" + " /* Pop the top of the push stack */\n" + " push_item__ = state__->push_stack__;\n" + " if(push_item__ == 0)\n" + " {\n" + " saved_block__ = 0;\n" + " state__->used__ = 0;\n" + " }\n" + " else\n" + " {\n" + " saved_block__ = push_item__->saved_block__;\n" + " state__->used__ = push_item__->saved_used__;\n" + " state__->push_stack__ = push_item__->next__;\n" + " }\n" + "\n" + " /* Free unnecessary blocks */\n" + " while(state__->blocks__ != saved_block__)\n" + " {\n" + " temp_block__ = state__->blocks__;\n" + " state__->blocks__ = temp_block__->next__;\n" + " free(temp_block__);\n" + " }\n" + "}\n" + "\n" + "/*\n" + " * Clear the node allocation pool completely.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodeclear(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodeclear()\n" + "{\n" + " YYNODESTATE *state__ = &fixed_state__;\n" + "#endif\n" + " struct YYNODESTATE_block *temp_block__;\n" + " while(state__->blocks__ != 0)\n" + " {\n" + " temp_block__ = state__->blocks__;\n" + " state__->blocks__ = temp_block__->next__;\n" + " free(temp_block__);\n" + " }\n" + " state__->push_stack__ = 0;\n" + " state__->used__ = 0;\n" + "}\n" + ; + static char const TreeCCSkel_c_skel_h[] = + "typedef struct\n" + "{\n" + " struct YYNODESTATE_block *blocks__;\n" + " struct YYNODESTATE_push *push_stack__;\n" + " int used__;\n" + "\n" + "} YYNODESTATE;\n" + ; + static char const TreeCCSkel_cpp_skel_cc[] = + "/*\n" + " * treecc node allocation routines for C++.\n" + " *\n" + " * Copyright (C) 2001 Southern Storm Software, Pty Ltd.\n" + " *\n" + " * This program is free software; you can redistribute it and/or modify\n" + " * it under the terms of the GNU General Public License as published by\n" + " * the Free Software Foundation; either version 2 of the License, or\n" + " * (at your option) any later version.\n" + " *\n" + " * This program is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " * GNU General Public License for more details.\n" + " *\n" + " * You should have received a copy of the GNU General Public License\n" + " * along with this program; if not, write to the Free Software\n" + " * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + " *\n" + " * As a special exception, when this file is copied by treecc into\n" + " * a treecc output file, you may use that output file without restriction.\n" + " */\n" + "\n" + "#ifndef YYNODESTATE_BLKSIZ\n" + "#define YYNODESTATE_BLKSIZ 2048\n" + "#endif\n" + "\n" + "/*\n" + " * Types used by the allocation routines.\n" + " */\n" + "struct YYNODESTATE_block\n" + "{\n" + " char data__[YYNODESTATE_BLKSIZ];\n" + " struct YYNODESTATE_block *next__;\n" + "\n" + "};\n" + "struct YYNODESTATE_push\n" + "{\n" + " struct YYNODESTATE_push *next__;\n" + " struct YYNODESTATE_block *saved_block__;\n" + " int saved_used__;\n" + "};\n" + "\n" + "/*\n" + " * Initialize the singleton instance.\n" + " */\n" + "#ifndef YYNODESTATE_REENTRANT\n" + "YYNODESTATE *YYNODESTATE::state__ = 0;\n" + "#endif\n" + "\n" + "/*\n" + " * Some macro magic to determine the default alignment\n" + " * on this machine. This will compile down to a constant.\n" + " */\n" + "#define YYNODESTATE_ALIGN_CHECK_TYPE(type,name) \\\n" + " struct _YYNODESTATE_align_##name { \\\n" + " char pad; \\\n" + " type field; \\\n" + " }\n" + "#define YYNODESTATE_ALIGN_FOR_TYPE(type) \\\n" + " ((unsigned)(&(((struct _YYNODESTATE_align_##type *)0)->field)))\n" + "#define YYNODESTATE_ALIGN_MAX(a,b) \\\n" + " ((a) > (b) ? (a) : (b))\n" + "#define YYNODESTATE_ALIGN_MAX3(a,b,c) \\\n" + " (YYNODESTATE_ALIGN_MAX((a), YYNODESTATE_ALIGN_MAX((b), (c))))\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(int, int);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(long, long);\n" + "#if defined(WIN32) && !defined(__CYGWIN__)\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(__int64, long_long);\n" + "#else\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(long long, long_long);\n" + "#endif\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(void *, void_p);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(float, float);\n" + "YYNODESTATE_ALIGN_CHECK_TYPE(double, double);\n" + "#define YYNODESTATE_ALIGNMENT \\\n" + " YYNODESTATE_ALIGN_MAX( \\\n" + " YYNODESTATE_ALIGN_MAX3 \\\n" + " (YYNODESTATE_ALIGN_FOR_TYPE(int), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(long), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(long_long)), \\\n" + " YYNODESTATE_ALIGN_MAX3 \\\n" + " (YYNODESTATE_ALIGN_FOR_TYPE(void_p), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(float), \\\n" + " YYNODESTATE_ALIGN_FOR_TYPE(double)))\n" + "\n" + "/*\n" + " * Constructor for YYNODESTATE.\n" + " */\n" + "YYNODESTATE::YYNODESTATE()\n" + "{\n" + " /* Initialize the allocation state */\n" + " blocks__ = 0;\n" + " push_stack__ = 0;\n" + " used__ = 0;\n" + "\n" + "#ifndef YYNODESTATE_REENTRANT\n" + " /* Register this object as the singleton instance */\n" + " if(!state__)\n" + " {\n" + " state__ = this;\n" + " }\n" + "#endif\n" + "}\n" + "\n" + "/*\n" + " * Destructor for YYNODESTATE.\n" + " */\n" + "YYNODESTATE::~YYNODESTATE()\n" + "{\n" + " /* Free all node memory */\n" + " clear();\n" + "\n" + "#ifndef YYNODESTATE_REENTRANT\n" + " /* We are no longer the singleton instance */\n" + " if(state__ == this)\n" + " {\n" + " state__ = 0;\n" + " }\n" + "#endif\n" + "}\n" + "\n" + "#ifdef YYNODESTATE_USE_ALLOCATOR\n" + "\n" + "/*\n" + " * Allocate a block of memory.\n" + " */\n" + "void *YYNODESTATE::alloc(size_t size__)\n" + "{\n" + " struct YYNODESTATE_block *block__;\n" + " void *result__;\n" + "\n" + " /* Round the size to the next alignment boundary */\n" + " size__ = (size__ + YYNODESTATE_ALIGNMENT - 1) &\n" + " ~(YYNODESTATE_ALIGNMENT - 1);\n" + "\n" + " /* Do we need to allocate a new block? */\n" + " block__ = blocks__;\n" + " if(!block__ || (used__ + size__) > YYNODESTATE_BLKSIZ)\n" + " {\n" + " if(size__ > YYNODESTATE_BLKSIZ)\n" + " {\n" + " /* The allocation is too big for the node pool */\n" + " return (void *)0;\n" + " }\n" + " block__ = new YYNODESTATE_block;\n" + " if(!block__)\n" + " {\n" + " /* The system is out of memory. The programmer can\n" + " inherit the \"failed\" method to report the\n" + " out of memory state and/or abort the program */\n" + " failed();\n" + " return (void *)0;\n" + " }\n" + " block__->next__ = blocks__;\n" + " blocks__ = block__;\n" + " used__ = 0;\n" + " }\n" + "\n" + " /* Allocate the memory and return it */\n" + " result__ = (void *)(block__->data__ + used__);\n" + " used__ += size__;\n" + " return result__;\n" + "}\n" + "\n" + "/*\n" + " * Deallocate a block of memory.\n" + " */\n" + "void YYNODESTATE::dealloc(void *ptr__, size_t size__)\n" + "{\n" + " /* Nothing to do for this type of node allocator */\n" + "}\n" + "\n" + "/*\n" + " * Push the node allocation state.\n" + " */\n" + "int YYNODESTATE::push()\n" + "{\n" + " struct YYNODESTATE_block *saved_block__;\n" + " int saved_used__;\n" + " struct YYNODESTATE_push *push_item__;\n" + "\n" + " /* Save the current state of the node allocation pool */\n" + " saved_block__ = blocks__;\n" + " saved_used__ = used__;\n" + "\n" + " /* Allocate space for a push item */\n" + " push_item__ = (struct YYNODESTATE_push *)\n" + " alloc(sizeof(struct YYNODESTATE_push));\n" + " if(!push_item__)\n" + " {\n" + " return 0;\n" + " }\n" + "\n" + " /* Copy the saved information to the push item */\n" + " push_item__->saved_block__ = saved_block__;\n" + " push_item__->saved_used__ = saved_used__;\n" + "\n" + " /* Add the push item to the push stack */\n" + " push_item__->next__ = push_stack__;\n" + " push_stack__ = push_item__;\n" + " return 1;\n" + "}\n" + "\n" + "/*\n" + " * Pop the node allocation state.\n" + " */\n" + "void YYNODESTATE::pop()\n" + "{\n" + " struct YYNODESTATE_push *push_item__;\n" + " struct YYNODESTATE_block *saved_block__;\n" + " struct YYNODESTATE_block *temp_block__;\n" + "\n" + " /* Pop the top of the push stack */\n" + " push_item__ = push_stack__;\n" + " if(push_item__ == 0)\n" + " {\n" + " saved_block__ = 0;\n" + " used__ = 0;\n" + " }\n" + " else\n" + " {\n" + " saved_block__ = push_item__->saved_block__;\n" + " used__ = push_item__->saved_used__;\n" + " push_stack__ = push_item__->next__;\n" + " }\n" + "\n" + " /* Free unnecessary blocks */\n" + " while(blocks__ != saved_block__)\n" + " {\n" + " temp_block__ = blocks__;\n" + " blocks__ = temp_block__->next__;\n" + " delete temp_block__;\n" + " }\n" + "}\n" + "\n" + "/*\n" + " * Clear the node allocation pool completely.\n" + " */\n" + "void YYNODESTATE::clear()\n" + "{\n" + " struct YYNODESTATE_block *temp_block__;\n" + " while(blocks__ != 0)\n" + " {\n" + " temp_block__ = blocks__;\n" + " blocks__ = temp_block__->next__;\n" + " delete temp_block__;\n" + " }\n" + " push_stack__ = 0;\n" + " used__ = 0;\n" + "}\n" + "\n" + "#endif /* YYNODESTATE_USE_ALLOCATOR */\n" + "\n" + "/*\n" + " * Default implementation of functions which may be overridden.\n" + " */\n" + "void YYNODESTATE::failed()\n" + "{\n" + "}\n" + "\n" + "#ifdef YYNODESTATE_TRACK_LINES\n" + "\n" + "char *YYNODESTATE::currFilename()\n" + "{\n" + " return (char *)0;\n" + "}\n" + "\n" + "long YYNODESTATE::currLinenum()\n" + "{\n" + " return 0;\n" + "}\n" + "\n" + "#endif\n" + ; + static char const TreeCCSkel_cpp_skel_h[] = + "private:\n" + "\n" + " struct YYNODESTATE_block *blocks__;\n" + " struct YYNODESTATE_push *push_stack__;\n" + " int used__;\n" + ; + static char const TreeCCSkel_c_gc_skel_h[] = + "typedef struct\n" + "{\n" + " int dummy__;\n" + "\n" + "} YYNODESTATE;\n" + ; + static char const TreeCCSkel_c_gc_skel_c[] = + "/*\n" + " * treecc node allocation routines for C.\n" + " *\n" + " * Copyright (C) 2003 Southern Storm Software, Pty Ltd.\n" + " *\n" + " * This program is free software; you can redistribute it and/or modify\n" + " * it under the terms of the GNU General Public License as published by\n" + " * the Free Software Foundation; either version 2 of the License, or\n" + " * (at your option) any later version.\n" + " *\n" + " * This program is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " * GNU General Public License for more details.\n" + " *\n" + " * You should have received a copy of the GNU General Public License\n" + " * along with this program; if not, write to the Free Software\n" + " * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + " *\n" + " * As a special exception, when this file is copied by treecc into\n" + " * a treecc output file, you may use that output file without restriction.\n" + " */\n" + "\n" + "#include \n" + "#include \n" + "\n" + "/*\n" + " * Initialize the node allocation pool.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodeinit(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodeinit()\n" + "{\n" + "#endif\n" + " GC_INIT();\n" + " GC_init();\n" + "}\n" + "\n" + "/*\n" + " * Allocate a block of memory.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void *yynodealloc(state__, size__)\n" + "YYNODESTATE *state__;\n" + "unsigned int size__;\n" + "{\n" + "#else\n" + "void *yynodealloc(size__)\n" + "unsigned int size__;\n" + "{\n" + "#endif\n" + " return (void *)GC_MALLOC((size_t)size__);\n" + "}\n" + "\n" + "/*\n" + " * Push the node allocation state. Not used in the GC version.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "int yynodepush(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "int yynodepush()\n" + "{\n" + "#endif\n" + " return 1;\n" + "}\n" + "\n" + "/*\n" + " * Pop the node allocation state. Not used in the GC version.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodepop(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodepop()\n" + "{\n" + "#endif\n" + "}\n" + "\n" + "/*\n" + " * Clear the node allocation pool completely. Not used in the GC version.\n" + " */\n" + "#ifdef YYNODESTATE_REENTRANT\n" + "void yynodeclear(state__)\n" + "YYNODESTATE *state__;\n" + "{\n" + "#else\n" + "void yynodeclear()\n" + "{\n" + "#endif\n" + "}\n" + ; + static char const TreeCCSkel_cpp_gc_skel_h[] = + "\n" + ; + static char const TreeCCSkel_cpp_gc_skel_cc[] = + "/*\n" + " * treecc node allocation routines for C++.\n" + " *\n" + " * Copyright (C) 2003 Southern Storm Software, Pty Ltd.\n" + " *\n" + " * This program is free software; you can redistribute it and/or modify\n" + " * it under the terms of the GNU General Public License as published by\n" + " * the Free Software Foundation; either version 2 of the License, or\n" + " * (at your option) any later version.\n" + " *\n" + " * This program is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " * GNU General Public License for more details.\n" + " *\n" + " * You should have received a copy of the GNU General Public License\n" + " * along with this program; if not, write to the Free Software\n" + " * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + " *\n" + " * As a special exception, when this file is copied by treecc into\n" + " * a treecc output file, you may use that output file without restriction.\n" + " */\n" + "\n" + "#include \n" + "\n" + "/*\n" + " * Initialize the singleton instance.\n" + " */\n" + "#ifndef YYNODESTATE_REENTRANT\n" + "YYNODESTATE *YYNODESTATE::state__ = 0;\n" + "#endif\n" + "\n" + "/*\n" + " * Constructor for YYNODESTATE.\n" + " */\n" + "YYNODESTATE::YYNODESTATE()\n" + "{\n" + " /* Initialize the garbage collector */\n" + " GC_INIT();\n" + " GC_init();\n" + "\n" + "#ifndef YYNODESTATE_REENTRANT\n" + " /* Register this object as the singleton instance */\n" + " if(!state__)\n" + " {\n" + " state__ = this;\n" + " }\n" + "#endif\n" + "}\n" + "\n" + "/*\n" + " * Destructor for YYNODESTATE.\n" + " */\n" + "YYNODESTATE::~YYNODESTATE()\n" + "{\n" + "#ifndef YYNODESTATE_REENTRANT\n" + " /* We are no longer the singleton instance */\n" + " if(state__ == this)\n" + " {\n" + " state__ = 0;\n" + " }\n" + "#endif\n" + "}\n" + "\n" + "#ifdef YYNODESTATE_USE_ALLOCATOR\n" + "\n" + "/*\n" + " * Allocate a block of memory.\n" + " */\n" + "void *YYNODESTATE::alloc(size_t size__)\n" + "{\n" + " return (void *)GC_MALLOC((size_t)size__);\n" + "}\n" + "\n" + "/*\n" + " * Deallocate a block of memory.\n" + " */\n" + "void YYNODESTATE::dealloc(void *ptr__, size_t size__)\n" + "{\n" + " /* Nothing to do for this type of node allocator */\n" + "}\n" + "\n" + "/*\n" + " * Push the node allocation state.\n" + " */\n" + "int YYNODESTATE::push()\n" + "{\n" + " /* Not used with the garbage collector */\n" + " return 1;\n" + "}\n" + "\n" + "/*\n" + " * Pop the node allocation state.\n" + " */\n" + "void YYNODESTATE::pop()\n" + "{\n" + " /* Not used with the garbage collector */\n" + "}\n" + "\n" + "/*\n" + " * Clear the node allocation pool completely.\n" + " */\n" + "void YYNODESTATE::clear()\n" + "{\n" + " /* Not used with the garbage collector */\n" + "}\n" + "\n" + "#endif /* YYNODESTATE_USE_ALLOCATOR */\n" + "\n" + "/*\n" + " * Default implementation of functions which may be overridden.\n" + " */\n" + "void YYNODESTATE::failed()\n" + "{\n" + "}\n" + "\n" + "#ifdef YYNODESTATE_TRACK_LINES\n" + "\n" + "char *YYNODESTATE::currFilename()\n" + "{\n" + " return (char *)0;\n" + "}\n" + "\n" + "long YYNODESTATE::currLinenum()\n" + "{\n" + " return 0;\n" + "}\n" + "\n" + "#endif\n" + ; + const char * const TreeCCSkelFiles[] = { + "c_skel.c", TreeCCSkel_c_skel_c, + "c_skel.h", TreeCCSkel_c_skel_h, + "cpp_skel.cc", TreeCCSkel_cpp_skel_cc, + "cpp_skel.h", TreeCCSkel_cpp_skel_h, + "c_gc_skel.h", TreeCCSkel_c_gc_skel_h, + "c_gc_skel.c", TreeCCSkel_c_gc_skel_c, + "cpp_gc_skel.h", TreeCCSkel_cpp_gc_skel_h, + "cpp_gc_skel.cc", TreeCCSkel_cpp_gc_skel_cc, + 0 + }; Index: llvm/test/Programs/MultiSource/Applications/treecc/stream.c diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/stream.c:1.1 *** /dev/null Tue Apr 6 12:53:42 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/stream.c Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,682 ---- + /* + * stream.c - Stream handling for writing source code. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include "system.h" + #include "input.h" + #include "info.h" + #include "errors.h" + + #ifdef __cplusplus + extern "C" { + #endif + + char *TreeCCDupString(char *str) + { + char *newstr = (char *)malloc(strlen(str) + 1); + if(!newstr) + { + TreeCCOutOfMemory(0); + } + strcpy(newstr, str); + return newstr; + } + + char *TreeCCResolvePathname(char *absolute, char *relative) + { + int len; + char *path; + if(!absolute) + { + return TreeCCDupString(relative); + } + len = strlen(absolute); + while(len > 0 && absolute[len - 1] != '/' && absolute[len - 1] != '\\') + { + --len; + } + if(len <= 0) + { + return TreeCCDupString(relative); + } + path = (char *)malloc(len + strlen(relative) + 1); + if(!path) + { + TreeCCOutOfMemory(0); + } + strncpy(path, absolute, len); + strcpy(path + len, relative); + return path; + } + + TreeCCStream *TreeCCStreamCreate(PTreeCCContext context, + char *filename, char *embedName, + int isHeader) + { + TreeCCStream *stream; + char *path; + + /* Resolve the filename into a path */ + if(isHeader < 0) + { + /* Already resolved by TreeCCStreamGetJava */ + isHeader = 0; + path = TreeCCDupString(filename); + } + else + { + path = TreeCCResolvePathname(context->input->filename, filename); + } + + /* Search for an existing stream for the file */ + stream = context->streamList; + while(stream != 0) + { + if(!strcmp(stream->filename, path)) + { + free(path); + return stream; + } + stream = stream->nextStream; + } + + /* Create a new stream */ + stream = (TreeCCStream *)malloc(sizeof(TreeCCStream)); + if(!stream) + { + TreeCCOutOfMemory(0); + } + stream->context = context; + stream->filename = path; + stream->embedName = (embedName ? TreeCCDupString(embedName) : + TreeCCDupString(filename)); + stream->linenum = 1; + stream->firstBuf = 0; + stream->lastBuf = 0; + stream->posn = TREECC_STREAM_BUFSIZ; + stream->forceCreate = context->force; + stream->readOnly = 0; + stream->isHeader = isHeader; + stream->defaultFile = 0; + stream->dirty = 0; + stream->firstDefn = 0; + stream->lastDefn = 0; + stream->nextStream = context->streamList; + context->streamList = stream; + return stream; + } + + TreeCCStream *TreeCCStreamGetJava(PTreeCCContext context, char *className) + { + char *filename; + int len; + TreeCCStream *stream; + if(context->outputDirectory) + { + len = strlen(context->outputDirectory) + strlen(className) + 7; + if((filename = (char *)malloc(len)) == 0) + { + TreeCCOutOfMemory(context->input); + } + strcpy(filename, context->outputDirectory); + len = strlen(context->outputDirectory); + filename[len] = '/'; + strcpy(filename + len + 1, className); + strcat(filename, ".java"); + ++len; + } + else + { + len = strlen(className) + 6; + if((filename = (char *)malloc(len)) == 0) + { + TreeCCOutOfMemory(context->input); + } + strcpy(filename, className); + strcat(filename, ".java"); + len = 0; + } + stream = TreeCCStreamCreate(context, filename, filename + len, -1); + free(filename); + return stream; + } + + void TreeCCStreamDestroy(TreeCCStream *stream) + { + TreeCCStreamDefn *defn, *nextDefn; + + /* Free the data buffers for the stream */ + TreeCCStreamClear(stream); + + /* Free the definition list for the stream */ + defn = stream->firstDefn; + while(defn != 0) + { + nextDefn = defn->next; + if(!(defn->refOnly)) + { + free(defn->code); + } + free(defn); + defn = nextDefn; + } + + /* Free the filenames */ + free(stream->filename); + free(stream->embedName); + + /* Free the stream itself */ + free(stream); + } + + void TreeCCStreamClear(TreeCCStream *stream) + { + TreeCCStreamBuf *buffer, *nextBuffer; + buffer = stream->firstBuf; + while(buffer != 0) + { + nextBuffer = buffer->next; + free(buffer); + buffer = nextBuffer; + } + stream->firstBuf = 0; + stream->lastBuf = 0; + stream->dirty = 0; + stream->posn = TREECC_STREAM_BUFSIZ; + stream->linenum = 1; + } + + /* + * Define the "MemCmp" function. + */ + #if HAVE_MEMCMP + #define MemCmp(s1,s2,size) (memcmp((s1),(s2),(size))) + #else + static int MemCmp(const char *s1, const char *s2, int size) + { + while(size > 0) + { + if(*s1 < *s2) + { + return -1; + } + else if(*s1 > *s2) + { + return 1; + } + ++s1; + ++s2; + --size; + } + return 0; + } + #endif + + int TreeCCStreamFlush(TreeCCStream *stream) + { + int result; + FILE *file; + TreeCCStreamBuf *buffer; + char tempbuf[TREECC_STREAM_BUFSIZ]; + int size, changed; + + /* Ignore default streams with no contents */ + if(stream->defaultFile && !(stream->firstBuf)) + { + return 1; + } + + /* Validate that the contents have changed non-trivially */ + if(!(stream->forceCreate) || stream->readOnly) + { + if((file = fopen(stream->filename, "r")) != NULL) + { + buffer = stream->firstBuf; + changed = 0; + while((size = fread(tempbuf, 1, TREECC_STREAM_BUFSIZ, file)) != 0) + { + if(!buffer) + { + changed = 1; + break; + } + if(buffer == stream->lastBuf) + { + if(stream->posn != size) + { + changed = 1; + break; + } + if(MemCmp(buffer->data, tempbuf, size) != 0) + { + changed = 1; + break; + } + } + else + { + if(size != TREECC_STREAM_BUFSIZ) + { + changed = 1; + break; + } + if(MemCmp(buffer->data, tempbuf, TREECC_STREAM_BUFSIZ) != 0) + { + changed = 1; + break; + } + } + buffer = buffer->next; + if(size < TREECC_STREAM_BUFSIZ) + { + size = 0; + break; + } + } + if(size == 0 && buffer != 0) + { + changed = 1; + } + fclose(file); + if(!changed) + { + return 1; + } + } + if(stream->readOnly) + { + fprintf(stderr, "%s: read-only file has different contents\n", + stream->filename); + return 0; + } + } + + /* Open the output file */ + if((file = fopen(stream->filename, "w")) == NULL) + { + perror(stream->filename); + return 0; + } + + /* Flush the data to the output file */ + result = TreeCCStreamFlushStdio(stream, file); + + /* Close the output file */ + fclose(file); + return result; + } + + int TreeCCStreamFlushStdio(TreeCCStream *stream, FILE *file) + { + TreeCCStreamBuf *buffer = stream->firstBuf; + while(buffer != 0) + { + if(buffer == stream->lastBuf) + { + if(fwrite(buffer->data, 1, stream->posn, file) != stream->posn) + { + return 0; + } + } + else + { + if(fwrite(buffer->data, 1, TREECC_STREAM_BUFSIZ, file) != + TREECC_STREAM_BUFSIZ) + { + return 0; + } + } + buffer = buffer->next; + } + return (fflush(file) == 0); + } + + /* + * Write the contents of a buffer to a stream. + */ + static void WriteBuffer(TreeCCStream *stream, const char *buf) + { + int len = strlen(buf); + int templen; + TreeCCStreamBuf *buffer; + stream->dirty = 1; + while(len > 0) + { + /* Add another buffer to the stream if necessary */ + if(stream->posn >= TREECC_STREAM_BUFSIZ) + { + buffer = (TreeCCStreamBuf *)malloc(sizeof(TreeCCStreamBuf)); + if(!buffer) + { + TreeCCOutOfMemory(0); + } + buffer->next = 0; + if(stream->lastBuf) + { + stream->lastBuf->next = buffer; + } + else + { + stream->firstBuf = buffer; + } + stream->lastBuf = buffer; + stream->posn = 0; + templen = TREECC_STREAM_BUFSIZ; + } + else + { + buffer = stream->lastBuf; + templen = TREECC_STREAM_BUFSIZ - stream->posn; + } + + /* Copy the data to the stream buffer */ + if(templen > len) + { + templen = len; + } + #if HAVE_MEMCPY + memcpy(buffer->data + stream->posn, buf, templen); + #else + { + char *s1 = buffer->data + stream->posn; + const char *s2 = buf; + int size = templen; + while(size > 0) + { + *s1++ = *s2++; + --size; + } + } + #endif + + /* Advance to the next part of the buffer to be written */ + buf += templen; + len -= templen; + stream->posn += templen; + } + } + + /* + * Update the line number position of a stream. + */ + static void UpdateLineNum(TreeCCStream *stream, const char *buf) + { + #if HAVE_STRCHR + while((buf = strchr(buf, '\n')) != 0) + { + ++buf; + ++(stream->linenum); + } + #else + while(*buf != '\0') + { + if(*buf == '\n') + { + ++(stream->linenum); + } + ++buf; + } + #endif + } + + void TreeCCStreamPrint(TreeCCStream *stream, const char *format, ...) + { + char tempbuf[4096]; + + /* Print the formatted data to tempbuf */ + VA_START; + #if HAVE_VSNPRINTF + vsnprintf(tempbuf, sizeof(tempbuf), format, VA_GET_LIST); + #elif HAVE__VSNPRINTF + _vsnprintf(tempbuf, sizeof(tempbuf), format, VA_GET_LIST); + #else + vsprintf(tempbuf, format, VA_GET_LIST); + #endif + VA_END; + + /* Write the contents of "tempbuf" to the stream */ + WriteBuffer(stream, tempbuf); + + /* Count newlines in the buffer to update the line number */ + UpdateLineNum(stream, tempbuf); + } + + void TreeCCStreamCode(TreeCCStream *stream, char *code) + { + WriteBuffer(stream, code); + UpdateLineNum(stream, code); + } + + /* + * Put a single character to a stream buffer. + */ + static void _StreamPut(int ch, TreeCCStream *stream) + { + char buf[2]; + buf[0] = (char)ch; + buf[1] = '\0'; + WriteBuffer(stream, buf); + } + #define StreamPut(ch,stream) \ + do { \ + if((stream)->posn < TREECC_STREAM_BUFSIZ) \ + { \ + (stream)->lastBuf->data[((stream)->posn)++] = (ch); \ + (stream)->dirty = 1; \ + } \ + else \ + { \ + _StreamPut((ch), (stream)); \ + } \ + } while (0) + + void TreeCCStreamCodeIndent(TreeCCStream *stream, char *code, int indent) + { + int temp; + while(*code != '\0') + { + StreamPut(*code, stream); + if(*code == '\n') + { + ++(stream->linenum); + for(temp = 0; temp < indent; ++temp) + { + StreamPut('\t', stream); + } + } + ++code; + } + } + + void TreeCCStreamCodeIndentCustom(TreeCCStream *stream, char *code, + char indentchar, int indent) + { + int temp; + while(*code != '\0') + { + StreamPut(*code, stream); + if(*code == '\n') + { + ++(stream->linenum); + for(temp = 0; temp < indent; ++temp) + { + StreamPut(indentchar, stream); + } + } + ++code; + } + } + + + void TreeCCStreamFixLine(TreeCCStream *stream) + { + TreeCCStreamLine(stream, stream->linenum + 1, stream->embedName); + } + + void TreeCCStreamAddLiteral(TreeCCStream *stream, char *code, + char *filename, long linenum, + int atEnd, int refOnly) + { + TreeCCStreamDefn *defn; + + /* Bail out if the stream is NULL (can happen in "test_parse" sometimes) */ + if(!stream) + { + return; + } + + /* Allocate space for a definition block */ + defn = (TreeCCStreamDefn *)malloc(sizeof(TreeCCStreamDefn)); + if(!defn) + { + TreeCCOutOfMemory(0); + } + + /* Initialize the definition block */ + defn->code = code; + defn->filename = filename; + defn->linenum = linenum; + defn->atEnd = atEnd; + defn->refOnly = refOnly; + defn->next = 0; + + /* Add the definition block to the stream's definition list */ + if(stream->lastDefn) + { + stream->lastDefn->next = defn; + } + else + { + stream->firstDefn = defn; + } + stream->lastDefn = defn; + } + + /* + * Output a macro name that has been generated from a filename. + */ + static void OutputMacroName(TreeCCStream *stream, const char *filename) + { + while(*filename != '\0') + { + if((*filename >= 'A' && *filename <= 'Z') || + (*filename >= 'a' && *filename <= 'z') || + (*filename >= '0' && *filename <= '9')) + { + StreamPut(*filename, stream); + } + else + { + StreamPut('_', stream); + } + ++filename; + } + StreamPut('\n', stream); + ++(stream->linenum); + } + + /* + * Output a list of definitions to a header or source stream. + */ + static void OutputDefns(TreeCCStream *stream, int atEnd) + { + TreeCCStreamDefn *defn = stream->firstDefn; + int sawDefn = 0; + while(defn != 0) + { + if(defn->atEnd == atEnd) + { + TreeCCStreamLine(stream, defn->linenum, defn->filename); + WriteBuffer(stream, defn->code); + UpdateLineNum(stream, defn->code); + if(*(defn->code) != '\0' && + defn->code[strlen(defn->code) - 1] != '\n') + { + /* Terminate the final line */ + StreamPut('\n', stream); + ++(stream->linenum); + } + sawDefn = 1; + } + defn = defn->next; + } + if(sawDefn) + { + TreeCCStreamFixLine(stream); + } + } + + void TreeCCStreamHeaderTop(TreeCCStream *stream) + { + char *filename = stream->embedName; + TreeCCStreamPrint(stream, + "/* %s. Generated automatically by treecc */\n", filename); + TreeCCStreamPrint(stream, "#ifndef __%s_", stream->context->yy_replacement); + OutputMacroName(stream, filename); + TreeCCStreamPrint(stream, "#define __%s_", stream->context->yy_replacement); + OutputMacroName(stream, filename); + OutputDefns(stream, 0); + } + + void TreeCCStreamHeaderBottom(TreeCCStream *stream) + { + OutputDefns(stream, 1); + TreeCCStreamPrint(stream, "#endif\n"); + } + + void TreeCCStreamSourceTop(TreeCCStream *stream) + { + TreeCCStreamPrint(stream, "/* %s. Generated automatically by treecc */\n", + stream->embedName); + OutputDefns(stream, 0); + } + + void TreeCCStreamSourceTopCS(TreeCCStream *stream) + { + OutputDefns(stream, 0); + } + + void TreeCCStreamSourceBottom(TreeCCStream *stream) + { + OutputDefns(stream, 1); + } + + void TreeCCStreamLine(TreeCCStream *stream, long linenum, + const char *filename) + { + if(stream->context->print_lines) + { + int len; + if(stream->context->strip_filenames) + { + len = strlen(filename); + while(len > 0 && filename[len - 1] != '/' && + filename[len - 1] != '\\') + { + --len; + } + filename += len; + } + TreeCCStreamPrint(stream, "#line %ld \"%s\"\n", linenum, filename); + } + } + + #ifdef __cplusplus + }; + #endif Index: llvm/test/Programs/MultiSource/Applications/treecc/stream.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/stream.h:1.1 *** /dev/null Tue Apr 6 12:53:42 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/stream.h Tue Apr 6 12:53:30 2004 *************** *** 0 **** --- 1,204 ---- + /* + * stream.h - Stream handling for writing source code. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_STREAM_H + #define _TREECC_STREAM_H + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * Stream buffer. + */ + #define TREECC_STREAM_BUFSIZ 2048 + typedef struct _tagTreeCCStreamBuf + { + char data[TREECC_STREAM_BUFSIZ]; + struct _tagTreeCCStreamBuf *next; + + } TreeCCStreamBuf; + + /* + * Stream literal code definition. + */ + typedef struct _tagTreeCCStreamDefn + { + char *code; + char *filename; + long linenum; + int atEnd; + int refOnly; + struct _tagTreeCCStreamDefn *next; + + } TreeCCStreamDefn; + + /* + * Structure of a stream. + */ + typedef struct _tagTreeCCStream TreeCCStream; + typedef struct _tagTreeCCContext *PTreeCCContext; + struct _tagTreeCCStream + { + PTreeCCContext context; /* Context that owns the stream */ + char *filename; /* Name of the file we are writing */ + char *embedName; /* Name of the file to embed in source */ + long linenum; /* Line number we are currently on */ + TreeCCStreamBuf *firstBuf; /* First buffer attached to the stream */ + TreeCCStreamBuf *lastBuf; /* Last buffer attached to the stream */ + int posn; /* Position within the last buffer */ + int forceCreate : 1; /* Force creation of the file */ + int readOnly : 1; /* File is read-only */ + int isHeader : 1; /* File is a header */ + int defaultFile : 1; /* File is a discardable default */ + int dirty : 1; /* Something useful has been written */ + TreeCCStreamDefn *firstDefn; /* First definition for the stream */ + TreeCCStreamDefn *lastDefn; /* Last definition for the stream */ + TreeCCStream *nextStream; /* Next stream associated with context */ + + }; + + /* + * Duplicate a string into the heap. + */ + char *TreeCCDupString(char *str); + + /* + * Resolve a pathname. The return value is malloc'ed. + */ + char *TreeCCResolvePathname(char *absolute, char *relative); + + /* + * Create an output stream. + */ + TreeCCStream *TreeCCStreamCreate(PTreeCCContext context, + char *filename, char *embedName, + int isHeader); + + /* + * Get the stream that corresponds to a Java class. + */ + TreeCCStream *TreeCCStreamGetJava(PTreeCCContext context, char *className); + + /* + * Destroy an output stream. + */ + void TreeCCStreamDestroy(TreeCCStream *stream); + + /* + * Clear the contents of a stream. + */ + void TreeCCStreamClear(TreeCCStream *stream); + + /* + * Flush the contents of a stream to the underlying file. + * Returns zero if an error occurred during writing. + */ + int TreeCCStreamFlush(TreeCCStream *stream); + + /* + * Flush the contents of a stream to a specific stdio file. + */ + int TreeCCStreamFlushStdio(TreeCCStream *stream, FILE *file); + + /* + * If we are using GCC, then make it perform some extra + * error checking for printf-style formats. + */ + #ifdef __GNUC__ + #define TREECC_PRNFMT(n,m) \ + __attribute__ ((__format__ (__printf__, n, m))) + #else + #define TREECC_PRNFMT(n,m) + #endif + + /* + * Print formatted data to a stream. + */ + void TreeCCStreamPrint(TreeCCStream *stream, const char *format, ...) + TREECC_PRNFMT(2, 3); + + /* + * Output a block of literal code to a stream. + */ + void TreeCCStreamCode(TreeCCStream *stream, char *code); + + /* + * Output a block of literal code to a stream which is indented. + * The first line is not indented. + */ + void TreeCCStreamCodeIndent(TreeCCStream *stream, char *code, int indent); + + /* + * Output a block of literal code to a stream which is indented. + * The first line is not indented. This version supports custom indent chars. + */ + void TreeCCStreamCodeIndentCustom(TreeCCStream *stream, char *code, + char indentchar, int indent); + + /* + * Fix the line number information in the output stream + * after outputting a block of code. + */ + void TreeCCStreamFixLine(TreeCCStream *stream); + + /* + * Add a literal definition block to a stream. + */ + void TreeCCStreamAddLiteral(TreeCCStream *stream, char *code, + char *filename, long linenum, + int atEnd, int refOnly); + + /* + * Output extra information that is needed at the top of a header file. + */ + void TreeCCStreamHeaderTop(TreeCCStream *stream); + + /* + * Output extra information that is needed at the bottom of a header file. + */ + void TreeCCStreamHeaderBottom(TreeCCStream *stream); + + /* + * Output extra information that is needed at the top of a source file. + */ + void TreeCCStreamSourceTop(TreeCCStream *stream); + + /* + * Output extra information that is needed at the top of a source file for C#. + */ + void TreeCCStreamSourceTopCS(TreeCCStream *stream); + + /* + * Output extra information that is needed at the bottom of a source file. + */ + void TreeCCStreamSourceBottom(TreeCCStream *stream); + + /* + * Print a "#line" directive to an output stream. + */ + void TreeCCStreamLine(TreeCCStream *stream, long linenum, + const char *filename); + + #ifdef __cplusplus + }; + #endif + + #endif /* _TREECC_STREAM_H */ Index: llvm/test/Programs/MultiSource/Applications/treecc/system.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/system.h:1.1 *** /dev/null Tue Apr 6 12:53:42 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/system.h Tue Apr 6 12:53:31 2004 *************** *** 0 **** --- 1,65 ---- + /* + * system.h - Import useful functions from the system libraries. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #ifndef _TREECC_SYSTEM_H + #define _TREECC_SYSTEM_H + + #include "config.h" + + /* + * Standard C headers. + */ + #include + #if HAVE_STDLIB_H + #include + #endif + #if HAVE_STRING_H + #include + #else + #if HAVE_STRINGS_H + #include + #endif + #endif + + /* + * Handle varargs. + */ + #ifdef HAVE_STDARG_H + #include + #define VA_LIST va_list + #define VA_START va_list va; va_start(va, format) + #define VA_END va_end(va) + #define VA_GET_LIST va + #else + #ifdef HAVE_VARARGS_H + #include + #define VA_LIST va_list + #define VA_START va_list va; va_start(va) + #define VA_END va_end(va) + #define VA_GET_LIST va + #else + #define VA_LIST int + #define VA_START + #define VA_END + #define VA_GET_LIST 0 + #endif + #endif + + #endif /* _TREECC_SYSTEM_H */ From criswell at cs.uiuc.edu Tue Apr 6 12:56:06 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:56:06 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.am Makefile.in binary_readme.txt essay.html extending.txt mkdoc mkhtml mkpdf texinfo.tex treecc.1 treecc.texi Message-ID: <200404061754.MAA01173@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc/doc: Makefile.am added (r1.1) Makefile.in added (r1.1) binary_readme.txt added (r1.1) essay.html added (r1.1) extending.txt added (r1.1) mkdoc added (r1.1) mkhtml added (r1.1) mkpdf added (r1.1) texinfo.tex added (r1.1) treecc.1 added (r1.1) treecc.texi added (r1.1) --- Log message: Adding in documentation for good measure. --- Diffs of the changes: (+9697 -0) Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.am diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.am:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.am Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,3 ---- + man_MANS = treecc.1 + info_TEXINFOS = treecc.texi + CLEANFILES = treecc.info treecc.info-1 treecc.info-2 treecc.info-3 Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.in diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.in:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/Makefile.in Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,360 ---- + # Makefile.in generated automatically by automake 1.4 from Makefile.am + + # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, + # with or without modifications, as long as this notice is preserved. + + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY, to the extent permitted by law; without + # even the implied warranty of MERCHANTABILITY or FITNESS FOR A + # PARTICULAR PURPOSE. + + + SHELL = @SHELL@ + + srcdir = @srcdir@ + top_srcdir = @top_srcdir@ + VPATH = @srcdir@ + prefix = @prefix@ + exec_prefix = @exec_prefix@ + + bindir = @bindir@ + sbindir = @sbindir@ + libexecdir = @libexecdir@ + datadir = @datadir@ + sysconfdir = @sysconfdir@ + sharedstatedir = @sharedstatedir@ + localstatedir = @localstatedir@ + libdir = @libdir@ + infodir = @infodir@ + mandir = @mandir@ + includedir = @includedir@ + oldincludedir = /usr/include + + DESTDIR = + + pkgdatadir = $(datadir)/@PACKAGE@ + pkglibdir = $(libdir)/@PACKAGE@ + pkgincludedir = $(includedir)/@PACKAGE@ + + top_builddir = .. + + ACLOCAL = @ACLOCAL@ + AUTOCONF = @AUTOCONF@ + AUTOMAKE = @AUTOMAKE@ + AUTOHEADER = @AUTOHEADER@ + + INSTALL = @INSTALL@ + INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) + INSTALL_DATA = @INSTALL_DATA@ + INSTALL_SCRIPT = @INSTALL_SCRIPT@ + transform = @program_transform_name@ + + NORMAL_INSTALL = : + PRE_INSTALL = : + POST_INSTALL = : + NORMAL_UNINSTALL = : + PRE_UNINSTALL = : + POST_UNINSTALL = : + build_alias = @build_alias@ + build_triplet = @build@ + host_alias = @host_alias@ + host_triplet = @host@ + target_alias = @target_alias@ + target_triplet = @target@ + AWK = @AWK@ + CC = @CC@ + EXEEXT = @EXEEXT@ + EXPR_CPP = @EXPR_CPP@ + LEX = @LEX@ + LN_S = @LN_S@ + MAINT = @MAINT@ + MAKEINFO = @MAKEINFO@ + OBJEXT = @OBJEXT@ + PACKAGE = @PACKAGE@ + RANLIB = @RANLIB@ + VERSION = @VERSION@ + YACC = @YACC@ + + man_MANS = treecc.1 + info_TEXINFOS = treecc.texi + CLEANFILES = treecc.info treecc.info-1 treecc.info-2 treecc.info-3 + mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs + CONFIG_HEADER = ../config.h + CONFIG_CLEAN_FILES = + TEXI2DVI = texi2dvi + INFO_DEPS = treecc.info + DVIS = treecc.dvi + TEXINFOS = treecc.texi + man1dir = $(mandir)/man1 + MANS = $(man_MANS) + + NROFF = nroff + DIST_COMMON = Makefile.am Makefile.in texinfo.tex + + + DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + + TAR = gtar + GZIP_ENV = --best + all: all-redirect + .SUFFIXES: + .SUFFIXES: .dvi .info .ps .texi .texinfo .txi + $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile + + Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + + treecc.info: treecc.texi + treecc.dvi: treecc.texi + + + DVIPS = dvips + + .texi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + + .texi.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + + .texi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + + .texinfo.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + + .texinfo: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + + .texinfo.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + + .txi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + + .txi.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + + .txi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + .dvi.ps: + $(DVIPS) $< -o $@ + + install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + d=$(srcdir); \ + for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \ + if test -f $$d/$$ifile; then \ + echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \ + $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \ + else : ; fi; \ + done; \ + done + @$(POST_INSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\ + done; \ + else : ; fi + + uninstall-info: + $(PRE_UNINSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + ii=yes; \ + else ii=; fi; \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + test -z "$ii" \ + || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \ + done + @$(NORMAL_UNINSTALL) + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \ + done + + dist-info: $(INFO_DEPS) + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + d=$(srcdir); \ + for file in `cd $$d && eval echo $$base*`; do \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done; \ + done + + mostlyclean-aminfo: + -rm -f treecc.aux treecc.cp treecc.cps treecc.dvi treecc.fn treecc.fns \ + treecc.ky treecc.kys treecc.ps treecc.log treecc.pg \ + treecc.toc treecc.tp treecc.tps treecc.vr treecc.vrs \ + treecc.op treecc.tr treecc.cv treecc.cn + + clean-aminfo: + + distclean-aminfo: + + maintainer-clean-aminfo: + cd $(srcdir) && for i in $(INFO_DEPS); do \ + rm -f $$i; \ + if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \ + rm -f $$i-[0-9]*; \ + fi; \ + done + + install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + + uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done + install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man1 + uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 + tags: TAGS + TAGS: + + + distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + + subdir = doc + + distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu doc/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info + info-am: $(INFO_DEPS) + info: info-am + dvi-am: $(DVIS) + dvi: dvi-am + check-am: all-am + check: check-am + installcheck-am: + installcheck: installcheck-am + install-exec-am: + install-exec: install-exec-am + + install-data-am: install-info-am install-man + install-data: install-data-am + + install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + install: install-am + uninstall-am: uninstall-info uninstall-man + uninstall: uninstall-am + all-am: Makefile $(INFO_DEPS) $(MANS) + all-redirect: all-am + install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install + installdirs: + $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(mandir)/man1 + + + mostlyclean-generic: + + clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + + distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + + maintainer-clean-generic: + mostlyclean-am: mostlyclean-aminfo mostlyclean-generic + + mostlyclean: mostlyclean-am + + clean-am: clean-aminfo clean-generic mostlyclean-am + + clean: clean-am + + distclean-am: distclean-aminfo distclean-generic clean-am + + distclean: distclean-am + + maintainer-clean-am: maintainer-clean-aminfo maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + + maintainer-clean: maintainer-clean-am + + .PHONY: install-info-am uninstall-info mostlyclean-aminfo \ + distclean-aminfo clean-aminfo maintainer-clean-aminfo install-man1 \ + uninstall-man1 install-man uninstall-man tags distdir info-am info \ + dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ + install-exec install-data-am install-data install-am install \ + uninstall-am uninstall all-redirect all-am all installdirs \ + mostlyclean-generic distclean-generic clean-generic \ + maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/binary_readme.txt diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/binary_readme.txt:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/binary_readme.txt Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,58 ---- + + Tree Compiler-Compiler + ====================== + + The treecc program is designed to assist in the development of compilers + and other language-based tools. It manages the generation of code to handle + abstract syntax trees and operations upon the trees. + + A fuller account of why treecc exists and what it can be used for can + be found in the HTML documentation within the "doc\html" subdirectory, + and in the introductory article "doc\intro.html". + + Installing Treecc + ----------------- + + The zip file should be unpacked in a new directory on your hard drive. + For example, "C:\Treecc". Then add "C:\Treecc\bin" to your PATH to + be able to run the tool. + + To uninstall treecc, simply delete the entire contents of the install + directory. + + Obtaining the source and more recent versions + --------------------------------------------- + + The latest version of treecc can be obtained from the following Web site: + + http://www.southern-storm.com.au/treecc/ + + The source code is also available from this site, under the terms of the + GNU General Public License. + + The authors can be contacted via e-mail at the following address: + + treecc at southern-storm.com.au + + Copyright Considerations + ------------------------ + + Treecc is distributed under the terms of the GNU General Public License. + A copy of this can be found in the "COPYING" file. + + However, it is not our intention to restrict the use of treecc to only + free software providers. Use by commercial software vendors is welcome. + + When you use treecc on your own input files to generate source code as + output, the resulting source code files are also owned by you. You may + re-distribute unmodified copies of these output source files, and any + binaries derived from them, in any way you see fit. Executing treecc on + your input files does not automatically incur obligations under the GPL. + + If you modify treecc itself, and generate new output files as a result, + then you must release all source modifications to treecc with your program + so that other users can benefit from your changes under the terms of the GPL. + + Contact the authors if you have any questions regarding the above. + It is our intention to allow the same amount of access to treecc output + files as is currently available using the GNU Bison and Flex programs. Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/essay.html diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/essay.html:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/essay.html Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,596 ---- + + + Treecc: An Aspect-Oriented Approach to Writing Compilers + + +

        Treecc: An Aspect-Oriented Approach to Writing Compilers

        + + Rhys Weatherley, rweather at southern-storm.com.au.

        + + Copyright © 2001, 2002 Rhys Weatherley
        + Verbatim copying and distribution of this entire article is permitted + in any medium, provided this copyright notice is preserved.

        + + This is a copy of an article that was published in + Issue 2 + of Free Software Magazine.

        + +

        1. Introduction

        + + The C# compiler in Portable.NET [1] is built on top + of the "Tree Compiler Compiler" (treecc) utility program. + Treecc [2] is distributed as Free Software + under the terms of the GNU General Public License.

        + + This article provides some background of why treecc came about. It discusses + two common compiler implementation techniques, and the reasons why they + often fail to manage the complexity of large programming languages like C#.

        + + We then discuss a new programming technique called "Aspect-Oriented + Programming". Treecc is an example of applying this technique to managing + the complexity of compiler construction.

        + +

        2. Patterns and Compiler Design

        + + Compiler writing is generally seen as a black art, but in reality it isn't + all that hard. The basic compilation steps are:

        + +

          +
        1. Convert the program into an abstract syntax tree.
        2. +
        3. Perform type-checking and semantic analysis on the tree.
        4. +
        5. Rearrange the tree to perform optimisations.
        6. +
        7. Convert the tree into the target code.
        8. +
        + + The difficulty in writing compilers is not the steps involved, but rather + the sheer number of tiny little details to keep straight. Modern languages + contain large numbers of operators, which are all very similar, but slightly + different:

        + +

        + Add, substract, multiply, divide, remainder, shift left, shift right, + shift right unsigned, bitwise and, bitwise or, exclusive-or, negate, + bitwise not, logical not, logical and, logical or, ... +
        + + And that's just the operators. Introduce statements, arrays, type coercion, + method invocation, and class definition, and it becomes very easy to + forget something amongst the forest of code.

        + + In an attempt to control this complexity, two common pattern-based + approaches have arisen over the years: Inheritance and Visitor.

        + + The inheritance pattern can be characterised as follows:

        + +

          +
        1. Declare a node type for every syntactic element in the language. + All types ultimately inherit from "Node".
        2. +
        3. Declare virtual methods in "Node" for + operations on node types: semantic analysis, optimization, + code generation, etc.
        4. +
        5. Override the virtuals in sub-classes to provide the + compiler implementation.
        6. +

        + + The visitor pattern can be characterised as follows:

        + +

          +
        1. Declare a node type for every syntactic element in the language. + All types ultimately inherit from "Node".
        2. +
        3. Declare a "Visitor" class with abstract virtual + methods such as "VisitAdd", "VisitSub", + "VisitIf", "VisitFunction", + etc for all of the node types.
        4. +
        5. Define a "walking procedure" over "Node" objects for + walking around a syntax tree, making callbacks on a supplied + visitor object.
        6. +
        7. Create multiple classes that inherit from "Visitor", + one for each operation. Implement the "Visit*" + functions for that type of operation.
        8. +
        + + In the following sections, we will explore why these two patterns often + fail to manage compiler complexity, even when the programmer applies them + rigorously.

        + +

        3. The implementation language is your worst enemy

        + + We will start with the inheritance pattern. Consider that we've written + the following C# code during the "declare all the node types" phase of + the project:

        + +

        +
        public class UnaryExpression : Expression
        + {
        +     protected Expression expr;
        + 
        +     public UnaryExpression(Expression _expr) { expr = _expr; }
        + }
        + 
        + public class NegateExpression : UnaryExpression
        + {
        +     public NegateExpression(Expression _expr) : base(_expr) {}
        + }
        + 
        + public class UnaryPlusExpression : UnaryExpression
        + {
        +     public UnaryPlusExpression(Expression _expr) : base(_expr) {}
        + }
        + 
        + public class BitwiseNotExpression : UnaryExpression
        + {
        +     public BitwiseNotExpression(Expression _expr) : base(_expr) {}
        + }
        +
        + + We continue this process for several hundred other node types, gradually + building up the entire syntax tree. This will probably take several weeks + to complete for a substantial language like C#, assuming that we are writing + the parser alongside the node types.

        + + We now want to go in and implement type-checking, so we modify the + "UnaryExpression" class as follows:

        + +

        +
        public class UnaryExpression : Expression
        + {
        +     protected Expression expr;
        + 
        +     public UnaryExpression(Expression _expr) { expr = _expr; }
        + 
        +     public override LanguageType TypeCheck()
        +     {
        +         LanguageType type = expr.TypeCheck();
        +         if(type.IsInteger() || type.IsFloat())
        +         {
        +             return type;
        +         }
        +         throw new TypeCheckException();
        +     }
        + }
        +
        + + We've put the common unary expression type-checking code in a common base + class. This makes it easier to maintain because there is only one copy. + We continue the process over the next few weeks and months for all the + other operators, statements, and declarations in the language. So far, + so good.

        + + Unfortunately, we've made a mistake. The "BitwiseNot" + operator is only legal on integer values; not floating-point.

        + + But will we find this bug? It was several weeks ago when we first wrote + the "BitwiseNotExpression" class, and we have since forgotten + all about it. It may even have been written by another programmer on the + team, who has also forgotten all about it. When we build our compiler, + we don't get any errors because the implemention language is perfectly + happy with the above code.

        + + Surely testing will find it? We are building a test suite alongside + the code, right? Unfortunately, that doesn't help either. The test + suite for a major language will be at least as complex as the compiler + itself, and so there is always the temptation to abstract common tests + into common test classes. We've just shifted the bug into the test suite + and given ourselves a false sense of security.

        + + So we keep coding for several more months, adding lots more code. And then + a really nasty bug pops up. The "BitwiseNot" operator is acting + strangely, and we have no idea why. The system is now so complex, with + so many common base classes implementing fallback defaults, that tracking + this down becomes very hard.

        + + The inheritance pattern has a fatal flaw. Adding a new operation entails + a very large maintainence burden, because hundreds of classes must be + modified. This is very error-prone, so we try to abstract details into + common base classes. But this introduces other errors.

        + + The problem basically boils down to semantic analysis: the implementation + language does not have enough knowledge about the application domain to + spot the problem and warn us about it. So it happily compiles the code + and leaves us to hang ourselves on the system's complexity later. + Programming languages are supposed to help us manage complexity, not + make the problem worse!

        + + I wrote a number of compilers using the inheritance approach, and every + single time the complexity killed me. I needed fallback defaults for + code maintainence reasons, but using fallbacks introduced massive numbers + of bugs. I was stuck.

        + +

        4. Design patterns aren't always what they are cracked up to be

        + + After much hair-pulling, I searched Design Patterns + by Gamma, et al [3]. "Is there a better + way of doing this?". Visitor patterns are the answer: + the book even gives a compiler example.

        + + Visitors solve the "I forgot to implement the BitwiseNot" + problem. Because every node type has its own "Visit*" method, + we will get an error when we try to build the compiler without implementing + the operation for a node type. Of course, this assumes that we haven't + been dumb and implemented fallback defaults in the "Visitor" + base class.

        + + Instead of using virtual methods, we can implement visitors using + switch statements over node types. e.g.

        + +

        +
        switch(node.type)
        + {
        +     case Negate: ...
        +     case UnaryPlus: ...
        +     case BinaryNot: ...
        +     ...
        + }
        +
        + + However, switch statements have a similar flaw to inheritance: the + implementation language will not warn us if we forget to put in + a case for every node type. It will happily fall out through the + "default" case with no warning. Tracking down these bugs + can be just as hard as tracking down inheritance fallback bugs. + Using virtual methods is "safer", if not quite as efficient.

        + + Unfortunately, there is a catch with visitors, as explained in + Design Patterns:

        + +

        + Use the Visitor pattern when ... the classes defining the object + structure rarely change, but you often want to define new operations + over the structure. Changing the object structure classes requires + redefining the interface to all visitors, which is potentially + costly. If the object structure classes change often, then it's + probably better to define the operations in those classes. +
        + + During the early stages of writing a compiler, the node types change very + frequently. This activates the Achilles heel of the Visitor pattern, + and creates a maintainence nightmare. The book suggests that we should + use the inheritance approach to solve this problem.

        + +

        5. So which one do we use? Inheritance or Visitor?

        + + The inheritance pattern becomes a problem when new operations are needed. + The solution is visitors. Visitors become a problem when new node types + are needed. The solution is inheritance.

        + + What we have is a situation that the design patterns gurus didn't + consider: if the set of nodes and operations are both changing rapidly, + then we will have problems no matter what we do.

        + + We need a solution that combines the strengths of both patterns without + the drawbacks of either. We want the implementation language to catch + us when we forget something, but we also want it to handle large numbers + of nodes and operations smoothly. We want to split different operations + into different modules, but also keep them closely associated with the + node type.

        + + None of the standard patterns provide this combination of functionality, + because none of the existing implementation languages support both styles + of program design at the same time.

        + +

        6. Aspect-Oriented Programming

        + + A new field in language design has emerged in recent years called + "Aspect-Oriented Programming" (AOP). A good review of the field + can be found in the October 2001 issue of the "Communications of + the ACM" [4], and on the AspectJ Web site + [5].

        + + The following excerpt from the introduction to the AOP section in the + CACM issue describes the essential aspects of AOP, and the difference + between OOP and AOP:

        + +

        + AOP is based on the idea that computer systems are better programmed + by separately specifying the various concerns (properties or areas + of interest) of a system and some description of their relationships, + and then relying on mechanisms in the underlying AOP environment to + weave or compose them together into a coherent program. ... + While the tendancy in OOP's is to find commonality among classes + and push it up the inheritance tree, AOP attempts to realize + scattered concerns as first-class elements, and eject them + horizontally from the object structure. +
        + + Aspect-orientation gives us some hope of solving our compiler + complexity problems. When we moved from the inheritance pattern + to the visitor pattern, we were attempting to eject the operations + horizontally. But it didn't quite work as well as we had hoped: the + intrinsic complexity of the set of nodes kept interfering. AOP + allows us to take the idea further, without re-introducing the problems + that visitors have.

        + + We can view each operation on node types (semantic analysis, + optimization, code generation, etc) as an "aspect" of the compiler's + construction. The AOP language weaves these aspects with the node + types to create the final compiler.

        + + However, we don't really want to invent a completely new programming + language for compiler construction. We would have to implement this + new language using all of the flawed techniques that makes writing + compilers hard. It's a classic chicken and egg problem: we don't + want to replace a buggy compiler with a buggy compiler implementation + language.

        + + We can strike a compromise, similar to that used by lex and yacc. + Those tools use a custom syntax for the difficult parts, and a + pre-existing underlying language (usually C) to implement everything + else. The code is expanded by the tool and then compiled with the + underlying language's compiler.

        + + Treecc uses a domain-specific aspect-oriented programming language for + declaring and managing nodes and operations, and uses an underlying language + to implement the body of the operations. C, C++, C#, or Java can be used + as the underlying language, depending upon your personal preference.

        + + Treecc is about 13,000 lines of code in size, which is relatively + easy to debug by hand.

        + + Aside: treecc does not support all of the AOP features that are + described in the literature. Treecc weaves together classes from multiple + method definitions. Other AOP languages can also weave together methods + from fragments in multiple aspects. We concentrated on those AOP features + that were useful for compiler construction. Other features could be + incorporated at a later date.

        + +

        7. Using Treecc to Beat Inheritance Bugs

        + + Now that we've identified the problems of inheritance and visitor patterns + for compiler implementation, we will show how treecc helps the programmer + avoid these traps.

        + + The following is the treecc definition of our example node types: + +

        +
        %option lang = "C#"
        + 
        + %node Expression %abstract %typedef
        + 
        + %node UnaryExpression Expression %abstract =
        + {
        +     Expression expr;
        + }
        + 
        + %node NegateExpression UnaryExpression
        + %node UnaryPlusExpression UnaryExpression
        + %node BitwiseNotExpression UnaryExpression
        +
        + + Treecc converts this into a number of C# classes, one for each + node type. It also inserts helper methods for testing the type + of a node and for tracking source line numbers. If the output language + is C or C++, treecc will also insert code for allocating large numbers + of nodes efficiently.

        + + The type-checking operation (or "aspect") is declared as follows:

        + +

        +
        %operation %virtual LanguageType TypeCheck(Expression e)
        + 
        + TypeCheck(NegateExpression),
        + TypeCheck(UnaryPlusExpression)
        + {
        +     LanguageType type = e.expr.TypeCheck();
        +     if(type.IsInteger() || type.IsFloat())
        +     {
        +         return type;
        +     }
        +     throw new TypeCheckException();
        + }
        + 
        + TypeCheck(BitwiseNotExpression)
        + {
        +     LanguageType type = e.expr.TypeCheck();
        +     if(type.IsInteger())
        +     {
        +         return type;
        +     }
        +     throw new TypeCheckException();
        + }
        +
        + + We have not declared the operation to cover "Expression" or + "UnaryExpression". Instead, we list all of the applicable + subtypes explicitly. When treecc is run on the above file, it will check + that every non-abstract node type is handled by an operation case. If it finds + a missing type, it will report an error. Let's demonstrate that by adding a + new unary expression type:

        + +

        + %node LogicalNotExpression UnaryExpression
        +
        + eg.tc:17: node type `LogicalNotExpression' is not handled in operation `TypeCheck'
        +
        + + This is at the heart of treecc's power: it performs a large amount of + semantic analysis over the node types to determine if the programmer has + forgotten something. The programmer is notified of this early in + development process, when it is easier to fix the problem.

        + + As we discussed earlier, we want to implement common code in common + base classes to improve code sharing. However, this introduces + hard to find bugs. Treecc avoids the need to do this by allowing + the programmer to attach multiple cases to the same code block, + as in the case of "NegateExpression" and + "UnaryPlusExpression" above.

        + + An important feature of aspect-oriented languages is aspect modularity: + it should be possible to implement separate aspects in different parts + of the code. Treecc supports this by separating node and operation + definitions. Operations do not need to be implemented in the same + file as the nodes to which they apply, and multiple operations on + the same node types can be scattered through-out the code.

        + + Portable.NET takes this even further by separating individual operations + across multiple files for expressions, statements, declarations, etc. + This introduces a clearer structure to the code that makes it easier + to navigate the source during compiler construction. The semantic analysis + routines in treecc ensure that nothing is missed when all of the + separate modules are recombined.

        + +

        8. Painless Visitors

        + + The previous example used a "%virtual" operation, which + is defined over all node types. Treecc inserts the virtual method + body wherever it is required.

        + + Sometimes we don't want to define an operation as a virtual method. + We would prefer to use the visitor approach. The following is what + a visitor version of "TypeCheck" would look like: + +

        +
        %operation LanguageType TypeChecker::TypeCheck(Expression e) = {null}
        + 
        + TypeCheck(NegateExpression),
        + TypeCheck(UnaryPlusExpression)
        + {
        +     LanguageType type = TypeCheck(e.expr);
        +     if(type.IsInteger() || type.IsFloat())
        +     {
        +         return type;
        +     }
        +     throw new TypeCheckException();
        + }
        + 
        + TypeCheck(BitwiseNotExpression)
        + {
        +     LanguageType type = TypeCheck(e.expr);
        +     if(type.IsInteger())
        +     {
        +         return type;
        +     }
        +     throw new TypeCheckException();
        + }
        +
        + + This is almost identical to the previous version, except for the + definition of the operation, and the calling conventions for + "TypeCheck". Behind the scenes, treecc creates + a class called "TypeChecker" that contains a static + method called "TypeCheck". This is the visitor.

        + + Interestingly, if we had used C as the underlying language, then no + changes are necessary to the bodies of the operation cases. Only + the "%virtual" keyword changes. The C macro pre-processor + is used to smooth out the differences.

        + + This illustrates another useful property of treecc: it is very simple + to flip operations between inhertance-based virtuals and visitor-based + non-virtuals. This allows the programmer to start developing the compiler + one way, change their mind, and quickly flip to the other way.

        + + Normally, changing inheritance-based code into visitor-based code + would entail a complete system rewrite. Changing patterns with + treecc is trivial.

        + + This is a common property of aspect-oriented programming languages: + because the language takes care of the inserting the aspects into + the main classes, it is easier to change the style of insertion + without a major system overhaul.

        + + Non-virtual operations can be applied to multiple arguments, which + can be very useful when implementing coercions: + +

        +
        %enum SimpleType =
        + {
        +     Integer,
        +     Long,
        +     Float,
        +     Error
        + }
        + 
        + %operation %inline SimpleType Binary::Coerce
        +         ([SimpleType type1], [SimpleType type2]) = {Error}
        + 
        + Coerce(Integer, Integer)
        + {
        +     return Integer;
        + }
        + 
        + Coerce(Integer, Long),
        + Coerce(Long, Integer),
        + Coerce(Long, Long)
        + {
        +     return Long;
        + }
        + 
        + Coerce(Integer, Float),
        + Coerce(Float, Integer),
        + Coerce(Long, Float),
        + Coerce(Float, Float)
        + {
        +     return Float;
        + }
        + 
        + Coerce(Integer, Error),
        + Coerce(Error, Integer),
        + Coerce(Long, Error),
        + Coerce(Error, Long),
        + Coerce(Float, Error),
        + Coerce(Error, Float),
        + Coerce(Error, Error)
        + {
        +     return Error;
        + }
        +
        + + Treecc turns this into a highly efficient nested switch statement, + which would be extremely difficult to debug by hand. We actually + left out one of the cases above, so we get an error: + +
        eg.tc:48: case `Float, Long' is missing from operation `Coerce'
        + + Casts and coercions on primitive types can now be implemented as + simple table lookups, with treecc checking the completeness of the + table for us.

        + +

        9. Conclusion and Future Directions

        + + Treecc provides a new way to attack the complexity of compiler implementation + by automating error-prone tasks. It performs a large amount of semantic + analysis on the program to ensure that common problems are caught early + in the development cycle.

        + + Because treecc is based on an aspect-oriented foundation, it allows the + programmer to separate out concerns and deal with them individually. + Treecc puts the whole system back together in the most efficient manner + possible.

        + + The system is not necessarily complete. We'd like to experiment with + rule-based code generation techniques. At present, optimizers and + code generators must be written by hand, as operations on node types.

        + + A rule-based system would make it easier to build clever optimizers + as a set of pattern matching directives. Operations are already a + special class of pattern matcher, but they don't have any back-tracking + and retry capabilities.

        + + Another area that treecc can be applied to is the construction of + "Just In Time" compilers. The first phase of the JIT process is the + reconstruction of the intermediate code form of the program. This + intermediate code typically takes the form of abstract syntax trees or + three-address statements.

        + + Treecc is well-suited to the management of JIT intermediate forms. + Register allocation, dynamic flow analysis, and machine-dependent + code generation can be added as JIT aspects. We are currently + exploring the use of treecc to assist in the construction of a + JIT for Portable.NET

        + +

        References

        + + [1] Portable.NET Web Site, http://www.southern-storm.com.au/portable_net.html.

        + + [2] Treecc Web Site, http://www.southern-storm.com.au/treecc.html.

        + + [3] Gamma, et al., Design Patterns: Elements of + Reusable Object-Oriented Software, Addison-Wesley, 1995.

        + + [4] Aspect-Oriented Programming, Communications of + the ACM, October 2001.

        + + [5] AspectJ Web Site, http://www.aspectj.org/.

        + + + Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/extending.txt diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/extending.txt:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/extending.txt Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,99 ---- + Quick and Dirty Guide to Extending and Testing Treecc + + 1. Adding a new output language - Scaffolding + + The following is the bare scaffolding to link a new language into treecc: + + - Add a new identifier to the TREECC_LANG_* list in "info.h". + - Recognise the language name for the "lang" option in "options.c", + function "LangOption". + - Add a new case to the switch statement in "TreeCCGenerate" function + in the file "gen.c" for the language identifier, which calls a + function called "TreeCCGenerateLang", which you should prototype + in "gen.h". + - Add a new "gen_lang.c" file to the project (don't forget to + update Makefile.am), which implements the output routines. + + 2. Adding a new output language - Details + + The "gen_lang.c" file needs to export a single function called + "TreeCCGenerateLang", which iterates over all the nodes and operations + to output the final code. + + The "TreeCCGenerateLang" function must perform the following tasks, + roughly in this order: + + - Output any source header information that is required. + - Output node kinds, which are used to uniquely identify each + node type (e.g. "#define expression_kind 1" in C). In an OO + language, you can output these kind values + - Perform forward declaration of the node classes and operations, + if required by the output language (C# and Java don't need this, + but C does). + - Output the node allocation skeleton (normally not needed if + your language is garbage-collected). + - Define the node classes, and any factory create methods that + are required. You may also need to define a "state type" which + holds common allocation information. + - Output non-virtual operations, by calling "TreeCCGenerateNonVirtuals", + and passing it a function block ("TreeCCNonVirtual" type) to + assist with the output process. + - Output any source footer information that is required, including + helper functions for node allocation, kind testing, etc. + + It is usually easiest to start with one of the existing output languages + and then cut-and-paste yourself a new one. If you are using a non garbage + collected language such as C or C++, then start with either "gen_c.c" or + "gen_cpp.c" as a base. If you are using a garbage collected language + like C# or Java, then start with either "gen_cs.c" or "gen_java.c". + + The function "TreeCCNodeVisitAll" can be very useful for iterating over + all node types in the system: pass it a callback that provides your + language-specific node handling code. See "info.h" and "gen.h" for + other helper functions. + + Nodes and operations can be written to multiple output files, and you + must handle this properly. The functions in "stream.h" can assist with + this. The "header" and "source" fields in "TreeCCNode" and "TreeCCOperation" + describe where to output node and operation implementations. + + The actual API to nodes and operations is language-specific, but try + to follow the existing styles where possible. See "doc/treecc.texi" + for documentation on the existing API styles. + + 2. Testing all possible variants. + + There are lots of different output modes (re-entrant vs non re-entrant, + line tracking vs no line tracking, abstract factories, virtual vs non-virtual + operations, inline vs non-inline, etc). + + Your test cases in the "tests" directory should attempt to cover the + major areas. See the "output*.tst" files for the existing tests. You + shouldn't need to create "input" or "parse" tests, as they are generic. + + Once you have written a new "outputN.tst" file, generate test output + using "./test_output outputN.tst >outputN.out". Then hand-inspect the + "outputN.out" file for problems. Once you are satisfied that your + "gen_lang.c" code is generating the right output, add the following + line to "tests/test_list": + + test_output outputN + + After you have done this, you can run "make check" to verify that you + haven't broken anything as you made changes to the system. + + 3. Add an example. + + Go into the "examples" directory and add a new version of the expression + example for your language, to demonstrate how to use treecc with the + language. The examples doesn't necessarily need to compile - just give + a guide as to how to use the tool. + + 4. Write documentation. + + Add a new section to "doc/treecc.texi" describing the API for your + language, using the existing sections as to a guide to the text. + + 5. It's not as hard as your think! + + The above may look daunting, but it's mostly a cut-and-paste exercise. Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/mkdoc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/mkdoc:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/mkdoc Tue Apr 6 12:54:44 2004 *************** *** 0 **** --- 1,34 ---- + #!/bin/sh + # + # mkdoc - Make all forms of documentation for treecc from Texinfo input. + # + # Usage: mkdir outdir + + # Check the command-line. + if [ -z "$1" ]; then + echo "Usage: $0 outdir" + exit 1 + fi + + # Check that we are executed in the correct directory. + if [ ! -f treecc.texi ]; then + echo "Cannot find treecc.texi" + exit 1 + fi + + # Create the output directory. + if [ ! -d "$1" ]; then + mkdir "$1" + fi + + # Create the online HTML documentation. + ./mkhtml "$1" + + # Create the PDF documentation. + ./mkpdf + cp treecc.pdf "$1" + + # Pack up the HTML documentation into a tar.gz file. + cd "$1" + tar cfz treecc-doc.tar.gz *.html + exit 0 Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/mkhtml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/mkhtml:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/mkhtml Tue Apr 6 12:54:45 2004 *************** *** 0 **** --- 1,29 ---- + #!/bin/sh + # + # mkhtml - Make html documentation for treecc from Texinfo input. + # + # Usage: mkhtml outdir + + # Check the command-line. + if [ -z "$1" ]; then + echo "Usage: $0 outdir" + exit 1 + fi + + # Check that we are executed in the correct directory. + if [ ! -f treecc.texi ]; then + echo "Cannot find treecc.texi" + exit 1 + fi + + # Create the output directory. + if [ ! -d "$1" ]; then + mkdir "$1" + fi + + # Get the full pathname of the input file. + PATHNAME=`pwd`/treecc.texi + + # Change to the output directory and execute "texi2html". + cd "$1" + exec texi2html -split_chapter "$PATHNAME" Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/mkpdf diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/mkpdf:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/mkpdf Tue Apr 6 12:54:45 2004 *************** *** 0 **** --- 1,5 ---- + #!/bin/sh + # + # mkpdf - Make the PDF version of the treecc documentation + + exec texi2dvi --pdf treecc.texi Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/texinfo.tex diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/texinfo.tex:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/texinfo.tex Tue Apr 6 12:54:45 2004 *************** *** 0 **** --- 1,5484 ---- + % texinfo.tex -- TeX macros to handle Texinfo files. + % + % Load plain if necessary, i.e., if running under initex. + \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + % + \def\texinfoversion{1999-01-05}% + % + % Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98 + % Free Software Foundation, Inc. + % + % This texinfo.tex file 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 texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write + % to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + % Boston, MA 02111-1307, USA. + % + % In other words, you are welcome to use, share and improve this program. + % You are forbidden to forbid anyone else to use, share and improve + % what you give them. Help stamp out software-hoarding! + % + % Please try the latest version of texinfo.tex before submitting bug + % reports; you can get the latest version from: + % ftp://ftp.gnu.org/pub/gnu/texinfo.tex + % /home/gd/gnu/doc/texinfo.tex on the GNU machines. + % (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) + % ftp://tug.org/tex/texinfo.tex + % ftp://ctan.org/macros/texinfo/texinfo.tex + % (and all CTAN mirrors, finger ctan at ctan.org for a list). + % The texinfo.tex in the texinfo distribution itself could well be out + % of date, so if that's what you're using, please check. + % + % Send bug reports to bug-texinfo at gnu.org. + % Please include a precise test case in each bug report, + % including a complete document with which we can reproduce the problem. + % + % To process a Texinfo manual with TeX, it's most reliable to use the + % texi2dvi shell script that comes with the distribution. For simple + % manuals, however, you can get away with: + % tex foo.texi + % texindex foo.?? + % tex foo.texi + % tex foo.texi + % dvips foo.dvi -o # or whatever, to process the dvi file. + % The extra runs of TeX get the cross-reference information correct. + % Sometimes one run after texindex suffices, and sometimes you need more + % than two; texi2dvi does it as many times as necessary. + + \message{Loading texinfo [version \texinfoversion]:} + + % If in a .fmt file, print the version number + % and turn on active characters that we couldn't do earlier because + % they might have appeared in the input file name. + \everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + + % Save some parts of plain tex whose names we will redefine. + + \let\ptexb=\b + \let\ptexbullet=\bullet + \let\ptexc=\c + \let\ptexcomma=\, + \let\ptexdot=\. + \let\ptexdots=\dots + \let\ptexend=\end + \let\ptexequiv=\equiv + \let\ptexexclam=\! + \let\ptexi=\i + \let\ptexlbrace=\{ + \let\ptexrbrace=\} + \let\ptexstar=\* + \let\ptext=\t + + % We never want plain's outer \+ definition in Texinfo. + % For @tex, we can use \tabalign. + \let\+ = \relax + + + \message{Basics,} + \chardef\other=12 + + % If this character appears in an error message or help string, it + % starts a new line in the output. + \newlinechar = `^^J + + % Set up fixed words for English if not already set. + \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi + \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi + \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi + \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi + \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi + \ifx\putwordon\undefined \gdef\putwordon{on}\fi + \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi + \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi + \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi + \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi + \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi + \ifx\putwordShortContents\undefined \gdef\putwordShortContents{Short Contents}\fi + \ifx\putwordTableofContents\undefined\gdef\putwordTableofContents{Table of Contents}\fi + + % Ignore a token. + % + \def\gobble#1{} + + \hyphenation{ap-pen-dix} + \hyphenation{mini-buf-fer mini-buf-fers} + \hyphenation{eshell} + \hyphenation{white-space} + + % Margin to add to right of even pages, to left of odd pages. + \newdimen \bindingoffset + \newdimen \normaloffset + \newdimen\pagewidth \newdimen\pageheight + + % Sometimes it is convenient to have everything in the transcript file + % and nothing on the terminal. We don't just call \tracingall here, + % since that produces some useless output on the terminal. + % + \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% + \ifx\eTeXversion\undefined + \def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen + }% + \else + \def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen + }% + \fi + + % For @cropmarks command. + % Do @cropmarks to get crop marks. + % + \newif\ifcropmarks + \let\cropmarks = \cropmarkstrue + % + % Dimensions to add cropmarks at corners. + % Added by P. A. MacKay, 12 Nov. 1986 + % + \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines + \newdimen\cornerlong \cornerlong=1pc + \newdimen\cornerthick \cornerthick=.3pt + \newdimen\topandbottommargin \topandbottommargin=.75in + + % Main output routine. + \chardef\PAGE = 255 + \output = {\onepageout{\pagecontents\PAGE}} + + \newbox\headlinebox + \newbox\footlinebox + + % \onepageout takes a vbox as an argument. Note that \pagecontents + % does insertions, but you have to call it yourself. + \def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi + } + + \newinsert\margin \dimen\margin=\maxdimen + + \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} + {\catcode`\@ =11 + \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi + % marginal hacks, juha at viisa.uucp (Juha Takala) + \ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi + \dimen@=\dp#1 \unvbox#1 + \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi + \ifr at ggedbottom \kern-\dimen@ \vfil \fi} + } + + % Here are the rules for the cropmarks. Note that they are + % offset so that the space between them is truly \outerhsize or \outervsize + % (P. A. MacKay, 12 November, 1986) + % + \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} + \def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} + \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} + \def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + + % Parse an argument, then pass it to #1. The argument is the rest of + % the input line (except we remove a trailing comment). #1 should be a + % macro which expects an ordinary undelimited TeX argument. + % + \def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx + } + + % If the next token is an obeyed space (from an @example environment or + % the like), remove it and recurse. Otherwise, we're done. + \def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi + } + + % Remove a single space (as the delimiter token to the macro call). + {\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + + {\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% + } + + % Since all \c{,omment} does is throw away the argument, we can let TeX + % do that for us. The \relax here is matched by the \relax in the call + % in \parseargline; it could be more or less anything, its purpose is + % just to delimit the argument to the \c. + \def\argremovec#1\c#2\relax{\toks0 = {#1}} + \def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + + % \argremovec{,omment} might leave us with trailing spaces, though; e.g., + % @end itemize @c foo + % will have two active spaces as part of the argument with the + % `itemize'. Here we remove all active spaces from #1, and assign the + % result to \toks0. + % + % This loses if there are any *other* active characters besides spaces + % in the argument -- _ ^ +, for example -- since they get expanded. + % Fortunately, Texinfo does not define any such commands. (If it ever + % does, the catcode of the characters in questionwill have to be changed + % here.) But this means we cannot call \removeactivespaces as part of + % \argremovec{,omment}, since @c uses \parsearg, and thus the argument + % that \parsearg gets might well have any character at all in it. + % + \def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup + } + + % Change the active space to expand to nothing. + % + \begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} + \endgroup + + + \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + + %% These are used to keep @begin/@end levels from running away + %% Call \inENV within environments (after a \begingroup) + \newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} + \def\ENVcheck{% + \ifENV\errmessage{Still within an environment; press RETURN to continue} + \endgroup\fi} % This is not perfect, but it should reduce lossage + + % @begin foo is the same as @foo, for now. + \newhelp\EMsimple{Press RETURN to continue.} + + \outer\def\begin{\parsearg\beginxxx} + + \def\beginxxx #1{% + \expandafter\ifx\csname #1\endcsname\relax + {\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else + \csname #1\endcsname\fi} + + % @end foo executes the definition of \Efoo. + % + \def\end{\parsearg\endxxx} + \def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi + } + + % There is an environment #1, but it hasn't been started. Give an error. + % + \def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% + } + + % Define the control sequence \E#1 to give an unmatched @end error. + % + \def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% + } + + + % Single-spacing is done by various environments (specifically, in + % \nonfillstart and \quotations). + \newskip\singlespaceskip \singlespaceskip = 12.5pt + \def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip + } + + %% Simple single-character @ commands + + % @@ prints an @ + % Kludge this until the fonts are right (grr). + \def\@{{\tt\char64}} + + % This is turned off because it was never documented + % and you can use @w{...} around a quote to suppress ligatures. + %% Define @` and @' to be the same as ` and ' + %% but suppressing ligatures. + %\def\`{{`}} + %\def\'{{'}} + + % Used to generate quoted braces. + \def\mylbrace {{\tt\char123}} + \def\myrbrace {{\tt\char125}} + \let\{=\mylbrace + \let\}=\myrbrace + \begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef at lbracecmd[\{]% + @gdef at rbracecmd[\}]% + @endgroup + + % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent + % Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. + \let\, = \c + \let\dotaccent = \. + \def\ringaccent#1{{\accent23 #1}} + \let\tieaccent = \t + \let\ubaraccent = \b + \let\udotaccent = \d + + % Other special characters: @questiondown @exclamdown + % Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. + \def\questiondown{?`} + \def\exclamdown{!`} + + % Dotless i and dotless j, used for accents. + \def\imacro{i} + \def\jmacro{j} + \def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi + } + + % Be sure we're in horizontal mode when doing a tie, since we make space + % equivalent to this in @example-like environments. Otherwise, a space + % at the beginning of a line will start with \penalty -- and + % since \penalty is valid in vertical mode, we'd end up putting the + % penalty on the vertical list instead of in the new paragraph. + {\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } + } + + % @: forces normal size whitespace following. + \def\:{\spacefactor=1000 } + + % @* forces a line break. + \def\*{\hfil\break\hbox{}\ignorespaces} + + % @. is an end-of-sentence period. + \def\.{.\spacefactor=3000 } + + % @! is an end-of-sentence bang. + \def\!{!\spacefactor=3000 } + + % @? is an end-of-sentence query. + \def\?{?\spacefactor=3000 } + + % @w prevents a word break. Without the \leavevmode, @w at the + % beginning of a paragraph, when TeX is still in vertical mode, would + % produce a whole line of output instead of starting the paragraph. + \def\w#1{\leavevmode\hbox{#1}} + + % @group ... @end group forces ... to be all on one page, by enclosing + % it in a TeX vbox. We use \vtop instead of \vbox to construct the box + % to keep its height that of a normal line. According to the rules for + % \topskip (p.114 of the TeXbook), the glue inserted is + % max (\topskip - \ht (first item), 0). If that height is large, + % therefore, no glue is inserted, and the space between the headline and + % the text is small, which looks bad. + % + \def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment + } + % + % TeX puts in an \escapechar (i.e., `@') at the beginning of the help + % message, so this ends up printing `@group can only ...'. + % + \newhelp\groupinvalidhelp{% + group can only be used in environments such as @example,^^J% + where each line of input produces a line of output.} + + % @need space-in-mils + % forces a page break if there is not space-in-mils remaining. + + \newdimen\mil \mil=0.001in + + \def\need{\parsearg\needx} + + % Old definition--didn't work. + %\def\needx #1{\par % + %% This method tries to make TeX break the page naturally + %% if the depth of the box does not fit. + %{\baselineskip=0pt% + %\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak + %\prevdepth=-1000pt + %}} + + \def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + } + + % @br forces paragraph break + + \let\br = \par + + % @dots{} output an ellipsis using the current font. + % We do .5em per period so that it has the same spacing in a typewriter + % font as three actual period characters. + % + \def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + } + + % @enddots{} is an end-of-sentence ellipsis. + % + \def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 + } + + + % @page forces the start of a new page + % + \def\page{\par\vfill\supereject} + + % @exdent text.... + % outputs text on separate line in roman font, starting at standard page margin + + % This records the amount of indent in the innermost environment. + % That's how much \exdent should take out. + \newskip\exdentamount + + % This defn is used inside fill environments such as @defun. + \def\exdent{\parsearg\exdentyyy} + \def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + + % This defn is used inside nofill environments such as @example. + \def\nofillexdent{\parsearg\nofillexdentyyy} + \def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + + % @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + + \def\inmargin#1{% + \strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} + \newskip\inmarginspacing \inmarginspacing=1cm + \def\strutdepth{\dp\strutbox} + + %\hbox{{\rm#1}}\hfil\break}} + + % @include file insert text of that file as input. + % Allow normal characters that we make active in the argument (a file name). + \def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} + % Restore active chars for included file. + \def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile + \endgroup} + + \def\thisfile{} + + % @center line outputs that line, centered + + \def\center{\parsearg\centerzzz} + \def\centerzzz #1{{\advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \centerline{#1}}} + + % @sp n outputs n lines of vertical space + + \def\sp{\parsearg\spxxx} + \def\spxxx #1{\vskip #1\baselineskip} + + % @comment ...line which is ignored... + % @c is the same as @comment + % @ignore ... @end ignore is another way to write a comment + + \def\comment{\begingroup \catcode`\^^M=\other% + \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% + \commentxxx} + {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + + \let\c=\comment + + % @paragraphindent is defined for the Info formatting commands only. + \let\paragraphindent=\comment + + % Prevent errors for section commands. + % Used in @ignore and in failing conditionals. + \def\ignoresections{% + \let\chapter=\relax + \let\unnumbered=\relax + \let\top=\relax + \let\unnumberedsec=\relax + \let\unnumberedsection=\relax + \let\unnumberedsubsec=\relax + \let\unnumberedsubsection=\relax + \let\unnumberedsubsubsec=\relax + \let\unnumberedsubsubsection=\relax + \let\section=\relax + \let\subsec=\relax + \let\subsubsec=\relax + \let\subsection=\relax + \let\subsubsection=\relax + \let\appendix=\relax + \let\appendixsec=\relax + \let\appendixsection=\relax + \let\appendixsubsec=\relax + \let\appendixsubsection=\relax + \let\appendixsubsubsec=\relax + \let\appendixsubsubsection=\relax + \let\contents=\relax + \let\smallbook=\relax + \let\titlepage=\relax + } + + % Used in nested conditionals, where we have to parse the Texinfo source + % and so want to turn off most commands, in case they are used + % incorrectly. + % + \def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax + } + + % Ignore @ignore ... @end ignore. + % + \def\ignore{\doignore{ignore}} + + % Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. + % + \def\ifinfo{\doignore{ifinfo}} + \def\ifhtml{\doignore{ifhtml}} + \def\ifnottex{\doignore{ifnottex}} + \def\html{\doignore{html}} + \def\menu{\doignore{menu}} + \def\direntry{\doignore{direntry}} + + % @dircategory CATEGORY -- specify a category of the dir file + % which this file should belong to. Ignore this in TeX. + \let\dircategory = \comment + + % Ignore text until a line `@end #1'. + % + \def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1 at end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext + } + + % What we do to finish off ignored text. + % + \def\enddoignore{\endgroup\ignorespaces}% + + \newif\ifwarnedobs\warnedobsfalse + \def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi + } + + % **In TeX 3.0, setting text in \nullfont hangs tex. For a + % workaround (which requires the file ``dummy.tfm'' to be installed), + % uncomment the following line: + %%%%%\font\nullfont=dummy\let\obstexwarn=\relax + + % Ignore text, except that we keep track of conditional commands for + % purposes of nesting, up to an `@end #1' command. + % + \def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% + } + + % @set VAR sets the variable VAR to an empty value. + % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. + % + % Since we want to separate VAR from REST-OF-LINE (which might be + % empty), we can't just use \parsearg; we have to insert a space of our + % own to delimit the rest of the line, and then take it out again if we + % didn't need it. Make sure the catcode of space is correct to avoid + % losing inside @example, for instance. + % + \def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} + \def\setxxx#1{\setyyy#1 \endsetyyy} + \def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup + } + % Can't use \xdef to pre-expand #2 and save some time, since \temp or + % \next or other control sequences that we've defined might get us into + % an infinite loop. Consider `@set foo @cite{bar}'. + \def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + + % @clear VAR clears (i.e., unsets) the variable VAR. + % + \def\clear{\parsearg\clearxxx} + \def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + + % @value{foo} gets the text saved in variable foo. + % + { + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} + } + \def\valuexxx#1{\expandablevalue{#1}\endgroup} + + % We have this subroutine so that we can handle at least some @value's + % properly in indexes (we \let\value to this in \indexdummies). Ones + % whose names contain - or _ still won't work, but we can't do anything + % about that. The command has to be fully expandable, since the result + % winds up in the index file. This means that if the variable's value + % contains other Texinfo commands, it's almost certain it will fail + % (although perhaps we could fix that with sufficient work to do a + % one-level expansion on the result, instead of complete). + % + \def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi + } + + % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined + % with @set. + % + \def\ifset{\parsearg\ifsetxxx} + \def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi + } + \def\ifsetsucceed{\conditionalsucceed{ifset}} + \def\ifsetfail{\nestedignore{ifset}} + \defineunmatchedend{ifset} + + % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been + % defined with @set, or has been undefined with @clear. + % + \def\ifclear{\parsearg\ifclearxxx} + \def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi + } + \def\ifclearsucceed{\conditionalsucceed{ifclear}} + \def\ifclearfail{\nestedignore{ifclear}} + \defineunmatchedend{ifclear} + + % @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text + % following, through the first @end iftex (etc.). Make `@end iftex' + % (etc.) valid only after an @iftex. + % + \def\iftex{\conditionalsucceed{iftex}} + \def\ifnothtml{\conditionalsucceed{ifnothtml}} + \def\ifnotinfo{\conditionalsucceed{ifnotinfo}} + \defineunmatchedend{iftex} + \defineunmatchedend{ifnothtml} + \defineunmatchedend{ifnotinfo} + + % We can't just want to start a group at @iftex (for example) and end it + % at @end iftex, since then @set commands inside the conditional have no + % effect (they'd get reverted at the end of the group). So we must + % define \Eiftex to redefine itself to be its previous value. (We can't + % just define it to fail again with an ``unmatched end'' error, since + % the @ifset might be nested.) + % + \def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp + } + + % We need to expand lots of \csname's, but we don't want to expand the + % control sequences after we've constructed them. + % + \def\nece#1{\expandafter\noexpand\csname#1\endcsname} + + % @asis just yields its argument. Used with @table, for example. + % + \def\asis#1{#1} + + % @math means output in math mode. + % We don't use $'s directly in the definition of \math because control + % sequences like \math are expanded when the toc file is written. Then, + % we read the toc file back, the $'s will be normal characters (as they + % should be, according to the definition of Texinfo). So we must use a + % control sequence to switch into and out of math mode. + % + % This isn't quite enough for @math to work properly in indices, but it + % seems unlikely it will ever be needed there. + % + \let\implicitmath = $ + \def\math#1{\implicitmath #1\implicitmath} + + % @bullet and @minus need the same treatment as @math, just above. + \def\bullet{\implicitmath\ptexbullet\implicitmath} + \def\minus{\implicitmath-\implicitmath} + + % @refill is a no-op. + \let\refill=\relax + + % If working on a large document in chapters, it is convenient to + % be able to disable indexing, cross-referencing, and contents, for test runs. + % This is done with @novalidate (before @setfilename). + % + \newif\iflinks \linkstrue % by default we want the aux files. + \let\novalidate = \linksfalse + + % @setfilename is done at the beginning of every texinfo file. + % So open here the files we need to have open while reading the input. + % This makes it possible to make a .fmt file for texinfo. + \def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. + } + + % Called from \setfilename. + % + \def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% + } + + % @bye. + \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + + \message{fonts,} + % Font-change commands. + + % Texinfo sort of supports the sans serif font style, which plain TeX does not. + % So we set up a \sf analogous to plain's \rm, etc. + \newfam\sffam + \def\sf{\fam=\sffam \tensf} + \let\li = \sf % Sometimes we call it \li, not \sf. + + % We don't need math for this one. + \def\ttsl{\tenttsl} + + % Use Computer Modern fonts at \magstephalf (11pt). + \newcount\mainmagstep + \mainmagstep=\magstephalf + + % Set the font macro #1 to the font named #2, adding on the + % specified font prefix (normally `cm'). + % #3 is the font's design size, #4 is a scale factor + \def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + + % Use cm as the default font prefix. + % To specify the font prefix, you must define \fontprefix + % before you read in texinfo.tex. + \ifx\fontprefix\undefined + \def\fontprefix{cm} + \fi + % Support font families that don't use the same naming scheme as CM. + \def\rmshape{r} + \def\rmbshape{bx} %where the normal face is bold + \def\bfshape{b} + \def\bxshape{bx} + \def\ttshape{tt} + \def\ttbshape{tt} + \def\ttslshape{sltt} + \def\itshape{ti} + \def\itbshape{bxti} + \def\slshape{sl} + \def\slbshape{bxsl} + \def\sfshape{ss} + \def\sfbshape{ss} + \def\scshape{csc} + \def\scbshape{csc} + + \ifx\bigger\relax + \let\mainmagstep=\magstep1 + \setfont\textrm\rmshape{12}{1000} + \setfont\texttt\ttshape{12}{1000} + \else + \setfont\textrm\rmshape{10}{\mainmagstep} + \setfont\texttt\ttshape{10}{\mainmagstep} + \fi + % Instead of cmb10, you many want to use cmbx10. + % cmbx10 is a prettier font on its own, but cmb10 + % looks better when embedded in a line with cmr10. + \setfont\textbf\bfshape{10}{\mainmagstep} + \setfont\textit\itshape{10}{\mainmagstep} + \setfont\textsl\slshape{10}{\mainmagstep} + \setfont\textsf\sfshape{10}{\mainmagstep} + \setfont\textsc\scshape{10}{\mainmagstep} + \setfont\textttsl\ttslshape{10}{\mainmagstep} + \font\texti=cmmi10 scaled \mainmagstep + \font\textsy=cmsy10 scaled \mainmagstep + + % A few fonts for @defun, etc. + \setfont\defbf\bxshape{10}{\magstep1} %was 1314 + \setfont\deftt\ttshape{10}{\magstep1} + \def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + + % Fonts for indices and small examples (9pt). + % We actually use the slanted font rather than the italic, + % because texinfo normally uses the slanted fonts for that. + % Do not make many font distinctions in general in the index, since they + % aren't very useful. + \setfont\ninett\ttshape{9}{1000} + \setfont\ninettsl\ttslshape{10}{900} + \setfont\indrm\rmshape{9}{1000} + \setfont\indit\itshape{9}{1000} + \setfont\indsl\slshape{9}{1000} + \let\indtt=\ninett + \let\indttsl=\ninettsl + \let\indsf=\indrm + \let\indbf=\indrm + \setfont\indsc\scshape{10}{900} + \font\indi=cmmi9 + \font\indsy=cmsy9 + + % Fonts for title page: + \setfont\titlerm\rmbshape{12}{\magstep3} + \setfont\titleit\itbshape{10}{\magstep4} + \setfont\titlesl\slbshape{10}{\magstep4} + \setfont\titlett\ttbshape{12}{\magstep3} + \setfont\titlettsl\ttslshape{10}{\magstep4} + \setfont\titlesf\sfbshape{17}{\magstep1} + \let\titlebf=\titlerm + \setfont\titlesc\scbshape{10}{\magstep4} + \font\titlei=cmmi12 scaled \magstep3 + \font\titlesy=cmsy10 scaled \magstep4 + \def\authorrm{\secrm} + + % Chapter (and unnumbered) fonts (17.28pt). + \setfont\chaprm\rmbshape{12}{\magstep2} + \setfont\chapit\itbshape{10}{\magstep3} + \setfont\chapsl\slbshape{10}{\magstep3} + \setfont\chaptt\ttbshape{12}{\magstep2} + \setfont\chapttsl\ttslshape{10}{\magstep3} + \setfont\chapsf\sfbshape{17}{1000} + \let\chapbf=\chaprm + \setfont\chapsc\scbshape{10}{\magstep3} + \font\chapi=cmmi12 scaled \magstep2 + \font\chapsy=cmsy10 scaled \magstep3 + + % Section fonts (14.4pt). + \setfont\secrm\rmbshape{12}{\magstep1} + \setfont\secit\itbshape{10}{\magstep2} + \setfont\secsl\slbshape{10}{\magstep2} + \setfont\sectt\ttbshape{12}{\magstep1} + \setfont\secttsl\ttslshape{10}{\magstep2} + \setfont\secsf\sfbshape{12}{\magstep1} + \let\secbf\secrm + \setfont\secsc\scbshape{10}{\magstep2} + \font\seci=cmmi12 scaled \magstep1 + \font\secsy=cmsy10 scaled \magstep2 + + % \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. + % \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. + % \setfont\ssecsl\slshape{10}{\magstep1} + % \setfont\ssectt\ttshape{10}{\magstep1} + % \setfont\ssecsf\sfshape{10}{\magstep1} + + %\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. + %\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than + %\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. + %\setfont\ssectt\ttshape{10}{1315} + %\setfont\ssecsf\sfshape{10}{1315} + + %\let\ssecbf=\ssecrm + + % Subsection fonts (13.15pt). + \setfont\ssecrm\rmbshape{12}{\magstephalf} + \setfont\ssecit\itbshape{10}{1315} + \setfont\ssecsl\slbshape{10}{1315} + \setfont\ssectt\ttbshape{12}{\magstephalf} + \setfont\ssecttsl\ttslshape{10}{1315} + \setfont\ssecsf\sfbshape{12}{\magstephalf} + \let\ssecbf\ssecrm + \setfont\ssecsc\scbshape{10}{\magstep1} + \font\sseci=cmmi12 scaled \magstephalf + \font\ssecsy=cmsy10 scaled 1315 + % The smallcaps and symbol fonts should actually be scaled \magstep1.5, + % but that is not a standard magnification. + + % In order for the font changes to affect most math symbols and letters, + % we have to define the \textfont of the standard families. Since + % texinfo doesn't allow for producing subscripts and superscripts, we + % don't bother to reset \scriptfont and \scriptscriptfont (which would + % also require loading a lot more fonts). + % + \def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf + } + + + % The font-changing commands redefine the meanings of \tenSTYLE, instead + % of just \STYLE. We do this so that font changes will continue to work + % in math mode, where it is the current \fam that is relevant in most + % cases, not the current font. Plain TeX does \def\bf{\fam=\bffam + % \tenbf}, for example. By redefining \tenbf, we obviate the need to + % redefine \bf itself. + \def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} + \def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} + \def\titlefont#1{{\titlefonts\rm #1}} + \def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} + \def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} + \def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} + \let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? + \def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + + % Set up the default fonts, so we can use them for creating boxes. + % + \textfonts + + % Define these so they can be easily changed for other fonts. + \def\angleleft{$\langle$} + \def\angleright{$\rangle$} + + % Count depth in font-changes, for error checks + \newcount\fontdepth \fontdepth=0 + + % Fonts for short table of contents. + \setfont\shortcontrm\rmshape{12}{1000} + \setfont\shortcontbf\bxshape{12}{1000} + \setfont\shortcontsl\slshape{12}{1000} + + %% Add scribe-like font environments, plus @l for inline lisp (usually sans + %% serif) and @ii for TeX italic + + % \smartitalic{ARG} outputs arg in italics, followed by an italic correction + % unless the following character is such as not to need one. + \def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} + \def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} + \def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + + \let\i=\smartitalic + \let\var=\smartslanted + \let\dfn=\smartslanted + \let\emph=\smartitalic + \let\cite=\smartslanted + + \def\b#1{{\bf #1}} + \let\strong=\b + + % We can't just use \exhyphenpenalty, because that only has effect at + % the end of a paragraph. Restore normal hyphenation at the end of the + % group within which \nohyphenation is presumably called. + % + \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} + \def\restorehyphenation{\hyphenchar\font = `- } + + \def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null + } + \let\ttfont=\t + \def\samp#1{`\tclose{#1}'\null} + \setfont\smallrm\rmshape{8}{1000} + \font\smallsy=cmsy9 + \def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} + % The old definition, with no lozenge: + %\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} + \def\ctrl #1{{\tt \rawbackslash \hat}#1} + + % @file, @option are the same as @samp. + \let\file=\samp + \let\option=\samp + + % @code is a modification of @t, + % which makes spaces the same size as normal in the surrounding text. + \def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null + } + + % We *must* turn on hyphenation at `-' and `_' in \code. + % Otherwise, it is too hard to avoid overfull hboxes + % in the Emacs manual, the Library manual, etc. + + % Unfortunately, TeX uses one parameter (\hyphenchar) to control + % both hyphenation at - and hyphenation within words. + % We must therefore turn them both off (\tclose does that) + % and arrange explicitly to hyphenate at a dash. + % -- rms. + { + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} + } + + \def\realdash{-} + \def\codedash{-\discretionary{}{}{}} + \def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} + \def\codex #1{\tclose{#1}\endgroup} + + %\let\exp=\tclose %Was temporary + + % @kbd is like @code, except that if the argument is just one @key command, + % then @kbd has no effect. + + % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), + % `example' (@kbd uses ttsl only inside of @example and friends), + % or `code' (@kbd uses normal tty font always). + \def\kbdinputstyle{\parsearg\kbdinputstylexxx} + \def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi + } + \def\worddistinct{distinct} + \def\wordexample{example} + \def\wordcode{code} + + % Default is kbdinputdistinct. (Too much of a hassle to call the macro, + % the catcodes are wrong for parsearg to work.) + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + + \def\xkey{\key} + \def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% + \ifx\one\xkey\ifx\threex\three \key{#2}% + \else{\tclose{\kbdfont\look}}\fi + \else{\tclose{\kbdfont\look}}\fi} + + % For @url, @env, @command quotes seem unnecessary, so use \code. + \let\url=\code + \let\env=\code + \let\command=\code + + % @uref (abbreviation for `urlref') takes an optional second argument + % specifying the text to display. First (mandatory) arg is the url. + % Perhaps eventually put in a hypertex \special here. + % + \def\uref#1{\urefxxx #1,,\finish} + \def\urefxxx#1,#2,#3\finish{% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% + \else + \code{#1}% + \fi + } + + % rms does not like the angle brackets --karl, 17may97. + % So now @email is just like @uref. + %\def\email#1{\angleleft{\tt #1}\angleright} + \let\email=\uref + + % Check if we are currently using a typewriter font. Since all the + % Computer Modern typewriter fonts have zero interword stretch (and + % shrink), and it is reasonable to expect all typewriter fonts to have + % this property, we can check that font parameter. + % + \def\ifmonospace{\ifdim\fontdimen3\font=0pt } + + % Typeset a dimension, e.g., `in' or `pt'. The only reason for the + % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. + % + \def\dmn#1{\thinspace #1} + + \def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + + % @l was never documented to mean ``switch to the Lisp font'', + % and it is not used as such in any manual I can find. We need it for + % Polish suppressed-l. --karl, 22sep96. + %\def\l#1{{\li #1}\null} + + % Explicit font changes: @r, @sc, undocumented @ii. + \def\r#1{{\rm #1}} % roman font + \def\sc#1{{\smallcaps#1}} % smallcaps font + \def\ii#1{{\it #1}} % italic font + + % @acronym downcases the argument and prints in smallcaps. + \def\acronym#1{{\smallcaps \lowercase{#1}}} + + % @pounds{} is a sterling sign. + \def\pounds{{\it\$}} + + + \message{page headings,} + + \newskip\titlepagetopglue \titlepagetopglue = 1.5in + \newskip\titlepagebottomglue \titlepagebottomglue = 2pc + + % First the title page. Must do @settitle before @titlepage. + \newif\ifseenauthor + \newif\iffinishedtitlepage + + % Do an implicit @contents or @shortcontents after @end titlepage if the + % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. + % + \newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue + \newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + + \def\shorttitlepage{\parsearg\shorttitlepagezzz} + \def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + + \def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% + % \def\page{\oldpage \hbox{}} + } + + \def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \HEADINGSon + } + + \def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue + } + + %%% Set up page headings and footings. + + \let\thispage=\folio + + \newtoks\evenheadline % headline on even pages + \newtoks\oddheadline % headline on odd pages + \newtoks\evenfootline % footline on even pages + \newtoks\oddfootline % footline on odd pages + + % Now make Tex use those variables + \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} + \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} + \let\HEADINGShook=\relax + + % Commands to set those variables. + % For example, this is what @headings on does + % @evenheading @thistitle|@thispage|@thischapter + % @oddheading @thischapter|@thispage|@thistitle + % @evenfooting @thisfile|| + % @oddfooting ||@thisfile + + \def\evenheading{\parsearg\evenheadingxxx} + \def\oddheading{\parsearg\oddheadingxxx} + \def\everyheading{\parsearg\everyheadingxxx} + + \def\evenfooting{\parsearg\evenfootingxxx} + \def\oddfooting{\parsearg\oddfootingxxx} + \def\everyfooting{\parsearg\everyfootingxxx} + + {\catcode`\@=0 % + + \gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} + \gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% + \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + + \gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} + \gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% + \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + + \gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + + \gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} + \gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% + \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + + \gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} + \gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip + } + + \gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} + % + }% unbind the catcode of @. + + % @headings double turns headings on for double-sided printing. + % @headings single turns headings on for single-sided printing. + % @headings off turns them off. + % @headings on same as @headings double, retained for compatibility. + % @headings after turns on double-sided headings after this page. + % @headings doubleafter turns on double-sided headings after this page. + % @headings singleafter turns on single-sided headings after this page. + % By default, they are off at the start of a document, + % and turned `on' after @end titlepage. + + \def\headings #1 {\csname HEADINGS#1\endcsname} + + \def\HEADINGSoff{ + \global\evenheadline={\hfil} \global\evenfootline={\hfil} + \global\oddheadline={\hfil} \global\oddfootline={\hfil}} + \HEADINGSoff + % When we turn headings on, set the page number to 1. + % For double-sided printing, put current file name in lower left corner, + % chapter name on inside top of right hand pages, document + % title on inside top of left hand pages, and page numbers on outside top + % edge of all pages. + \def\HEADINGSdouble{ + \global\pageno=1 + \global\evenfootline={\hfil} + \global\oddfootline={\hfil} + \global\evenheadline={\line{\folio\hfil\thistitle}} + \global\oddheadline={\line{\thischapter\hfil\folio}} + \global\let\contentsalignmacro = \chapoddpage + } + \let\contentsalignmacro = \chappager + + % For single-sided printing, chapter title goes across top left of page, + % page number on top right. + \def\HEADINGSsingle{ + \global\pageno=1 + \global\evenfootline={\hfil} + \global\oddfootline={\hfil} + \global\evenheadline={\line{\thischapter\hfil\folio}} + \global\oddheadline={\line{\thischapter\hfil\folio}} + \global\let\contentsalignmacro = \chappager + } + \def\HEADINGSon{\HEADINGSdouble} + + \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} + \let\HEADINGSdoubleafter=\HEADINGSafter + \def\HEADINGSdoublex{% + \global\evenfootline={\hfil} + \global\oddfootline={\hfil} + \global\evenheadline={\line{\folio\hfil\thistitle}} + \global\oddheadline={\line{\thischapter\hfil\folio}} + \global\let\contentsalignmacro = \chapoddpage + } + + \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} + \def\HEADINGSsinglex{% + \global\evenfootline={\hfil} + \global\oddfootline={\hfil} + \global\evenheadline={\line{\thischapter\hfil\folio}} + \global\oddheadline={\line{\thischapter\hfil\folio}} + \global\let\contentsalignmacro = \chappager + } + + % Subroutines used in generating headings + % Produces Day Month Year style of output. + \def\today{\number\day\space + \ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\year} + + % Use this if you want the Month Day, Year style of output. + %\def\today{\ifcase\month\or + %January\or February\or March\or April\or May\or June\or + %July\or August\or September\or October\or November\or December\fi + %\space\number\day, \number\year} + + % @settitle line... specifies the title of the document, for headings + % It generates no output of its own + + \def\thistitle{No Title} + \def\settitle{\parsearg\settitlezzz} + \def\settitlezzz #1{\gdef\thistitle{#1}} + + + \message{tables,} + % Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + + % default indentation of table text + \newdimen\tableindent \tableindent=.8in + % default indentation of @itemize and @enumerate text + \newdimen\itemindent \itemindent=.3in + % margin between end of table item and start of table text. + \newdimen\itemmargin \itemmargin=.1in + + % used internally for \itemindent minus \itemmargin + \newdimen\itemmax + + % Note @table, @vtable, and @vtable define @item, @itemx, etc., with + % these defs. + % They also define \itemindex + % to index the item name in whatever manner is desired (perhaps none). + + \newif\ifitemxneedsnegativevskip + + \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + + \def\internalBitem{\smallbreak \parsearg\itemzzz} + \def\internalBitemx{\itemxpar \parsearg\itemzzz} + + \def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} + \def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + + \def\internalBkitem{\smallbreak \parsearg\kitemzzz} + \def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + + \def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + + \def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + + \def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi + } + + \def\item{\errmessage{@item while not in a table}} + \def\itemx{\errmessage{@itemx while not in a table}} + \def\kitem{\errmessage{@kitem while not in a table}} + \def\kitemx{\errmessage{@kitemx while not in a table}} + \def\xitem{\errmessage{@xitem while not in a table}} + \def\xitemx{\errmessage{@xitemx while not in a table}} + + % Contains a kludge to get @end[description] to work. + \def\description{\tablez{\dontindex}{1}{}{}{}{}} + + % @table, @ftable, @vtable. + \def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} + {\obeylines\obeyspaces% + \gdef\tablex #1^^M{% + \tabley\dontindex#1 \endtabley}} + + \def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} + {\obeylines\obeyspaces% + \gdef\ftablex #1^^M{% + \tabley\fnitemindex#1 \endtabley + \def\Eftable{\endgraf\afterenvbreak\endgroup}% + \let\Etable=\relax}} + + \def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} + {\obeylines\obeyspaces% + \gdef\vtablex #1^^M{% + \tabley\vritemindex#1 \endtabley + \def\Evtable{\endgraf\afterenvbreak\endgroup}% + \let\Etable=\relax}} + + \def\dontindex #1{} + \def\fnitemindex #1{\doind {fn}{\code{#1}}}% + \def\vritemindex #1{\doind {vr}{\code{#1}}}% + + {\obeyspaces % + \gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% + \tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + + \def\tablez #1#2#3#4#5#6{% + \aboveenvbreak % + \begingroup % + \def\Edescription{\Etable}% Necessary kludge. + \let\itemindex=#1% + \ifnum 0#3>0 \advance \leftskip by #3\mil \fi % + \ifnum 0#4>0 \tableindent=#4\mil \fi % + \ifnum 0#5>0 \advance \rightskip by #5\mil \fi % + \def\itemfont{#2}% + \itemmax=\tableindent % + \advance \itemmax by -\itemmargin % + \advance \leftskip by \tableindent % + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi% + \def\Etable{\endgraf\afterenvbreak\endgroup}% + \let\item = \internalBitem % + \let\itemx = \internalBitemx % + \let\kitem = \internalBkitem % + \let\kitemx = \internalBkitemx % + \let\xitem = \internalBxitem % + \let\xitemx = \internalBxitemx % + } + + % This is the counter used by @enumerate, which is really @itemize + + \newcount \itemno + + \def\itemize{\parsearg\itemizezzz} + + \def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} + } + + \def\itemizey #1#2{% + \aboveenvbreak % + \itemmax=\itemindent % + \advance \itemmax by -\itemmargin % + \advance \leftskip by \itemindent % + \exdentamount=\itemindent + \parindent = 0pt % + \parskip = \smallskipamount % + \ifdim \parskip=0pt \parskip=2pt \fi% + \def#2{\endgraf\afterenvbreak\endgroup}% + \def\itemcontents{#1}% + \let\item=\itemizeitem} + + % Set sfcode to normal for the chars that usually have another value. + % These are `.?!:;,' + \def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + + % \splitoff TOKENS\endmark defines \first to be the first token in + % TOKENS, and \rest to be the remainder. + % + \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + + % Allow an optional argument of an uppercase letter, lowercase letter, + % or number, to specify the first label in the enumerated list. No + % argument is the same as `1'. + % + \def\enumerate{\parsearg\enumeratezzz} + \def\enumeratezzz #1{\enumeratey #1 \endenumeratey} + \def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi + } + + % An @enumerate whose labels are integers. The starting integer is + % given in \thearg. + % + \def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% + } + + % The starting (lowercase) letter is in \thearg. + \def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% + } + + % The starting (uppercase) letter is in \thearg. + \def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% + } + + % Call itemizey, adding a period to the first argument and supplying the + % common last two arguments. Also subtract one from the initial value in + % \itemno, since @item increments \itemno. + % + \def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr + } + + % @alphaenumerate and @capsenumerate are abbreviations for giving an arg + % to @enumerate. + % + \def\alphaenumerate{\enumerate{a}} + \def\capsenumerate{\enumerate{A}} + \def\Ealphaenumerate{\Eenumerate} + \def\Ecapsenumerate{\Eenumerate} + + % Definition of @item while inside @itemize. + + \def\itemizeitem{% + \advance\itemno by 1 + {\let\par=\endgraf \smallbreak}% + \ifhmode \errmessage{In hmode at itemizeitem}\fi + {\parskip=0in \hskip 0pt + \hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% + \vadjust{\penalty 1200}}% + \flushcr} + + % @multitable macros + % Amy Hendrickson, 8/18/94, 3/6/96 + % + % @multitable ... @end multitable will make as many columns as desired. + % Contents of each column will wrap at width given in preamble. Width + % can be specified either with sample text given in a template line, + % or in percent of \hsize, the current width of text on page. + + % Table can continue over pages but will only break between lines. + + % To make preamble: + % + % Either define widths of columns in terms of percent of \hsize: + % @multitable @columnfractions .25 .3 .45 + % @item ... + % + % Numbers following @columnfractions are the percent of the total + % current hsize to be used for each column. You may use as many + % columns as desired. + + + % Or use a template: + % @multitable {Column 1 template} {Column 2 template} {Column 3 template} + % @item ... + % using the widest term desired in each column. + % + % For those who want to use more than one line's worth of words in + % the preamble, break the line within one argument and it + % will parse correctly, i.e., + % + % @multitable {Column 1 template} {Column 2 template} {Column 3 + % template} + % Not: + % @multitable {Column 1 template} {Column 2 template} + % {Column 3 template} + + % Each new table line starts with @item, each subsequent new column + % starts with @tab. Empty columns may be produced by supplying @tab's + % with nothing between them for as many times as empty columns are needed, + % ie, @tab at tab@tab will produce two empty columns. + + % @item, @tab, @multitable or @end multitable do not need to be on their + % own lines, but it will not hurt if they are. + + % Sample multitable: + + % @multitable {Column 1 template} {Column 2 template} {Column 3 template} + % @item first col stuff @tab second col stuff @tab third col + % @item + % first col stuff + % @tab + % second col stuff + % @tab + % third col + % @item first col stuff @tab second col stuff + % @tab Many paragraphs of text may be used in any column. + % + % They will wrap at the width determined by the template. + % @item at tab@tab This will be in third column. + % @end multitable + + % Default dimensions may be reset by user. + % @multitableparskip is vertical space between paragraphs in table. + % @multitableparindent is paragraph indent in table. + % @multitablecolmargin is horizontal space to be left between columns. + % @multitablelinespace is space to leave between table items, baseline + % to baseline. + % 0pt means it depends on current normal line spacing. + % + \newskip\multitableparskip + \newskip\multitableparindent + \newdimen\multitablecolspace + \newskip\multitablelinespace + \multitableparskip=0pt + \multitableparindent=6pt + \multitablecolspace=12pt + \multitablelinespace=0pt + + % Macros used to set up halign preamble: + % + \let\endsetuptable\relax + \def\xendsetuptable{\endsetuptable} + \let\columnfractions\relax + \def\xcolumnfractions{\columnfractions} + \newif\ifsetpercent + + % #1 is the part of the @columnfraction before the decimal point, which + % is presumably either 0 or the empty string (but we don't check, we + % just throw it away). #2 is the decimal part, which we use as the + % percent of \hsize for this column. + \def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable + } + + \newcount\colcount + \def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go + } + + % multitable syntax + \def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + % @multitable ... @end multitable definitions: + % + \def\multitable{\parsearg\dotable} + \def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr + } + + \def\setmultitablespacing{% test to see if user has set \multitablelinespace. + % If so, do nothing. If not, give it an appropriate dimension based on + % current baselineskip. + \ifdim\multitablelinespace=0pt + %% strut to put in table in case some entry doesn't have descenders, + %% to keep lines equally spaced + \let\multistrut = \strut + %% Test to see if parskip is larger than space between lines of + %% table. If not, do nothing. + %% If so, set to same dimension as multitablelinespace. + \else + \gdef\multistrut{\vrule height\multitablelinespace depth\dp0 + width0pt\relax} \fi + \ifdim\multitableparskip>\multitablelinespace + \global\multitableparskip=\multitablelinespace + \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. + \fi% + \ifdim\multitableparskip=0pt + \global\multitableparskip=\multitablelinespace + \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. + \fi} + + + \message{indexing,} + % Index generation facilities + + % Define \newwrite to be identical to plain tex's \newwrite + % except not \outer, so it can be used within \newindex. + {\catcode`\@=11 + \gdef\newwrite{\alloc at 7\write\chardef\sixt@@n}} + + % \newindex {foo} defines an index named foo. + % It automatically defines \fooindex such that + % \fooindex ...rest of line... puts an entry in the index foo. + % It also defines \fooindfile to be the number of the output channel for + % the file that accumulates this index. The file's extension is foo. + % The name of an index should be no more than 2 characters long + % for the sake of vms. + % + \def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} + } + + % @defindex foo == \newindex{foo} + + \def\defindex{\parsearg\newindex} + + % Define @defcodeindex, like @defindex except put all entries in @code. + + \def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} + } + + \def\defcodeindex{\parsearg\newcodeindex} + + % @synindex foo bar makes index foo feed into index bar. + % Do this instead of @defindex foo if you don't want it as a separate index. + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% + } + + % @syncodeindex foo bar similar, but put all entries made for index foo + % inside @code. + \def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% + } + + % Define \doindex, the driver for all \fooindex macros. + % Argument #1 is generated by the calling \fooindex macro, + % and it is "foo", the name of the index. + + % \doindex just uses \parsearg; it calls \doind for the actual work. + % This is because \doind is more useful to call from other macros. + + % There is also \dosubind {index}{topic}{subtopic} + % which makes an entry in a two-level index such as the operation index. + + \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} + \def\singleindexer #1{\doind{\indexname}{#1}} + + % like the previous two, but they put @code around the argument. + \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} + \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + + \def\indexdummies{% + \def\ { }% + % Take care of the plain tex accent commands. + \def\"{\realbackslash "}% + \def\`{\realbackslash `}% + \def\'{\realbackslash '}% + \def\^{\realbackslash ^}% + \def\~{\realbackslash ~}% + \def\={\realbackslash =}% + \def\b{\realbackslash b}% + \def\c{\realbackslash c}% + \def\d{\realbackslash d}% + \def\u{\realbackslash u}% + \def\v{\realbackslash v}% + \def\H{\realbackslash H}% + % Take care of the plain tex special European modified letters. + \def\oe{\realbackslash oe}% + \def\ae{\realbackslash ae}% + \def\aa{\realbackslash aa}% + \def\OE{\realbackslash OE}% + \def\AE{\realbackslash AE}% + \def\AA{\realbackslash AA}% + \def\o{\realbackslash o}% + \def\O{\realbackslash O}% + \def\l{\realbackslash l}% + \def\L{\realbackslash L}% + \def\ss{\realbackslash ss}% + % Take care of texinfo commands likely to appear in an index entry. + % (Must be a way to avoid doing expansion at all, and thus not have to + % laboriously list every single command here.) + \def\@{@}% will be @@ when we switch to @ as escape char. + % Need these in case \tex is in effect and \{ is a \delimiter again. + % But can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. + \let\{ = \mylbrace + \let\} = \myrbrace + \def\_{{\realbackslash _}}% + \def\w{\realbackslash w }% + \def\bf{\realbackslash bf }% + %\def\rm{\realbackslash rm }% + \def\sl{\realbackslash sl }% + \def\sf{\realbackslash sf}% + \def\tt{\realbackslash tt}% + \def\gtr{\realbackslash gtr}% + \def\less{\realbackslash less}% + \def\hat{\realbackslash hat}% + \def\TeX{\realbackslash TeX}% + \def\dots{\realbackslash dots }% + \def\result{\realbackslash result}% + \def\equiv{\realbackslash equiv}% + \def\expansion{\realbackslash expansion}% + \def\print{\realbackslash print}% + \def\error{\realbackslash error}% + \def\point{\realbackslash point}% + \def\copyright{\realbackslash copyright}% + \def\tclose##1{\realbackslash tclose {##1}}% + \def\code##1{\realbackslash code {##1}}% + \def\uref##1{\realbackslash uref {##1}}% + \def\url##1{\realbackslash url {##1}}% + \def\env##1{\realbackslash env {##1}}% + \def\command##1{\realbackslash command {##1}}% + \def\option##1{\realbackslash option {##1}}% + \def\dotless##1{\realbackslash dotless {##1}}% + \def\samp##1{\realbackslash samp {##1}}% + \def\,##1{\realbackslash ,{##1}}% + \def\t##1{\realbackslash t {##1}}% + \def\r##1{\realbackslash r {##1}}% + \def\i##1{\realbackslash i {##1}}% + \def\b##1{\realbackslash b {##1}}% + \def\sc##1{\realbackslash sc {##1}}% + \def\cite##1{\realbackslash cite {##1}}% + \def\key##1{\realbackslash key {##1}}% + \def\file##1{\realbackslash file {##1}}% + \def\var##1{\realbackslash var {##1}}% + \def\kbd##1{\realbackslash kbd {##1}}% + \def\dfn##1{\realbackslash dfn {##1}}% + \def\emph##1{\realbackslash emph {##1}}% + \def\acronym##1{\realbackslash acronym {##1}}% + % + % Handle some cases of @value -- where the variable name does not + % contain - or _, and the value does not contain any + % (non-fully-expandable) commands. + \let\value = \expandablevalue + % + \unsepspaces + } + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\\leavevmode \penalty \@M \ ). + {\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + + % \indexnofonts no-ops all font-change commands. + % This is used when outputting the strings to sort the index by. + \def\indexdummyfont#1{#1} + \def\indexdummytex{TeX} + \def\indexdummydots{...} + + \def\indexnofonts{% + % Just ignore accents. + \let\,=\indexdummyfont + \let\"=\indexdummyfont + \let\`=\indexdummyfont + \let\'=\indexdummyfont + \let\^=\indexdummyfont + \let\~=\indexdummyfont + \let\==\indexdummyfont + \let\b=\indexdummyfont + \let\c=\indexdummyfont + \let\d=\indexdummyfont + \let\u=\indexdummyfont + \let\v=\indexdummyfont + \let\H=\indexdummyfont + \let\dotless=\indexdummyfont + % Take care of the plain tex special European modified letters. + \def\oe{oe}% + \def\ae{ae}% + \def\aa{aa}% + \def\OE{OE}% + \def\AE{AE}% + \def\AA{AA}% + \def\o{o}% + \def\O{O}% + \def\l{l}% + \def\L{L}% + \def\ss{ss}% + \let\w=\indexdummyfont + \let\t=\indexdummyfont + \let\r=\indexdummyfont + \let\i=\indexdummyfont + \let\b=\indexdummyfont + \let\emph=\indexdummyfont + \let\strong=\indexdummyfont + \let\cite=\indexdummyfont + \let\sc=\indexdummyfont + %Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |... + %\let\tt=\indexdummyfont + \let\tclose=\indexdummyfont + \let\code=\indexdummyfont + \let\url=\indexdummyfont + \let\uref=\indexdummyfont + \let\env=\indexdummyfont + \let\command=\indexdummyfont + \let\option=\indexdummyfont + \let\file=\indexdummyfont + \let\samp=\indexdummyfont + \let\kbd=\indexdummyfont + \let\key=\indexdummyfont + \let\var=\indexdummyfont + \let\TeX=\indexdummytex + \let\dots=\indexdummydots + \def\@{@}% + } + + % To define \realbackslash, we must make \ not be an escape. + % We must first make another character (@) an escape + % so we do not become unable to do a definition. + + {\catcode`\@=0 \catcode`\\=\other + @gdef at realbackslash{\}} + + \let\indexbackslash=0 %overridden during \printindex. + \let\SETmarginindex=\relax % put index entries in margin (undocumented)? + + % For \ifx comparisons. + \def\emptymacro{\empty} + + % Most index entries go through here, but \dosubind is the general case. + % + \def\doind#1#2{\dosubind{#1}{#2}\empty} + + % Workhorse for all \fooindexes. + % #1 is name of index, #2 is stuff to put there, #3 is subentry -- + % \empty if called from \doind, as we usually are. The main exception + % is with defuns, which call us directly. + % + \def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If third (subentry) arg is present, add it to the index string. + \ifx\thirdarg\emptymacro \else + \toks0 = {#3}% + \edef\temp{\temp{\the\toks0}}% + \fi + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% + } + + % The index entry written in the file actually looks like + % \entry {sortstring}{page}{topic} + % or + % \entry {sortstring}{page}{topic}{subtopic} + % The texindex program reads in these files and writes files + % containing these kinds of lines: + % \initial {c} + % before the first topic whose initial is c + % \entry {topic}{pagelist} + % for a topic that is used without subtopics + % \primary {topic} + % for the beginning of a topic that is used with subtopics + % \secondary {subtopic}{pagelist} + % for each subtopic. + + % Define the user-accessible indexing commands + % @findex, @vindex, @kindex, @cindex. + + \def\findex {\fnindex} + \def\kindex {\kyindex} + \def\cindex {\cpindex} + \def\vindex {\vrindex} + \def\tindex {\tpindex} + \def\pindex {\pgindex} + + \def\cindexsub {\begingroup\obeylines\cindexsub} + {\obeylines % + \gdef\cindexsub "#1" #2^^M{\endgroup % + \dosubind{cp}{#2}{#1}}} + + % Define the macros used in formatting output of the sorted index material. + + % @printindex causes a particular index (the ??s file) to get printed. + % It does not print any chapter heading (usually an @unnumbered). + % + \def\printindex{\parsearg\doprintindex} + \def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 + \endgroup} + + % These macros are used by the sorted index file itself. + % Change them to control the appearance of the index. + + \def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak + }} + + % This typesets a paragraph consisting of #1, dot leaders, and then #2 + % flush to the right margin. It is used for index and table of contents + % entries. The paragraph is indented by \leftskip. + % + \def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par + \endgroup} + + % Like \dotfill except takes at least 1 em. + \def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + + \def\primary #1{\line{#1\hfil}} + + \newskip\secondaryindent \secondaryindent=0.5cm + + \def\secondary #1#2{ + {\parfillskip=0in \parskip=0in + \hangindent =1in \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par + }} + + % Define two-column mode, which we use to typeset indexes. + % Adapted from the TeXbook, page 416, which is to say, + % the manmac.tex format used to print the TeXbook itself. + \catcode`\@=11 + + \newbox\partialpage + \newdimen\doublecolumnhsize + + \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage = \vbox{% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case, we must prevent the second \partialpage from + % simply overwriting the first, causing us to lose the page. + % This will preserve it until a real output routine can ship it + % out. Generally, \partialpage will be empty when this runs and + % this will be a no-op. + \unvbox\partialpage + % + % Unvbox the main output page. + \unvbox255 + \kern-\topskip \kern\baselineskip + }}% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize + } + + % The double-column output routine for all double-column pages except + % the last. + % + \def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty + } + \def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \advance\vsize by \ht\partialpage + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% + } + \def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize + } + \def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen at .}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar + } + \catcode`\@ = \other + + + \message{sectioning,} + % Define chapters, sections, etc. + + \newcount\chapno + \newcount\secno \secno=0 + \newcount\subsecno \subsecno=0 + \newcount\subsubsecno \subsubsecno=0 + + % This counter is funny since it counts through charcodes of letters A, B, ... + \newcount\appendixno \appendixno = `\@ + \def\appendixletter{\char\the\appendixno} + + % Each @chapter defines this as the name of the chapter. + % page headings and footings can use it. @section does likewise. + \def\thischapter{} + \def\thissection{} + + \newcount\absseclevel % used to calculate proper heading level + \newcount\secbase\secbase=0 % @raise/lowersections modify this count + + % @raisesections: treat @section as chapter, @subsection as section, etc. + \def\raisesections{\global\advance\secbase by -1} + \let\up=\raisesections % original BFox name + + % @lowersections: treat @chapter as section, @section as subsection, etc. + \def\lowersections{\global\advance\secbase by 1} + \let\down=\lowersections % original BFox name + + % Choose a numbered-heading macro + % #1 is heading level if unmodified by @raisesections or @lowersections + % #2 is text for heading + \def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 + \ifcase\absseclevel + \chapterzzz{#2} + \or + \seczzz{#2} + \or + \numberedsubseczzz{#2} + \or + \numberedsubsubseczzz{#2} + \else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi + \fi + } + + % like \numhead, but chooses appendix heading levels + \def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 + \ifcase\absseclevel + \appendixzzz{#2} + \or + \appendixsectionzzz{#2} + \or + \appendixsubseczzz{#2} + \or + \appendixsubsubseczzz{#2} + \else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi + \fi + } + + % like \numhead, but chooses numberless heading levels + \def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 + \ifcase\absseclevel + \unnumberedzzz{#2} + \or + \unnumberedseczzz{#2} + \or + \unnumberedsubseczzz{#2} + \or + \unnumberedsubsubseczzz{#2} + \else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi + \fi + } + + % @chapter, @appendix, @unnumbered. + \def\thischaptername{No Chapter Title} + \outer\def\chapter{\parsearg\chapteryyy} + \def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz + \def\chapterzzz #1{% + \secno=0 \subsecno=0 \subsubsecno=0 + \global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% + \chapmacro {#1}{\the\chapno}% + \gdef\thissection{#1}% + \gdef\thischaptername{#1}% + % We don't substitute the actual chapter name into \thischapter + % because we don't want its macros evaluated now. + \xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% + \temp + \donoderef + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec + } + + \outer\def\appendix{\parsearg\appendixyyy} + \def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz + \def\appendixzzz #1{% + \secno=0 \subsecno=0 \subsubsecno=0 + \global\advance \appendixno by 1 + \message{\putwordAppendix\space \appendixletter}% + \chapmacro {#1}{\putwordAppendix{} \appendixletter}% + \gdef\thissection{#1}% + \gdef\thischaptername{#1}% + \xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% + \temp + \appendixnoderef + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec + } + + % @centerchap is like @unnumbered, but the heading is centered. + \outer\def\centerchap{\parsearg\centerchapyyy} + \def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + + % @top is like @unnumbered. + \outer\def\top{\parsearg\unnumberedyyy} + + \outer\def\unnumbered{\parsearg\unnumberedyyy} + \def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz + \def\unnumberedzzz #1{% + \secno=0 \subsecno=0 \subsubsecno=0 + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}\message{(\the\toks0)}% + % + \unnumbchapmacro {#1}% + \gdef\thischapter{#1}\gdef\thissection{#1}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% + \temp + \unnumbnoderef + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec + } + + % Sections. + \outer\def\numberedsec{\parsearg\secyyy} + \def\secyyy #1{\numhead1{#1}} % normally calls seczzz + \def\seczzz #1{% + \subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % + \gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% + \temp + \donoderef + \nobreak + } + + \outer\def\appendixsection{\parsearg\appendixsecyyy} + \outer\def\appendixsec{\parsearg\appendixsecyyy} + \def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz + \def\appendixsectionzzz #1{% + \subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % + \gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% + \temp + \appendixnoderef + \nobreak + } + + \outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} + \def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz + \def\unnumberedseczzz #1{% + \plainsecheading {#1}\gdef\thissection{#1}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% + \temp + \unnumbnoderef + \nobreak + } + + % Subsections. + \outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} + \def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz + \def\numberedsubseczzz #1{% + \gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % + \subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% + \temp + \donoderef + \nobreak + } + + \outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} + \def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz + \def\appendixsubseczzz #1{% + \gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % + \subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% + \temp + \appendixnoderef + \nobreak + } + + \outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} + \def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz + \def\unnumberedsubseczzz #1{% + \plainsubsecheading {#1}\gdef\thissection{#1}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% + \temp + \unnumbnoderef + \nobreak + } + + % Subsubsections. + \outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} + \def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz + \def\numberedsubsubseczzz #1{% + \gdef\thissection{#1}\global\advance \subsubsecno by 1 % + \subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% + \temp + \donoderef + \nobreak + } + + \outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} + \def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz + \def\appendixsubsubseczzz #1{% + \gdef\thissection{#1}\global\advance \subsubsecno by 1 % + \subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% + \temp + \appendixnoderef + \nobreak + } + + \outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} + \def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz + \def\unnumberedsubsubseczzz #1{% + \plainsubsubsecheading {#1}\gdef\thissection{#1}% + \toks0 = {#1}% + \edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% + \temp + \unnumbnoderef + \nobreak + } + + % These are variants which are not "outer", so they can appear in @ifinfo. + % Actually, they should now be obsolete; ordinary section commands should work. + \def\infotop{\parsearg\unnumberedzzz} + \def\infounnumbered{\parsearg\unnumberedzzz} + \def\infounnumberedsec{\parsearg\unnumberedseczzz} + \def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} + \def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + + \def\infoappendix{\parsearg\appendixzzz} + \def\infoappendixsec{\parsearg\appendixseczzz} + \def\infoappendixsubsec{\parsearg\appendixsubseczzz} + \def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + + \def\infochapter{\parsearg\chapterzzz} + \def\infosection{\parsearg\sectionzzz} + \def\infosubsection{\parsearg\subsectionzzz} + \def\infosubsubsection{\parsearg\subsubsectionzzz} + + % These macros control what the section commands do, according + % to what kind of chapter we are in (ordinary, appendix, or unnumbered). + % Define them by default for a numbered chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec + + % Define @majorheading, @heading and @subheading + + % NOTE on use of \vbox for chapter headings, section headings, and such: + % 1) We use \vbox rather than the earlier \line to permit + % overlong headings to fold. + % 2) \hyphenpenalty is set to 10000 because hyphenation in a + % heading is obnoxious; this forbids it. + % 3) Likewise, headings look best if no \parindent is used, and + % if justification is not attempted. Hence \raggedright. + + + \def\majorheading{\parsearg\majorheadingzzz} + \def\majorheadingzzz #1{% + {\advance\chapheadingskip by 10pt \chapbreak }% + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + + \def\chapheading{\parsearg\chapheadingzzz} + \def\chapheadingzzz #1{\chapbreak % + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + + % @heading, @subheading, @subsubheading. + \def\heading{\parsearg\plainsecheading} + \def\subheading{\parsearg\plainsubsecheading} + \def\subsubheading{\parsearg\plainsubsubsecheading} + + % These macros generate a chapter, section, etc. heading only + % (including whitespace, linebreaking, etc. around it), + % given all the information in convenient, parsed form. + + %%% Args are the skip and penalty (usually negative) + \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + + \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + + %%% Define plain chapter starts, and page on/off switching for it + % Parameter controlling skip before chapter headings (if needed) + + \newskip\chapheadingskip + + \def\chapbreak{\dobreak \chapheadingskip {-4000}} + \def\chappager{\par\vfill\supereject} + \def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + + \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + + \def\CHAPPAGoff{% + \global\let\contentsalignmacro = \chappager + \global\let\pchapsepmacro=\chapbreak + \global\let\pagealignmacro=\chappager} + + \def\CHAPPAGon{% + \global\let\contentsalignmacro = \chappager + \global\let\pchapsepmacro=\chappager + \global\let\pagealignmacro=\chappager + \global\def\HEADINGSon{\HEADINGSsingle}} + + \def\CHAPPAGodd{ + \global\let\contentsalignmacro = \chapoddpage + \global\let\pchapsepmacro=\chapoddpage + \global\let\pagealignmacro=\chapoddpage + \global\def\HEADINGSon{\HEADINGSdouble}} + + \CHAPPAGon + + \def\CHAPFplain{ + \global\let\chapmacro=\chfplain + \global\let\unnumbchapmacro=\unnchfplain + \global\let\centerchapmacro=\centerchfplain} + + % Plain chapter opening. + % #1 is the text, #2 the chapter number or empty if unnumbered. + \def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak + } + + % Plain opening for unnumbered. + \def\unnchfplain#1{\chfplain{#1}{}} + + % @centerchap -- centered and unnumbered. + \let\centerparametersmaybe = \relax + \def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% + }} + + \CHAPFplain % The default + + \def\unnchfopen #1{% + \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak + } + + \def\chfopen #1#2{\chapoddpage {\chapfonts + \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% + \par\penalty 5000 % + } + + \def\centerchfopen #1{% + \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak + } + + \def\CHAPFopen{ + \global\let\chapmacro=\chfopen + \global\let\unnumbchapmacro=\unnchfopen + \global\let\centerchapmacro=\centerchfopen} + + + % Section titles. + \newskip\secheadingskip + \def\secheadingbreak{\dobreak \secheadingskip {-1000}} + \def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} + \def\plainsecheading#1{\sectionheading{sec}{}{#1}} + + % Subsection titles. + \newskip \subsecheadingskip + \def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} + \def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} + \def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + + % Subsubsection titles. + \let\subsubsecheadingskip = \subsecheadingskip + \let\subsubsecheadingbreak = \subsecheadingbreak + \def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} + \def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + + % Print any size section title. + % + % #1 is the section type (sec/subsec/subsubsec), #2 is the section + % number (maybe empty), #3 the text. + \def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak + } + + + \message{toc,} + \newwrite\tocfile + + % Write an entry to the toc file, opening it if necessary. + % Called from @chapter, etc. We supply {\folio} at the end of the + % argument, which will end up as the last argument to the \...entry macro. + % + % We open the .toc file here instead of at @setfilename or any other + % given time so that @contents can be put in the document anywhere. + % + \newif\iftocfileopened + \def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi + } + + \newskip\contentsrightmargin \contentsrightmargin=1in + \newcount\savepageno + \newcount\lastnegativepageno \lastnegativepageno = -1 + + % Finish up the main text and prepare to read what we've written + % to \tocfile. + % + \def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha at piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi + } + + + % Normal (long) toc. + \def\contents{% + \startcontents{\putwordTableofContents}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno + } + + % And just the chapters. + \def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno + } + \let\shortcontents = \summarycontents + + % These macros generate individual entries in the table of contents. + % The first argument is the chapter or section name. + % The last argument is the page number. + % The arguments in between are the chapter number, section number, ... + + % Chapter-level things, for both the long and short contents. + \def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + + % See comments in \dochapentry re vbox and related settings + \def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% + } + + % Typeset the label for a chapter or appendix for the short contents. + % The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. + % We could simplify the code here by writing out an \appendixentry + % command in the toc file for appendices, instead of using \chapentry + % for both, but it doesn't seem worth it. + \setbox0 = \hbox{\shortcontrm \putwordAppendix } + \newdimen\shortappendixwidth \shortappendixwidth = \wd0 + + \def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% + } + + \def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} + \def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + + % Sections. + \def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} + \def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + + % Subsections. + \def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} + \def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + + % And subsubsections. + \def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} + \def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + + % This parameter controls the indentation of the various levels. + \newdimen\tocindent \tocindent = 3pc + + % Now for the actual typesetting. In all these, #1 is the text and #2 is the + % page number. + % + % If the toc has to be broken over pages, we want it to be at chapters + % if at all possible; hence the \penalty. + \def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip + } + + \def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% + \endgroup} + + \def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% + \endgroup} + + \def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% + \endgroup} + + % Final typesetting of a toc entry; we use the same \entry macro as for + % the index entries, but we want to suppress hyphenation here. (We + % can't do that in the \entry macro, since index entries might consist + % of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) + \def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% + \endgroup} + + % Space between chapter (or whatever) number and the title. + \def\labelspace{\hskip1em \relax} + + \def\dopageno#1{{\rm #1}} + \def\doshortpageno#1{{\rm #1}} + + \def\chapentryfonts{\secfonts \rm} + \def\secentryfonts{\textfonts} + \let\subsecentryfonts = \textfonts + \let\subsubsecentryfonts = \textfonts + + + \message{environments,} + + % Since these characters are used in examples, it should be an even number of + % \tt widths. Each \tt character is 1en, so two makes it 1em. + % Furthermore, these definitions must come after we define our fonts. + \newbox\dblarrowbox \newbox\longdblarrowbox + \newbox\pushcharbox \newbox\bullbox + \newbox\equivbox \newbox\errorbox + + %{\tentt + %\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} + %\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} + %\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} + %\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} + % Adapted from the manmac format (p.420 of TeXbook) + %\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex + % depth .1ex\hfil} + %} + + % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. + \def\point{$\star$} + \def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} + \def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} + \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + \def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + + % Adapted from the TeXbook's \boxit. + {\tentt \global\dimen0 = 3em}% Width of the box. + \dimen2 = .55pt % Thickness of rules + % The text. (`r' is open on the right, `e' somewhat less so on the left.) + \setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + + \global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + + % The @error{} command. + \def\error{\leavevmode\lower.7ex\copy\errorbox} + + % @tex ... @end tex escapes into raw Tex temporarily. + % One exception: @ is still an escape character, so that @end tex works. + % But \@ or @@ will get a plain tex @ character. + + \def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% + \let\Etex=\endgroup} + + % Define @lisp ... @endlisp. + % @lisp does a \begingroup so it can rebind things, + % including the definition of @endlisp (which normally is erroneous). + + % Amount to narrow the margins by for @lisp. + \newskip\lispnarrowing \lispnarrowing=0.4in + + % This is the definition that ^^M gets inside @lisp, @example, and other + % such environments. \null is better than a space, since it doesn't + % have any width. + \def\lisppar{\null\endgraf} + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + {\obeyspaces % + \gdef\sepspaces{\obeyspaces\let =\tie}} + + % Define \obeyedspace to be our active space, whatever it is. This is + % for use in \parsearg. + {\sepspaces% + \global\let\obeyedspace= } + + % This space is always present above and below environments. + \newskip\envskipamount \envskipamount = 0pt + + % Make spacing and below environment symmetrical. We use \parskip here + % to help in doing that, since in @example-like environments \parskip + % is reset to zero; thus the \afterenvbreak inserts no space -- but the + % start of the next paragraph will insert \parskip + % + \def\aboveenvbreak{{\advance\envskipamount by \parskip + \endgraf \ifdim\lastskip<\envskipamount + \removelastskip \penalty-50 \vskip\envskipamount \fi}} + + \let\afterenvbreak = \aboveenvbreak + + % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. + \let\nonarrowing=\relax + + % @cartouche ... @end cartouche: draw rectangle w/rounded corners around + % environment contents. + \font\circle=lcircle10 + \newdimen\circthick + \newdimen\cartouter\newdimen\cartinner + \newskip\normbskip\newskip\normpskip\newskip\normlskip + \circthick=\fontdimen8\circle + % + \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth + \def\ctr{{\hskip 6pt\circle\char'010}} + \def\cbl{{\circle\char'012\hskip -6pt}} + \def\cbr{{\hskip 6pt\circle\char'011}} + \def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} + \def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} + % + \newskip\lskip\newskip\rskip + + \long\def\cartouche{% + \begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \endgroup + }} + + + % This macro is called at the beginning of all the @example variants, + % inside a group. + \def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi + } + + % Define the \E... control sequence only if we are inside the particular + % environment, so the error checking in \end will work. + % + % To end an @example-like environment, we first end the paragraph (via + % \afterenvbreak's vertical glue), and then the group. That way we keep + % the zero \parskip that the environments set -- \parskip glue will be + % inserted at the beginning of the next paragraph in the document, after + % the environment. + % + \def\nonfillfinish{\afterenvbreak\endgroup} + + % @lisp: indented, narrowed, typewriter font. + \def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return + } + + % @example: Same as @lisp. + \def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + + % @small... is usually equivalent to the non-small (@smallbook + % redefines). We must call \example (or whatever) last in the + % definition, since it reads the return following the @example (or + % whatever) command. + % + % This actually allows (for example) @end display inside an + % @smalldisplay. Too bad, but makeinfo will catch the error anyway. + % + \def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} + \def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} + \def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} + \def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + + % Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. + % Originally contributed by Pavel at xerox. + \def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \indexfonts + \lisp + } + + % @display: same as @lisp except keep current font. + % + \def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble + } + + % @smalldisplay (when @smallbook): @display plus smaller fonts. + % + \def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \indexfonts \rm + \display + } + + % @format: same as @display except don't narrow margins. + % + \def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble + } + + % @smallformat (when @smallbook): @format plus smaller fonts. + % + \def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \indexfonts \rm + \format + } + + % @flushleft (same as @format). + % + \def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + + % @flushright. + % + \def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble + } + + % @quotation does normal linebreaking (hence we can't use \nonfillstart) + % and narrows the margins. + % + \def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi + } + + + \message{defuns,} + % Define formatter for defuns + % First, allow user to change definition object font (\df) internally + \def\setdeffont #1 {\csname DEF#1\endcsname} + + \newskip\defbodyindent \defbodyindent=.4in + \newskip\defargsindent \defargsindent=50pt + \newskip\deftypemargin \deftypemargin=12pt + \newskip\deflastargmargin \deflastargmargin=18pt + + \newcount\parencount + % define \functionparens, which makes ( and ) and & do special things. + % \functionparens affects the group it is contained in. + \def\activeparens{% + \catcode`\(=\active \catcode`\)=\active \catcode`\&=\active + \catcode`\[=\active \catcode`\]=\active} + + % Make control sequences which act like normal parenthesis chars. + \let\lparen = ( \let\rparen = ) + + {\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + + % Be sure that we always have a definition for `(', etc. For example, + % if the fn name has parens in it, \boldbrax will not be in effect yet, + % so TeX would otherwise complain about undefined control sequence. + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + + \gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + % This is used to turn on special parens + % but make & act ordinary (given that it's active). + \gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + + % Definitions of (, ) and & used in args for functions. + % This is the definition of ( outside of all parentheses. + \gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 + } + % + % This is the definition of ( when already inside a level of parens. + \gdef\opnested{\char`\(\global\advance\parencount by 1 } + % + \gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } + % If we encounter &foo, then turn on ()-hacking afterwards + \gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } + % + \gdef\normalparens{\boldbrax\let&=\ampnr} + } % End of definition inside \activeparens + %% These parens (in \boldbrax) actually are a little bolder than the + %% contained text. This is especially needed for [ and ] + \def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } + \def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } + \def\ampnr{\&} + \def\lbrb{{\bf\char`\[}} + \def\rbrb{{\bf\char`\]}} + + % First, defname, which formats the header line itself. + % #1 should be the function name. + % #2 should be the type of definition, such as "Function". + + \def\defname #1#2{% + % Get the values of \leftskip and \rightskip as they were + % outside the @def... + \dimen2=\leftskip + \advance\dimen2 by -\defbodyindent + \noindent + \setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% + \dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line + \dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations + \parshape 2 0in \dimen0 \defargsindent \dimen1 + % Now output arg 2 ("Function" or some such) + % ending at \deftypemargin from the right margin, + % but stuck inside a box of width 0 so it does not interfere with linebreaking + {% Adjust \hsize to exclude the ambient margins, + % so that \rightline will obey them. + \advance \hsize by -\dimen2 + \rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% + % Make all lines underfull and no complaints: + \tolerance=10000 \hbadness=10000 + \advance\leftskip by -\defbodyindent + \exdentamount=\defbodyindent + {\df #1}\enskip % Generate function name + } + + % Actually process the body of a definition + % #1 should be the terminating control sequence, such as \Edefun. + % #2 should be the "another name" control sequence, such as \defunx. + % #3 should be the control sequence that actually processes the header, + % such as \defunheader. + + \def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2{\begingroup\obeylines\activeparens\spacesplit#3}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup % + \catcode 61=\active % 61 is `=' + \obeylines\activeparens\spacesplit#3} + + % #1 is the \E... control sequence to end the definition (which we define). + % #2 is the \...x control sequence for consecutive fns (which we define). + % #3 is the control sequence to call to resume processing. + % #4, delimited by the space, is the class name. + % + \def\defmethparsebody#1#2#3#4 {\begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + + % @deftypemethod has an extra argument that nothing else does. Sigh. + % #1 is the \E... control sequence to end the definition (which we define). + % #2 is the \...x control sequence for consecutive fns (which we define). + % #3 is the control sequence to call to resume processing. + % #4, delimited by the space, is the class name. + % #5 is the method's return type. + % + \def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + + \def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 {\def#4{##1}% + \begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + + % These parsing functions are similar to the preceding ones + % except that they do not make parens into active characters. + % These are used for "variables" since they have no arguments. + + \def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2{\begingroup\obeylines\spacesplit#3}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup % + \catcode 61=\active % + \obeylines\spacesplit#3} + + % This is used for \def{tp,vr}parsebody. It could probably be used for + % some of the others, too, with some judicious conditionals. + % + \def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines + } + + \def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% + } + + % This loses on `@deftp {Data Type} {struct termios}' -- it thinks the + % type is just `struct', because we lose the braces in `{struct + % termios}' when \spacesplit reads its undelimited argument. Sigh. + % \let\deftpparsebody=\defvrparsebody + % + % So, to get around this, we put \empty in with the type name. That + % way, TeX won't find exactly `{...}' as an undelimited argument, and + % won't strip off the braces. + % + \def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty + } + + % Fine, but then we have to eventually remove the \empty *and* the + % braces (if any). That's what this does. + % + \def\removeemptybraces\empty#1\relax{#1} + + % After \spacesplit has done its work, this is called -- #1 is the final + % thing to call, #2 the type name (which starts with \empty), and #3 + % (which might be empty) the arguments. + % + \def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% + }% + + \def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 {\def#4{##1}% + \begingroup\obeylines\spacesplit{#3{##2}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\spacesplit{#3{#5}}} + + % Split up #2 at the first space token. + % call #1 with two arguments: + % the first is all of #2 before the space token, + % the second is all of #2 after that space token. + % If #2 contains no space token, all of it is passed as the first arg + % and the second is passed as empty. + + {\obeylines + \gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% + \long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% + \ifx\relax #3% + #1{#2}{}\else #1{#2}{#3#4}\fi}} + + % So much for the things common to all kinds of definitions. + + % Define @defun. + + % First, define the processing that is wanted for arguments of \defun + % Use this to expand the args and terminate the paragraph they make up + + \def\defunargs #1{\functionparens \sl + % Expand, preventing hyphenation at `-' chars. + % Note that groups don't affect changes in \hyphenchar. + \hyphenchar\tensl=0 + #1% + \hyphenchar\tensl=45 + \ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% + \interlinepenalty=10000 + \advance\rightskip by 0pt plus 1fil + \endgraf\nobreak\vskip -\parskip\nobreak + } + + \def\deftypefunargs #1{% + % Expand, preventing hyphenation at `-' chars. + % Note that groups don't affect changes in \hyphenchar. + % Use \boldbraxnoamp, not \functionparens, so that & is not special. + \boldbraxnoamp + \tclose{#1}% avoid \code because of side effects on active chars + \interlinepenalty=10000 + \advance\rightskip by 0pt plus 1fil + \endgraf\nobreak\vskip -\parskip\nobreak + } + + % Do complete processing of one @defun or @defunx line already parsed. + + % @deffn Command forward-char nchars + + \def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + + \def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% + \begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % @defun == @deffn Function + + \def\defun{\defparsebody\Edefun\defunx\defunheader} + + \def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index + \begingroup\defname {#1}{Function}% + \defunargs {#2}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % @deftypefun int foobar (int @var{foo}, float @var{bar}) + + \def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + + % #1 is the data type. #2 is the name and args. + \def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} + % #1 is the data type, #2 the name, #3 the args. + \def\deftypefunheaderx #1#2 #3\relax{% + \doind {fn}{\code{#2}}% Make entry in function index + \begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% + \deftypefunargs {#3}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + + \def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + + % \defheaderxcond#1\relax$$$ + % puts #1 in @code, followed by a space, but does nothing if #1 is null. + \def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + + % #1 is the classification. #2 is the data type. #3 is the name and args. + \def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} + % #1 is the classification, #2 the data type, #3 the name, #4 the args. + \def\deftypefnheaderx #1#2#3 #4\relax{% + \doind {fn}{\code{#3}}% Make entry in function index + \begingroup + \normalparens % notably, turn off `&' magic, which prevents + % at least some C++ text from working + \defname {\defheaderxcond#2\relax$$$#3}{#1}% + \deftypefunargs {#4}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % @defmac == @deffn Macro + + \def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + + \def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index + \begingroup\defname {#1}{Macro}% + \defunargs {#2}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % @defspec == @deffn Special Form + + \def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + + \def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index + \begingroup\defname {#1}{Special Form}% + \defunargs {#2}\endgroup % + \catcode 61=\other % Turn off change made in \defparsebody + } + + % This definition is run if you use @defunx + % anywhere other than immediately after a @defun or @defunx. + + \def\deffnx #1 {\errmessage{@deffnx in invalid context}} + \def\defunx #1 {\errmessage{@defunx in invalid context}} + \def\defmacx #1 {\errmessage{@defmacx in invalid context}} + \def\defspecx #1 {\errmessage{@defspecx in invalid context}} + \def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} + \def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} + \def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}} + + % @defmethod, and so on + + % @defop CATEGORY CLASS OPERATION ARG... + + \def\defop #1 {\def\defoptype{#1}% + \defopparsebody\Edefop\defopx\defopheader\defoptype} + + \def\defopheader #1#2#3{% + \dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index + \begingroup\defname {#2}{\defoptype{} on #1}% + \defunargs {#3}\endgroup % + } + + % @deftypemethod CLASS RETURN-TYPE METHOD ARG... + % + \def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} + % + % #1 is the class name, #2 the data type, #3 the method name, #4 the args. + \def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup + } + + % @defmethod == @defop Method + % + \def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + % + % #1 is the class name, #2 the method name, #3 the args. + \def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup + } + + % @defcv {Class Option} foo-class foo-flag + + \def\defcv #1 {\def\defcvtype{#1}% + \defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + + \def\defcvarheader #1#2#3{% + \dosubind {vr}{\code{#2}}{of #1}% Make entry in var index + \begingroup\defname {#2}{\defcvtype{} of #1}% + \defvarargs {#3}\endgroup % + } + + % @defivar == @defcv {Instance Variable} + + \def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + + \def\defivarheader #1#2#3{% + \dosubind {vr}{\code{#2}}{of #1}% Make entry in var index + \begingroup\defname {#2}{Instance Variable of #1}% + \defvarargs {#3}\endgroup % + } + + % These definitions are run if you use @defmethodx, etc., + % anywhere other than immediately after a @defmethod, etc. + + \def\defopx #1 {\errmessage{@defopx in invalid context}} + \def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} + \def\defcvx #1 {\errmessage{@defcvx in invalid context}} + \def\defivarx #1 {\errmessage{@defivarx in invalid context}} + + % Now @defvar + + % First, define the processing that is wanted for arguments of @defvar. + % This is actually simple: just print them in roman. + % This must expand the args and terminate the paragraph they make up + \def\defvarargs #1{\normalparens #1% + \interlinepenalty=10000 + \endgraf\nobreak\vskip -\parskip\nobreak} + + % @defvr Counter foo-count + + \def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + + \def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% + \begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + + % @defvar == @defvr Variable + + \def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + + \def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index + \begingroup\defname {#1}{Variable}% + \defvarargs {#2}\endgroup % + } + + % @defopt == @defvr {User Option} + + \def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + + \def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index + \begingroup\defname {#1}{User Option}% + \defvarargs {#2}\endgroup % + } + + % @deftypevar int foobar + + \def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + + % #1 is the data type. #2 is the name, perhaps followed by text that + % is actually part of the data type, which should not be put into the index. + \def\deftypevarheader #1#2{% + \dovarind#2 \relax% Make entry in variables index + \begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% + \interlinepenalty=10000 + \endgraf\nobreak\vskip -\parskip\nobreak + \endgroup} + \def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + + % @deftypevr {Global Flag} int enable + + \def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + + \def\deftypevrheader #1#2#3{\dovarind#3 \relax% + \begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} + \interlinepenalty=10000 + \endgraf\nobreak\vskip -\parskip\nobreak + \endgroup} + + % This definition is run if you use @defvarx + % anywhere other than immediately after a @defvar or @defvarx. + + \def\defvrx #1 {\errmessage{@defvrx in invalid context}} + \def\defvarx #1 {\errmessage{@defvarx in invalid context}} + \def\defoptx #1 {\errmessage{@defoptx in invalid context}} + \def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} + \def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + + % Now define @deftp + % Args are printed in bold, a slight difference from @defvar. + + \def\deftpargs #1{\bf \defvarargs{#1}} + + % @deftp Class window height width ... + + \def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + + \def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% + \begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + + % This definition is run if you use @deftpx, etc + % anywhere other than immediately after a @deftp, etc. + + \def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + + \message{macros,} + % @macro. + + % To do this right we need a feature of e-TeX, \scantokens, + % which we arrange to emulate with a temporary file in ordinary TeX. + \ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{#1}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup + } + \else + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + \let\xeatspaces\eatspaces\scantokens{#1}\endgroup} + \fi + + \newcount\paramno % Count of parameters + \newtoks\macname % Macro name + \newif\ifrecursive % Is it recursive? + + % Utility routines. + % Thisdoes \let #1 = #2, except with \csnames. + \def\cslet#1#2{% + \expandafter\expandafter + \expandafter\let + \expandafter\expandafter + \csname#1\endcsname + \csname#2\endcsname} + + % Trim leading and trailing spaces off a string. + % Concepts from aro-bend problem 15 (see CTAN). + {\catcode`\@=11 + \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} + \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} + \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} + \def\unbrace#1{#1} + \unbrace{\gdef\trim@@@ #1 } #2@{#1} + } + + % Trim a single trailing ^^M off a string. + {\catcode`\^^M=12\catcode`\Q=3% + \gdef\eatcr #1{\eatcra #1Q^^MQ}% + \gdef\eatcra#1^^MQ{\eatcrb#1Q}% + \gdef\eatcrb#1Q#2Q{#1}% + } + + % Macro bodies are absorbed as an argument in a context where + % all characters are catcode 10, 11 or 12, except \ which is active + % (as in normal texinfo). It is necessary to change the definition of \. + + % It's necessary to have hard CRs when the macro is executed. This is + % done by making ^^M (\endlinechar) catcode 12 when reading the macro + % body, and then making it the \newlinechar in \scanmacro. + + \def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + + \def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + + % \mbodybackslash is the definition of \ in @macro bodies. + % It maps \foo\ => \csname macarg.foo\endcsname => #N + % where N is the macro parameter number. + % We define \csname macarg.\endcsname to be \realbackslash, so + % \\ in macro replacement text gets you a backslash. + + {\catcode`@=0 @catcode`@\=@active + @gdef at usembodybackslash{@let\=@mbodybackslash} + @gdef at mbodybackslash#1\{@csname macarg.#1 at endcsname} + } + \expandafter\def\csname macarg.\endcsname{\realbackslash} + + \def\macro{\recursivefalse\parsearg\macroxxx} + \def\rmacro{\recursivetrue\parsearg\macroxxx} + + \def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \expandafter\ifx \csname macsave.\the\macname\endcsname \relax + \cslet{macsave.\the\macname}{\the\macname}% + \else + \message{Warning: redefining \the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + + \def\unmacro{\parsearg\unmacroxxx} + \def\unmacroxxx#1{% + \expandafter\ifx \csname macsave.\the\macname\endcsname \relax + \errmessage{Macro \the\macname\ not defined.}% + \else + \cslet{#1}{macsave.#1}% + \expandafter\let \csname macsave.\the\macname\endcsname \undefined + \fi + } + + % This makes use of the obscure feature that if the last token of a + % is #, then the preceding argument is delimited by + % an opening brace, and that opening brace is not consumed. + \def\getargs#1{\getargsxxx#1{}} + \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} + \def\getmacname #1 #2\relax{\macname={#1}} + \def\getmacargs#1{\def\argl{#1}} + + % Parse the optional {params} list. Set up \paramno and \paramlist + % so \defmacro knows what to do. Define \macarg.blah for each blah + % in the params list, to be ##N where N is the position in that list. + % That gets used by \mbodybackslash (above). + + % We need to get `macro parameter char #' into several definitions. + % The technique used is stolen from LaTeX: let \hash be something + % unexpandable, insert that wherever you need a #, and then redefine + % it to # just before using the token list produced. + % + % The same technique is used to protect \eatspaces till just before + % the macro is used. + + \def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} + \def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + + % These two commands read recursive and nonrecursive macro bodies. + % (They're different since rec and nonrec macros end differently.) + + \long\def\parsemacbody#1 at end macro% + {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + \long\def\parsermacbody#1 at end rmacro% + {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + + % This defines the macro itself. There are six cases: recursive and + % nonrecursive macros of zero, one, and many arguments. + % Much magic with \expandafter here. + % \xdef is used so that macro definitions will survive the file + % they're defined in; @include reads the file inside a group. + \def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname} + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname} + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + + \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + + % \braceorline decides whether the next nonwhitespace character is a + % {. If so it reads up to the closing }, if not, it reads the whole + % line. Whatever was read is then fed to the next control sequence + % as an argument (by \parsebrace or \parsearg) + \def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} + \def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + + + \message{cross references,} + \newwrite\auxfile + + \newif\ifhavexrefs % True if xref values are known. + \newif\ifwarnedxrefs % True if we warned once that they aren't known. + + % @inforef is relatively simple. + \def\inforef #1{\inforefzzz #1,,,,**} + \def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + + % @node's job is to define \lastnode. + \def\node{\ENVcheck\parsearg\nodezzz} + \def\nodezzz#1{\nodexxx [#1,]} + \def\nodexxx[#1,#2]{\gdef\lastnode{#1}} + \let\nwnode=\node + \let\lastnode=\relax + + % The sectioning commands (@chapter, etc.) call these. + \def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi + } + \def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi + } + \def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi + } + + + % @anchor{NAME} -- define xref target at arbitrary point. + % + \def\anchor#1{\setref{#1}{Ynothing}} + + + % \setref{NAME}{SNT} defines a cross-reference point NAME, namely + % NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have + % to set \indexdummies so commands such as @code in a section title + % aren't expanded. It would be nicer not to expand the titles in the + % first place, but there's so many layers that that is hard to do. + % + \def\setref#1#2{{% + \indexdummies + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2} + }} + + % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is + % the node name, #2 the name of the Info cross-reference, #3 the printed + % node name, #4 the name of the Info file, #5 the name of the printed + % manual. All but the node name can be omitted. + % + \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} + \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} + \def\ref#1{\xrefX[#1,,,,,,,]} + \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \endgroup} + + % \dosetq is the interface for calls from other macros + + % Use \normalturnoffactive so that punctuation chars such as underscore + % and backslash work in node names. (\turnoffactive doesn't do \.) + \def\dosetq#1#2{% + {\let\folio=0 + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% + } + + % \internalsetq {foo}{page} expands into + % CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} + % When the aux file is read, ' is the escape character + + \def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + + % Things to be expanded by \internalsetq + + \def\Ypagenumber{\folio} + + \def\Ytitle{\thissection} + + \def\Ynothing{} + + \def\Ysectionnumberandtype{% + \ifnum\secno=0 \putwordChapter\xreftie\the\chapno % + \else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % + \else \ifnum \subsubsecno=0 % + \putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % + \else % + \putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % + \fi \fi \fi } + + \def\Yappendixletterandtype{% + \ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% + \else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % + \else \ifnum \subsubsecno=0 % + \putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % + \else % + \putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % + \fi \fi \fi } + + \gdef\xreftie{'tie} + + % Use TeX 3.0's \inputlineno to get the line number, for better error + % messages, but if we're using an old version of TeX, don't do anything. + % + \ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. + \else + \def\linenumber{\the\inputlineno:\space} + \fi + + % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. + % If its value is nonempty, SUFFIX is output afterward. + + \def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. + } + + % This is the macro invoked by entries in the aux file. + % + \def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname + } + + % Read the last existing aux file, if any. No error if none exists. + \def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux + \endgroup} + + + % Footnotes. + + \newcount \footnoteno + + % The trailing space in the following definition for supereject is + % vital for proper filling; pages come out unaligned when you do a + % pagealignmacro call if that space before the closing brace is + % removed. (Generally, numeric constants should always be followed by a + % space to prevent strange expansion errors.) + \def\supereject{\par\penalty -20000\footnoteno =0 } + + % @footnotestyle is meaningful for info output only. + \let\footnotestyle=\comment + + \let\ptexfootnote=\footnote + + {\catcode `\@=11 + % + % Auto-number footnotes. Otherwise like plain. + \gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz + }% + + % Don't bother with the trickery in plain.tex to not require the + % footnote text as a parameter. Our footnotes don't need to be so general. + % + % Oh yes, they do; otherwise, @ifset and anything else that uses + % \parseargline fail inside footnotes because the tokens are fixed when + % the footnote is read. --karl, 16nov96. + % + \long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z at skip + \rightskip\z at skip + \spaceskip\z at skip + \xspaceskip\z at skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo at t + } + \def\fo at t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f at t\fi \next} + \def\f@@t{\bgroup\aftergroup\@foot\let\next} + \def\f at t#1{#1\@foot} + \def\@foot{\strut\egroup} + + }%end \catcode `\@=11 + + % Set the baselineskip to #1, and the lineskip and strut size + % correspondingly. There is no deep meaning behind these magic numbers + % used as factors; they just match (closely enough) what Knuth defined. + % + \def\lineskipfactor{.08333} + \def\strutheightpercent{.70833} + \def\strutdepthpercent {.29167} + % + \def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% + } + + % @| inserts a changebar to the left of the current line. It should + % surround any changed text. This approach does *not* work if the + % change spans more than two lines of output. To handle that, we would + % have adopt a much more difficult approach (putting marks into the main + % vertical list for the beginning and end of each change). + % + \def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% + } + + % For a final copy, take out the rectangles + % that mark overfull boxes (in case you have decided + % that the text looks ok even though it passes the margin). + % + \def\finalout{\overfullrule=0pt} + + % @image. We use the macros from epsf.tex to support this. + % If epsf.tex is not installed and @image is used, we complain. + % + % Check for and read epsf.tex up front. If we read it only at @image + % time, we might be inside a group, and then its definitions would get + % undone and the next image would fail. + \openin 1 = epsf.tex + \ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex + \fi + % + \newif\ifwarnednoepsf + \newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://ftp.tug.org/tex/epsf.tex.} + % + % Only complain once about lack of epsf.tex. + \def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi + } + % + % Arguments to @image: + % #1 is (mandatory) image filename; we tack on .eps extension. + % #2 is (optional) width, #3 is (optional) height. + % #4 is just the usual extra ignored arg for parsing this stuff. + \def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + % If the image is by itself, center it. + \ifvmode + \nobreak\medskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + \epsfbox{#1.eps}% + \fi + } + + + \message{paper sizes,} + % And other related parameters. + + \newdimen\defaultparindent \defaultparindent = 15pt + + \chapheadingskip = 15pt plus 4pt minus 2pt + \secheadingskip = 12pt plus 3pt minus 2pt + \subsecheadingskip = 9pt plus 2pt minus 2pt + + % Prevent underfull vbox error messages. + \vbadness = 10000 + + % Don't be so finicky about underfull hboxes, either. + \hbadness = 2000 + + % Following George Bush, just get rid of widows and orphans. + \widowpenalty=10000 + \clubpenalty=10000 + + % Use TeX 3.0's \emergencystretch to help line breaking, but if we're + % using an old version of TeX, don't do anything. We want the amount of + % stretch added to depend on the line length, hence the dependence on + % \hsize. This makes it come to about 9pt for the 8.5x11 format. We + % call this whenever the paper size is set. + % + \def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = \hsize + \divide\emergencystretch by 45 + \fi + } + + % Parameters in order: 1) textheight; 2) textwidth; 3) voffset; + % 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can + % set \parskip and call \setleading for \baselineskip. + % + \def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch + } + + % @letterpaper (the default). + \def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% + }} + + % Use @smallbook to reset parameters for 7x9.5 (or so) format. + \def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx + }} + + % Use @afourpaper to print on European A4 paper. + \def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt + }} + + % A specific text layout, 24x15cm overall, intended for A4 paper. Top margin + % 29mm, hence bottom margin 28mm, nominal side margin 3cm. + \def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 + }} + + % Use @afourwide to print on European A4 paper in wide format. + \def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 + } + + % @pagesizes TEXTHEIGHT[,TEXTWIDTH] + % Perhaps we should allow setting the margins, \topskip, \parskip, + % and/or leading, also. Or perhaps we should compute them somehow. + % + \def\pagesizes{\parsearg\pagesizesxxx} + \def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} + \def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% + }} + + % Set default to letter. + % + \letterpaper + + \message{and turning on texinfo input format.} + + % Define macros to output various characters with catcode for normal text. + \catcode`\"=\other + \catcode`\~=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\+=\other + \def\normaldoublequote{"} + \def\normaltilde{~} + \def\normalcaret{^} + \def\normalunderscore{_} + \def\normalverticalbar{|} + \def\normalless{<} + \def\normalgreater{>} + \def\normalplus{+} + + % This macro is used to make a character print one way in ttfont + % where it can probably just be output, and another way in other fonts, + % where something hairier probably needs to be done. + % + % #1 is what to print if we are indeed using \tt; #2 is what to print + % otherwise. Since all the Computer Modern typewriter fonts have zero + % interword stretch (and shrink), and it is reasonable to expect all + % typewriter fonts to have this, we can check that font parameter. + % + \def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + + % Turn off all special characters except @ + % (and those which the user can use as if they were ordinary). + % Most of these we simply print from the \tt font, but for some, we can + % use math or other variants that look better in normal text. + + \catcode`\"=\active + \def\activedoublequote{{\tt\char34}} + \let"=\activedoublequote + \catcode`\~=\active + \def~{{\tt\char126}} + \chardef\hat=`\^ + \catcode`\^=\active + \def^{{\tt \hat}} + + \catcode`\_=\active + \def_{\ifusingtt\normalunderscore\_} + % Subroutine for the previous macro. + \def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + + \catcode`\|=\active + \def|{{\tt\char124}} + \chardef \less=`\< + \catcode`\<=\active + \def<{{\tt \less}} + \chardef \gtr=`\> + \catcode`\>=\active + \def>{{\tt \gtr}} + \catcode`\+=\active + \def+{{\tt \char 43}} + %\catcode 27=\active + %\def^^[{$\diamondsuit$} + + % Set up an active definition for =, but don't enable it most of the time. + {\catcode`\==\active + \global\def={{\tt \char 61}}} + + \catcode`+=\active + \catcode`\_=\active + + % If a .fmt file is being used, characters that might appear in a file + % name cannot be active until we have parsed the command line. + % So turn them off again, and have \everyjob (or @setfilename) turn them on. + % \otherifyactive is called near the end of this file. + \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + + \catcode`\@=0 + + % \rawbackslashxx output one backslash character in current font + \global\chardef\rawbackslashxx=`\\ + %{\catcode`\\=\other + %@gdef at rawbackslashxx{\}} + + % \rawbackslash redefines \ as input to do \rawbackslashxx. + {\catcode`\\=\active + @gdef at rawbackslash{@let\=@rawbackslashxx }} + + % \normalbackslash outputs one backslash in fixed width font. + \def\normalbackslash{{\tt\rawbackslashxx}} + + % Say @foo, not \foo, in error messages. + \escapechar=`\@ + + % \catcode 17=0 % Define control-q + \catcode`\\=\active + + % Used sometimes to turn off (effectively) the active characters + % even after parsing them. + @def at turnoffactive{@let"=@normaldoublequote + @let\=@realbackslash + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus} + + @def at normalturnoffactive{@let"=@normaldoublequote + @let\=@normalbackslash + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus} + + % Make _ and + \other characters, temporarily. + % This is canceled by @fixbackslash. + @otherifyactive + + % If a .fmt file is being used, we don't want the `\input texinfo' to show up. + % That is what \eatinput is for; after that, the `\' should revert to printing + % a backslash. + % + @gdef at eatinput input texinfo{@fixbackslash} + @global at let\ = @eatinput + + % On the other hand, perhaps the file did not have a `\input texinfo'. Then + % the first `\{ in the file would cause an error. This macro tries to fix + % that, assuming it is called before the first `\' could plausibly occur. + % Also back turn on active characters that might appear in the input + % file name, in case not using a pre-dumped format. + % + @gdef at fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + + % These look ok in all fonts, so just make them not special. The @rm below + % makes sure that the current font starts out as the newly loaded cmr10 + @catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + + @textfonts + @rm + + @c Local variables: + @c eval: (add-hook 'write-file-hooks 'time-stamp) + @c page-delimiter: "^\\\\message" + @c time-stamp-start: "def\\\\texinfoversion{" + @c time-stamp-format: "%:y-%02m-%02d" + @c time-stamp-end: "}" + @c End: Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.1 diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.1:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.1 Tue Apr 6 12:54:45 2004 *************** *** 0 **** --- 1,113 ---- + .\" Copyright (c) 2001 Southern Storm Software, Pty Ltd. + .\" + .\" This program is free software; you can redistribute it and/or modify + .\" it under the terms of the GNU General Public License as published by + .\" the Free Software Foundation; either version 2 of the License, or + .\" (at your option) any later version. + .\" + .\" This program is distributed in the hope that it will be useful, + .\" but WITHOUT ANY WARRANTY; without even the implied warranty of + .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + .\" GNU General Public License for more details. + .\" + .\" You should have received a copy of the GNU General Public License + .\" along with this program; if not, write to the Free Software + .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + .TH treecc 1 "19 June 2001" "Southern Storm Software" "" + .SH NAME + treecc \- tree compiler-compiler + .SH SYNOPSIS + .ll +8 + .B treecc + [ options ] + .I input + \&... + .SH DESCRIPTION + .B Treecc + converts input files in the treecc syntax into source + code that permits creating and walking abstract syntax trees. + It is intended for use in developing compilers, in concert with + existing tools such as \fBlex\fR(1) and \fByacc\fR(1). + The treecc syntax is described in the \fBtreecc\fR texinfo + topic. + .SH OPTIONS + .TP + .B \-o \fIfile\fB, \-\-output \fIfile\fR + Set the name of the output file. If this option is not supplied, + then the name of the first input file will be used, with its + extension changed to ".c". If the input is stdin, the default + output file is "yy_tree.c". + + This option may be overridden using the "%output" keyword in + the input files. + .TP + .B \-h \fIfile\fB, \-\-header \fIfile\fR + Set the name of the header output file. This is only used for + the C and C++ languages. If this option is not supplied, + then the name of the output file will be used, with its extension + changed to ".h". If the input is stdin, the default header output + file is "yy_tree.h". + + This option may be overriden using the "%header" keyword in the + input files. + + If this option is used with a language that does not require + headers, it will be ignored. + .TP + .B \-d \fIdir\fB, \-\-output\-dir \fIdir\fR + Set the name of the Java output directory. This is only used for + the Java language. If this option is not supplied, then the directory + corresponding to the first input file is used. If the input is stdin, + the default is the current directory. + + This option may be overriden using the "%outdir" keyword in the + input files. + + If this option is used with a language other than Java, it will be ignored. + .TP + .B \-e \fIext\fB, \-\-extension \fIext\fR + Change the default output file extension to \fIext\fR, instead of + ".c". The value \fIext\fR can have a leading dot, but this is + not required. + .TP + .B \-f, \-\-force\-create + \fBTreecc\fR attempts to optimise the creation of output files + so that they are only modified if a non-trivial change has + occurred in the input. This can reduce the number of source + code recompiles when \fBtreecc\fR is used in combination + with \fBmake\fR(1). + + This option forces the output files to be created, even if they + are the same as existing files with the same name. + + The directive "%option force" can be used in the input files + to achieve the same effect as this option. + .TP + .B \-O \fIopt\fB, \-\-option \fIopt\fR + Set a treecc option value. This is a command-line version of + the "%option" keyword in the input files. + .TP + .B \-n, \-\-no\-output + Suppress the generation of output files. \fBTreecc\fR parses the + input files, checks for errors, and then stops. + .TP + .B \-\-help + Print a usage message for the \fBtreecc\fR program. + .TP + .B \-v, \-\-version + Print the version of the \fBtreecc\fR program. + .TP + .B \-\- + Marks the end of the command-line options, and the beginning of + the input filenames. You may need to use this if your filename + begins with '-'. e.g. "treecc -- -input.tc". This is not needed + if the input is stdin: "treecc -" is perfectly valid. + .SH "AUTHOR" + Written by Southern Storm Software, Pty Ltd. + + http://www.southern-storm.com.au/ + .SH "SEE ALSO" + lex(1), yacc(1), make(1) + .SH "DIAGNOSTICS" + Exit status is 1 if an error occurred while processing the input. + Otherwise the exit status is 0. Index: llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.texi diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.texi:1.1 *** /dev/null Tue Apr 6 12:54:55 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/doc/treecc.texi Tue Apr 6 12:54:45 2004 *************** *** 0 **** --- 1,2916 ---- + \input texinfo @c -*-texinfo-*- + @c %** start of header + @setfilename treecc.info + @settitle Tree Compiler-Compiler + @setchapternewpage off + @c %** end of header + + @dircategory DotGNU + @direntry + * TreeCC: (treecc). Generate code for compilers to build + abstract syntax trees. + @end direntry + + @ifinfo + The treecc program converts descriptions of abstract syntax + trees into source code that can be used to support compiler + development. + + @noindent + Copyright @copyright{} 2001 Southern Storm Software, Pty Ltd + @*Copyright @copyright{} 2003 Free Software Foundation, Inc. + @end ifinfo + + @titlepage + @sp 10 + @center @titlefont{Tree Compiler-Compiler} + + @vskip 50pt + + @center{Rhys Weatherley} + + @vskip 50pt + @center{Copyright @copyright{} 2001, 2002 Southern Storm Software, Pty Ltd} + @center{Copyright @copyright{} 2003 Free Software Foundation, Inc.} + @end titlepage + + @c ----------------------------------------------------------------------- + + @node Top, Overview, , (dir) + @menu + * Overview:: Treecc in brief + * Expression Example:: A simple example of using treecc + * Invoking Treecc:: Invoking treecc from the command-line + * Syntax:: Syntax of input files + * Line Tracking:: Tracking line numbers in source files + * Output APIs:: API's that are available in the generated output + * Full Expression Example:: Full code for the expression example + * EBNF Syntax:: Full EBNF syntax for treecc input files + * Index:: Index of concepts and facilities + @end menu + + @c ----------------------------------------------------------------------- + + @node Overview, Expression Example, Top, Top + @chapter Overview + @cindex Overview + + @section Introduction + + Traditional compiler construction tools such as lex and yacc focus on + the lexical analysis and parsing phases of compilation. But they + provide very little to support semantic analysis and code generation. + + Yacc allows grammar rules to be tagged with semantic actions and values, + but it doesn't provide any routines that assist in the process of tree + building, semantic analysis, or code generation. Because those processes + are language-specific, yacc leaves the details to the programmer. + + Support for semantic analysis was also a lot simpler in the languages + that were prevalent when lex and yacc were devised. C and Pascal + require declare before use, which allows the semantic information + about a statement to be determined within the parser at the point of + use. at footnote{K&R C did allow functions that weren't declared to be called, + but only if they returned an "int". This allowed the compiler to + guess the declaration if it wasn't available, and to proceed as + though all symbols were declared before use.} If extensive optimization + is not required, then code generation can also be performed within + the grammar, leading to a simple one-pass compiler structure. + + Modern languages allow deferred declaration of methods, fields, and + types. For example, Java allows a method to refer to a field that + is declared further down the .java source file. A field can be + declared with a type whose class definition has not yet been parsed. + + Hence, most of the semantic analysis that used to be performed inline + within a yacc grammar must now be performed after the entire program + has been parsed. Tree building and walking is now more important + than it was in older declare before use languages. + + @section Tree walking: the need for something better + + Building parse tree data structures and walking them is not terribly + difficult, but it is extremely time-consuming and error-prone. A + modern programming language may have hundreds of node types, divided + into categories for statements, expressions, types, declarations, etc. + When a new programming language is being devised, new node types may + be added quite frequently. This has ramifications in trying to manage + the code's complexity. at footnote{Implementing an existing programming + language has the same problems as a new language. Most programming + languages are too large to be implemented all at once, and so the problem + must be tackled in stages. These stages are very similar to those the + programmer goes through implementing a new language.} + + For example, consider nodes that correspond to programming language + types in a C-like language. There will be node types for integer + types, floating-point types, pointers, structures, functions, etc. + There will be semantic analysis routines for testing types for + equality, comparing types for coercions and casts, evaluating the + size of a type for memory layout purposes, determining if the type + falls into a general category such as "integer" or "pointer", etc. + + Let's say we wanted to add a new "128-bit integer" type to this + language. Adding a new node type is fairly straight-forward. + But we also need to track down every place in the code where the + compiler walks a type or deals with integers and add an appropriate + case for the new type. This is very error-prone. Such code is + likely to be split over many files, and good coding practices only + help to a certain extent. + + This problem gets worse when new kinds of expressions and statements + are added to the language. The change not only affects semantic + analysis, but also optimization and code generation. Some compilers + use multiple passes over the tree to perform optimization, with + different algorithms used in each pass. Code generation may use a + number of different strategies, depending upon how an expression or + statement is used. If even one of these places is missed when the + new node type is added, then there is the potential for a very nasty + bug that may go unnoticed for months or years. + + Object-oriented languages such as C++ can help a bit in constructing + robust tree structures. The base class can declare abstract methods + for any semantic analysis, optimization, or code generation routine + that needs to be implemented for all members of the node category. + But another code maintainence problem arises. What happens when + we want to add a new optimization pass in the future? We must go + into hundreds of classes and implement the methods. + + To avoid changing hundreds of classes, texts on Design Patterns + suggest using a Visitor pattern. Then the new optimization pass + can be encapsulated in a visitor. This would work, except for + the following drawback of visitor patterns, as described in Gamma, + et al: + + @quotation + @emph{The Visitor pattern makes it hard to add new subclasses of + Element. Each new ConcreteElement gives rise to a new abstract + operation on Visitor and a corresponding implementation in + every ConcreteVisitor class.} + + @emph{... The Visitor class hierarchy can be difficult to maintain + when new ConcreteElement classes are added frequently. In such + cases, it's probably easier just to define operations on the + classes that make up the structure.} + @end quotation + + That is, if we add a new node type in the future, we have a large + maintainence problem on our hands. The solution is to scatter the + implementation through-out every class, which is the situation we + were trying to avoid by using the Visitor pattern. + + Because compiler construction deals with a large set of rapidly + changing node types and operations, neither of the usual approaches + work very well. + + The ideal programming language for designing compilers needs to have + some way to detect when the programmer forgets to implement an operation + for a new node type, and to ensure that a new operation covers all + existing node types adequately. Existing OO languages do not perform + this kind of global error checking. What few checking procedures they + have change the maintainence problem into a different problem of + similar complexity. + + @section Aspect-oriented programming + + A new field in language design has emerged in recent years called + "Aspect-Oriented Programming" (AOP). A good review of the field + can be found in the October 2001 issue of the @emph{Communications of + the ACM}, and on the AspectJ Web site, @url{http://www.aspectj.org/}. + + The following excerpt from the introduction to the AOP section in the + CACM issue describes the essential aspects of AOP, and the difference + between OOP and AOP: + + @quotation + @emph{AOP is based on the idea that computer systems are better programmed + by separately specifying the various concerns (properties or areas + of interest) of a system and some description of their relationships, + and then relying on mechanisms in the underlying AOP environment to + weave or compose them together into a coherent program. ... + While the tendancy in OOP's is to find commonality among classes + and push it up the inheritance tree, AOP attempts to realize + scattered concerns as first-class elements, and eject them + horizontally from the object structure.} + @end quotation + + Aspect-orientation gives us some hope of solving our compiler + complexity problems. We can view each operation on node types + (semantic analysis, optimization, code generation, etc) as an + "aspect" of the compiler's construction. The AOP language weaves + these aspects with the node types to create the final compiler. + + @section The treecc approach + + We don't really want to implement a new programming language + just for compiler construction. Especially since the new language's + implementation would have all of the problems described above and would + therefore also be difficult to debug and maintain. + + The approach that we take with "treecc" is similar to that used by + "yacc". A simple rule-based language is devised that is used to describe + the intended behaviour declaratively. Embedded code is used to provide + the specific implementation details. A translator then converts the input + into source code that can be compiled in the usual fashion. + + The translator is responsible for generating the tree building and + walking code, and for checking that all relevant operations have been + implemented on the node types. Functions are provided that make + it easier to build and walk the tree data structures from within + a "yacc" grammar and other parts of the compiler. + + @c ----------------------------------------------------------------------- + + @node Expression Example, Invoking Treecc, Overview, Top + @chapter A simple example for expressions + @cindex Expression example + + Consider the following yacc grammar for a simple expression language: + + @example + %token INT FLOAT + + %% + + expr: INT + | FLOAT + | '(' expr ')' + | expr '+' expr + | expr '-' expr + | expr '*' expr + | expr '/' expr + | '-' expr + ; + @end example + + (We will ignore the problems of precedence and associativity and + assume that the reader is familiar with how to resolve such issues + in yacc grammars). + + There are 7 types of nodes for this grammar: @samp{intnum}, @samp{floatnum}, + @samp{plus}, @samp{minus}, @samp{multiply}, @samp{divide}, and @samp{negate}. + They are defined in treecc as follows: + + @example + %node expression %abstract %typedef + + %node binary expression %abstract = + @{ + expression *expr1; + expression *expr2; + @} + + %node unary expression %abstract = + @{ + expression *expr; + @} + + %node intnum expression = + @{ + int num; + @} + + %node floatnum expression = + @{ + float num; + @} + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node negate unary + @end example + + We have introduced three extra node types that refer + to any expression, binary expressions, and unary expressions. These + can be seen as superclasses in an OO-style framework. We have + declared these node types as @samp{abstract} because the yacc grammar + will not be permitted to create instances of these classes directly. + + The @samp{binary}, @samp{unary}, @samp{intnum}, and @samp{floatnum} + node types have field definitions associated with them. These have + a similar syntax to C @code{struct} declarations. + + The yacc grammar is augmented as follows to build the parse tree: + + @example + %union @{ + expression *node; + int inum; + float fnum; + @} + + %token INT FLOAT + + %type expr + %type INT + %type FLOAT + + %% + + expr: INT @{ $$ = intnum_create($1); @} + | FLOAT @{ $$ = floatnum_create($1); @} + | '(' expr ')' @{ $$ = $2; @} + | expr '+' expr @{ $$ = plus_create($1, $3); @} + | expr '-' expr @{ $$ = minus_create($1, $3); @} + | expr '*' expr @{ $$ = multiply_create($1, $3); @} + | expr '/' expr @{ $$ = divide_create($1, $3); @} + | '-' expr @{ $$ = negate_create($2); @} + ; + @end example + + The treecc translator generates the @samp{*_create} functions so that + the rest of the compiler can build the necessary data structures + on demand. The parameters to the @samp{*_create} functions + are identical in type and order to the members of the structure for + that node type. + + Because @samp{expression}, @samp{binary}, and @samp{unary} are abstract, + there will be no @samp{*_create} functions associated with them. This will + help the programmer catch certain kinds of errors. + + The type that is returned from a @samp{*_create} function is the first + superclass of the node that has a @samp{%typedef} keyword associated with it; + @samp{expression *} in this case. + + @section Storing extra information + + Normally we will want to store extra information with a node beyond + that which is extracted by the yacc grammar. In our expression + example, we probably want to store type information in the nodes + so that we can determine if the whole expression is integer or + floating point during semantic analysis. We can add type information + to the @samp{expression} node type as follows: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + @end example + + The @samp{%nocreate} flag indicates that the field should not be passed + to the @samp{*_create} functions as a parameter. i.e. it provides semantic + information that isn't present in the grammar. When nodes are created, + any fields that are declared as @samp{%nocreate} will be undefined in value. + A default value can be specified as follows: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type = @{int_type@}; + @} + @end example + + Default values must be enclosed in @samp{@{} and @samp{@}} because they are + pieces of code in the underlying source language (C, C++, etc), instead + of tokens in the treecc syntax. Any legitimate expression in the + underlying source language may be used. + + We also need to arrange for @samp{type_code} to be declared. One way to + do this is by adding a @samp{%decls} section to the front of the treecc + input file: + + @example + %decls %@{ + + typedef enum + @{ + int_type, + float_type + + @} type_code; + + %@} + @end example + + We could have introduced the definition by placing a @samp{#include} + directive into the @samp{%decls} section instead, or by defining a + treecc enumerated type: + + @example + %enum type_code = + @{ + int_type, + float_type + @} + @end example + + Now that we have these definitions, type-inferencing can be implemented + as follows: + + @example + %operation void infer_type(expression *e) + + infer_type(binary) + @{ + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == float_type || e->expr2->type == float_type) + @{ + e->type = float_type; + @} + else + @{ + e->type = int_type; + @} + @} + + infer_type(unary) + @{ + infer_type(e->expr); + e->type = e->expr->type; + @} + + infer_type(intnum) + @{ + e->type = int_type; + @} + @end example + + This example demonstrates using the abstract node types @samp{binary} and + @samp{unary} to define operations on all subclasses. The treecc translator + will generate code for a full C function called @samp{infer_type} that + incorporates all of the cases. + + But hang on a second! What happened to @samp{floatnum}? Where did it + go? It turns out that treecc will catch this. It will report + an error to the effect that @samp{node type `floatnum' is not handled in + operation `infer_type'}. Here is its definition: + + @example + infer_type(floatnum) + @{ + e->type = float_type; + @} + @end example + + As we can see, treecc has just caught a bug in the language + implementation and reported it to us as soon as we introduced it. + + Let's now extend the language with a @samp{power} operator: + + @example + yacc: + + expr: expr '^' expr @{ $$ = create_power($1, $3); @} + ; + + treecc: + + %node power binary + @end example + + That's all there is to it! When treecc re-translates the input + file, it will modify the definition of @samp{infer_type} to include the + extra case for @samp{power} nodes. Because @samp{power} is a subclass of + @samp{binary}, treecc already knows how to perform type inferencing for the + new node and it doesn't warn us about a missing declaration. + + What if we wanted to restrict the second argument of @samp{power} to be + an integer value? We can add the following case to @samp{infer_type}: + + @example + infer_type(power) + @{ + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr2->type != int_type) + @{ + error("second argument to `^' is not an integer"); + @} + + e->type = e->expr1->type; + @} + @end example + + The translator now notices that there is a more specific implementation + of @samp{infer_type} for @samp{power}, and won't use the @samp{binary} + case for it. + + The most important thing to realise here is that the translator always + checks that there are sufficient declarations for @samp{infer_type} to cover + all relevant node types. If it detects a lack, it will immediately + raise an error to the user. This allows tree coverage problems to + be found a lot sooner than with the traditional approach. + + @xref{Full Expression Example}, for a complete listing of the above + example files. + + @c ----------------------------------------------------------------------- + + @node Invoking Treecc, Syntax, Expression Example, Top + @chapter Invoking treecc from the command-line + @cindex Invoking treecc + @cindex Command-line options + + The general form of treecc's command-line syntax is as follows: + + @example + treecc [OPTIONS] INPUT ... + @end example + + Treecc accepts the following command-line options: + + @table @code + @item -o FILE + @itemx --output FILE + Set the name of the output file to @samp{FILE}. If this option is not + supplied, then the name of the first input file will be used, with its + extension changed to @samp{.c}. If the input is standard input, + the default output file is @samp{yy_tree.c}. + + This option may be overridden using the @samp{%output} keyword in + the input files. + + @item -h FILE + @itemx --header FILE + Set the name of the header output file to @samp{FILE}. This is only + used for the C and C++ output languages. If this option is not supplied, + then the name of the output file will be used, with its extension + changed to @samp{.h}. If the input is standard input, the default header + output file is @samp{yy_tree.h}. + + This option may be overriden using the @samp{%header} keyword in the + input files. If this option is used with a language that does not require + headers, it will be ignored. + + @item -d DIR + @itemx --output-dir DIR + Set the name of the Java output directory to @samp{DIR}. This is only + used for the Java language. If this option is not supplied, then the + directory corresponding to the first input file is used. If the input + is standard input, the default is the current directory. + + This option may be overriden using the @samp{%outdir} keyword in the + input files. If this option is used with a language other than Java, + it will be ignored. + + @item -e EXT + @itemx --extension EXT + Change the default output file extension to @samp{ext}, instead of + @samp{.c}. The value @samp{ext} can have a leading dot, but this is + not required. + + @item -f + @itemx --force-create + Treecc normally attempts to optimise the creation of output files + so that they are only modified if a non-trivial change has + occurred in the input. This can reduce the number of source + code recompiles when treecc is used in combination with make. + + This option forces the output files to be created, even if they + are the same as existing files with the same name. + + The declaration @samp{%option force} can be used in the input files + to achieve the same effect as this option. + + @item -O OPT + @itemx --option OPT + Set a treecc option value. This is a command-line version of + the @samp{%option} keyword in the input files. + + @item -n + @itemx --no-output + Suppress the generation of output files. Treecc parses the + input files, checks for errors, and then stops. + + @item --help + Print a usage message for the treecc program. + + @item -v + @itemx --version + Print the version of the treecc program. + + @item -- + Marks the end of the command-line options, and the beginning of + the input filenames. You may need to use this if your filename + begins with @samp{-}. e.g. @samp{treecc -- -input.tc}. This is + not needed if the input is standard input: @samp{treecc -} + is perfectly valid. + @end table + + @c ----------------------------------------------------------------------- + + @node Syntax, Nodes, Invoking Treecc, Top + @chapter Syntax of input files + @cindex Syntax + + Treecc input files consist of zero or more declarations that define + nodes, operations, options, etc. The following sections describe each + of these elements. + + @menu + * Nodes:: Node declarations + * Types:: Types used in fields and parameters + * Enumerations:: Enumerated type declarations + * Operations:: Operation declarations + * Options:: Options that modify treecc's behaviour + * Literal Code:: Literal code declarations + * Changing Files:: Changing input and output files + @end menu + + @c ----------------------------------------------------------------------- + + @node Nodes, Types, Syntax, Syntax + @section Node declarations + @cindex Nodes + @cindex %node keyword + @cindex Fields + + Node types are defined using the @samp{node} keyword in input files. + The general form of the declaration is: + + @example + %node NAME [ PNAME ] [ FLAGS ] [ = FIELDS ] + @end example + + @table @samp + @item NAME + An identifier that is used to refer to the node type elsewhere + in the treecc definition. It is also the name of the type that will be + visible to the programmer in literal code blocks. + + @item PNAME + An identifier that refers to the parent node type that @samp{NAME} inherits + from. If @samp{PNAME} is not supplied, then @samp{NAME} is a top-level + declaration. It is legal to supply a @samp{PNAME} that has not yet + been defined in the input. + + @item FLAGS + Any combination of @samp{%abstract} and @samp{%typedef}: + + @table @samp + @item %abstract + @cindex %abstract keyword + The node type cannot be constructed by the programmer. In addition, + the programmer does not need to define operation cases for this node + type if all subtypes have cases associated with them. + + @item %typedef + @cindex %typedef keyword + The node type is used as the common return type for node creation + functions. Top-level declarations must have a @samp{%typedef} keyword. + @end table + @end table + + The @samp{FIELDS} part of a node declaration defines the fields that + make up the node type. Each field has the following general form: + + @example + [ %nocreate ] TYPE FNAME [ = VALUE ] ';' + @end example + + @table @samp + @item %nocreate + @cindex %nocreate keyword + The field is not used in the node's constructor. When the node is + constructed, the value of this field will be undefined unless + @samp{VALUE} is specified. + + @item TYPE + The type that is associated with the field. Types can be declared + using a subset of the C declaration syntax, augmented with some C++ + and Java features. @xref{Types}, for more information. + + @item FNAME + The name to associate with the field. Treecc verifies that the field + does not currently exist in this node type, or in any of its ancestor + node types. + + @item VALUE + The default value to assign to the field in the node's constructor. + This can only be used on fields that are declared with @samp{%nocreate}. + The value must be enclosed in braces. For example @samp{@{NULL@}} would + be used to initialize a field with @samp{NULL}. + + The braces are required because the default value is expressed in + the underlying source language, and can use any of the usual constant + declaration features present in that language. + @end table + + When the output language is C, treecc creates a struct-based type + called @samp{NAME} that contains the fields for @samp{NAME} and + all of its ancestor classes. The type also contains some house-keeping + fields that are used internally by the generated code. The following + is an example: + + @example + typedef struct binary__ binary; + struct binary__ @{ + const struct binary_vtable__ *vtable__; + int kind__; + char *filename__; + long linenum__; + type_code type; + expression * expr1; + expression * expr2; + @}; + @end example + + The programmer should avoid using any identifier that + ends with @samp{__}, because it may clash with house-keeping + identifiers that are generated by treecc. + + When the output language is C++, Java, or C#, treecc creates a class + called @samp{NAME}, that inherits from the class @samp{PNAME}. + The field definitions for @samp{NAME} are converted into public members + in the output. + + @c ----------------------------------------------------------------------- + + @node Types, Enumerations, Nodes, Syntax + @section Types used in fields and parameters + @cindex Types + + Types that are used in field and parameter declarations have a + syntax which is subset of features found in C, C++, and Java: + + @example + TypeAndName ::= Type [ IDENTIFIER ] + + Type ::= TypeName + | Type '*' + | Type '&' + | Type '[' ']' + + TypeName ::= IDENTIFIER @{ IDENTIFIER @} + @end example + + Types are usually followed by an identifier that names the field or + parameter. The name is required for fields and is optional for parameters. + For example @samp{int} is usually equivalent to @samp{int x} in parameter + declarations. + + The following are some examples of using types: + + @example + int + int x + const char *str + expression *expr + Element[][] array + Item& + unsigned int y + const Element + @end example + + The grammar used by treecc is slightly ambiguous. The last example above + declares a parameter called @samp{Element}, that has type @samp{const}. + The programmer probably intended to declare an anonymous parameter with type + @samp{const Element} instead. + + This ambiguity is unavoidable given that treecc is not fully + aware of the underlying language's type system. When treecc + sees a type that ends in a sequence of identifiers, it will + always interpret the last identifier as the field or parameter + name. Thus, the programmer must write the following instead: + + @example + const Element e + @end example + + Treecc cannot declare types using the full power of C's type system. + The most common forms of declarations are supported, and the rest + can usually be obtained by defining a @samp{typedef} within a + literal code block. @xref{Literal Code}, for more information + on literal code blocks. + + It is the responsibility of the programmer to use type constructs + that are supported by the underlying programming language. Types such + as @samp{const char *} will give an error when the output is compiled + with a Java compiler, for example. + + @c ----------------------------------------------------------------------- + + @node Enumerations, Operations, Types, Syntax + @section Enumerated type declarations + @cindex Enumerations + @cindex enum declaration + @cindex %enum keyword + + Enumerated types are a special kind of node type that can be used + by the programmer for simple values that don't require a full abstract + syntax tree node. The following is an example of defining a list + of the primitive machine types used in a Java virtual machine: + + @example + %enum JavaType = + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + @} + @end example + + Enumerations are useful when writing code generators and type + inferencing routines. The general form is: + + @example + %enum NAME = @{ VALUES @} + @end example + + @table @samp + @item NAME + An identifier to be used to name the enumerated type. The name must + not have been previously used as a node type, an enumerated type, or + an enumerated value. + + @item VALUES + A comma-separated list of identifiers that name the values within + the enumeration. Each of the names must be unique, and must not have + been used previously as a node type, an enumerated type, or an + enumerated value. + @end table + + Logically, each enumerated value is a special node type that inherits from + a parent node type corresponding to the enumerated type @samp{NAME}. + + When the output language is C or C++, treecc generates an enumerated + typedef for @samp{NAME} that contains the enumerated values in the + same order as was used in the input file. The typedef name can be + used elsewhere in the code as the type of the enumeration. + + When the output language is Java, treecc generates a class called + @samp{NAME} that contains the enumerated values as integer constants. + Elsewhere in the code, the type @samp{int} must be used to declare + variables of the enumerated type. Enumerated values are referred + to as @samp{NAME.VALUE}. If the enumerated type is used as a trigger + parameter, then @samp{NAME} must be used instead of @samp{int}: + treecc will convert the type when the Java code is output. + + When the output language is C#, treecc generates an enumerated value + type called @samp{NAME} that contains the enumerated values as + members. The C# type @samp{NAME} can be used elsewhere in the code + as the type of the enumeration. Enumerated values are referred to + as @samp{NAME.VALUE}. + + @c ----------------------------------------------------------------------- + + @node Operations, Options, Enumerations, Syntax + @section Operation declarations + @cindex Operations + @cindex operation declarations + @cindex operation cases + @cindex %operation keyword + @cindex trigger parameters + + Operations are declared in two parts: the declaration, and the + cases. The declaration part defines the prototype for the + operation and the cases define how to handle specific kinds of + nodes for the operation. + + Operations are defined over one or more trigger parameters. Each + trigger parameter specifies a node type or an enumerated type that + is selected upon to determine what course of action to take. The + following are some examples of operation declarations: + + @example + %operation void infer_type(expression *e) + %operation type_code common_type([type_code t1], [type_code t2]) + @end example + + Trigger parameters are specified by enclosing them in square + brackets. If none of the parameters are enclosed in square + brackets, then treecc assumes that the first parameter is the + trigger. + + The general form of an operation declaration is as follows: + + @example + %operation @{ %virtual | %inline | %split @} RTYPE [CLASS::]NAME(PARAMS) + @end example + + @table @samp + @item %virtual + @cindex %virtual keyword + Specifies that the operation is associated with a node type as + a virtual method. There must be only one trigger parameter, + and it must be the first parameter. + + Non-virtual operations are written to the output source files + as global functions. + + @item %inline + @cindex %inline keyword + Optimise the generation of the operation code so that all cases + are inline within the code for the function itself. This can + only be used with non-virtual operations, and may improve + code efficiency if there are lots of operation cases with a + small amount of code in each. + + @item %split + @cindex %split keyword + Split the generation of the multi-trigger operation code across + multiple functions, to reduce the size of each individual function. + It is sometimes necessary to split large @code{%inline} operations + to avoid compiler limits on function size. + + @item RTYPE + The type of the return value for the operation. This should be + @samp{void} if the operation does not have a return value. + + @item CLASS + The name of the class to place the operation's definition within. + This can only be used with non-virtual operations, and is + intended for languages such as Java and C# that cannot declare + methods outside of classes. The class name will be ignored if + the output language is C. + + If a class name is required, but the programmer did not supply it, + then @samp{NAME} will be used as the default. The exception to + this is the C# language: @samp{CLASS} must always be supplied and + it must be different from @samp{NAME}. This is due to a "feature" + in some C# compilers that forbid a method with the same name as + its enclosing class. + + @item NAME + The name of the operation. + + @item PARAMS + The parameters to the operation. Trigger parameters may be + enclosed in square brackets. Trigger parameters must be + either node types or enumerated types. + @end table + + Once an operation has been declared, the programmer can specify + its cases anywhere in the input files. It is not necessary that + the cases appear after the operation, or that they be contiguous + within the input files. This permits the programmer to place + operation cases where they are logically required for maintainence + reasons. + + There must be sufficient operation cases defined to cover every + possible combination of node types and enumerated values that + inherit from the specified trigger types. An operation case + has the following general form: + + @example + NAME(TRIGGERS) [, NAME(TRIGGERS2) ...] + @{ + CODE + @} + @end example + + @table @samp + @item NAME + The name of the operation for which this case applies. + + @item TRIGGERS + A comma-separated list of node types or enumerated values that + define the specific case that is handled by the following code. + + @item CODE + Source code in the output source language that implements the + operation case. + @end table + + Multiple trigger combinations can be associated with a single + block of code, by listing them all, separated by commas. For + example: + + @example + common_type(int_type, int_type) + @{ + return int_type; + @} + + common_type(int_type, float_type), + common_type(float_type, int_type), + common_type(float_type, float_type) + @{ + return float_type; + @} + @end example + + @c ----------------------------------------------------------------------- + + @node Options, Literal Code, Operations, Syntax + @section Options that modify treecc's behaviour + @cindex Options + @cindex option declaration + @cindex %option keyword + + "(*)" is used below to indicate an option that is enabled by default. + + @table @samp + @item %option track_lines + @cindex track_lines option + Enable the generation of code that can track the current filename and + line number when nodes are created. @xref{Line Tracking}, for more + information. (*) + + @item %option no_track_lines + @cindex no_track_lines option + Disable the generation of code that performs line number tracking. + + @item %option singletons + @cindex singletons option + Optimise the creation of singleton node types. These are + node types without any fields. Treecc can optimise the code + so that only one instance of a singleton node type exists in + the system. This can speed up the creation of nodes for + constants within compilers. (*) + + Singleton optimisations will have no effect if @samp{track_lines} + is enabled, because line tracking uses special hidden fields in + every node. + + @item %option no_singletons + @cindex no_singletons option + Disable the optimisation of singleton node types. + + @item %option reentrant + @cindex reentrant option + Enable the generation of reentrant code that does not rely + upon any global variables. Separate copies of the compiler + state can be used safely in separate threads. However, the + same copy of the compiler state cannot be used safely in two or + more threads. + + @item %option no_reentrant + @cindex no_reentrant option + Disable the generation of reentrant code. The interface to + node management functions is simpler, but cannot be used + in a threaded environment. (*) + + @item %option force + @cindex force option + Force output source files to be written, even if they are + unchanged. This option can also be set using the @samp{-f} + command-line option. + + @item %option no_force + @cindex no_force option + Don't force output source files to be written if they are the + same as before. (*) + + This option can help smooth integration of treecc with make. + Only those output files that have changed will be modified. + This reduces the number of files that the underlying source + language compiler must process after treecc is executed. + + @item %option virtual_factory + @cindex virtual_factory option + Use virtual methods in the node type factories, so that the + programmer can subclass the factory and provide new + implementations of node creation functions. This option is + ignored for C, which does not use factories. + + @item %option no_virtual_factory + @cindex no_virtual_factory option + Don't use virtual methods in the node type factories. (*) + + @item %option abstract_factory + @cindex abstract_factory option + Use abstract virtual methods in the node type factories. + The programmer is responsible for subclassing the factory + to provide node creation functionality. + + @item %option no_abstract_factory + @cindex no_abstract_factory option + Don't use abstract virtual methods in the node type factories. (*) + + @item %option kind_in_node + @cindex kind_in_node option + Put the kind field in the node, for more efficient access at runtime. (*) + + @item %option kind_in_vtable + @cindex kind_in_vtable option + Put the kind field in the vtable, and not the node. This saves some + memory, at the cost of slower access to the kind value at runtime. + This option only applies when the language is C. The kind field is + always placed in the node in other languages, because it isn't possible + to modify the vtable. + + @item %option prefix = PREFIX + @cindex prefix option + Specify the prefix to be used in output files in place of "yy". + + @item %option state_type = NAME + @cindex state_type option + Specify the name of the state type. The state type is generated + by treecc to perform centralised memory management and reentrancy + support. The default value is @samp{YYNODESTATE}. If the output language + uses factories, then this will also be the name of the factory + base class. + + @item %option namespace = NAME + @cindex namespace option + Specify the namespace to write definitions to in the output + source files. This option is ignored when the output language + is C. + + @item %option package = NAME + @cindex package option + Same as @samp{%option namespace = NAME}. Provided because @samp{package} + is more natural for Java programmers. + + @item %option base = NUM + @cindex base option + Specify the numeric base to use for allocating numeric values to + node types. By default, node type allocation begins at 1. + + @item %option lang = LANGUAGE + @cindex lang option + Specify the output language. Must be one of @code{"C"}, @code{"C++"}, + @code{"Java"}, or @code{"C#"}. The default is @code{"C"}. + + @item %option block_size = NUM + @cindex block_size option + Specify the size of the memory blocks to use in C and C++ node allocators. + + @item %option strip_filenames + @cindex strip_filenames option + Strip filenames down to their base name in @code{#line} directives. + i.e. strip off the directory component. This can be helpful in + combination with the @code{%include %readonly} command when + treecc input files may processed from different directories, + causing common output files to change unexpectedly. + + @item %option no_strip_filenames + @cindex no_strip_filenames option + Don't strip filenames in @code{#line} directives. (*) + + @item %option internal_access + @cindex internal_access option + Use @code{internal} as the access mode for classes in C#, rather than + @code{public}. + + @item %option public_access + @cindex public_access option + Use @code{public} as the access mode for classes in C#, rather than + @code{internal}. (*) + + @item %option print_lines + @cindex print_lines option + Print @code{#line} markers in languages that use them. (*) + + @item %option no_print_lines + @cindex no_print_lines option + Do not print @code{#line} markers, even in languages that normally + use them. + + @item %option allocator + @cindex allocator option + Use treecc's standard node allocator for C and C++. This option has + no effect for other output languages. (*) + + @item %option no_allocator + @cindex no_allocator option + Do not use treecc's standard node allocator for C and C++. This can be + useful when the programmer wants to redirect node allocation to their + own routines. + + @item %option gc_allocator + @cindex gc_allocator option + Use libgc as a garbage-collecting node allocator for C and C++. This + option has no effect for other output languages. + + @item %option no_gc_allocator + @cindex no_gc_allocator option + Do not use libgc as a garbage-collecting node allocator for C and C++. (*) + + @item %option base_type + @cindex base_type option + Specify the base type for the root node of the treecc node heirarchy. + The default is no base type. + + @end table + + @c ----------------------------------------------------------------------- + + @node Literal Code, Changing Files, Options, Syntax + @section Literal code declarations + @cindex Literal code + + Sometimes it is necessary to embed literal code within output @samp{.h} + and source files. Usually this is to @samp{#include} definitions + from other files, or to define functions that cannot be easily expressed + as operations. + + A literal code block is specified by enclosing it in @samp{%@{} and + @samp{%@}}. The block can also be prefixed with the following flags: + + @table @samp + @item %decls + @cindex %decls keyword + Write the literal code to the currently active declaration header file, + instead of the source file. + + @item %both + @cindex %both keyword + Write the literal code to both the currently active declaration header file + and the currently active source file. + + @item %end + @cindex %end keyword + Write the literal code to the end of the file, instead of the beginning. + @end table + + Another form of literal code block is one which begins with @samp{%%} and + extends to the end of the current input file. This form implicitly has + the @samp{%end} flag. + + @c ----------------------------------------------------------------------- + + @node Changing Files, Line Tracking, Literal Code, Syntax + @section Changing input and output files + @cindex Changing files + + Most treecc compiler definitions will be too large to be manageable + in a single input file. They also will be too large to write to a + single output file, because that may overload the source language + compiler. + + Multiple input files can be specified on the command-line, or + they can be explicitly included by other input files with + the following declarations: + + @table @samp + @item %include [ %readonly ] FILENAME + @cindex include declaration + @cindex %include keyword + @cindex %readonly keyword + Include the contents of the specified file at the current point + within the current input file. @samp{FILENAME} is interpreted + relative to the name of the current input file. + + If the @samp{%readonly} keyword is supplied, then any output + files that are generated by the included file must be read-only. + That is, no changes are expected by performing the inclusion. + + The @samp{%readonly} keyword is useful for building compilers + in layers. The programmer may group a large number of useful + node types and operations together that are independent of the + particulars of a given language. The programmer then defines + language-specific compilers that "inherit" the common definitions. + + Read-only inclusions ensure that any extensions that are added + by the language-specific parts do not "leak" into the common code. + @end table + + Output files can be changed using the follow declarations: + + @table @samp + @item %header FILENAME + @cindex header declaration + @cindex %header keyword + Change the currently active declaration header file to @samp{FILENAME}, + which is interpreted relative to the current input file. This option + has no effect for languages without header files (Java and C#). + + Any node types and operations that are defined after a @samp{%header} + declaration will be declared in @samp{FILENAME}. + + @item %output FILENAME + @cindex output declaration + @cindex %output keyword + Change the currently active source file to @samp{FILENAME}, + which is interpreted relative to the current input file. This option + has no effect for languages that require a single class per file (Java). + + Any node types and operations that are defined after a @samp{%header} + declaration will have their implementations placed in @samp{FILENAME}. + + @item %outdir DIRNAME + @cindex outdir declaration + @cindex %outdir keyword + Change the output source directory to @samp{DIRNAME}. This is only + used for Java, which requires that a single file be used for each class. + All classes are written to the specified directory. By default, + @samp{DIRNAME} is the current directory where treecc was invoked. + @end table + + When treecc generates the output source code, it must insert several + common house-keeping functions and classes into the code. By default, + these are written to the first header and source files. This can + be changed with the @samp{%common} declaration: + + @table @samp + @item %common + @cindex common declaration + @cindex %common keyword + Output the common house-keeping code to the currently active + declaration header file and the currently active source file. + This is typically used as follows: + + @example + %header "common.h" + %output "common.c" + %common + @end example + @end table + + @c ----------------------------------------------------------------------- + + @node Line Tracking, Output APIs, Changing Files, Top + @chapter Tracking line numbers in source files + @cindex Line tracking + + When compilers emit error messages to the programmer, it is generally + a good idea to indicate which file and which line gave rise to the + error. Syntax errors can be emitted fairly easily because the parser + usually has access to the current line number. However, semantic + errors are harder to report because the parser may no longer be + active when the error is detected. + + Treecc can generate code that automatically keeps track of what line + in the source file was active when a node is created. Every node + has two extra private fields that specify the name of the file and the + line number. Semantic analysis routines can query this information + when reporting errors. + + Because treecc is not aware of how to obtain this information, the + programmer must supply some additional functions. @xref{Output APIs}, + for more information. + + @xref{Output APIs}, for more information. + + @c ----------------------------------------------------------------------- + + @node Output APIs, C Language, Line Tracking, Top + @chapter API's available in the generated output + @cindex Output APIs + + The source code that is generated by treecc exports a number of + application programmer interfaces (API's) to the programmer. These + can be used elsewhere in the compiler implementation to manipulate + abstract syntax trees. The following sections describe the API's + for each of the output languages. + + @menu + * C Language:: C Language API's + * C++ Language:: C++ Language API's + * Java Language:: Java Language API's + * C# Language:: C# Language API's + * Ruby Language:: Ruby Language API's + @end menu + + @c ----------------------------------------------------------------------- + + @node C Language, C++ Language, Output APIs, Output APIs + @section C Language APIs + @cindex C APIs + + In the C output language, each node type is converted into a @samp{typedef} + that contains the node's fields, and the fields of its ancestor node + types. The following example demonstrates how treecc node declarations + are converted into C source code: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + %node binary expression %abstract = + @{ + expression *expr1; + expression *expr2; + @} + %node plus binary + @end example + + becomes: + + @example + typedef struct expression__ expression; + typedef struct binary__ binary; + typedef struct plus__ plus; + + struct expression__ @{ + const struct expression_vtable__ *vtable__; + int kind__; + char *filename__; + long linenum__; + type_code type; + @}; + struct binary__ @{ + const struct binary_vtable__ *vtable__; + int kind__; + char *filename__; + long linenum__; + type_code type; + expression * expr1; + expression * expr2; + @}; + struct plus__ @{ + const struct plus_vtable__ *vtable__; + int kind__; + char *filename__; + long linenum__; + type_code type; + expression * expr1; + expression * expr2; + @}; + @end example + + Programmers should avoid using any identifiers that end in + @samp{__}. Such identifiers are reserved for internal use by treecc + and its support routines. + + For each non-abstract node type called @samp{NAME}, treecc generates a + function called @samp{NAME_create} that creates nodes of that type. + The general form of the function's prototype is as follows: + + @example + TYPE *NAME_create([YYNODESTATE *state,] PARAMS) + @end example + + @table @samp + @item TYPE + The return node type, which is the nearest ancestor that has the + @samp{%typedef} flag. + + @item NAME + The name of the node type that is being created. + + @item state + The system state, if reentrant code is being generated. + + @item PARAMS + The create parameters, consisting of every field that does not + have the @samp{%nocreate} flag. The parameters appear in the + same order as the fields in the node types, from the top-most + ancestor down to the node type itself. For example: + + @example + expression *plus_create(expression * expr1, expression * expr2); + @end example + @end table + + Enumerated types are converted into a C @samp{typedef} with the + same name and values: + + @example + %enum JavaType = + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + @} + @end example + + becomes: + + @example + typedef enum + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + + @} JavaType; + @end example + + Virtual operations are converted into C macros that invoke the + correct vtable entry on a node type: + + @example + %operation %virtual void infer_type(expression *e) + @end example + + becomes: + + @example + #define infer_type(this__) \ + ((*(((struct expression_vtable__ *) \ + ((this__)->vtable__))->infer_type_v__)) \ + ((expression *)(this__))) + @end example + + Calls to @samp{infer_type} can then be made with @samp{infer_type(node)}. + + Non-virtual operations are converted into C functions: + + @example + %operation void infer_type(expression *e) + @end example + + becomes: + + @example + extern void infer_type(expression *e); + @end example + + Because virtual and non-virtual operations use a similar call syntax, + it is very easy to convert a virtual operation into a non-virtual + operation when the output language is C. This isn't possible with + the other output languages. + + Other house-keeping tasks are performed by the following functions + and macros. Some of these must be supplied by the programmer. + The @samp{state} parameter is required only if a reentrant compiler is + being built. + + @table @code + @item int yykind(ANY *node) + @cindex yykind macro + Gets the numeric kind value associated with a particular node. + The kind value for node type @samp{NAME} is called @samp{NAME_kind}. + + @item const char *yykindname(ANY *node) + @cindex yykindname macro + Gets the name of the node kind associated with a particular node. + This may be helpful for debugging and logging code. + + @item int yyisa(ANY *node, type) + @cindex yyisa macro + Determines if @samp{node} is an instance of the node type @samp{type}. + + @item char *yygetfilename(ANY *node) + @cindex yygetfilename macro + Gets the filename corresponding to where @samp{node} was created + during parsing. This macro is only generated if @samp{%option track_lines} + was specified. + + @item long yygetlinenum(ANY *node) + @cindex yygetlinenum macro + Gets the line number corresponding to where @samp{node} was created + during parsing. This macro is only generated if @samp{%option track_lines} + was specified. + + @item void yysetfilename(ANY *node, char *value) + @cindex yysetfilename macro + Sets the filename associated with @samp{node} to @samp{value}. The + string is not copied, so @samp{value} must persist for the lifetime + of the node. This macro will rarely be required, unless a node + corresponds to a different line than the current parse line. This + macro is only generated if @samp{%option track_lines} was specified. + + @item void yysetlinenum(ANY *node, long value) + @cindex yysetlinenum macro + Sets the line number associated with @samp{node} to @samp{value}. + This macro will rarely be required, unless a node corresponds to a + different line than the current parse line. This macro is only + generated if @samp{%option track_lines} was specified. + + @item char *yycurrfilename([YYNODESTATE *state]) + @cindex yycurrfilename function + Get the name of the current input file from the parser. The pointer + that is returned from this function is stored as-is: the string is + not copied. Therefore, the value must persist for at least as long + as the node will persist. This function must be supplied by the programmer + if @samp{%option track_lines} was specified. + + @item long yycurrlinenum([YYNODESTATE *state]) + @cindex yycurrlinenum function + Get the number of the current input line from the parser. This + function must be supplied by the programmer if @samp{%option track_lines} + was specified. + + @item void yynodeinit([YYNODESTATE *state]) + @cindex yynodeinit function + Initializes the node memory manager. If the system is reentrant, then + the node memory manager is @samp{state}. Otherwise a global node + memory manager is used. + + @item void *yynodealloc([YYNODESTATE *state,] unsigned int size) + @cindex yynodealloc function + Allocates a block of memory of @samp{size} bytes in size from the + node memory manager. This function is called automatically from + the node-specific @samp{*_create} functions. The programmer will + not normally need to call this function. + + This function will return @code{NULL} if the system is out of + memory, or if @samp{size} is too large to be allocated within + the node memory manager. If the system is out of memory, then + @samp{yynodealloc} will call @samp{yynodefailed} prior to + returning @code{NULL}. + + @item int yynodepush([YYNODESTATE *state]) + @cindex yynodepush function + Pushes the current node memory manager position. The next time + @code{yynodepop} is called, the node memory manager will reset to + the pushed position. This function returns zero if the system + is out of memory. + + @item void yynodepop([YYNODESTATE *state]) + @cindex yynodepop function + Pops the current node memory manager position. This function has + no effect if @code{yynodepush} was not called previously. + + The @code{yynodepush} and @code{yynodepop} functions can be used + to perform a simple kind of garbage collection on nodes. When + the parser enters a scope, it pushes the node memory manager + position. After all definitions in the scope have been dealt + with, the parser pops the node memory manager to reclaim all + of the memory used. + + @item void yynodeclear([YYNODESTATE *state]) + @cindex yynodeclear function + Clears the entire node memory manager and returns it to the + state it had after calling @code{yynodeinit}. This is typically + used upon program shutdown to free all remaining node memory. + + @item void yynodefailed([YYNODESTATE *state]) + @cindex yynodefailed function + Called when @code{yynodealloc} or @code{yynodepush} detects that + the system is out of memory. This function must be supplied by + the programmer. The programmer may choose to exit to program + when the system is out of memory; in which case @code{yynodealloc} + will never return @code{NULL}. + @end table + + @c ----------------------------------------------------------------------- + + @node C++ Language, Java Language, C Language, Output APIs + @section C++ Language APIs + @cindex C++ APIs + + In the C++ output language, each node type is converted into a @samp{class} + that contains the node's fields, virtual operations, and other house-keeping + definitions. The following example demonstrates how treecc node declarations + are converted into C++ source code: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + %node binary expression %abstract = + @{ + expression *expr1; + expression *expr2; + @} + %node plus binary + @end example + + becomes: + + @example + class expression + @{ + protected: + + int kind__; + char *filename__; + long linenum__; + + public: + + int getKind() const @{ return kind__; @} + const char *getFilename() const @{ return filename__; @} + int getLinenum() const @{ return linenum__; @} + void setFilename(char *filename) @{ filename__ = filename; @} + void setLinenum(long linenum) @{ linenum__ = linenum; @} + + void *operator new(size_t); + void operator delete(void *, size_t); + + protected: + + expression(); + + public: + + type_code type; + + virtual int isA(int kind) const; + virtual const char *getKindName() const; + + protected: + + virtual ~expression(); + + @}; + + class binary : public expression + @{ + protected: + + binary(expression * expr1, expression * expr2); + + public: + + expression * expr1; + expression * expr2; + + virtual int isA(int kind) const; + virtual const char *getKindName() const; + + protected: + + virtual ~binary(); + + @}; + + class plus : public binary + @{ + public: + + plus(expression * expr1, expression * expr2); + + public: + + virtual int isA(int kind) const; + virtual const char *getKindName() const; + + protected: + + virtual ~plus(); + + @}; + @end example + + The following standard methods are available on every node type: + + @table @code + @item int getKind() + @cindex getKind method (C++) + Gets the numeric kind value associated with a particular node. + The kind value for node type @samp{NAME} is called @samp{NAME_kind}. + + @item virtual const char *getKindName() + @cindex getKindName method (C++) + Gets the name of the node kind associated with a particular node. + This may be helpful for debugging and logging code. + + @item virtual int isA(int kind) + @cindex isA method (C++) + Determines if the node is a member of the node type that corresponds + to the numeric kind value @samp{kind}. + + @item const char *getFilename() + @cindex getFilename method (C++) + Gets the filename corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item long getLinenum() + @cindex getLinenum method (C++) + Gets the line number corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item void setFilename(char *value) + @cindex setFilename method (C++) + Sets the filename associated with the node to @samp{value}. The + string is not copied, so @samp{value} must persist for the lifetime + of the node. This method will rarely be required, unless a node + corresponds to a different line than the current parse line. This + method is only generated if @samp{%option track_lines} was specified. + + @item void setLinenum(long value) + @cindex setLinenum method (C++) + Sets the line number associated with the node to @samp{value}. + This method will rarely be required, unless a node corresponds to a + different line than the current parse line. This method is only + generated if @samp{%option track_lines} was specified. + @end table + + If the generated code is non-reentrant, then the constructor for the + class can be used to construct nodes of the specified node type. The + constructor parameters are the same as the fields within the node type's + definition, except for @samp{%nocreate} fields. + + If the generated code is reentrant, then nodes cannot be constructed + using the C++ @samp{new} operator. The @samp{*Create} methods + on the @samp{YYNODESTATE} factory class must be used instead. + + The @samp{YYNODESTATE} class contains a number of house-keeping methods + that are used to manage nodes: + + @table @code + @item static YYNODESTATE *getState() + @cindex getState method (C++) + Gets the global @samp{YYNODESTATE} instance that is being used by + non-reentrant code. If an instance has not yet been created, + this method will create one. + + When using non-reentrant code, the programmer will normally subclass + @samp{YYNODESTATE}, override some of the methods below, and then + construct an instance of the subclass. This constructed instance + will then be returned by future calls to @samp{getState}. + + @item void *alloc(size_t size) + @cindex alloc method (C++) + Allocates a block of memory of @samp{size} bytes in size from the + node memory manager. This function is called automatically from + the node-specific constructors and @samp{*Create} methods. The programmer + will not normally need to call this function. + + This function will return @code{NULL} if the system is out of + memory, or if @samp{size} is too large to be allocated within + the node memory manager. If the system is out of memory, then + @samp{alloc} will call @samp{failed} prior to returning @code{NULL}. + + @item int push() + @cindex push method (C++) + Pushes the current node memory manager position. The next time + @code{pop} is called, the node memory manager will reset to + the pushed position. This function returns zero if the system + is out of memory. + + @item void pop() + @cindex pop method (C++) + Pops the current node memory manager position. This function has + no effect if @code{push} was not called previously. + + The @code{push} and @code{pop} methods can be used + to perform a simple kind of garbage collection on nodes. When + the parser enters a scope, it pushes the node memory manager + position. After all definitions in the scope have been dealt + with, the parser pops the node memory manager to reclaim all + of the memory used. + + @item void clear() + @cindex clear method (C++) + Clears the entire node memory manager and returns it to the + state it had after construction. + + @item virtual void failed() + @cindex failed method (C++) + Called when @code{alloc} or @code{push} detects that + the system is out of memory. This method is typically + overridden by the programmer in subclasses. The programmer may + choose to exit to program when the system is out of memory; in + which case @code{alloc} will never return @code{NULL}. + + @item virtual char *currFilename() + @cindex currFilename method (C++) + Get the name of the current input file from the parser. The pointer + that is returned from this function is stored as-is: the string is + not copied. Therefore, the value must persist for at least as long + as the node will persist. This method is usually overrriden by + the programmer in subclasses if @samp{%option track_lines} was specified. + + @item virtual long currLinenum() + @cindex currLinenum method (C++) + Get the number of the current input line from the parser. This + method is usually overridden by the programmer in subclasses + if @samp{%option track_lines} was specified. + @end table + + The programmer will typically subclass @samp{YYNODESTATE} to provide + additional functionality, and then create an instance of this class + to act as the node memory manager and node creation factory. + + @c ----------------------------------------------------------------------- + + @node Java Language, C# Language, C++ Language, Output APIs + @section Java Language APIs + @cindex Java APIs + + In the Java output language, each node type is converted into a @samp{class} + that contains the node's fields, virtual operations, and other house-keeping + definitions. The following example demonstrates how treecc node declarations + are converted into Java source code: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + %node binary expression %abstract = + @{ + expression expr1; + expression expr2; + @} + %node plus binary + @end example + + becomes: + + @example + public class expression + @{ + protected int kind__; + protected String filename__; + protected long linenum__; + + public int getKind() @{ return kind__; @} + public String getFilename() @{ return filename__; @} + public long getLinenum() const @{ return linenum__; @} + public void setFilename(String filename) @{ filename__ = filename; @} + public void setLinenum(long linenum) @{ linenum__ = linenum; @} + + public static final int KIND = 1; + + public type_code type; + + protected expression() + @{ + this.kind__ = KIND; + this.filename__ = YYNODESTATE.getState().currFilename(); + this.linenum__ = YYNODESTATE.getState().currLinenum(); + @} + + public int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return 0; + @} + + public String getKindName() + @{ + return "expression"; + @} + @} + + public class binary extends expression + @{ + public static final int KIND = 2; + + public expression expr1; + public expression expr2; + + protected binary(expression expr1, expression expr2) + @{ + super(); + this.kind__ = KIND; + this.expr1 = expr1; + this.expr2 = expr2; + @} + + public int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return super.isA(kind); + @} + + public String getKindName() + @{ + return "binary"; + @} + @} + + public class plus extends binary + @{ + public static final int KIND = 3; + + public plus(expression expr1, expression expr2) + @{ + super(expr1, expr2); + this.kind__ = KIND; + @} + + public int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return super.isA(kind); + @} + + public String getKindName() + @{ + return "plus"; + @} + @} + @end example + + The following standard members are available on every node type: + + @table @code + @item int KIND + @cindex KIND field (Java) + The kind value for the node type corresponding to this class. + + @item int getKind() + @cindex getKind method (Java) + Gets the numeric kind value associated with a particular node. + The kind value for node type @samp{NAME} is called @samp{NAME.KIND}. + + @item String getKindName() + @cindex getKindName method (Java) + Gets the name of the node kind associated with a particular node. + This may be helpful for debugging and logging code. + + @item int isA(int kind) + @cindex isA method (Java) + Determines if the node is a member of the node type that corresponds + to the numeric kind value @samp{kind}. + + @item String getFilename() + @cindex getFilename method (Java) + Gets the filename corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item long getLinenum() + @cindex getLinenum method (Java) + Gets the line number corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item void setFilename(String value) + @cindex setFilename method (Java) + Sets the filename associated with the node to @samp{value}. + This method will rarely be required, unless a node corresponds to + a different line than the current parse line. This method is only + generated if @samp{%option track_lines} was specified. + + @item void setLinenum(long value) + @cindex setLinenum method (Java) + Sets the line number associated with the node to @samp{value}. + This method will rarely be required, unless a node corresponds to a + different line than the current parse line. This method is only + generated if @samp{%option track_lines} was specified. + @end table + + If the generated code is non-reentrant, then the constructor for the + class can be used to construct nodes of the specified node type. The + constructor parameters are the same as the fields within the node type's + definition, except for @samp{%nocreate} fields. + + If the generated code is reentrant, then nodes cannot be constructed + using the Java @samp{new} operator. The @samp{*Create} methods + on the @samp{YYNODESTATE} factory class must be used instead. + + Enumerated types are converted into a Java @samp{class}: + + @example + %enum JavaType = + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + @} + @end example + + becomes: + + @example + public class JavaType + @{ + public static final int JT_BYTE = 0; + public static final int JT_SHORT = 1; + public static final int JT_CHAR = 2; + public static final int JT_INT = 3; + public static final int JT_LONG = 4; + public static final int JT_FLOAT = 5; + public static final int JT_DOUBLE = 6; + public static final int JT_OBJECT_REF = 7; + @} + @end example + + References to enumerated types in fields and operation parameters + are replaced with the type @samp{int}. + + Virtual operations are converted into public methods on the Java + node classes. + + Non-virtual operations are converted into a static method within + a class named for the operation. For example, + + @example + %operation void InferType::infer_type(expression e) + @end example + + becomes: + + @example + public class InferType + @{ + public static void infer_type(expression e) + @{ + ... + @} + @} + @end example + + If the class name (@samp{InferType} in the above example) is omitted, + then the name of the operation is used as both the class name and the + the method name. + + The @samp{YYNODESTATE} class contains a number of house-keeping methods + that are used to manage nodes: + + @table @code + @item static YYNODESTATE getState() + @cindex getState method (Java) + Gets the global @samp{YYNODESTATE} instance that is being used by + non-reentrant code. If an instance has not yet been created, + this method will create one. + + When using non-reentrant code, the programmer will normally subclass + @samp{YYNODESTATE}, override some of the methods below, and then + construct an instance of the subclass. This constructed instance + will then be returned by future calls to @samp{getState}. + + This method will not be present if a reentrant system is being + generated. + + @item String currFilename() + @cindex currFilename method (Java) + Get the name of the current input file from the parser. This method + is usually overrriden by the programmer in subclasses if + @samp{%option track_lines} was specified. + + @item long currLinenum() + @cindex currLinenum method (Java) + Get the number of the current input line from the parser. This + method is usually overridden by the programmer in subclasses + if @samp{%option track_lines} was specified. + @end table + + The programmer will typically subclass @samp{YYNODESTATE} to provide + additional functionality, and then create an instance of this class + to act as the global state and node creation factory. + + @c ----------------------------------------------------------------------- + + @node C# Language, Ruby Language, Java Language, Output APIs + @section C# Language APIs + @cindex C# APIs + + In the C# output language, each node type is converted into a @samp{class} + that contains the node's fields, virtual operations, and other house-keeping + definitions. The following example demonstrates how treecc node declarations + are converted into C# source code: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + %node binary expression %abstract = + @{ + expression expr1; + expression expr2; + @} + %node plus binary + @end example + + becomes: + + @example + public class expression + @{ + protected int kind__; + protected String filename__; + protected long linenum__; + + public int getKind() @{ return kind__; @} + public String getFilename() @{ return filename__; @} + public long getLinenum() const @{ return linenum__; @} + public void setFilename(String filename) @{ filename__ = filename; @} + public void setLinenum(long linenum) @{ linenum__ = linenum; @} + + public const int KIND = 1; + + public type_code type; + + protected expression() + @{ + this.kind__ = KIND; + this.filename__ = YYNODESTATE.getState().currFilename(); + this.linenum__ = YYNODESTATE.getState().currLinenum(); + @} + + public virtual int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return 0; + @} + + public virtual String getKindName() + @{ + return "expression"; + @} + @} + + public class binary : expression + @{ + public const int KIND = 2; + + public expression expr1; + public expression expr2; + + protected binary(expression expr1, expression expr2) + : expression() + @{ + this.kind__ = KIND; + this.expr1 = expr1; + this.expr2 = expr2; + @} + + public override int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return base.isA(kind); + @} + + public override String getKindName() + @{ + return "binary"; + @} + @} + + public class plus : binary + @{ + public const int KIND = 5; + + public plus(expression expr1, expression expr2) + : binary(expr1, expr2) + @{ + this.kind__ = KIND; + @} + + public override int isA(int kind) + @{ + if(kind == KIND) + return 1; + else + return base.isA(kind); + @} + + public override String getKindName() + @{ + return "plus"; + @} + @} + @end example + + The following standard members are available on every node type: + + @table @code + @item const int KIND + @cindex KIND field (C#) + The kind value for the node type corresponding to this class. + + @item int getKind() + @cindex getKind method (C#) + Gets the numeric kind value associated with a particular node. + The kind value for node type @samp{NAME} is called @samp{NAME.KIND}. + + @item virtual String getKindName() + @cindex getKindName method (C#) + Gets the name of the node kind associated with a particular node. + This may be helpful for debugging and logging code. + + @item virtual int isA(int kind) + @cindex isA method (C#) + Determines if the node is a member of the node type that corresponds + to the numeric kind value @samp{kind}. + + @item String getFilename() + @cindex getFilename method (C#) + Gets the filename corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item long getLinenum() + @cindex getLinenum method (C#) + Gets the line number corresponding to where the node was created + during parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @item void setFilename(String value) + @cindex setFilename method (C#) + Sets the filename associated with the node to @samp{value}. + This method will rarely be required, unless a node corresponds to + a different line than the current parse line. This method is only + generated if @samp{%option track_lines} was specified. + + @item void setLinenum(long value) + @cindex setLinenum method (C#) + Sets the line number associated with the node to @samp{value}. + This method will rarely be required, unless a node corresponds to a + different line than the current parse line. This method is only + generated if @samp{%option track_lines} was specified. + @end table + + If the generated code is non-reentrant, then the constructor for the + class can be used to construct nodes of the specified node type. The + constructor parameters are the same as the fields within the node type's + definition, except for @samp{%nocreate} fields. + + If the generated code is reentrant, then nodes cannot be constructed + using the C# @samp{new} operator. The @samp{*Create} methods + on the @samp{YYNODESTATE} factory class must be used instead. + + Enumerated types are converted into a C# @samp{enum} definition: + + @example + %enum JavaType = + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + @} + @end example + + becomes: + + @example + public enum JavaType + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF, + @} + @end example + + Virtual operations are converted into public virtual methods on the C# + node classes. + + Non-virtual operations are converted into a static method within + a class named for the operation. For example, + + @example + %operation void InferType::infer_type(expression e) + @end example + + becomes: + + @example + public class InferType + @{ + public static void infer_type(expression e) + @{ + ... + @} + @} + @end example + + If the class name (@samp{InferType} in the above example) is omitted, + then the name of the operation is used as both the class name and the + the method name. + + The @samp{YYNODESTATE} class contains a number of house-keeping methods + that are used to manage nodes: + + @table @code + @item static YYNODESTATE getState() + @cindex getState method (C#) + Gets the global @samp{YYNODESTATE} instance that is being used by + non-reentrant code. If an instance has not yet been created, + this method will create one. + + When using non-reentrant code, the programmer will normally subclass + @samp{YYNODESTATE}, override some of the methods below, and then + construct an instance of the subclass. This constructed instance + will then be returned by future calls to @samp{getState}. + + This method will not be present if a reentrant system is being + generated. + + @item virtual String currFilename() + @cindex currFilename method (C#) + Get the name of the current input file from the parser. This method + is usually overrriden by the programmer in subclasses if + @samp{%option track_lines} was specified. + + @item virtual long currLinenum() + @cindex currLinenum method (C#) + Get the number of the current input line from the parser. This + method is usually overridden by the programmer in subclasses + if @samp{%option track_lines} was specified. + @end table + + The programmer will typically subclass @samp{YYNODESTATE} to provide + additional functionality, and then create an instance of this class + to act as the global state and node creation factory. + + @c ----------------------------------------------------------------------- + + @node Ruby Language, Full Expression Example, C# Language, Output APIs + @section Ruby Language APIs + @cindex Ruby APIs + + In the Ruby output language, each node type is converted into a + @samp{class} that contains the node's fields, operations, and other + house-keeping definitions. The following example demonstrates how + treecc node declarations are converted into Ruby source code: + + @example + %node expression %abstract %typedef = + @{ + %nocreate type_code type; + @} + %node binary expression %abstract = + @{ + expression expr1; + expression expr2; + @} + %node plus binary + @end example + + becomes: + + @example + class YYNODESTATE + + @@@@state = nil + + def YYNODESTATE.state + return @@@@state unless @@@@state.nil? + @@@@state = YYNODESTATE.new() + return @@@@state + end + + def intialize + @@@@state = self + end + + def currFilename + return nil + end + + def currLinenum + return 0 + end + end + + class Expression + protected + attr_reader :kind + public + + attr_accessor :Linenum, :Filename + + attr_accessor :type + + KIND = 1 + + def initialize() + @@kind = KIND + @@Filename = YYNODESTATE.state.currFilename() + @@Linenum = YYNODESTATE.state.currLinenum() + end + + def isA(kind) + if(@@kind == KIND) then + return true + else + return 0 + end + end + + def KindName + return "Expression" + end + + end + + class Binary < Expression + + attr_accessor :expr1 + attr_accessor :expr2 + + KIND = 2 + + def initialize(expr1, expr2) + super(expr1, expr2) + @@kind = KIND + self.expr1 = expr1 + self.expr2 = expr2 + end + + def isA(kind) + if(@@kind == Kind) then + return true + else + return super(kind) + end + end + + def KindName + return "Binary" + end + + end + + class Plus < Binary + + KIND = 3 + + def initialize(expr1, expr2) + super(expr1, expr2expr1, expr2) + @@kind = KIND + end + + def isA(kind) + if(@@kind == KIND) then + return true + else + return super(kind) + end + end + + def KindName + return "Plus" + end + + end + @end example + + The following standard members are available on every node type: + + @table @code + @item KIND + @cindex KIND field (Ruby) + The kind value for the node type corresponding to this class. + The kind value for node type @samp{NAME} is called @samp{NAME::KIND}. + + @item KindName + @cindex KindName field (Ruby) + The name of the node kind associated with a particular node. This may + be helpful for debugging and logging code. + + @item isA(int kind) + @cindex isA method (Ruby) + Determines if the node is a member of the node type that corresponds + to the numeric kind value @samp{kind}. + + @item Filename + @cindex Filename field (Ruby) + The filename corresponding to where the node was created during parsing. + This method is only generated if @samp{%option track_lines} was + specified. + + @item Linenum() + @cindex Linenum field (Ruby) + The line number corresponding to where the node was created during + parsing. This method is only generated if @samp{%option track_lines} + was specified. + + @end table + + @c Don't know if this is true for ruby + @ignore + If the generated code is non-reentrant, then the constructor for the + class can be used to construct nodes of the specified node type. The + constructor parameters are the same as the fields within the node type's + definition, except for @samp{%nocreate} fields. + + If the generated code is reentrant, then nodes cannot be constructed + using the C# @samp{new} operator. The @samp{*Create} methods + on the @samp{YYNODESTATE} factory class must be used instead. + @end ignore + + Enumerated types are converted into a Ruby @samp{class} definition: + + @example + %enum JavaType = + @{ + JT_BYTE, + JT_SHORT, + JT_CHAR, + JT_INT, + JT_LONG, + JT_FLOAT, + JT_DOUBLE, + JT_OBJECT_REF + @} + @end example + + becomes: + + @example + + class JavaType + JT_BYTE = 0 + JT_SHORT = 1 + JT_CHAR = 2 + JT_INT = 3 + JT_LONG = 4 + JT_FLOAT = 5 + JT_DOUBLE = 6 + JT_OBJECT_REF = 7 + end + + @end example + + @c + Virtual operations are converted into public methods on the Ruby + node classes. + + Non-virtual operations are converted into a class method within + a class named for the operation. For example, + + @example + %operation void InferType::infer_type(expression e) + @end example + + becomes: + + @example + class InferType + def InferType.infer_type(expression e) + ... + end + end + @end example + + If the class name (@samp{InferType} in the above example) is omitted, + then the name of the operation is used as both the class name and the + the method name. You then get a method with a name starting with an + uppercase letter. However, Ruby methods start with lowercase methods. + So never forget the class name. + + The @samp{YYNODESTATE} class contains a number of house-keeping methods + that are used to manage nodes: + + @table @code + @item YYNODESTATE::state() + @cindex state field (Ruby) + Gets the global @samp{YYNODESTATE} instance that is being used by + non-reentrant code. If an instance has not yet been created, + this method will create one. + + @c Don't know if the following is correct + @ignore + + When using non-reentrant code, the programmer will normally subclass + @samp{YYNODESTATE}, override some of the methods below, and then + construct an instance of the subclass. This constructed instance + will then be returned by future calls to @samp{getState}. + + This method will not be present if a reentrant system is being + generated. + + @end ignore + + @item currFilename + @cindex currFilename field (Ruby) + The name of the current input file from the parser. This fields + accessor method is usually overrriden by the programmer in subclasses if + @samp{%option track_lines} was specified. + + @item currLinenum + @cindex currLinenum field (Ruby) + The number of the current input line from the parser. This fields + accessor method is usually overridden by the programmer in subclasses if + @samp{%option track_lines} was specified. + @end table + + The programmer will typically subclass @samp{YYNODESTATE} to provide + additional functionality, and then create an instance of this class + to act as the global state and node creation factory. + + @c ----------------------------------------------------------------------- + + @node Full Expression Example, EBNF Syntax, Ruby Language, Top + @appendix Full expression example code + @cindex Full expression example + + The full treecc input file for the expression example is as follows: + + @example + %enum type_code = + @{ + int_type, + float_type + @} + + %node expression %abstract %typedef = + @{ + %nocreate type_code type = @{int_type@}; + @} + + %node binary expression %abstract = + @{ + expression *expr1; + expression *expr2; + @} + + %node unary expression %abstract = + @{ + expression *expr; + @} + + %node intnum expression = + @{ + int num; + @} + + %node floatnum expression = + @{ + float num; + @} + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node power binary + %node negate unary + + %operation void infer_type(expression *e) + + infer_type(binary) + @{ + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == float_type || e->expr2->type == float_type) + @{ + e->type = float_type; + @} + else + @{ + e->type = int_type; + @} + @} + + infer_type(unary) + @{ + infer_type(e->expr); + e->type = e->expr->type; + @} + + infer_type(intnum) + @{ + e->type = int_type; + @} + + infer_type(floatnum) + @{ + e->type = float_type; + @} + + infer_type(power) + @{ + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr2->type != int_type) + @{ + error("second argument to `^' is not an integer"); + @} + + e->type = e->expr1->type; + @} + @end example + + The full yacc grammar is as follows: + + @example + %union @{ + expression *node; + int inum; + float fnum; + @} + + %token INT FLOAT + + %type expr + %type INT + %type FLOAT + + %% + + expr: INT @{ $$ = intnum_create($1); @} + | FLOAT @{ $$ = floatnum_create($1); @} + | '(' expr ')' @{ $$ = $2; @} + | expr '+' expr @{ $$ = plus_create($1, $3); @} + | expr '-' expr @{ $$ = minus_create($1, $3); @} + | expr '*' expr @{ $$ = multiply_create($1, $3); @} + | expr '/' expr @{ $$ = divide_create($1, $3); @} + | expr '^' expr @{ $$ = power_create($1, $3); @} + | '-' expr @{ $$ = negate_create($2); @} + ; + @end example + + @c ----------------------------------------------------------------------- + + @node EBNF Syntax, Index, Full Expression Example, Top + @appendix EBNF syntax for treecc input files + @cindex EBNF syntax + + The EBNF syntax for treecc input files uses the following + lexical tokens: + + @example + IDENTIFIER ::= @{ @} + + STRING ::= '"' '"' + | "'" "'" + + LITERAL_DEFNS ::= "%@{" "%@}" + + LITERAL_END ::= "%%" + + LITERAL_CODE ::= '@{' '@}' + @end example + + In addition, anything that begins with "%" in the following syntax + is a lexical keyword. + + The EBNF syntax is as follows: + + @example + File ::= @{ Declaration @} + + Declaration ::= Node + | Operation + | OperationCase + | Option + | Enum + | Literal + | Header + | Output + | Common + | Include + + Node ::= %node IDENTIFIER [ IDENTIFIER ] @{ NodeFlag @} [ '=' Fields ] + + NodeFlag ::= %abstract | %typedef + + Fields ::= '@{' @{ Field @} '@}' + + Field ::= [ %nocreate ] TypeAndName [ '=' LITERAL_CODE ] ';' + + TypeAndName ::= Type [ IDENTIFIER ] + + Type ::= TypeName + | Type '*' + | Type '&' + | Type '[' ']' + + TypeName ::= IDENTIFIER @{ IDENTIFIER @} + + Operation ::= %operation @{ OperFlag @} Type + [ ClassName ] IDENTIFIER '(' [ Params ] ')' + [ '=' LITERAL_CODE ] [ ';' ] + + OperFlag ::= %virtual | %inline | %split + + ClassName ::= IDENTIFIER "::" + + Params ::= Param @{ ',' Param @} + + Param ::= TypeAndName | '[' TypeAndName ']' + + OperationCase ::= OperationHead @{ ',' OperationHead @} LITERAL_CODE + + OperationHead ::= IDENTIFIER '(' [ TypeList ] ')' + + TypeList ::= IDENTIFIER @{ ',' IDENTIFIER @} + + Option ::= %option IDENTIFIER [ '=' Value ] + + Value ::= IDENTIFIER | STRING + + Enum ::= %enum IDENTIFIER '=' '@{' EnumBody [ ',' ] '@}' + + EnumBody ::= IDENTIFIER @{ ',' IDENTIFIER @} + + Literal ::= @{ LiteralFlag @} (LITERAL_DEFNS | LITERAL_END) + + LiteralFlag ::= %both | %decls | %end + + Header ::= %header STRING + + Output ::= %output STRING + + Common ::= %common + + Include ::= %include [ %readonly ] STRING + + @end example + + @c ----------------------------------------------------------------------- + + @page + + @node Index, , EBNF Syntax, Top + @unnumbered Index + + @printindex cp + + @contents + @bye From criswell at cs.uiuc.edu Tue Apr 6 12:56:43 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:56:43 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/examples/ Message-ID: <200404061753.MAA01091@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc/examples: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/treecc/examples added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 12:56:58 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:56:58 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/examples/README expr_c.tc expr_cpp.tc expr_cs.tc expr_java.tc expr_ruby.tc Message-ID: <200404061754.MAA01119@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc/examples: README added (r1.1) expr_c.tc added (r1.1) expr_cpp.tc added (r1.1) expr_cs.tc added (r1.1) expr_java.tc added (r1.1) expr_ruby.tc added (r1.1) --- Log message: Committing original README file and treecc example input files. --- Diffs of the changes: (+2023 -0) Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/README diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/README:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/README Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,28 ---- + This directory contains a number of example files of using treecc + to implement expression grammars. The code is more involved than + the examples in the Texinfo documentation to give you a better feel + for how to use treecc in a realistic setting. + + expr_c.tc Treecc input file for the C version of the example + gram_c.y Yacc input file for the C version of the example + scan_c.l Lex input file for the C version of the example + + expr_cpp.tc Treecc input file for the C++ version of the example + gram_cpp.yy Yacc input file for the C++ version of the example + scan_cpp.ll Lex input file for the C++ version of the example + + expr_java.tc Treecc input file for the Java version of the example + eval_value.java Helper class used by the Java version of the example + mkjava Shell script for building the Java version of the example + + expr_cs.tc Treecc input file for the C# version of the example + mkcsharp Shell script for building the C# version of the example + + expr_ruby.tc Treecc input file for the Ruby version of the example + + The C++ example demonstrates creating a reentrant system. + + The Java and C# versions build and compile, but cannot run because + they don't yet have lexing or parsing support. + + The Java version is built in a subdirectory called "outjava". Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_c.tc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_c.tc:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_c.tc Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,447 ---- + /* + * expr_c.tc - Expression example treecc input file for C. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + /* + * Include the following declarations into the ".h" file. + */ + %decls %{ + + /* + * Value that is computed by "eval_expr" below. + */ + typedef union + { + int int_value; + float float_value; + + } eval_value; + + %} + + /* + * Include the following declarations into the ".c" file. + */ + %{ + #include + #include + #include + + #include "expr_c.h" + + %} + + /* + * Define the type code that is associated with a node + * in the syntax tree. We use "error_type" to indicate + * a failure during type inferencing. + */ + %enum type_code = + { + error_type, + int_type, + float_type + } + + /* + * Define the node types that make up the syntax. + */ + %node expression %abstract %typedef = + { + %nocreate type_code type = {error_type}; + } + + %node binary expression %abstract = + { + expression *expr1; + expression *expr2; + } + + %node unary expression %abstract = + { + expression *expr; + } + + %node intnum expression = + { + int num; + } + + %node floatnum expression = + { + float num; + } + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node power binary + %node negate unary + + %node cast expression = + { + type_code new_type; + expression *expr; + } + + /* + * Define the "infer_type" operation as a non-virtual. + */ + %operation void infer_type(expression *e) + + infer_type(binary) + { + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == error_type || e->expr2->type == error_type) + { + e->type = error_type; + } + else if(e->expr1->type == float_type || e->expr2->type == float_type) + { + e->type = float_type; + } + else + { + e->type = int_type; + } + } + + infer_type(unary) + { + infer_type(e->expr); + e->type = e->expr->type; + } + + infer_type(intnum) + { + e->type = int_type; + } + + infer_type(floatnum) + { + e->type = float_type; + } + + infer_type(power) + { + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == error_type || e->expr2->type == error_type) + { + e->type = error_type; + } + else if(e->expr2->type != int_type) + { + fprintf(stderr, "%s:%ld: second argument to `^' is not an integer\n", + yygetfilename(e), yygetlinenum(e)); + e->type = error_type; + } + else + { + e->type = e->expr1->type; + } + } + + infer_type(cast) + { + infer_type(e->expr); + + if(e->expr->type != error_type) + { + e->type = e->new_type; + } + else + { + e->type = error_type; + } + } + + /* + * Define the "eval_expr" operation as a virtual. + */ + %operation %virtual eval_value eval_expr(expression *e) + + eval_expr(plus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = eval_expr(e->expr1); + eval_value value2 = eval_expr(e->expr2); + + /* Coerce to the common type */ + coerce(&value1, e->expr1->type, e->type); + coerce(&value2, e->expr2->type, e->type); + + /* Evaluate the operator */ + if(e->type == int_type) + { + value1.int_value += value2.int_value; + } + else + { + value1.float_value += value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(minus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = eval_expr(e->expr1); + eval_value value2 = eval_expr(e->expr2); + + /* Coerce to the common type */ + coerce(&value1, e->expr1->type, e->type); + coerce(&value2, e->expr2->type, e->type); + + /* Evaluate the operator */ + if(e->type == int_type) + { + value1.int_value -= value2.int_value; + } + else + { + value1.float_value -= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(multiply) + { + /* Evaluate the sub-expressions */ + eval_value value1 = eval_expr(e->expr1); + eval_value value2 = eval_expr(e->expr2); + + /* Coerce to the common type */ + coerce(&value1, e->expr1->type, e->type); + coerce(&value2, e->expr2->type, e->type); + + /* Evaluate the operator */ + if(e->type == int_type) + { + value1.int_value *= value2.int_value; + } + else + { + value1.float_value *= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(divide) + { + /* Evaluate the sub-expressions */ + eval_value value1 = eval_expr(e->expr1); + eval_value value2 = eval_expr(e->expr2); + + /* Coerce to the common type */ + coerce(&value1, e->expr1->type, e->type); + coerce(&value2, e->expr2->type, e->type); + + /* Evaluate the operator */ + if(e->type == int_type) + { + if(value2.int_value != 0) + { + value1.int_value /= value2.int_value; + } + else + { + fprintf(stderr, "%s:%ld: division by zero\n", + yygetfilename(e), yygetlinenum(e)); + value1.int_value = 0; + } + } + else + { + value1.float_value /= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(power) + { + /* Evaluate the sub-expressions */ + eval_value value1 = eval_expr(e->expr1); + eval_value value2 = eval_expr(e->expr2); + + /* Evaluate the operator */ + if(e->type == int_type) + { + value1.int_value = (int)(pow((double)(value1.int_value), + (double)(value2.int_value))); + } + else + { + value1.float_value = (float)(pow((double)(value1.float_value), + (double)(value2.int_value))); + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(negate) + { + /* Evaluate the sub-expression */ + eval_value value = eval_expr(e->expr); + + /* Evaluate the operator */ + if(e->type == int_type) + { + value.int_value = -(value.int_value); + } + else + { + value.float_value = -(value.float_value); + } + + /* Return the result to the caller */ + return value; + } + + eval_expr(cast) + { + /* Evaluate the sub-expression */ + eval_value value = eval_expr(e->expr); + + /* Cast to the final type */ + coerce(&value, e->expr->type, e->type); + + /* Return the result to the caller */ + return value; + } + + eval_expr(intnum) + { + eval_value value; + value.int_value = e->num; + return value; + } + + eval_expr(floatnum) + { + eval_value value; + value.float_value = e->num; + return value; + } + + /* + * Define the "coerce" operation as an inline non-virtual. + */ + %operation %inline void coerce + (eval_value *value, [type_code from], [type_code to]) + + coerce(int_type, float_type) + { + value->float_value = (float)(value->int_value); + } + + coerce(float_type, int_type) + { + value->int_value = (int)(value->float_value); + } + + coerce(type_code, type_code) + { + /* Nothing to do here */ + } + + /* + * Include the following code at the end of the ".c" file. + */ + %end %{ + + /* + * Global data used by the expression parser. + */ + char *progname; + char *filename; + long linenum; + + /* + * Entry points that are imported from the yacc parser. + */ + extern void yyrestart(FILE *file); + extern int yyparse(void); + + /* + * Main entry point for the expression parser and evaluator. + */ + int main(int argc, char *argv[]) + { + FILE *file; + progname = argv[0]; + linenum = 1; + if(argc < 2) + { + filename = "stdin"; + yyrestart(stdin); + } + else if((file = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + return 1; + } + else + { + filename = argv[1]; + yyrestart(file); + } + return yyparse(); + } + + /* + * Get the name of the current input file in use by the parser. + */ + char *yycurrfilename(void) + { + return filename; + } + + /* + * Get the line number for the current input line in use by the parser. + */ + long yycurrlinenum(void) + { + return linenum; + } + + /* + * Report memory failure and exit. + */ + void yynodefailed(void) + { + fputs(progname, stderr); + fputs(": virtual memory exhausted\n", stderr); + exit(1); + } + + %} Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cpp.tc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cpp.tc:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cpp.tc Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,502 ---- + /* + * expr_cpp.tc - Expression example treecc input file for C++. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + %option lang = "C++" + %option reentrant + + %header "expr_cpp.h" + %output "expr_cpp.cc" + + /* + * Include the following declarations into the ".h" file. + */ + %decls %{ + + /* + * Value that is computed by "eval_expr" below. + */ + typedef union + { + int int_value; + float float_value; + + } eval_value; + + %} + + /* + * Include the following declarations into the ".cc" file. + */ + %{ + #include + #include + #include + #include + + #include "expr_cpp.h" + + %} + + /* + * Define the type code that is associated with a node + * in the syntax tree. We use "error_type" to indicate + * a failure during type inferencing. + */ + %enum type_code = + { + error_type, + int_type, + float_type + } + + /* + * Define the node types that make up the syntax. + */ + %node expression %abstract %typedef = + { + %nocreate type_code type = {error_type}; + } + + %node binary expression %abstract = + { + expression *expr1; + expression *expr2; + } + + %node unary expression %abstract = + { + expression *expr; + } + + %node intnum expression = + { + int num; + } + + %node floatnum expression = + { + float num; + } + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node power binary + %node negate unary + + %node cast expression = + { + type_code new_type; + expression *expr; + } + + /* + * Define the "infer_type" operation as a non-virtual. + */ + %operation void infer_type(expression *e) + + infer_type(binary) + { + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == error_type || e->expr2->type == error_type) + { + e->type = error_type; + } + else if(e->expr1->type == float_type || e->expr2->type == float_type) + { + e->type = float_type; + } + else + { + e->type = int_type; + } + } + + infer_type(unary) + { + infer_type(e->expr); + e->type = e->expr->type; + } + + infer_type(intnum) + { + e->type = int_type; + } + + infer_type(floatnum) + { + e->type = float_type; + } + + infer_type(power) + { + infer_type(e->expr1); + infer_type(e->expr2); + + if(e->expr1->type == error_type || e->expr2->type == error_type) + { + e->type = error_type; + } + else if(e->expr2->type != int_type) + { + cerr << e->getFilename() << ":" << e->getLinenum() << + ": second argument to `^' is not an integer" << endl; + e->type = error_type; + } + else + { + e->type = e->expr1->type; + } + } + + infer_type(cast) + { + infer_type(e->expr); + + if(e->expr->type != error_type) + { + e->type = e->new_type; + } + else + { + e->type = error_type; + } + } + + /* + * Define the "eval_expr" operation as a virtual. + */ + %operation %virtual eval_value eval_expr(expression *this) + + eval_expr(plus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1->eval_expr(); + eval_value value2 = expr2->eval_expr(); + + /* Coerce to the common type */ + coerce(&value1, expr1->type, type); + coerce(&value2, expr2->type, type); + + /* Evaluate the operator */ + if(type == int_type) + { + value1.int_value += value2.int_value; + } + else + { + value1.float_value += value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(minus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1->eval_expr(); + eval_value value2 = expr2->eval_expr(); + + /* Coerce to the common type */ + coerce(&value1, expr1->type, type); + coerce(&value2, expr2->type, type); + + /* Evaluate the operator */ + if(type == int_type) + { + value1.int_value -= value2.int_value; + } + else + { + value1.float_value -= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(multiply) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1->eval_expr(); + eval_value value2 = expr2->eval_expr(); + + /* Coerce to the common type */ + coerce(&value1, expr1->type, type); + coerce(&value2, expr2->type, type); + + /* Evaluate the operator */ + if(type == int_type) + { + value1.int_value *= value2.int_value; + } + else + { + value1.float_value *= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(divide) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1->eval_expr(); + eval_value value2 = expr2->eval_expr(); + + /* Coerce to the common type */ + coerce(&value1, expr1->type, type); + coerce(&value2, expr2->type, type); + + /* Evaluate the operator */ + if(type == int_type) + { + if(value2.int_value != 0) + { + value1.int_value /= value2.int_value; + } + else + { + cerr << getFilename() << ":" << getLinenum() << + ": division by zero" << endl; + value1.int_value = 0; + } + } + else + { + value1.float_value /= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(power) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1->eval_expr(); + eval_value value2 = expr2->eval_expr(); + + /* Evaluate the operator */ + if(type == int_type) + { + value1.int_value = (int)(pow((double)(value1.int_value), + (double)(value2.int_value))); + } + else + { + value1.float_value = (float)(pow((double)(value1.float_value), + (double)(value2.int_value))); + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(negate) + { + /* Evaluate the sub-expression */ + eval_value value = expr->eval_expr(); + + /* Evaluate the operator */ + if(type == int_type) + { + value.int_value = -(value.int_value); + } + else + { + value.float_value = -(value.float_value); + } + + /* Return the result to the caller */ + return value; + } + + eval_expr(cast) + { + /* Evaluate the sub-expression */ + eval_value value = expr->eval_expr(); + + /* Cast to the final type */ + coerce(&value, expr->type, type); + + /* Return the result to the caller */ + return value; + } + + eval_expr(intnum) + { + eval_value value; + value.int_value = num; + return value; + } + + eval_expr(floatnum) + { + eval_value value; + value.float_value = num; + return value; + } + + /* + * Define the "coerce" operation as an inline non-virtual. + */ + %operation %inline void coerce + (eval_value *value, [type_code from], [type_code to]) + + coerce(int_type, float_type) + { + value->float_value = (float)(value->int_value); + } + + coerce(float_type, int_type) + { + value->int_value = (int)(value->float_value); + } + + coerce(type_code, type_code) + { + /* Nothing to do here */ + } + + /* + * Include the following code at the end of the ".h" file. + */ + %end %decls %{ + + /* + * Inherit YYNODESTATE to provide additional functionality. + */ + class NodeState : public YYNODESTATE + { + private: + + char *progname; + char *filename; + long linenum; + + public: + + NodeState(char *_progname, char *_filename) + : YYNODESTATE() + { + filename = _filename; + linenum = 1; + } + virtual ~NodeState(); + + public: + + virtual char *currFilename(); + virtual long currLinenum(); + virtual void failed(); + + void incLine() { ++linenum; } + + }; + + %} + + /* + * Include the following code at the end of the ".cc" file. + */ + %end %{ + + /* + * Entry points that are imported from the yacc parser. + */ + extern void yyrestart(FILE *file); + extern int yyparse(void *); + + /* + * Main entry point for the expression parser and evaluator. + */ + int main(int argc, char *argv[]) + { + FILE *file; + char *filename; + int retval; + + /* Parse the command-line arguments and open the input file */ + if(argc < 2) + { + filename = "stdin"; + file = stdin; + } + else if((file = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + return 1; + } + else + { + filename = argv[1]; + } + + /* Create the node factory and state object */ + NodeState *state = new NodeState(argv[0], filename); + + /* Parse and evaluate the expressions in the input */ + retval = yyparse(state); + + /* Clean up and exit */ + delete state; + return retval; + } + + /* + * Destructor for NodeState. + */ + NodeState::~NodeState() + { + /* Nothing needs to be done here */ + } + + /* + * Get the name of the current input file in use by the parser. + */ + char *NodeState::currFilename() + { + return filename; + } + + /* + * Get the line number for the current input line in use by the parser. + */ + long NodeState::currLinenum() + { + return linenum; + } + + /* + * Report memory failure and exit. + */ + void NodeState::failed() + { + cerr << progname << ": virtual memory exhausted" << endl; + exit(1); + } + + %} Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cs.tc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cs.tc:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_cs.tc Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,366 ---- + /* + * expr_cs.tc - Expression example treecc input file for C#. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + %option lang = "C#" + + %output "expr_cs.cs" + + /* + * Include the following declarations in the ".cs" file. + */ + %{ + + public class eval_value + { + public int int_value; + public float float_value; + } + + %} + + /* + * Define the type code that is associated with a node + * in the syntax tree. We use "error_type" to indicate + * a failure during type inferencing. + */ + %enum type_code = + { + error_type, + int_type, + float_type + } + + /* + * Define the node types that make up the syntax. + */ + %node expression %abstract %typedef = + { + %nocreate type_code type = {type_code.error_type}; + } + + %node binary expression %abstract = + { + expression expr1; + expression expr2; + } + + %node unary expression %abstract = + { + expression expr; + } + + %node intnum expression = + { + int num; + } + + %node floatnum expression = + { + float num; + } + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node power binary + %node negate unary + + %node cast expression = + { + type_code new_type; + expression expr; + } + + /* + * Define the "infer_type" operation as a non-virtual. + */ + %operation void InferType::infer_type(expression e) + + infer_type(binary) + { + infer_type(e.expr1); + infer_type(e.expr2); + + if(e.expr1.type == type_code.error_type || + e.expr2.type == type_code.error_type) + { + e.type = type_code.error_type; + } + else if(e.expr1.type == type_code.float_type || + e.expr2.type == type_code.float_type) + { + e.type = type_code.float_type; + } + else + { + e.type = type_code.int_type; + } + } + + infer_type(unary) + { + infer_type(e.expr); + e.type = e.expr.type; + } + + infer_type(intnum) + { + e.type = type_code.int_type; + } + + infer_type(floatnum) + { + e.type = type_code.float_type; + } + + infer_type(power) + { + infer_type(e.expr1); + infer_type(e.expr2); + + if(e.expr1.type == type_code.error_type || + e.expr2.type == type_code.error_type) + { + e.type = type_code.error_type; + } + else if(e.expr2.type != type_code.int_type) + { + Console.Error.WriteLine(e.getFilename() + ":" + e.getLinenum() + + ": second argument to `^' is not an integer"); + e.type = type_code.error_type; + } + else + { + e.type = e.expr1.type; + } + } + + infer_type(cast) + { + infer_type(e.expr); + + if(e.expr.type != type_code.error_type) + { + e.type = e.new_type; + } + else + { + e.type = type_code.error_type; + } + } + + /* + * Define the "eval_expr" operation as a virtual. + */ + %operation %virtual eval_value eval_expr(expression *this) + + eval_expr(plus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + Coerce.coerce(value1, expr1.type, type); + Coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value += value2.int_value; + } + else + { + value1.float_value += value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(minus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + Coerce.coerce(value1, expr1.type, type); + Coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value -= value2.int_value; + } + else + { + value1.float_value -= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(multiply) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + Coerce.coerce(value1, expr1.type, type); + Coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value *= value2.int_value; + } + else + { + value1.float_value *= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(divide) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + Coerce.coerce(value1, expr1.type, type); + Coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + if(value2.int_value != 0) + { + value1.int_value /= value2.int_value; + } + else + { + Console.Error.WriteLine(getFilename() + ":" + getLinenum() + + ": division by zero"); + value1.int_value = 0; + } + } + else + { + value1.float_value /= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(power) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value = (int)(Math.Pow((double)(value1.int_value), + (double)(value2.int_value))); + } + else + { + value1.float_value = (float)(Math.Pow((double)(value1.float_value), + (double)(value2.int_value))); + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(negate) + { + /* Evaluate the sub-expression */ + eval_value value = expr.eval_expr(); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value.int_value = -(value.int_value); + } + else + { + value.float_value = -(value.float_value); + } + + /* Return the result to the caller */ + return value; + } + + eval_expr(cast) + { + /* Evaluate the sub-expression */ + eval_value value = expr.eval_expr(); + + /* Cast to the final type */ + Coerce.coerce(value, expr.type, type); + + /* Return the result to the caller */ + return value; + } + + eval_expr(intnum) + { + eval_value value = new eval_value(); + value.int_value = num; + return value; + } + + eval_expr(floatnum) + { + eval_value value = new eval_value(); + value.float_value = num; + return value; + } + + /* + * Define the "coerce" operation as an inline non-virtual. + */ + %operation %inline void Coerce::coerce + (eval_value value, [type_code from], [type_code to]) + + coerce(int_type, float_type) + { + value.float_value = (float)(value.int_value); + } + + coerce(float_type, int_type) + { + value.int_value = (int)(value.float_value); + } + + coerce(type_code, type_code) + { + /* Nothing to do here */ + } Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_java.tc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_java.tc:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_java.tc Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,351 ---- + /* + * expr_java.tc - Expression example treecc input file for Java. + * + * Copyright (C) 2001 Southern Storm Software, Pty Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + %option lang = "Java" + + /* + * Define the type code that is associated with a node + * in the syntax tree. We use "error_type" to indicate + * a failure during type inferencing. + */ + %enum type_code = + { + error_type, + int_type, + float_type + } + + /* + * Define the node types that make up the syntax. + */ + %node expression %abstract %typedef = + { + %nocreate type_code type = {type_code.error_type}; + } + + %node binary expression %abstract = + { + expression expr1; + expression expr2; + } + + %node unary expression %abstract = + { + expression expr; + } + + %node intnum expression = + { + int num; + } + + %node floatnum expression = + { + float num; + } + + %node plus binary + %node minus binary + %node multiply binary + %node divide binary + %node power binary + %node negate unary + + %node cast expression = + { + type_code new_type; + expression expr; + } + + /* + * Define the "infer_type" operation as a non-virtual. + */ + %operation void infer_type(expression e) + + infer_type(binary) + { + infer_type(e.expr1); + infer_type(e.expr2); + + if(e.expr1.type == type_code.error_type || + e.expr2.type == type_code.error_type) + { + e.type = type_code.error_type; + } + else if(e.expr1.type == type_code.float_type || + e.expr2.type == type_code.float_type) + { + e.type = type_code.float_type; + } + else + { + e.type = type_code.int_type; + } + } + + infer_type(unary) + { + infer_type(e.expr); + e.type = e.expr.type; + } + + infer_type(intnum) + { + e.type = type_code.int_type; + } + + infer_type(floatnum) + { + e.type = type_code.float_type; + } + + infer_type(power) + { + infer_type(e.expr1); + infer_type(e.expr2); + + if(e.expr1.type == type_code.error_type || + e.expr2.type == type_code.error_type) + { + e.type = type_code.error_type; + } + else if(e.expr2.type != type_code.int_type) + { + System.err.println(e.getFilename() + ":" + e.getLinenum() + + ": second argument to `^' is not an integer"); + e.type = type_code.error_type; + } + else + { + e.type = e.expr1.type; + } + } + + infer_type(cast) + { + infer_type(e.expr); + + if(e.expr.type != type_code.error_type) + { + e.type = e.new_type; + } + else + { + e.type = type_code.error_type; + } + } + + /* + * Define the "eval_expr" operation as a virtual. + */ + %operation %virtual eval_value eval_expr(expression *this) + + eval_expr(plus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + coerce.coerce(value1, expr1.type, type); + coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value += value2.int_value; + } + else + { + value1.float_value += value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(minus) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + coerce.coerce(value1, expr1.type, type); + coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value -= value2.int_value; + } + else + { + value1.float_value -= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(multiply) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + coerce.coerce(value1, expr1.type, type); + coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value *= value2.int_value; + } + else + { + value1.float_value *= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(divide) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Coerce to the common type */ + coerce.coerce(value1, expr1.type, type); + coerce.coerce(value2, expr2.type, type); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + if(value2.int_value != 0) + { + value1.int_value /= value2.int_value; + } + else + { + System.err.println(getFilename() + ":" + getLinenum() + + ": division by zero"); + value1.int_value = 0; + } + } + else + { + value1.float_value /= value2.float_value; + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(power) + { + /* Evaluate the sub-expressions */ + eval_value value1 = expr1.eval_expr(); + eval_value value2 = expr2.eval_expr(); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value1.int_value = (int)(Math.pow((double)(value1.int_value), + (double)(value2.int_value))); + } + else + { + value1.float_value = (float)(Math.pow((double)(value1.float_value), + (double)(value2.int_value))); + } + + /* Return the result to the caller */ + return value1; + } + + eval_expr(negate) + { + /* Evaluate the sub-expression */ + eval_value value = expr.eval_expr(); + + /* Evaluate the operator */ + if(type == type_code.int_type) + { + value.int_value = -(value.int_value); + } + else + { + value.float_value = -(value.float_value); + } + + /* Return the result to the caller */ + return value; + } + + eval_expr(cast) + { + /* Evaluate the sub-expression */ + eval_value value = expr.eval_expr(); + + /* Cast to the final type */ + coerce.coerce(value, expr.type, type); + + /* Return the result to the caller */ + return value; + } + + eval_expr(intnum) + { + eval_value value = new eval_value(); + value.int_value = num; + return value; + } + + eval_expr(floatnum) + { + eval_value value = new eval_value(); + value.float_value = num; + return value; + } + + /* + * Define the "coerce" operation as an inline non-virtual. + */ + %operation %inline void coerce + (eval_value value, [type_code from], [type_code to]) + + coerce(int_type, float_type) + { + value.float_value = (float)(value.int_value); + } + + coerce(float_type, int_type) + { + value.int_value = (int)(value.float_value); + } + + coerce(type_code, type_code) + { + /* Nothing to do here */ + } Index: llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_ruby.tc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_ruby.tc:1.1 *** /dev/null Tue Apr 6 12:54:27 2004 --- llvm/test/Programs/MultiSource/Applications/treecc/examples/expr_ruby.tc Tue Apr 6 12:54:17 2004 *************** *** 0 **** --- 1,329 ---- + /* + * expr_ruby.tc - Expression example treecc input file for Ruby. + * + * Copyright (C) 2001, 2002 Southern Storm Software, Pty Ltd. + * + * Hacked by Peter Minten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + %option lang = "Ruby" + + %output "expr_ruby.rb" + + /* + * Include the following declarations in the ".rb" file. + */ + %{ + + class Eval_value + Int_value = 0 + Float_value = 0 + end + + %} + + /* + * Define the type code that is associated with a node + * in the syntax tree. We use "error_type" to indicate + * a failure during type inferencing. + */ + %enum Type_code = + { + Error_type, + Int_type, + Float_type + } + + /* + * Define the node types that make up the syntax. + */ + %node Expression %abstract %typedef = + { + %nocreate Type_code type = {Type_code::Error_type}; + } + + %node Binary Expression %abstract = + { + Expression expr1; + Expression expr2; + } + + %node Unary Expression %abstract = + { + Expression expr; + } + + %node Intnum Expression = + { + int num; + } + + %node Floatnum Expression = + { + float num; + } + + %node Plus Binary + %node Minus Binary + %node Multiply Binary + %node Divide Binary + %node Power Binary + %node Negate Unary + + %node Cast Expression = + { + Type_code new_type; + Expression expr; + } + + /* + * Define the "infer_type" operation as a non-virtual. + */ + %operation void InferType::infer_type(Expression e) + + infer_type(Binary) + { + infer_type(e.expr1) + infer_type(e.expr2) + + if (e.expr1.type == Type_code::Error_type || e.expr2.type == Type_code::Error_type) then + e.type = Type_code::Error_type + elsif (e.expr1.type == Type_code::Float_type || e.expr2.type == Type_code::Float_type) then + e.type = Type_code::Float_type + else + e.type = Type_code::Int_type + end + } + + infer_type(Unary) + { + infer_type(e.expr) + e.type = e.expr.type + } + + infer_type(Intnum) + { + e.type = Type_code::Int_type + } + + infer_type(Floatnum) + { + e.type = Type_code::Float_type + } + + infer_type(Power) + { + infer_type(e.expr1) + infer_type(e.expr2) + + if (e.expr1.type == Type_code::Error_type || e.expr2.type == Type_code::Error_type) then + e.type = Type_code::Error_type + elsif (e.expr2.type != Type_code::Int_type) then + p (e.getFilename() + ":" + e.getLinenum() + ": second argument to `^' is not an integer") + e.type = Type_code::Error_type + else + e.type = e.expr1.type + end + } + + infer_type(Cast) + { + infer_type(e.expr) + + if(e.expr.type != Type_code::Error_type) + e.type = e.new_type + else + e.type = Type_code::Error_type + end + } + + /* + * Define the "eval_expr" operation as a virtual. + */ + %operation %virtual eval_value eval_expr(Expression this) + + eval_expr(Plus) + { + # Evaluate the sub-Expressions + eval_value value1 = expr1.eval_expr + eval_value value2 = expr2.eval_expr + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value2, expr2.type, type) + + # Evaluate the operator + if (type == Type_code::Int_type) then + value1.Int_value += value2.Int_value + else + value1.Float_value += value2.Float_value + end + + # Return the result to the caller + return value1 + } + + eval_expr(Minus) + { + # Evaluate the sub-Expressions + eval_value value1 = expr1.eval_expr() + eval_value value2 = expr2.eval_expr() + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value2, expr2.type, type) + + # Evaluate the operator + if(type == Type_code::Int_type) then + value1.Int_value -= value2.Int_value + else + value1.Float_value -= value2.Float_value; + end + + # Return the result to the caller + return value1 + } + + eval_expr(Multiply) + { + # Evaluate the sub-Expressions + eval_value value1 = expr1.eval_expr() + eval_value value2 = expr2.eval_expr() + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value2, expr2.type, type) + + # Evaluate the operator + if(type == Type_code::Int_type) then + value1.Int_value *= value2.Int_value + else + value1.Float_value *= value2.Float_value; + end + + # Return the result to the caller + return value1 + } + + eval_expr(Divide) + { + # Evaluate the sub-Expressions + eval_value value1 = expr1.eval_expr() + eval_value value2 = expr2.eval_expr() + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value2, expr2.type, type) + + # Evaluate the operator + if(type == Type_code::Int_type) then + value1.Int_value -= value2.Int_value + else + value1.Float_value -= value2.Float_value; + end + + # Return the result to the caller + return value1 + } + + eval_expr(Power) + { + # Evaluate the sub-Expressions + eval_value value1 = expr1.eval_expr() + eval_value value2 = expr2.eval_expr() + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value2, expr2.type, type) + + # Evaluate the operator + if(type == Type_code::Int_type) then + value1.Int_value = value1.Int_value ^ value2.Int_value + else + value1.Float_value = value1.Float_value ^ value2.Float_value; + end + + # Return the result to the caller + return value1 + } + + eval_expr(Negate) + { + # Evaluate the sub-Expression + eval_value value = expr.eval_expr() + + # Coerce to the common type + Coerce.coerce(value1, expr1.type, type) + Coerce.coerce(value, expr.type, type) + + # Evaluate the operator + if(type == Type_code::Int_type) then + value.Int_value = -1 * value.Int_value + else + value.Float_value = -1 * value.Float_value; + end + + # Return the result to the caller + return value + } + + eval_expr(Cast) + { + # Evaluate the sub-Expression + eval_value value = expr.eval_expr() + + # Coerce to the common type + Coerce.coerce(value, expr.type, type) + + # Return the result to the caller + return value + } + + eval_expr(Intnum) + { + value = eval_value.new + value.Int_value = num + return value + } + + eval_expr(Floatnum) + { + value = eval_value.new + value.Float_value = num + return value + } + + /* + * Define the "coerce" operation as an inline non-virtual. + */ + %operation %inline void Coerce::coerce + (value, [Type_code from], [Type_code to]) + + coerce(Int_type, Float_type) + { + value.Float_value = value.Int_value.to_f; + } + + coerce(Float_type, Int_type) + { + value.Int_value = value.Float_value.to_i; + } + + coerce(Type_code, Type_code) + { + # Nothing to do here + } From criswell at cs.uiuc.edu Tue Apr 6 12:57:15 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 12:57:15 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/doc/ Message-ID: <200404061754.MAA01140@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc/doc: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/treecc/doc added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 13:09:03 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 13:09:03 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/treecc/Makefile Message-ID: <200404061808.NAA02246@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/treecc: Makefile updated: 1.1 -> 1.2 --- Log message: Corrected run time options. Currently, this only runs treecc on the input and then terminates (i.e. the -n option means "no output"). Eventually, the code will need to be modified to print to stdout or the Makefile will need new rules for generating the output files. But, for now, this will at least ensure that it compiles and sort of works. --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/MultiSource/Applications/treecc/Makefile diff -u llvm/test/Programs/MultiSource/Applications/treecc/Makefile:1.1 llvm/test/Programs/MultiSource/Applications/treecc/Makefile:1.2 --- llvm/test/Programs/MultiSource/Applications/treecc/Makefile:1.1 Tue Apr 6 12:53:30 2004 +++ llvm/test/Programs/MultiSource/Applications/treecc/Makefile Tue Apr 6 13:08:00 2004 @@ -2,5 +2,5 @@ PROG = treecc #LDFLAGS += -lstdc++ #LIBS += -lstdc++ -STDIN_FILENAME=$(BUILD_SRC_DIR)/tests/input3.tst +RUN_OPTIONS=-n $(BUILD_SRC_DIR)/examples/expr_cpp.tc include ../../Makefile.multisrc From criswell at cs.uiuc.edu Tue Apr 6 13:10:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 13:10:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/Makefile Message-ID: <200404061809.NAA02264@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications: Makefile updated: 1.6 -> 1.7 --- Log message: Added treecc to the list of program to test on Linux. I'm hoping that treecc will be usable for pool allocation, and it's one more program that to put LLVM through to make sure it hasn't regressed. --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/MultiSource/Applications/Makefile diff -u llvm/test/Programs/MultiSource/Applications/Makefile:1.6 llvm/test/Programs/MultiSource/Applications/Makefile:1.7 --- llvm/test/Programs/MultiSource/Applications/Makefile:1.6 Tue Apr 6 11:03:17 2004 +++ llvm/test/Programs/MultiSource/Applications/Makefile Tue Apr 6 13:09:23 2004 @@ -6,7 +6,7 @@ PARALLEL_DIRS = Burg aha sgefa siod lambda-0.1.3 d ifeq ($(OS),Linux) -PARALLEL_DIRS += hbd +PARALLEL_DIRS += treecc hbd endif include $(LEVEL)/test/Programs/Makefile.programs From lattner at cs.uiuc.edu Tue Apr 6 14:23:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 14:23:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200404061922.OAA00752@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.67 -> 1.68 --- Log message: Fix incorrect encoding of some ADC and SBB instuctions --- Diffs of the changes: (+9 -9) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.67 llvm/lib/Target/X86/X86InstrInfo.td:1.68 --- llvm/lib/Target/X86/X86InstrInfo.td:1.67 Mon Apr 5 21:02:11 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Apr 6 14:20:32 2004 @@ -532,8 +532,8 @@ def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 def ADC32rr : I <"adc", 0x11, MRMDestReg>; // R32 += R32+Carry -def ADC32rm : Im32 <"adc", 0x11, MRMSrcMem >; // R32 += [mem32]+Carry -def ADC32mr : Im32 <"adc", 0x13, MRMDestMem>; // [mem32] += R32+Carry +def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry +def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry def ADC32ri : Ii32 <"adc", 0x81, MRM2r >; // R32 += I32+Carry def ADC32ri8 : Ii8 <"adc", 0x83, MRM2r >; // R32 += I8+Carry def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry @@ -561,13 +561,13 @@ def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 -def SBB32rr : I <"sbb", 0x19, MRMDestReg>; // R32 -= R32+Borrow -def SBB32rm : Im32 <"sbb", 0x19, MRMSrcMem >; // R32 -= [mem32]+Borrow -def SBB32mr : Im32 <"sbb", 0x1B, MRMDestMem>; // [mem32] -= R32+Borrow -def SBB32ri : Ii32 <"sbb", 0x81, MRM3r >; // R32 -= I32+Borrow -def SBB32ri8 : Ii8 <"sbb", 0x83, MRM3r >; // R32 -= I8+Borrow -def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Borrow -def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Borrow +def SBB32rr : I <"sbb", 0x19, MRMDestReg>; // R32 -= R32+Carry +def SBB32mr : Im32 <"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry +def SBB32rm : Im32 <"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry +def SBB32ri : Ii32 <"sbb", 0x81, MRM3r >; // R32 -= I32+Carry +def SBB32ri8 : Ii8 <"sbb", 0x83, MRM3r >; // R32 -= I8+Carry +def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Carry +def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Carry def IMUL16rr : I <"imul", 0xAF, MRMSrcReg>, TB, OpSize, Pattern<(set R16, (times R16, R16))>; def IMUL32rr : I <"imul", 0xAF, MRMSrcReg>, TB , Pattern<(set R32, (times R32, R32))>; From lattner at cs.uiuc.edu Tue Apr 6 14:30:01 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 14:30:01 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200404061929.OAA00821@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.217 -> 1.218 --- Log message: Fix PR313: http://llvm.cs.uiuc.edu/PR313 : [x86] JIT miscompiles unsigned short to floating point --- Diffs of the changes: (+1 -2) Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.217 llvm/lib/Target/X86/InstSelectSimple.cpp:1.218 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.217 Tue Apr 6 12:34:50 2004 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Tue Apr 6 14:29:36 2004 @@ -2640,8 +2640,7 @@ if (PromoteType) { unsigned TmpReg = makeAnotherReg(PromoteType); - unsigned Opc = SrcTy->isSigned() ? X86::MOVSX16rr8 : X86::MOVZX16rr8; - BuildMI(*BB, IP, Opc, 1, TmpReg).addReg(SrcReg); + BuildMI(*BB, IP, PromoteOpcode, 1, TmpReg).addReg(SrcReg); SrcTy = PromoteType; SrcClass = getClass(PromoteType); SrcReg = TmpReg; From kuba at cs.uiuc.edu Tue Apr 6 14:32:01 2004 From: kuba at cs.uiuc.edu (Takahiro Kuba) Date: Tue Apr 6 14:32:01 2004 Subject: [llvm-commits] CVS: llvm/utils/TableGen/TableGen.cpp Message-ID: <200404061931.OAA20279@cypher.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: TableGen.cpp updated: 1.25 -> 1.26 --- Log message: add tablgen backend for really simple instruction selector --- Diffs of the changes: (+7 -1) Index: llvm/utils/TableGen/TableGen.cpp diff -u llvm/utils/TableGen/TableGen.cpp:1.25 llvm/utils/TableGen/TableGen.cpp:1.26 --- llvm/utils/TableGen/TableGen.cpp:1.25 Fri Feb 13 10:37:43 2004 +++ llvm/utils/TableGen/TableGen.cpp Tue Apr 6 14:30:56 2004 @@ -23,6 +23,7 @@ #include "RegisterInfoEmitter.h" #include "InstrInfoEmitter.h" #include "InstrSelectorEmitter.h" +#include "SimpleInstrSelEmitter.h" #include #include #include @@ -35,7 +36,7 @@ GenRegisterEnums, GenRegister, GenRegisterHeader, GenInstrEnums, GenInstrs, GenInstrSelector, PrintEnums, - Parse, + Parse, GenSimpInstrSel, }; namespace { @@ -57,6 +58,8 @@ "Generate instruction descriptions"), clEnumValN(GenInstrSelector, "gen-instr-selector", "Generate an instruction selector"), + clEnumValN(GenSimpInstrSel, "gen-simp-instr-sel", + "Generate a simple instruction selector"), clEnumValN(PrintEnums, "print-enums", "Print enum values for a class"), clEnumValN(Parse, "parse", @@ -471,6 +474,9 @@ *Out << "\n"; break; } + case GenSimpInstrSel: + SimpleInstrSelEmitter(Records).run(*Out); + break; default: assert(1 && "Invalid Action"); return 1; From kuba at cs.uiuc.edu Tue Apr 6 14:32:15 2004 From: kuba at cs.uiuc.edu (Takahiro Kuba) Date: Tue Apr 6 14:32:15 2004 Subject: [llvm-commits] CVS: llvm/utils/TableGen/SimpleInstrSelEmitter.cpp SimpleInstrSelEmitter.h Message-ID: <200404061931.OAA20294@cypher.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: SimpleInstrSelEmitter.cpp added (r1.1) SimpleInstrSelEmitter.h added (r1.1) --- Log message: Tablegen backend for really simple instruction selector --- Diffs of the changes: (+514 -0) Index: llvm/utils/TableGen/SimpleInstrSelEmitter.cpp diff -c /dev/null llvm/utils/TableGen/SimpleInstrSelEmitter.cpp:1.1 *** /dev/null Tue Apr 6 14:31:42 2004 --- llvm/utils/TableGen/SimpleInstrSelEmitter.cpp Tue Apr 6 14:31:31 2004 *************** *** 0 **** --- 1,453 ---- + //===- SimpleInstrSelEmitter.cpp - Generate a Simple Instruction Selector ------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This tablegen backend is responsible for emitting an instruction selector + // + // + //===----------------------------------------------------------------------===// + #include "InstrInfoEmitter.h" + #include "SimpleInstrSelEmitter.h" + #include "CodeGenWrappers.h" + #include "Record.h" + #include "Support/Debug.h" + #include "Support/StringExtras.h" + #include + + + #include "Record.h" + #include "Support/CommandLine.h" + #include "Support/Signals.h" + #include "Support/FileUtilities.h" + #include "CodeEmitterGen.h" + #include "RegisterInfoEmitter.h" + #include "InstrInfoEmitter.h" + #include "InstrSelectorEmitter.h" + #include "SimpleInstrSelEmitter.h" + #include + #include + #include + #include + + namespace llvm { + + std::string FnDecs; + + // run - Emit the main instruction description records for the target... + void SimpleInstrSelEmitter::run(std::ostream &OS) { + + + // EmitSourceFileHeader("Mark's Instruction Selector for the X86 target", OS); + + + // OS << "#include \"llvm/CodeGen/MachineInstrBuilder.h\"\n"; + + // OS << "#include \"llvm/Constants.h\"\n"; + // OS << "#include \"llvm/DerivedTypes.h\"\n"; + // OS << "#include \"llvm/Function.h\"\n"; + // OS << "#include \"llvm/Instructions.h\"\n"; + // OS << "#include \"llvm/IntrinsicLowering.h\"\n"; + // OS << "#include \"llvm/Pass.h\"\n"; + // OS << "#include \"llvm/CodeGen/MachineConstantPool.h\"\n"; + // OS << "#include \"llvm/CodeGen/MachineFrameInfo.h\"\n"; + // OS << "#include \"llvm/CodeGen/MachineFunction.h\"\n"; + // OS << "#include \"llvm/CodeGen/MachineInstrBuilder.h\"\n"; + // OS << "#include \"llvm/CodeGen/SSARegMap.h\"\n"; + // OS << "#include \"llvm/Target/MRegisterInfo.h\"\n"; + // OS << "#include \"llvm/Target/TargetMachine.h\"\n"; + // OS << "#include \"llvm/Support/InstVisitor.h\"\n"; + + // OS << "using namespace llvm;\n\n"; + + + FnDecs = ""; + + // for each InstrClass + + std::vector Recs = Records.getAllDerivedDefinitions("InstrClass"); + for (unsigned i = 0, e = Recs.size(); i != e; ++i) { + std::string InstrClassName = Recs[i]->getName(); + OS << "// Generate BMI instructions for " << InstrClassName << "\n\n"; + OS << "void ISel::visit"; + OS << Recs[i]->getValueAsString("FunctionName"); + OS << "(" << Recs[i]->getValueAsString("InstructionName") << " &I)\n{" << "\n"; + // for each supported InstrSubclass + + OS << spacing() << "unsigned DestReg = getReg(I);\n"; + OS << spacing() << "unsigned Op0Reg = getReg(I.getOperand(0));\n"; + OS << spacing() << "unsigned Op1Reg = getReg(I.getOperand(1));\n"; + OS << spacing() << "Value *Op0Val = I.getOperand(0);\n"; + OS << spacing() << "Value *Op1Val = I.getOperand(1);\n"; + + OS << spacing() << "MachineBasicBlock::iterator IP = BB->end();\n"; + + OS << std::endl; + + ListInit *SupportedSubclasses = Recs[i]->getValueAsListInit("Supports"); + + //OS << spacing() << InstrClassName << "Prep();" << "\n"; + //FnDecs += "void ISel::" + InstrClassName + "Prep() {\n\n}\n\n"; + + std::vector vi; + + // generate subclasses nested switch statements + InstrSubclasses(OS, InstrClassName, InstrClassName, SupportedSubclasses, vi, 0); + + //OS << spacing() << InstrClassName << "Post();\n"; + //FnDecs += "void ISel::" + InstrClassName + "Post() {\n\n}\n\n"; + + OS << "}\n"; + OS << "\n\n\n"; + + } // for each instrclass + + // OS << "} //namespace\n"; + + + #if 0 + // print out function stubs + OS << "\n\n\n//Functions\n\n" << FnDecs; + + // print out getsubclass() definitions + std::vector SubclassColRec = Records.getAllDerivedDefinitions("InstrSubclassCollection"); + for (unsigned j=0, m=SubclassColRec.getSize(); j!=m; ++j) { + std::string SubclassName = SubclassColRec[j]->getName(); + FnDecs += "unsigned ISel::get" + SubclassName + "() {\n\n"; + + ListInit* list = dynamic_cast(SubclassColRec[j].getValueAsListInit("List")); + + for (unsigned k=0; n=list.getSize(); k!=n; ++k) { + + FnDecs += "}\n\n"; + } + #endif + + } //run + + + + // find instructions that match all the subclasses (only support for 1 now) + Record* SimpleInstrSelEmitter::findInstruction(std::ostream &OS, std::string cl, std::vector& vi) { + std::vector Recs = Records.getAllDerivedDefinitions("TargInstrSet"); + + for (unsigned i = 0, e = Recs.size(); i != e; ++i) { + Record* thisClass = Recs[i]->getValueAsDef("Class"); + + if (thisClass->getName() == cl) { + + // get the Subclasses this supports + ListInit* SubclassList = Recs[i]->getValueAsListInit("List"); + + bool Match = true; + + if (SubclassList->getSize() != vi.size()) + Match = false; + + // match the instruction's supported subclasses with the subclasses we are looking for + + for (unsigned j=0, f=SubclassList->getSize(); j!=f; ++j) { + DefInit* SubclassDef = dynamic_cast(SubclassList->getElement(j)); + Record* thisSubclass = SubclassDef->getDef(); + + std::string searchingFor = vi[j]; + + if (thisSubclass->getName() != searchingFor) { + Match = false; + } + + } // for each subclass list + + if (Match == true) { return Recs[i]; } + + } //if instrclass matches + + } // for all instructions + + // if no instructions found, return NULL + return NULL; + + } //findInstruction + + + + Record* SimpleInstrSelEmitter::findRegister(std::ostream &OS, std::string regname) { + std::vector Recs = Records.getAllDerivedDefinitions("Register"); + + for (unsigned i = 0, e = Recs.size(); i != e; ++i) { + Record* thisReg = Recs[i]; + + if (thisReg->getName() == regname) return Recs[i]; + } + + return NULL; + + } + + // handle "::" and "+" etc + std::string SimpleInstrSelEmitter::formatRegister(std::ostream &OS, std::string regname) { + std::string Reg; + std::string suffix; + + int x = std::strcspn(regname.c_str(),"+-"); + + // operate on text before "+" or "-", append it back at the end + Reg = regname.substr(0,x); + suffix = regname.substr(x,regname.length()); + + unsigned int y = std::strcspn(Reg.c_str(),":"); + + if (y == Reg.length()) { // does not contain "::" + + Record* RegRec = findRegister(OS,Reg); + + assert(RegRec && "Register not found!"); + + if (RegRec->getValueAsString("Namespace") != "Virtual") { + Reg = RegRec->getValueAsString("Namespace") + "::" + RegRec->getName(); + } else { + Reg = RegRec->getName(); + } + } // regular case + + // append + or - at the end again (i.e. X86::EAX+1) + Reg = Reg + suffix; + + return Reg; + } + + + // take information in the instruction class and generate the correct BMI call + void SimpleInstrSelEmitter::generateBMIcall(std::ostream &OS, std::string MBB, std::string IP, std::string Opcode, int NumOperands, ListInit &instroperands, ListInit &operands) { + + // find Destination Register + StringInit* DestRegStr = dynamic_cast(operands.getElement(0)); + std::string DestReg = formatRegister(OS,DestRegStr->getValue()); + + OS << "BuildMI("; + OS << MBB << ", "; + OS << IP << ", "; + OS << Opcode << ", "; + OS << NumOperands; + + if (DestReg != "Pseudo") { + OS << ", " << DestReg << ")"; + } else { + OS << ")"; + } + + // handle the .add stuff + for (unsigned i=0, e=instroperands.getSize(); i!=e; ++i) { + DefInit* OpDef = dynamic_cast(instroperands.getElement(i)); + StringInit* RegStr = dynamic_cast(operands.getElement(i+1)); + + Record* Op = OpDef->getDef(); + + std::string opstr = Op->getValueAsString("Name"); + + std::string regname; + + if (opstr == "Register") { + regname = formatRegister(OS,RegStr->getValue()); + } else { + regname = RegStr->getValue(); + } + + OS << ".add" << opstr << "(" << regname << ")"; + } + + OS << ";\n"; + + } //generateBMIcall + + + std::string SimpleInstrSelEmitter::spacing() { + return globalSpacing; + } + + std::string SimpleInstrSelEmitter::addspacing() { + globalSpacing += " "; + return globalSpacing; + } + + std::string SimpleInstrSelEmitter::remspacing() { + globalSpacing = globalSpacing.substr(0,globalSpacing.length()-2); + return globalSpacing; + } + + + // recursively print out the subclasses of an instruction + // + void SimpleInstrSelEmitter::InstrSubclasses(std::ostream &OS, std::string prefix, std::string InstrClassName, ListInit* SupportedSubclasses, std::vector& vi, unsigned depth) { + + + if (depth >= SupportedSubclasses->getSize()) { + return; + } + + // get the subclass collection + + DefInit* InstrSubclassColl = dynamic_cast(SupportedSubclasses->getElement(depth)); + + Record* InstrSubclassRec = InstrSubclassColl->getDef(); + + std::string SubclassName = InstrSubclassRec->getName(); + + + if (InstrSubclassRec->getValueAsString("PreCode") != "") { + // OS << spacing() << prefix << "_" << Subclass->getName() << "_Prep();\n"; + OS << spacing() << InstrSubclassRec->getValueAsString("PreCode") << "\n\n"; + } + + + OS << spacing() << "// Looping through " << SubclassName << "\n"; + + OS << spacing() << "switch (" << SubclassName <<") {\n"; + addspacing(); + + ListInit* SubclassList = InstrSubclassRec->getValueAsListInit("List"); + + for (unsigned k=0, g = SubclassList->getSize(); k!=g; ++k) { + + DefInit* SubclassDef = dynamic_cast(SubclassList->getElement(k)); + + Record* Subclass = SubclassDef->getDef(); + + OS << spacing() << "// " << prefix << "_" << Subclass->getName() << "\n"; + OS << spacing() << "case " << Subclass->getName() << ":\n"; + addspacing(); + OS << spacing() << "{\n"; + + + vi.push_back(Subclass->getName()); + + // go down hierarchy + InstrSubclasses(OS, prefix + "_" + Subclass->getName(), InstrClassName, SupportedSubclasses, vi, depth+1); + + // find the record that matches this + Record *theInstructionSet = findInstruction(OS, InstrClassName, vi); + + // only print out the assertion if this is a leaf + if ( (theInstructionSet == NULL) && (depth == (SupportedSubclasses->getSize() - 1)) ) { + + OS << spacing() << "assert(0 && \"No instructions defined for " << InstrClassName << " instructions of subclasses " << prefix << "_" << Subclass->getName() << "!\");" << "\n"; + + } else if (theInstructionSet != NULL) { + + if (theInstructionSet->getValueAsString("PreCode") != "") { + OS << spacing() << theInstructionSet->getValueAsString("PreCode") << "\n\n"; + } + + ListInit *theInstructions = theInstructionSet->getValueAsListInit("Instructions"); + + ListInit *registerlists = theInstructionSet->getValueAsListInit("Operands"); // not necessarily registers anymore, but the name will stay for now + + for (unsigned l=0, h=theInstructions->getSize(); l!=h; ++l) { + + DefInit *theInstructionDef = dynamic_cast(theInstructions->getElement(l)); + Record *theInstruction = theInstructionDef->getDef(); + + ListInit *operands = theInstruction->getValueAsListInit("Params"); + + OS << spacing(); + + ListInit* registers = dynamic_cast(registerlists->getElement(l)); + + // handle virtual instructions here before going to generateBMIcall + + if (theInstruction->getValueAsString("Namespace") == "Virtual") { + + // create reg for different sizes + std::string Instr = theInstruction->getName(); + StringInit* DestRegInit = dynamic_cast(registers->getElement(0)); + std::string DestReg = DestRegInit->getValue(); + std::string theType; + + if (Instr == "NullInstruction") { } // do nothing + else if (Instr == "CreateRegByte") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SByteTy);\n"; + else if (Instr == "CreateRegShort") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SShortTy);\n"; + else if (Instr == "CreateRegInt") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SIntTy);\n"; + else if (Instr == "CreateRegLong") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SLongTy);\n"; + else if (Instr == "CreateRegUByte") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UByteTy);\n"; + else if (Instr == "CreateRegUShort") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UShortTy);\n"; + else if (Instr == "CreateRegUInt") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UIntTy);\n"; + else if (Instr == "CreateRegULong") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::ULongTy);\n"; + else if (Instr == "CreateRegFloat") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::FloatTy);\n"; + else if (Instr == "CreateRegDouble") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::DoubleTy);\n"; + else if (Instr == "CreateRegPointer") + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::PointerTy_;\n"; + else + OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SByteTy);\n"; // create a byte by default + + + } else { + std::string InstrName; + + if (theInstruction->getValueAsString("Namespace") != "Virtual") { + InstrName = theInstruction->getValueAsString("Namespace") + "::" + theInstruction->getValueAsString("Name"); + } else { + // shouldn't ever happen, virtual instrs should be caught before this + InstrName = theInstruction->getValueAsString("Name"); + } + + generateBMIcall(OS, "*BB","IP",InstrName,theInstruction->getValueAsInt("NumOperands"),*operands,*registers); + } + + } + + if (theInstructionSet->getValueAsString("PostCode") != "") { + OS << spacing() << theInstructionSet->getValueAsString("PostCode") << "\n\n"; + } + + } + + + + if (InstrSubclassRec->getValueAsString("PostCode") != "") { + //OS << spacing() << "// " << prefix << "_" << Subclass->getName() << "_Prep();\n"; + OS << spacing() << InstrSubclassRec->getValueAsString("PostCode") << "\n\n"; + } + + + OS << spacing() << "break;\n"; + + OS << spacing() << "}\n\n"; + + remspacing(); + + vi.pop_back(); + } + + // provide a default case for the switch + + OS << spacing() << "default:\n"; + OS << spacing() << " assert(0 && \"No instructions defined for " << InstrClassName << " instructions of subclasses " << prefix << "_" << SubclassName << "!\");" << "\n"; + OS << spacing() << " break;\n\n"; + + remspacing(); + OS << spacing() << "}\n"; + + } + + + // ret br switch invoke unwind + // add sub mul div rem setcc (eq ne lt gt le ge) + // and or xor sbl sbr + // malloc free alloca load store + // getelementptr phi cast call vanext vaarg + + } // End llvm namespace Index: llvm/utils/TableGen/SimpleInstrSelEmitter.h diff -c /dev/null llvm/utils/TableGen/SimpleInstrSelEmitter.h:1.1 *** /dev/null Tue Apr 6 14:31:42 2004 --- llvm/utils/TableGen/SimpleInstrSelEmitter.h Tue Apr 6 14:31:31 2004 *************** *** 0 **** --- 1,61 ---- + //===- SimpleInstrSelEmitter.h - Generate a Simple Instruction Selector ----*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This tablegen backend is responsible for emitting a simple instruction selector + // + // + //===----------------------------------------------------------------------===// + + #ifndef SIMPLE_INSTR_SELECTOR_EMITTER_H + #define SIMPLE_INSTR_SELECTOR_EMITTER_H + + #include "TableGenBackend.h" + #include "CodeGenWrappers.h" + #include + #include + #include + + namespace llvm { + + class Init; + class InstrSelectorEmitter; + + + /// InstrSelectorEmitter - The top-level class which coordinates construction + /// and emission of the instruction selector. + /// + class SimpleInstrSelEmitter : public TableGenBackend { + RecordKeeper &Records; + std::string globalSpacing; + + public: + SimpleInstrSelEmitter(RecordKeeper &R) : Records(R) {globalSpacing = " ";} + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); + + Record* SimpleInstrSelEmitter::findInstruction(std::ostream &OS, std::string cl, std::vector& vi); + + Record* SimpleInstrSelEmitter::findRegister(std::ostream &OS, std::string regname); + + std::string SimpleInstrSelEmitter::formatRegister(std::ostream &OS, std::string regname); + + void SimpleInstrSelEmitter::generateBMIcall(std::ostream &OS, std::string MBB, std::string IP, std::string Opcode, int NumOperands, ListInit &l, ListInit &r); + + void SimpleInstrSelEmitter::InstrSubclasses(std::ostream &OS, std::string prefix, std::string InstrClassName, ListInit* SupportedSubclasses, std::vector& vi, unsigned depth); + + std::string spacing(); + std::string addspacing(); + std::string remspacing(); + + }; + + } // End llvm namespace + + #endif From kuba at cs.uiuc.edu Tue Apr 6 14:35:03 2004 From: kuba at cs.uiuc.edu (Takahiro Kuba) Date: Tue Apr 6 14:35:03 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrSel.td X86InstrSelInfo.td Makefile X86.h X86TargetMachine.cpp Message-ID: <200404061934.OAA20327@cypher.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrSel.td added (r1.1) X86InstrSelInfo.td added (r1.1) Makefile updated: 1.15 -> 1.16 X86.h updated: 1.25 -> 1.26 X86TargetMachine.cpp updated: 1.53 -> 1.54 --- Log message: Tablgen files for really simple instruction selector --- Diffs of the changes: (+653 -2) Index: llvm/lib/Target/X86/X86InstrSel.td diff -c /dev/null llvm/lib/Target/X86/X86InstrSel.td:1.1 *** /dev/null Tue Apr 6 14:34:10 2004 --- llvm/lib/Target/X86/X86InstrSel.td Tue Apr 6 14:34:00 2004 *************** *** 0 **** --- 1,393 ---- + //===- X86InstrSel.td - Describe the X86 Instruction Selector -------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file is used by the instruction selector and is used to map + // LLVM instructions to a corresponding set of machine instructions + // + // + //===----------------------------------------------------------------------===// + + include "../Target.td" + + // ret br switch invoke unwind + // add sub mul div rem setcc (eq ne lt gt le ge) + // and or xor sbl sbr + // malloc free alloca load store + // getelementptr phi cast call vanext vaarg + + + class InstrSubclass { + int Value = v; + } + + // provide a grouping of InstrSubclasses + class InstrSubclassCollection l> { + list List = l; + string PreCode = pre; + string PostCode = post; + } + + // virtual registers + let Namespace = "Virtual" in { + def DestReg : Register; + def DestRegp1 : Register; // DestReg+1 + def Op0Reg : Register; + def Op0Regp1 : Register; // Op0Reg+1 + def Op1Reg : Register; + def Op1Regp1 : Register; // Op1Reg+1 + def TmpReg01 : Register; + def TmpReg01p1: Register; + def TmpReg02 : Register; + def TmpReg02p1: Register; + def NullReg : Register; // represents no register + } + + class InstrClass l> { + string FunctionName = fn; + string InstructionName = n; + string PreCode = pre; + string PostCode = post; + + // add lists of what subclasses this InstrClass supports + list Supports = l; + } + + + // helper class to build BMI instruction + class addedOperand { + string Name = op; + } + + def MBI_Reg : addedOperand<"Reg">; + def MBI_GlobalAddr : addedOperand<"GlobalAddr">; + def MBI_ZImm : addedOperand<"ZImm">; + + def MBI_DirectMem : addedOperand<"DirectMem">; + def MBI_RegOffset : addedOperand<"RegOffset">; + def MBI_FrameRef : addedOperand<"FrameRef">; + def MBI_ConstPoolRef : addedOperand<"ConstPoolRef">; + def MBI_CCReg : addedOperand<"CCReg">; + def MBI_RegDef : addedOperand<"RegDef">; + def MBI_PCDisp : addedOperand<"PCDisp">; + def MBI_MReg : addedOperand<"MReg">; + def MBI_SImm : addedOperand<"SImm">; + def MBI_MBB : addedOperand<"MBB">; + def MBI_FrameIndex : addedOperand<"FrameIndex">; + def MBI_ConstPoolIdx : addedOperand<"ConstPoolIdx">; + def MBI_ExternSymbol : addedOperand<"ExternSymbol">; + + + class TargInstr lops> { + + string Name = n; // make this a reference to the Instruction class + string Namespace; + int NumOperands = numops; + list Params = lops; // will this work for mem-mem instrs, destination is implicitly a register + + } //TargInstr + + + let Namespace = "Virtual" in { + // virtual instructions for creating registers + def CreateRegInt : TargInstr<"CreateRegInt",0,[]>; + def CreateRegByte : TargInstr<"CreateRegByte",0,[]>; + def CreateRegShort: TargInstr<"CreateRegShort",0,[]>; + def CreateRegLong : TargInstr<"CreateRegLong",0,[]>; + + def CreateRegUInt : TargInstr<"CreateRegUInt",0,[]>; + def CreateRegUByte : TargInstr<"CreateRegUByte",0,[]>; + def CreateRegUShort: TargInstr<"CreateRegUShort",0,[]>; + def CreateRegULong : TargInstr<"CreateRegULong",0,[]>; + + def CreateRegFloat : TargInstr<"CreateRegFloat",0,[]>; + def CreateRegDouble : TargInstr<"CreateRegDouble",0,[]>; + def CreateRegPointer: TargInstr<"CreateRegPointer",0,[]>; + + def NullInstr : TargInstr<"NullInstruction",0,[]>; // ignored + } + + class TargInstrSet l, list targs, list> r> { + InstrClass Class = c; + + list List = l; + list Instructions = targs; + list< list > Operands = r; // generalized for all operand types + + string PreCode = pre; + string PostCode = post; + } + + + + // -------------------------------------------------------------------- + // Begin architecture-specific information + // -------------------------------------------------------------------- + + include "X86RegisterInfo.td" + include "X86InstrSelInfo.td" + + + // set up the subclasses of instructions + // value is what the subclass's case value + def cByte : InstrSubclass<1>; + def cInt : InstrSubclass<2>; + def cShort : InstrSubclass<3>; + def cFP : InstrSubclass<4>; + def cLong : InstrSubclass<5>; + + def EQ : InstrSubclass<1>; + def NE : InstrSubclass<2>; + def LT : InstrSubclass<3>; + def GE : InstrSubclass<4>; + def GT : InstrSubclass<5>; + def LE : InstrSubclass<6>; + + def True : InstrSubclass<1>; + def False : InstrSubclass<0>; + + def NegOne : InstrSubclass<-1>; + def PosOne : InstrSubclass<1>; + def Cons :InstrSubclass<2>; + def Other : InstrSubclass<0>; + + def Regular: InstrSubclass<0>; + def Zero : InstrSubclass<0>; + + def NoOps : InstrSubclass<0>; + def Ops : InstrSubclass<1>; + + def Signed : InstrSubclass<0>; + def Unsigned : InstrSubclass<1>; + + def SuccessorIsNextBB : InstrSubclass<0>; + def SuccessorIsNotNextBB: InstrSubclass<1>; + + def Cond: InstrSubclass<0>; + def Uncond: InstrSubclass<1>; + + def ConstTwo: InstrSubclass<2>; + def ConstNotTwo: InstrSubclass<3>; + + def Reg: InstrSubclass<6>; + + + // group subclasses, specify how to determine instruction subclass + def OperandSize: InstrSubclassCollection<"unsigned OperandSize = getClassB(Op0Val->getType());","", [cByte, cShort, cInt, cFP, cLong]>; + def Conditional: InstrSubclassCollection<"unsigned Conditional;", "", [EQ, NE, LT, GE, GT, LE]>; + def SpecialCase: InstrSubclassCollection<"unsigned SpecialCase;", "", [True, False]>; + + //TODO write funcs for separating out special cases + def AddSpecialCases: InstrSubclassCollection<"Subclasses AddSpecialCases = Other;", "", [NegOne,PosOne,Cons,Other]>; + def SubSpecialCases: InstrSubclassCollection<"unsigned SubSpecialCases = Other;", "", [NegOne,PosOne,Cons,Other]>; + def XorSpecialCases: InstrSubclassCollection<"unsigned XorSpecialCases = Other;","", [NegOne,Other]>; + + + + // Instruction subclasses, as defined in llvm/Instructions.h: + // iTerminators.h : ReturnInst, BranchInst, SwitchInst, InvokeInst, UnwindInst + // iPHINode.h : PHINode, + // iOperators.h : SetCondInst, + // iMemory.h : AllocationInst, MallocInst, AllocaInst, FreeInst, LoadInst, StoreInst, GetElementPtrInst, + // iOther.h : CastInst, CallInst, ShiftInst, VANextInst, VAArgInst, + // InstrTypes.h : TerminatorInst, BinaryOperator + + // general classes of LLVM instructions, and the subclass sets that apply to them + def add : InstrClass<"BinaryOperator","Add","","",[AddSpecialCases, OperandSize]>; + def sub : InstrClass<"BinaryOperator","Sub","","",[SubSpecialCases, OperandSize]>; + // def mul : InstrClass<"BinaryOperator","Mul","","",[OperandSize]>; + // def div : InstrClass<"BinaryOperator","Div","","",[OperandSize]>; + // def rem : InstrClass<"BinaryOperator","Rem","","",[OperandSize]>; + def logic_and : InstrClass<"BinaryOperator","And","","",[OperandSize]>; + def logic_or : InstrClass<"BinaryOperator","Or","","",[OperandSize]>; + def logic_xor : InstrClass<"BinaryOperator","Xor","","",[XorSpecialCases, OperandSize]>; + // //def mov : InstrClass<"ShiftInst","Mov","","",[OperandSize]>; + + // def setcc: InstrClass<"SetCondInst","SetCondInst","","",[OperandSize]>; + // def branch : InstrClass<"BranchInst","BranchInst","","",[Conditional]>; + + // def retrn : InstrClass<"ReturnInst","ReturnInst","","",[]>; + + // definition of machine instructions for instruction subclasses + + + // ADD + + def ADD_Other_cByte : TargInstrSet; + def ADD_Other_cShort : TargInstrSet; + def ADD_Other_cInt : TargInstrSet; + def ADD_Other_cLong : TargInstrSet; + def ADD_Other_cFP : TargInstrSet; + def ADD_Constant_cByte : TargInstrSet; + def ADD_Constant_cShort :TargInstrSet; + def ADD_Constant_cInt :TargInstrSet; + def ADD_PosOne_cByte : TargInstrSet; + def ADD_PosOne_cShort : TargInstrSet; + def ADD_PosOne_cInt : TargInstrSet; + def ADD_NegOne_cByte : TargInstrSet; + def ADD_NegOne_cShort : TargInstrSet; + def ADD_NegOne_cInt : TargInstrSet; + + + // SUBTRACT + + def SUB_Other_cByte : TargInstrSet; + def SUB_Other_cShort : TargInstrSet; + def SUB_Other_cInt : TargInstrSet; + def SUB_Other_cLong : TargInstrSet; + def SUB_Other_cFP : TargInstrSet; + def SUB_Constant_cByte : TargInstrSet; + def SUB_Constant_cShort :TargInstrSet; + def SUB_Constant_cInt :TargInstrSet; + def SUB_PosOne_cByte : TargInstrSet; + def SUB_PosOne_cShort : TargInstrSet; + def SUB_PosOne_cInt : TargInstrSet; + def SUB_NegOne_cByte : TargInstrSet; + def SUB_NegOne_cShort : TargInstrSet; + def SUB_NegOne_cInt : TargInstrSet; + + + // def SHIFT_S_L_Const_Byte : + // def SHIFT_S_L_Const_Short : + // def SHIFT_S_L_Const_Int : + // def SHIFT_S_L_Const_SHLDIR32 : + // def SHIFT_S_L_Reg_Byte : + // def SHIFT_S_L_Reg_Short : + // def SHIFT_S_L_Reg_Int : + // def SHIFT_S_R_Const_Byte : + // def SHIFT_S_R_Const_Short : + // def SHIFT_S_R_Const_Int : + // def SHIFT_S_R_Const_SHRDIR32 : + // def SHIFT_S_R_Reg_Byte : + // def SHIFT_S_R_Reg_Short : + // def SHIFT_S_R_Reg_Int : + // def SHIFT_U_L_Const_Byte : + // def SHIFT_U_L_Const_Short : + // def SHIFT_U_L_Const_Int : + // def SHIFT_U_L_Const_SHLDIR32 : + // def SHIFT_U_L_Reg_Byte : + // def SHIFT_U_L_Reg_Short : + // def SHIFT_U_L_Reg_Int : + // def SHIFT_U_R_Const_Byte : + // def SHIFT_U_R_Const_Short : + // def SHIFT_U_R_Const_Int : + // def SHIFT_U_R_Const_SHRDIR32 : + // def SHIFT_U_R_Reg_Byte : + // def SHIFT_U_R_Reg_Short : + // def SHIFT_U_R_Reg_Int : + + + // def CMP_i_Byte : TargInstrSet; + // def CMP_i_Short : TargInstrSet; + // def CMP_i_Int : TargInstrSet; + // //def CMP_i_Long : // not supported + // def CMP_z_Byte : TargInstrSet(Op1); uint64_t Op1v = cast(CI)->getRawValue(); Op1v &= (1ULL << (8 << Class)) - 1;","",[Zero,cByte],[TESTrr8],[["DestReg","Op0Reg","Op0Reg"]]>; + // def CMP_z_Short : TargInstrSet(Op1); uint64_t Op1v = cast(CI)->getRawValue(); Op1v &= (1ULL << (8 << Class)) - 1;","",[Zero,cShort],[TESTrr16],[["DestReg","Op0Reg","Op0Reg"]]>; + // def CMP_z_Int : TargInstrSet(Op1); uint64_t Op1v = cast(CI)->getRawValue(); Op1v &= (1ULL << (8 << Class)) - 1;","",[Zero,cInt],[TESTrr32],[["DestReg","Op0Reg","Op0Reg"]]>; + // //def CMP_z_Long : // not supported + // def CMP_r_Byte : TargInstrSet; + // def CMP_r_Short : TargInstrSet; + // def CMP_r_Int : TargInstrSet; + // //def CMP_r_Long : // two cases of long, depending on num of operands + // def CMP_r_FP : TargInstrSet; + + + // def RET_NoOps : TargInstrSet; + // def RET_Op_Byte : TargInstrSetgetType()));","",[Ops,cByte],[IMPLICIT_USE],[["NullReg","EAX","ESP"]]>; + // def RET_Op_Short : TargInstrSetgetType()));","",[Ops,cShort],[IMPLICIT_USE],[["NullReg","EAX","ESP"]]>; + // def RET_Op_Int : TargInstrSetgetType()));","",[Ops,cInt],[IMPLICIT_USE],[["NullReg","EAX","ESP"]]>; + // def RET_Op_FP : TargInstrSet; + // def RET_Op_Long : TargInstrSet; + + + // def BR_Uncond : TargInstrSet; + // def BR_Cond_S_EQ : + // def BR_Cond_S_NE + // def BR_Cond_S_B + // def BR_Cond_S_AE + // def BR_Cond_S_A + // def BR_Cond_S_BE + // def BR_Cond_U_EQ + // def BR_Cond_U_NE + // def BR_Cond_U_LT + // def BR_Cond_U_GE + // def BR_Cond_U_GT + // def BR_Cond_U_LE + // def BR_Cond_U_S + // def BR_Cond_U_NS + + + // def CALL_Byte + // def CALL_Short + // def CALL_Int + // def CALL_Long + // def CALL_FP + + + def AND_Byte : TargInstrSet; + def AND_Short : TargInstrSet; + def AND_Int : TargInstrSet; + def AND_Long : TargInstrSet; + + + def OR_Byte : TargInstrSet; + def OR_Short : TargInstrSet; + def OR_Int : TargInstrSet; + def OR_Long : TargInstrSet; + + + def XOR_NegOne_Byte : TargInstrSet; + def XOR_NegOne_Short: TargInstrSet; + def XOR_NegOne_Int : TargInstrSet; + //def XOR_NegOne_Long : // not supported (treat as regular long XOR) + def XOR_Other_Byte : TargInstrSet; + def XOR_Other_Short : TargInstrSet; + def XOR_Other_Int : TargInstrSet; + def XOR_Other_Long : TargInstrSet; + + + + // // TODO support for arbitrary values as operand arguments + // // or make ConstantInt versions as well-known variables + // // ConstantInt, unsigned Val + // def MUL_ConstTwo_Byte : TargInstrSet(I.getOperand(1)); unsigned Val = (unsigned)CI->getRawValue(); unsigned Shift = ExactLog2(Val);","",[ConstTwo,cByte],[SHLir32],[["DestReg","Op0Reg","Shift-1"]]>; + // def MUL_ConstTwo_Short : TargInstrSet(I.getOperand(1)); unsigned Val = (unsigned)CI->getRawValue(); unsigned Shift = ExactLog2(Val);","",[ConstTwo,cShort],[SHLir32],[["DestReg","Op0Reg","Shift-1"]]>; + // def MUL_ConstTwo_Int : TargInstrSet(I.getOperand(1)); unsigned Val = (unsigned)CI->getRawValue(); unsigned Shift = ExactLog2(Val);","",[ConstTwo,cInt],[SHLir32],[["DestReg","Op0Reg","Shift-1"]]>; + // def MUL_ConstNotTwo_Byte : TargInstrSet; //TODO fixme, define ConstRHS + // def MUL_ConstNotTwo_Short : TargInstrSet; + // def MUL_ConstNotTwo_Int : TargInstrSet; + // //def MUL_ConstNotTwo_Long : + // //def MUL_ConstNotTwo_FP : + // def MUL_Reg_Byte : TargInstrSet; + // def MUL_Reg_Short : TargInstrSet; + // def MUL_Reg_Int : TargInstrSet; + // //def MUL_Reg_Long : // not supported (assert) + // def MUL_Reg_FP : TargInstrSet; + + // def STO_Byte + // def STO_Short + // def STO_Int + // def STO_FP + // def STO_Long + + + // DIVREM + + // CAST + + // PHI + + // LOAD ARGS TO VIRTUAL REGS + + // COPY CONSTANT + + //TODO + // handling various operand options + // allowing for arbitrary code or operand arguments + // generate skeletons for selector function + // Index: llvm/lib/Target/X86/X86InstrSelInfo.td diff -c /dev/null llvm/lib/Target/X86/X86InstrSelInfo.td:1.1 *** /dev/null Tue Apr 6 14:34:10 2004 --- llvm/lib/Target/X86/X86InstrSelInfo.td Tue Apr 6 14:34:00 2004 *************** *** 0 **** --- 1,241 ---- + + let Namespace = "X86" in { + + // def PHI : TargInstr<"PHI", 2, [MBI_Reg, MBI_Reg]>; + // def NOOP : TargInstr<"NOOP", 2, [MBI_Reg, MBI_Reg]>; + // def ADJCALLSTACKDOWN : TargInstr<"ADJCALLSTACKDOWN", 2, [MBI_Reg, MBI_Reg]>; + // def ADJCALLSTACKUP : TargInstr<"ADJCALLSTACKUP", 2, [MBI_Reg, MBI_Reg]>; + def IMPLICIT_USE : TargInstr<"IMPLICIT_USE", 2, [MBI_Reg, MBI_Reg]>; + def IMPLICIT_DEF : TargInstr<"IMPLICIT_DEF", 0, []>; + + def RET : TargInstr<"RET", 0, []>; + def JMP : TargInstr<"JMP", 1, [MBI_PCDisp]>; + // def JB : TargInstr<"JB", 2, [MBI_Reg, MBI_Reg]>; + // def JAE : TargInstr<"JAE", 2, [MBI_Reg, MBI_Reg]>; + // def JE : TargInstr<"JE", 2, [MBI_Reg, MBI_Reg]>; + // def JNE : TargInstr<"JNE", 2, [MBI_Reg, MBI_Reg]>; + // def JBE : TargInstr<"JBE", 2, [MBI_Reg, MBI_Reg]>; + // def JA : TargInstr<"JA", 2, [MBI_Reg, MBI_Reg]>; + // def JS : TargInstr<"JS", 2, [MBI_Reg, MBI_Reg]>; + // def JNS : TargInstr<"JNS", 2, [MBI_Reg, MBI_Reg]>; + // def JL : TargInstr<"JL", 2, [MBI_Reg, MBI_Reg]>; + // def JGE : TargInstr<"JGE", 2, [MBI_Reg, MBI_Reg]>; + // def JLE : TargInstr<"JLE", 2, [MBI_Reg, MBI_Reg]>; + // def JG : TargInstr<"JG", 2, [MBI_Reg, MBI_Reg]>; + // def LEAVE : TargInstr<"LEAVE", 2, [MBI_Reg, MBI_Reg]>; + // def BSWAPr32 : TargInstr<"BSWAPr32", 2, [MBI_Reg, MBI_Reg]>; + // def XCHGrr8 : TargInstr<"XCHGrr8", 2, [MBI_Reg, MBI_Reg]>; + // def XCHGrr16 : TargInstr<"XCHGrr16", 2, [MBI_Reg, MBI_Reg]>; + // def XCHGrr32 : TargInstr<"XCHGrr32", 2, [MBI_Reg, MBI_Reg]>; + // def LEAr16 : TargInstr<"LEAr16", 2, [MBI_Reg, MBI_Reg]>; + // def LEAr32 : TargInstr<"LEAr32", 2, [MBI_Reg, MBI_Reg]>; + def MOVrr8 : TargInstr<"MOV8rr", 1, [MBI_Reg]>; + def MOVrr16 : TargInstr<"MOV16rr", 1, [MBI_Reg]>; + def MOVrr32 : TargInstr<"MOV32rr", 1, [MBI_Reg]>; + def MOVir8 : TargInstr<"MOV8ir", 1, [MBI_ZImm]>; + def MOVir16 : TargInstr<"MOV16ir", 1, [MBI_ZImm]>; + def MOVir32 : TargInstr<"MOV32ir", 1, [MBI_ZImm]>; + // def MOVim8 : TargInstr<"MOVim8", 2, [MBI_Reg, MBI_ZImm]>; + // def MOVim16 : TargInstr<"MOVim16", 2, [MBI_Reg, MBI_ZImm]>; + // def MOVim32 : TargInstr<"MOVim32", 2, [MBI_Reg, MBI_ZImm]>; + def MOVmr8 : TargInstr<"MOV8mr", 4, [MBI_FrameRef]>; + def MOVmr16 : TargInstr<"MOV16mr", 4, [MBI_FrameRef]>; + def MOVmr32 : TargInstr<"MOV32mr", 4, [MBI_FrameRef]>; + def MOVrm8 : TargInstr<"MOV8rm", 5, [MBI_FrameRef, MBI_Reg]>; // 5 Operands?, stores to NULL + def MOVrm16 : TargInstr<"MOV16rm", 5, [MBI_FrameRef, MBI_Reg]>; // 5 Operands?, stores to NULL + def MOVrm32 : TargInstr<"MOV32rm", 5, [MBI_FrameRef, MBI_Reg]>; // 5 Operands?, stores to NULL + def MULr8 : TargInstr<"MUL8r", 1, [MBI_Reg]>; + // def MULr16 : TargInstr<"MULr16", 2, [MBI_Reg, MBI_Reg]>; + // def MULr32 : TargInstr<"MULr32", 2, [MBI_Reg, MBI_Reg]>; + def DIVr8 : TargInstr<"DIV8r", 1, [MBI_Reg]>; // "DestReg" as arg, "1" as the dest + def DIVr16 : TargInstr<"DIV16r", 1, [MBI_Reg]>; + def DIVr32 : TargInstr<"DIV32r", 1, [MBI_Reg]>; + def IDIVr8 : TargInstr<"IDIV8r", 1, [MBI_Reg]>; + def IDIVr16 : TargInstr<"IDIV16r", 1, [MBI_Reg]>; + def IDIVr32 : TargInstr<"IDIV32r", 1, [MBI_Reg]>; + // def CBW : TargInstr<"CBW", 2, [MBI_Reg, MBI_Reg]>; + // def CWD : TargInstr<"CWD", 2, [MBI_Reg, MBI_Reg]>; + // def CDQ : TargInstr<"CDQ", 2, [MBI_Reg, MBI_Reg]>; + + def NEGr8 : TargInstr<"NEG8r", 1, [MBI_Reg]>; + def NEGr16 : TargInstr<"NEG16r", 1, [MBI_Reg]>; + def NEGr32 : TargInstr<"NEG32r", 1, [MBI_Reg]>; + def NOTr8 : TargInstr<"NOT8r", 1, [MBI_Reg]>; + def NOTr16 : TargInstr<"NOT16r", 1, [MBI_Reg]>; + def NOTr32 : TargInstr<"NOT32r", 1, [MBI_Reg]>; + def INCr8 : TargInstr<"INC8r", 1, [MBI_Reg]>; + def INCr16 : TargInstr<"INC16r", 1, [MBI_Reg]>; + def INCr32 : TargInstr<"INC32r", 1, [MBI_Reg]>; + def DECr8 : TargInstr<"DEC8r", 1, [MBI_Reg]>; + def DECr16 : TargInstr<"DEC16r", 1, [MBI_Reg]>; + def DECr32 : TargInstr<"DEC32r", 1, [MBI_Reg]>; + + def ADDrr8 : TargInstr<"ADD8rr", 2, [MBI_Reg, MBI_Reg]>; + def ADDrr16 : TargInstr<"ADD16rr", 2, [MBI_Reg, MBI_Reg]>; + def ADDrr32 : TargInstr<"ADD32rr", 2, [MBI_Reg, MBI_Reg]>; + def ADDri8 : TargInstr<"ADD8ri", 2, [MBI_Reg, MBI_ZImm]>; + def ADDri16 : TargInstr<"ADD16ri", 2, [MBI_Reg, MBI_ZImm]>; + def ADDri32 : TargInstr<"ADD32ri", 2, [MBI_Reg, MBI_ZImm]>; + def ADDri16b : TargInstr<"ADD16bri", 2, [MBI_Reg, MBI_ZImm]>; + def ADDri32b : TargInstr<"ADD32bri", 2, [MBI_Reg, MBI_ZImm]>; + def ADCrr32 : TargInstr<"ADC32rr", 2, [MBI_Reg, MBI_Reg]>; + def SUBrr8 : TargInstr<"SUB8rr", 2, [MBI_Reg, MBI_Reg]>; + def SUBrr16 : TargInstr<"SUB16rr", 2, [MBI_Reg, MBI_Reg]>; + def SUBrr32 : TargInstr<"SUB32rr", 2, [MBI_Reg, MBI_Reg]>; + def SUBri8 : TargInstr<"SUB8ri", 2, [MBI_Reg, MBI_ZImm]>; + def SUBri16 : TargInstr<"SUB16ri", 2, [MBI_Reg, MBI_ZImm]>; + def SUBri32 : TargInstr<"SUB32ri", 2, [MBI_Reg, MBI_ZImm]>; + def SUBri16b : TargInstr<"SUB16bri", 2, [MBI_Reg, MBI_ZImm]>; + def SUBri32b : TargInstr<"SUB32bri", 2, [MBI_Reg, MBI_ZImm]>; + def SBBrr32 : TargInstr<"SBB32rr", 2, [MBI_Reg, MBI_Reg]>; + def IMULrr16 : TargInstr<"IMUL16rr", 2, [MBI_Reg, MBI_Reg]>; + def IMULrr32 : TargInstr<"IMUL32rr", 2, [MBI_Reg, MBI_Reg]>; + def IMULri16 : TargInstr<"IMUL16ri", 2, [MBI_Reg, MBI_ZImm]>; + def IMULri32 : TargInstr<"IMUL32ri", 2, [MBI_Reg, MBI_ZImm]>; + def IMULri16b : TargInstr<"IMUL16bri", 2, [MBI_Reg, MBI_ZImm]>; + def IMULri32b : TargInstr<"IMUL32bri", 2, [MBI_Reg, MBI_ZImm]>; + + def ANDrr8 : TargInstr<"AND8rr", 2, [MBI_Reg, MBI_Reg]>; + def ANDrr16 : TargInstr<"AND16rr", 2, [MBI_Reg, MBI_Reg]>; + def ANDrr32 : TargInstr<"AND32rr", 2, [MBI_Reg, MBI_Reg]>; + def ANDri8 : TargInstr<"AND8ri", 2, [MBI_Reg, MBI_ZImm]>; + def ANDri16 : TargInstr<"AND16ri", 2, [MBI_Reg, MBI_ZImm]>; + def ANDri32 : TargInstr<"AND32ri", 2, [MBI_Reg, MBI_ZImm]>; + def ANDri16b : TargInstr<"AND16bri", 2, [MBI_Reg, MBI_ZImm]>; + def ANDri32b : TargInstr<"AND32bri", 2, [MBI_Reg, MBI_ZImm]>; + def ORrr8 : TargInstr<"OR8rr", 2, [MBI_Reg, MBI_Reg]>; + def ORrr16 : TargInstr<"OR16rr", 2, [MBI_Reg, MBI_Reg]>; + def ORrr32 : TargInstr<"OR32rr", 2, [MBI_Reg, MBI_Reg]>; + def ORri8 : TargInstr<"OR8ri", 2, [MBI_Reg, MBI_ZImm]>; + def ORri16 : TargInstr<"OR16ri", 2, [MBI_Reg, MBI_ZImm]>; + def ORri32 : TargInstr<"OR32ri", 2, [MBI_Reg, MBI_ZImm]>; + def ORri16b : TargInstr<"OR16bri", 2, [MBI_Reg, MBI_ZImm]>; + def ORri32b : TargInstr<"OR32bri", 2, [MBI_Reg, MBI_ZImm]>; + def XORrr8 : TargInstr<"XOR8rr", 2, [MBI_Reg, MBI_Reg]>; + def XORrr16 : TargInstr<"XOR16rr", 2, [MBI_Reg, MBI_Reg]>; + def XORrr32 : TargInstr<"XOR32rr", 2, [MBI_Reg, MBI_Reg]>; + def XORri8 : TargInstr<"XOR8ri", 2, [MBI_Reg, MBI_ZImm]>; + def XORri16 : TargInstr<"XOR16ri", 2, [MBI_Reg, MBI_ZImm]>; + def XORri32 : TargInstr<"XOR32ri", 2, [MBI_Reg, MBI_ZImm]>; + def XORri16b : TargInstr<"XOR16bri", 2, [MBI_Reg, MBI_ZImm]>; + def XORri32b : TargInstr<"XOR32bri", 2, [MBI_Reg, MBI_ZImm]>; + + def TESTrr8 : TargInstr<"TEST8rr", 2, [MBI_Reg, MBI_Reg]>; + def TESTrr16 : TargInstr<"TEST16rr", 2, [MBI_Reg, MBI_Reg]>; + def TESTrr32 : TargInstr<"TEST32rr", 2, [MBI_Reg, MBI_Reg]>; + def TESTri8 : TargInstr<"TEST8ri", 2, [MBI_Reg, MBI_ZImm]>; + def TESTri16 : TargInstr<"TEST16ri", 2, [MBI_Reg, MBI_ZImm]>; + def TESTri32 : TargInstr<"TEST32ri", 2, [MBI_Reg, MBI_ZImm]>; + + def SHLrr8 : TargInstr<"SHL8rr", 1, [MBI_Reg]>; + def SHLrr16 : TargInstr<"SHL16rr", 1, [MBI_Reg]>; + def SHLrr32 : TargInstr<"SHL32rr", 1, [MBI_Reg]>; + def SHLir8 : TargInstr<"SHL8ir", 2, [MBI_Reg, MBI_ZImm]>; + def SHLir16 : TargInstr<"SHL16ir", 2, [MBI_Reg, MBI_ZImm]>; + def SHLir32 : TargInstr<"SHL32ir", 2, [MBI_Reg, MBI_ZImm]>; + def SHRrr8 : TargInstr<"SHR8rr", 1, [MBI_Reg]>; + def SHRrr16 : TargInstr<"SHR16rr", 1, [MBI_Reg]>; + def SHRrr32 : TargInstr<"SHR32rr", 1, [MBI_Reg]>; + def SHRir8 : TargInstr<"SHR8ir", 2, [MBI_Reg, MBI_ZImm]>; + def SHRir16 : TargInstr<"SHR16ir", 2, [MBI_Reg, MBI_ZImm]>; + def SHRir32 : TargInstr<"SHR32ir", 2, [MBI_Reg, MBI_ZImm]>; + def SARrr8 : TargInstr<"SAR8rr", 1, [MBI_Reg]>; + def SARrr16 : TargInstr<"SAR16rr", 1, [MBI_Reg]>; + def SARrr32 : TargInstr<"SAR32rr", 1, [MBI_Reg]>; + def SARir8 : TargInstr<"SAR8ir", 2, [MBI_Reg, MBI_ZImm]>; + def SARir16 : TargInstr<"SAR16ir", 2, [MBI_Reg, MBI_ZImm]>; + def SARir32 : TargInstr<"SAR32ir", 2, [MBI_Reg, MBI_ZImm]>; + + def SHLDrr32 : TargInstr<"SHLD32rr", 2, [MBI_Reg, MBI_Reg]>; + def SHLDir32 : TargInstr<"SHLD32ir", 3, [MBI_Reg, MBI_Reg, MBI_ZImm]>; + def SHRDrr32 : TargInstr<"SHRD32rr", 2, [MBI_Reg, MBI_Reg]>; + def SHRDir32 : TargInstr<"SHRD32ir", 3, [MBI_Reg, MBI_Reg, MBI_ZImm]>; + + def SAHF : TargInstr<"SAHF", 0, []>; // store in "1" ? + // def SETBr : TargInstr<"SETBr", 2, [MBI_Reg, MBI_Reg]>; + // def SETAEr : TargInstr<"SETAEr", 2, [MBI_Reg, MBI_Reg]>; + // def SETEr : TargInstr<"SETEr", 2, [MBI_Reg, MBI_Reg]>; + def SETNEr : TargInstr<"SETNEr", 0, []>; + // def SETBEr : TargInstr<"SETBEr", 2, [MBI_Reg, MBI_Reg]>; + // def SETAr : TargInstr<"SETAr", 2, [MBI_Reg, MBI_Reg]>; + // def SETSr : TargInstr<"SETSr", 2, [MBI_Reg, MBI_Reg]>; + // def SETNSr : TargInstr<"SETNSr", 2, [MBI_Reg, MBI_Reg]>; + // def SETLr : TargInstr<"SETLr", 2, [MBI_Reg, MBI_Reg]>; + // def SETGEr : TargInstr<"SETGEr", 2, [MBI_Reg, MBI_Reg]>; + // def SETLEr : TargInstr<"SETLEr", 2, [MBI_Reg, MBI_Reg]>; + // def SETGr : TargInstr<"SETGr", 2, [MBI_Reg, MBI_Reg]>; + def CMOVErr16 : TargInstr<"CMOVE16rr", 2, [MBI_Reg, MBI_Reg]>; + def CMOVNErr32: TargInstr<"CMOVNE32rr", 2, [MBI_Reg, MBI_Reg]>; + + def CMPrr8 : TargInstr<"CMP8rr", 2, [MBI_Reg, MBI_Reg]>; + def CMPrr16 : TargInstr<"CMP16rr", 2, [MBI_Reg, MBI_Reg]>; + def CMPrr32 : TargInstr<"CMP32rr", 2, [MBI_Reg, MBI_Reg]>; + def CMPri8 : TargInstr<"CMP8ri", 2, [MBI_Reg, MBI_ZImm]>; + def CMPri16 : TargInstr<"CMP16ri", 2, [MBI_Reg, MBI_ZImm]>; + def CMPri32 : TargInstr<"CMP32ri", 2, [MBI_Reg, MBI_ZImm]>; + + def MOVSXr16r8 : TargInstr<"MOVSX16rr8", 1, [MBI_Reg]>; + def MOVSXr32r8 : TargInstr<"MOVSX32rr8", 1, [MBI_Reg]>; + def MOVSXr32r16: TargInstr<"MOVSX32rr16", 1, [MBI_Reg]>; + def MOVZXr16r8 : TargInstr<"MOVZX16rr8", 1, [MBI_Reg]>; + def MOVZXr32r8 : TargInstr<"MOVZX32rr8", 1, [MBI_Reg]>; + def MOVZXr32r16: TargInstr<"MOVZX32rr16", 1, [MBI_Reg]>; + + def FP_REG_KILL : TargInstr<"FP_REG_KILL",0, []>; + + def FpMOV : TargInstr<"FpMOV", 1, [MBI_Reg]>; + def FpADD : TargInstr<"FpADD", 2, [MBI_Reg, MBI_Reg]>; + def FpSUB : TargInstr<"FpSUB", 2, [MBI_Reg, MBI_Reg]>; + def FpMUL : TargInstr<"FpMUL", 2, [MBI_Reg, MBI_Reg]>; + def FpDIV : TargInstr<"FpDIV", 2, [MBI_Reg, MBI_Reg]>; + def FpUCOM : TargInstr<"FpUCOM", 2, [MBI_Reg, MBI_Reg]>; + // def FpGETRESULT : TargInstr<"FpGETRESULT", 2, [MBI_Reg, MBI_Reg]>; + def FpSETRESULT : TargInstr<"FpSETRESULT", 1, [MBI_Reg]>; + // def FLDrr : TargInstr<"FLDrr", 2, [MBI_Reg, MBI_Reg]>; + def FLDr32 : TargInstr<"FLD32r", 1, [MBI_ConstPoolRef]>; // MBI_FrameRef also? instructions can be passed different operands + def FLDr64 : TargInstr<"FLD64r", 1, [MBI_ConstPoolRef]>; + // def FLDr80 : TargInstr<"FLDr80", 2, [MBI_Reg, MBI_Reg]>; + def FILDr16 : TargInstr<"FILD16r", 5, [MBI_FrameRef]>; + def FILDr32 : TargInstr<"FILD32r", 5, [MBI_FrameRef]>; + def FILDr64 : TargInstr<"FILD64r", 5, [MBI_FrameRef]>; + def FSTr32 : TargInstr<"FST32r", 5, [MBI_FrameRef, MBI_Reg]>; // ? + // def FSTr64 : TargInstr<"FST64r", 2, [MBI_Reg, MBI_Reg]>; + // def FSTPr32 : TargInstr<"FSTP32r", 2, [MBI_Reg, MBI_Reg]>; + // def FSTPr64 : TargInstr<"FSTP64r", 2, [MBI_Reg, MBI_Reg]>; + // def FSTPr80 : TargInstr<"FSTP80r", 2, [MBI_Reg, MBI_Reg]>; + // def FSTrr : TargInstr<"FSTrr", 2, [MBI_Reg, MBI_Reg]>; + // def FSTPrr : TargInstr<"FSTPrr", 2, [MBI_Reg, MBI_Reg]>; + def FISTr16 : TargInstr<"FIST16r", 5, [MBI_FrameRef, MBI_Reg]>; + def FISTr32 : TargInstr<"FIST32r", 5, [MBI_FrameRef, MBI_Reg]>; + // def FISTPr16 : TargInstr<"FISTP16r", 2, [MBI_Reg, MBI_Reg]>; + // def FISTPr32 : TargInstr<"FISTP32r", 2, [MBI_Reg, MBI_Reg]>; + def FISTPr64 : TargInstr<"FISTP64r", 5, [MBI_FrameRef, MBI_Reg]>; + // def FXCH : TargInstr<"FXCH", 2, [MBI_Reg, MBI_Reg]>; + def FLD0 : TargInstr<"FLD0", 0, []>; + def FLD1 : TargInstr<"FLD1", 0, []>; + // def FADDST0r : TargInstr<"FADDST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FADDrST0 : TargInstr<"FADDrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FADDPrST0 : TargInstr<"FADDPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBRST0r : TargInstr<"FSUBRST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBrST0 : TargInstr<"FSUBrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBPrST0 : TargInstr<"FSUBPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBST0r : TargInstr<"FSUBST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBRrST0 : TargInstr<"FSUBRrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FSUBRPrST0 : TargInstr<"FSUBRPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FMULST0r : TargInstr<"FMULST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FMULrST0 : TargInstr<"FMULrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FMULPrST0 : TargInstr<"FMULPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVRST0r : TargInstr<"FDIVRST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVrST0 : TargInstr<"FDIVrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVPrST0 : TargInstr<"FDIVPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVST0r : TargInstr<"FDIVST0r", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVRrST0 : TargInstr<"FDIVRrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FDIVRPrST0 : TargInstr<"FDIVRPrST0", 2, [MBI_Reg, MBI_Reg]>; + // def FUCOMr : TargInstr<"FUCOMr", 2, [MBI_Reg, MBI_Reg]>; + // def FUCOMPr : TargInstr<"FUCOMPr", 2, [MBI_Reg, MBI_Reg]>; + // def FUCOMPPr : TargInstr<"FUCOMPPr", 2, [MBI_Reg, MBI_Reg]>; + def FNSTSWr8 : TargInstr<"FNSTSWr8", 0, []>; // store in "0" ? + // def FNSTCWm16 : TargInstr<"FNSTCWm16", 2, [MBI_Reg, MBI_Reg]>; + def FLDCWm16 : TargInstr<"FLDCWm16", 4, [MBI_FrameRef]>; + + } //namespace Index: llvm/lib/Target/X86/Makefile diff -u llvm/lib/Target/X86/Makefile:1.15 llvm/lib/Target/X86/Makefile:1.16 --- llvm/lib/Target/X86/Makefile:1.15 Thu Nov 6 18:34:33 2003 +++ llvm/lib/Target/X86/Makefile Tue Apr 6 14:33:59 2004 @@ -13,7 +13,8 @@ # Make sure that tblgen is run, first thing. $(SourceDepend): X86GenRegisterInfo.h.inc X86GenRegisterNames.inc \ X86GenRegisterInfo.inc X86GenInstrNames.inc \ - X86GenInstrInfo.inc X86GenInstrSelector.inc + X86GenInstrInfo.inc X86GenSimpInstrSelector.inc \ + X86GenInstrSelector.inc X86GenRegisterNames.inc:: $(SourceDir)/X86.td $(SourceDir)/X86RegisterInfo.td \ $(SourceDir)/../Target.td $(TBLGEN) @@ -40,10 +41,16 @@ @echo "Building X86.td instruction information with tblgen" $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-desc -o $@ +X86GenSimpInstrSelector.inc:: $(SourceDir)/X86InstrSel.td $(TBLGEN) + @echo "Building X86.td simple instruction selector with tblgen" + $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-simp-instr-sel -o $@ + X86GenInstrSelector.inc:: $(SourceDir)/X86.td $(SourceDir)/X86InstrInfo.td \ $(SourceDir)/../Target.td $(TBLGEN) @echo "Building X86.td instruction selector with tblgen" $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-selector -o $@ + + clean:: $(VERB) rm -f *.inc Index: llvm/lib/Target/X86/X86.h diff -u llvm/lib/Target/X86/X86.h:1.25 llvm/lib/Target/X86/X86.h:1.26 --- llvm/lib/Target/X86/X86.h:1.25 Sun Dec 28 15:23:38 2003 +++ llvm/lib/Target/X86/X86.h Tue Apr 6 14:33:59 2004 @@ -29,6 +29,12 @@ /// FunctionPass *createX86SimpleInstructionSelector(TargetMachine &TM); +/// createX86ReallySimpleInstructionSelector - This pass converts an LLVM +/// function into a machine code representation in an even simpler fashion +/// than above. +/// +FunctionPass *createX86ReallySimpleInstructionSelector(TargetMachine &TM); + /// createX86PatternInstructionSelector - This pass converts an LLVM function /// into a machine code representation using pattern matching and a machine /// description file. Index: llvm/lib/Target/X86/X86TargetMachine.cpp diff -u llvm/lib/Target/X86/X86TargetMachine.cpp:1.53 llvm/lib/Target/X86/X86TargetMachine.cpp:1.54 --- llvm/lib/Target/X86/X86TargetMachine.cpp:1.53 Wed Mar 31 16:03:46 2004 +++ llvm/lib/Target/X86/X86TargetMachine.cpp Tue Apr 6 14:34:00 2004 @@ -33,6 +33,8 @@ cl::opt DisableOutput("disable-x86-llc-output", cl::Hidden, cl::desc("Disable the X86 asm printer, for use " "when profiling the code generator.")); + cl::opt NoSimpleISel("disable-simple-isel", cl::init(true), + cl::desc("Use the hand coded 'simple' X86 instruction selector")); } // allocateX86TargetMachine - Allocate and return a subclass of TargetMachine @@ -67,8 +69,10 @@ // FIXME: Implement the switch instruction in the instruction selector! PM.add(createLowerSwitchPass()); - if (NoPatternISel) + if (NoPatternISel && NoSimpleISel) PM.add(createX86SimpleInstructionSelector(*this)); + else if (NoPatternISel) + PM.add(createX86ReallySimpleInstructionSelector(*this)); else PM.add(createX86PatternInstructionSelector(*this)); From kuba at cs.uiuc.edu Tue Apr 6 14:36:05 2004 From: kuba at cs.uiuc.edu (Takahiro Kuba) Date: Tue Apr 6 14:36:05 2004 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86SimpInstrSelector.cpp Message-ID: <200404061935.OAA20345@cypher.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86SimpInstrSelector.cpp added (r1.1) --- Log message: file based off InstSelectSimple.cpp, slowly being replaced by generated code from the really simple X86 instruction selector tablegen backend --- Diffs of the changes: (+2831 -0) Index: llvm/lib/Target/X86/X86SimpInstrSelector.cpp diff -c /dev/null llvm/lib/Target/X86/X86SimpInstrSelector.cpp:1.1 *** /dev/null Tue Apr 6 14:35:27 2004 --- llvm/lib/Target/X86/X86SimpInstrSelector.cpp Tue Apr 6 14:35:17 2004 *************** *** 0 **** --- 1,2831 ---- + //===-- InstSelectSimple.cpp - A simple instruction selector for x86 ------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file defines a simple peephole instruction selector for the x86 target + // + //===----------------------------------------------------------------------===// + + #include "X86.h" + #include "X86InstrBuilder.h" + #include "X86InstrInfo.h" + #include "llvm/Constants.h" + #include "llvm/DerivedTypes.h" + #include "llvm/Function.h" + #include "llvm/Instructions.h" + #include "llvm/IntrinsicLowering.h" + #include "llvm/Pass.h" + #include "llvm/CodeGen/MachineConstantPool.h" + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/SSARegMap.h" + #include "llvm/Target/MRegisterInfo.h" + #include "llvm/Target/TargetMachine.h" + #include "llvm/Support/GetElementPtrTypeIterator.h" + #include "llvm/Support/InstVisitor.h" + #include "llvm/Support/CFG.h" + #include "Support/Statistic.h" + using namespace llvm; + + namespace { + Statistic<> + NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added"); + } + + namespace { + struct ISel : public FunctionPass, InstVisitor { + TargetMachine &TM; + MachineFunction *F; // The function we are compiling into + MachineBasicBlock *BB; // The current MBB we are compiling + int VarArgsFrameIndex; // FrameIndex for start of varargs area + int ReturnAddressIndex; // FrameIndex for the return address + + std::map RegMap; // Mapping between Val's and SSA Regs + + // MBBMap - Mapping between LLVM BB -> Machine BB + std::map MBBMap; + + ISel(TargetMachine &tm) : TM(tm), F(0), BB(0) {} + + /// runOnFunction - Top level implementation of instruction selection for + /// the entire function. + /// + bool runOnFunction(Function &Fn) { + // First pass over the function, lower any unknown intrinsic functions + // with the IntrinsicLowering class. + LowerUnknownIntrinsicFunctionCalls(Fn); + + F = &MachineFunction::construct(&Fn, TM); + + // Create all of the machine basic blocks for the function... + for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) + F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I)); + + BB = &F->front(); + + // Set up a frame object for the return address. This is used by the + // llvm.returnaddress & llvm.frameaddress intrinisics. + ReturnAddressIndex = F->getFrameInfo()->CreateFixedObject(4, -4); + + // Copy incoming arguments off of the stack... + LoadArgumentsToVirtualRegs(Fn); + + // Instruction select everything except PHI nodes + visit(Fn); + + // Select the PHI nodes + SelectPHINodes(); + + // Insert the FP_REG_KILL instructions into blocks that need them. + InsertFPRegKills(); + + RegMap.clear(); + MBBMap.clear(); + F = 0; + // We always build a machine code representation for the function + return true; + } + + virtual const char *getPassName() const { + return "X86 Simple Instruction Selection"; + } + + /// visitBasicBlock - This method is called when we are visiting a new basic + /// block. This simply creates a new MachineBasicBlock to emit code into + /// and adds it to the current MachineFunction. Subsequent visit* for + /// instructions will be invoked for all instructions in the basic block. + /// + void visitBasicBlock(BasicBlock &LLVM_BB) { + BB = MBBMap[&LLVM_BB]; + } + + /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the + /// function, lowering any calls to unknown intrinsic functions into the + /// equivalent LLVM code. + /// + void LowerUnknownIntrinsicFunctionCalls(Function &F); + + /// LoadArgumentsToVirtualRegs - Load all of the arguments to this function + /// from the stack into virtual registers. + /// + void LoadArgumentsToVirtualRegs(Function &F); + + /// SelectPHINodes - Insert machine code to generate phis. This is tricky + /// because we have to generate our sources into the source basic blocks, + /// not the current one. + /// + void SelectPHINodes(); + + /// InsertFPRegKills - Insert FP_REG_KILL instructions into basic blocks + /// that need them. This only occurs due to the floating point stackifier + /// not being aggressive enough to handle arbitrary global stackification. + /// + void InsertFPRegKills(); + + // Visitation methods for various instructions. These methods simply emit + // fixed X86 code for each instruction. + // + + // Control flow operators + void visitReturnInst(ReturnInst &RI); + void visitBranchInst(BranchInst &BI); + + struct ValueRecord { + Value *Val; + unsigned Reg; + const Type *Ty; + ValueRecord(unsigned R, const Type *T) : Val(0), Reg(R), Ty(T) {} + ValueRecord(Value *V) : Val(V), Reg(0), Ty(V->getType()) {} + }; + void doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args); + void visitCallInst(CallInst &I); + void visitIntrinsicCall(Intrinsic::ID ID, CallInst &I); + + // Arithmetic operators + void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass); + void visitAdd(BinaryOperator &B);// visitSimpleBinary(B, 0); } + void visitSub(BinaryOperator &B);// { visitSimpleBinary(B, 1); } + void doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI, + unsigned DestReg, const Type *DestTy, + unsigned Op0Reg, unsigned Op1Reg); + void doMultiplyConst(MachineBasicBlock *MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, const Type *DestTy, + unsigned Op0Reg, unsigned Op1Val); + void visitMul(BinaryOperator &B); + + void visitDiv(BinaryOperator &B) { visitDivRem(B); } + void visitRem(BinaryOperator &B) { visitDivRem(B); } + void visitDivRem(BinaryOperator &B); + + // Bitwise operators + void visitAnd(BinaryOperator &B);// { visitSimpleBinary(B, 2); } + void visitOr (BinaryOperator &B);// { visitSimpleBinary(B, 3); } + void visitXor(BinaryOperator &B);// { visitSimpleBinary(B, 4); } + + // Comparison operators... + void visitSetCondInst(SetCondInst &I); + unsigned EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, + MachineBasicBlock *MBB, + MachineBasicBlock::iterator MBBI); + + // Memory Instructions + void visitLoadInst(LoadInst &I); + void visitStoreInst(StoreInst &I); + void visitGetElementPtrInst(GetElementPtrInst &I); + void visitAllocaInst(AllocaInst &I); + void visitMallocInst(MallocInst &I); + void visitFreeInst(FreeInst &I); + + // Other operators + void visitShiftInst(ShiftInst &I); + void visitPHINode(PHINode &I) {} // PHI nodes handled by second pass + void visitCastInst(CastInst &I); + void visitVANextInst(VANextInst &I); + void visitVAArgInst(VAArgInst &I); + + void visitInstruction(Instruction &I) { + std::cerr << "Cannot instruction select: " << I; + abort(); + } + + /// promote32 - Make a value 32-bits wide, and put it somewhere. + /// + void promote32(unsigned targetReg, const ValueRecord &VR); + + /// getAddressingMode - Get the addressing mode to use to address the + /// specified value. The returned value should be used with addFullAddress. + void getAddressingMode(Value *Addr, unsigned &BaseReg, unsigned &Scale, + unsigned &IndexReg, unsigned &Disp); + + + /// getGEPIndex - This is used to fold GEP instructions into X86 addressing + /// expressions. + void getGEPIndex(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + std::vector &GEPOps, + std::vector &GEPTypes, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp); + + /// isGEPFoldable - Return true if the specified GEP can be completely + /// folded into the addressing mode of a load/store or lea instruction. + bool isGEPFoldable(MachineBasicBlock *MBB, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp); + + /// emitGEPOperation - Common code shared between visitGetElementPtrInst and + /// constant expression GEP support. + /// + void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned TargetReg); + + /// emitCastOperation - Common code shared between visitCastInst and + /// constant expression cast support. + /// + void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator IP, + Value *Src, const Type *DestTy, unsigned TargetReg); + + /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary + /// and constant expression support. + /// + void emitSimpleBinaryOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, + unsigned OperatorClass, unsigned TargetReg); + + void emitDivRemOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + unsigned Op0Reg, unsigned Op1Reg, bool isDiv, + const Type *Ty, unsigned TargetReg); + + /// emitSetCCOperation - Common code shared between visitSetCondInst and + /// constant expression support. + /// + void emitSetCCOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, unsigned Opcode, + unsigned TargetReg); + + /// emitShiftOperation - Common code shared between visitShiftInst and + /// constant expression support. + /// + void emitShiftOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op, Value *ShiftAmount, bool isLeftShift, + const Type *ResultTy, unsigned DestReg); + + + /// copyConstantToRegister - Output the instructions required to put the + /// specified constant into the specified register. + /// + void copyConstantToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator MBBI, + Constant *C, unsigned Reg); + + /// makeAnotherReg - This method returns the next register number we haven't + /// yet used. + /// + /// Long values are handled somewhat specially. They are always allocated + /// as pairs of 32 bit integer values. The register number returned is the + /// lower 32 bits of the long value, and the regNum+1 is the upper 32 bits + /// of the long value. + /// + unsigned makeAnotherReg(const Type *Ty) { + assert(dynamic_cast(TM.getRegisterInfo()) && + "Current target doesn't have X86 reg info??"); + const X86RegisterInfo *MRI = + static_cast(TM.getRegisterInfo()); + if (Ty == Type::LongTy || Ty == Type::ULongTy) { + const TargetRegisterClass *RC = MRI->getRegClassForType(Type::IntTy); + // Create the lower part + F->getSSARegMap()->createVirtualRegister(RC); + // Create the upper part. + return F->getSSARegMap()->createVirtualRegister(RC)-1; + } + + // Add the mapping of regnumber => reg class to MachineFunction + const TargetRegisterClass *RC = MRI->getRegClassForType(Ty); + return F->getSSARegMap()->createVirtualRegister(RC); + } + + /// getReg - This method turns an LLVM value into a register number. This + /// is guaranteed to produce the same register number for a particular value + /// every time it is queried. + /// + unsigned getReg(Value &V) { return getReg(&V); } // Allow references + unsigned getReg(Value *V) { + // Just append to the end of the current bb. + MachineBasicBlock::iterator It = BB->end(); + return getReg(V, BB, It); + } + unsigned getReg(Value *V, MachineBasicBlock *MBB, + MachineBasicBlock::iterator IPt) { + unsigned &Reg = RegMap[V]; + if (Reg == 0) { + Reg = makeAnotherReg(V->getType()); + RegMap[V] = Reg; + } + + // If this operand is a constant, emit the code to copy the constant into + // the register here... + // + if (Constant *C = dyn_cast(V)) { + copyConstantToRegister(MBB, IPt, C, Reg); + RegMap.erase(V); // Assign a new name to this constant if ref'd again + } else if (GlobalValue *GV = dyn_cast(V)) { + // Move the address of the global into the register + BuildMI(*MBB, IPt, X86::MOV32ri, 1, Reg).addGlobalAddress(GV); + RegMap.erase(V); // Assign a new name to this address if ref'd again + } + + return Reg; + } + }; + } + + /// TypeClass - Used by the X86 backend to group LLVM types by their basic X86 + /// Representation. + /// + enum TypeClass { + cByte, cShort, cInt, cFP, cLong + }; + + enum Subclasses { + NegOne, PosOne, Cons, Other + }; + + + + /// getClass - Turn a primitive type into a "class" number which is based on the + /// size of the type, and whether or not it is floating point. + /// + static inline TypeClass getClass(const Type *Ty) { + switch (Ty->getPrimitiveID()) { + case Type::SByteTyID: + case Type::UByteTyID: return cByte; // Byte operands are class #0 + case Type::ShortTyID: + case Type::UShortTyID: return cShort; // Short operands are class #1 + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return cInt; // Int's and pointers are class #2 + + case Type::FloatTyID: + case Type::DoubleTyID: return cFP; // Floating Point is #3 + + case Type::LongTyID: + case Type::ULongTyID: return cLong; // Longs are class #4 + default: + assert(0 && "Invalid type to getClass!"); + return cByte; // not reached + } + } + + // getClassB - Just like getClass, but treat boolean values as bytes. + static inline TypeClass getClassB(const Type *Ty) { + if (Ty == Type::BoolTy) return cByte; + return getClass(Ty); + } + + + /// copyConstantToRegister - Output the instructions required to put the + /// specified constant into the specified register. + /// + void ISel::copyConstantToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Constant *C, unsigned R) { + if (ConstantExpr *CE = dyn_cast(C)) { + unsigned Class = 0; + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: + emitGEPOperation(MBB, IP, CE->getOperand(0), + CE->op_begin()+1, CE->op_end(), R); + return; + case Instruction::Cast: + emitCastOperation(MBB, IP, CE->getOperand(0), CE->getType(), R); + return; + + case Instruction::Xor: ++Class; // FALL THROUGH + case Instruction::Or: ++Class; // FALL THROUGH + case Instruction::And: ++Class; // FALL THROUGH + case Instruction::Sub: ++Class; // FALL THROUGH + case Instruction::Add: + emitSimpleBinaryOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1), + Class, R); + return; + + case Instruction::Mul: { + unsigned Op0Reg = getReg(CE->getOperand(0), MBB, IP); + unsigned Op1Reg = getReg(CE->getOperand(1), MBB, IP); + doMultiply(MBB, IP, R, CE->getType(), Op0Reg, Op1Reg); + return; + } + case Instruction::Div: + case Instruction::Rem: { + unsigned Op0Reg = getReg(CE->getOperand(0), MBB, IP); + unsigned Op1Reg = getReg(CE->getOperand(1), MBB, IP); + emitDivRemOperation(MBB, IP, Op0Reg, Op1Reg, + CE->getOpcode() == Instruction::Div, + CE->getType(), R); + return; + } + + case Instruction::SetNE: + case Instruction::SetEQ: + case Instruction::SetLT: + case Instruction::SetGT: + case Instruction::SetLE: + case Instruction::SetGE: + emitSetCCOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1), + CE->getOpcode(), R); + return; + + case Instruction::Shl: + case Instruction::Shr: + emitShiftOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1), + CE->getOpcode() == Instruction::Shl, CE->getType(), R); + return; + + default: + std::cerr << "Offending expr: " << C << "\n"; + assert(0 && "Constant expression not yet handled!\n"); + } + } + + if (C->getType()->isIntegral()) { + unsigned Class = getClassB(C->getType()); + + if (Class == cLong) { + // Copy the value into the register pair. + uint64_t Val = cast(C)->getRawValue(); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addImm(Val & 0xFFFFFFFF); + BuildMI(*MBB, IP, X86::MOV32ri, 1, R+1).addImm(Val >> 32); + return; + } + + assert(Class <= cInt && "Type not handled yet!"); + + static const unsigned IntegralOpcodeTab[] = { + X86::MOV8ri, X86::MOV16ri, X86::MOV32ri + }; + + if (C->getType() == Type::BoolTy) { + BuildMI(*MBB, IP, X86::MOV8ri, 1, R).addImm(C == ConstantBool::True); + } else { + ConstantInt *CI = cast(C); + BuildMI(*MBB, IP, IntegralOpcodeTab[Class],1,R).addImm(CI->getRawValue()); + } + } else if (ConstantFP *CFP = dyn_cast(C)) { + if (CFP->isExactlyValue(+0.0)) + BuildMI(*MBB, IP, X86::FLD0, 0, R); + else if (CFP->isExactlyValue(+1.0)) + BuildMI(*MBB, IP, X86::FLD1, 0, R); + else { + // Otherwise we need to spill the constant to memory... + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(CFP); + const Type *Ty = CFP->getType(); + + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + unsigned LoadOpcode = Ty == Type::FloatTy ? X86::FLD32m : X86::FLD64m; + addConstantPoolReference(BuildMI(*MBB, IP, LoadOpcode, 4, R), CPI); + } + + } else if (isa(C)) { + // Copy zero (null pointer) to the register. + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addImm(0); + } else if (ConstantPointerRef *CPR = dyn_cast(C)) { + BuildMI(*MBB, IP, X86::MOV32ri, 1, R).addGlobalAddress(CPR->getValue()); + } else { + std::cerr << "Offending constant: " << C << "\n"; + assert(0 && "Type not handled yet!"); + } + } + + /// LoadArgumentsToVirtualRegs - Load all of the arguments to this function from + /// the stack into virtual registers. + /// + void ISel::LoadArgumentsToVirtualRegs(Function &Fn) { + // Emit instructions to load the arguments... On entry to a function on the + // X86, the stack frame looks like this: + // + // [ESP] -- return address + // [ESP + 4] -- first argument (leftmost lexically) + // [ESP + 8] -- second argument, if first argument is four bytes in size + // ... + // + unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot + MachineFrameInfo *MFI = F->getFrameInfo(); + + for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { + unsigned Reg = getReg(*I); + + int FI; // Frame object index + switch (getClassB(I->getType())) { + case cByte: + FI = MFI->CreateFixedObject(1, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); + break; + case cShort: + FI = MFI->CreateFixedObject(2, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); + break; + case cInt: + FI = MFI->CreateFixedObject(4, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + break; + case cLong: + FI = MFI->CreateFixedObject(8, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); + ArgOffset += 4; // longs require 4 additional bytes + break; + case cFP: + unsigned Opcode; + if (I->getType() == Type::FloatTy) { + Opcode = X86::FLD32m; + FI = MFI->CreateFixedObject(4, ArgOffset); + } else { + Opcode = X86::FLD64m; + FI = MFI->CreateFixedObject(8, ArgOffset); + ArgOffset += 4; // doubles require 4 additional bytes + } + addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); + break; + default: + assert(0 && "Unhandled argument type!"); + } + ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... + } + + // If the function takes variable number of arguments, add a frame offset for + // the start of the first vararg value... this is used to expand + // llvm.va_start. + if (Fn.getFunctionType()->isVarArg()) + VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset); + } + + + /// SelectPHINodes - Insert machine code to generate phis. This is tricky + /// because we have to generate our sources into the source basic blocks, not + /// the current one. + /// + void ISel::SelectPHINodes() { + const TargetInstrInfo &TII = TM.getInstrInfo(); + const Function &LF = *F->getFunction(); // The LLVM function... + for (Function::const_iterator I = LF.begin(), E = LF.end(); I != E; ++I) { + const BasicBlock *BB = I; + MachineBasicBlock &MBB = *MBBMap[I]; + + // Loop over all of the PHI nodes in the LLVM basic block... + MachineBasicBlock::iterator PHIInsertPoint = MBB.begin(); + for (BasicBlock::const_iterator I = BB->begin(); + PHINode *PN = const_cast(dyn_cast(I)); ++I) { + + // Create a new machine instr PHI node, and insert it. + unsigned PHIReg = getReg(*PN); + MachineInstr *PhiMI = BuildMI(MBB, PHIInsertPoint, + X86::PHI, PN->getNumOperands(), PHIReg); + + MachineInstr *LongPhiMI = 0; + if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy) + LongPhiMI = BuildMI(MBB, PHIInsertPoint, + X86::PHI, PN->getNumOperands(), PHIReg+1); + + // PHIValues - Map of blocks to incoming virtual registers. We use this + // so that we only initialize one incoming value for a particular block, + // even if the block has multiple entries in the PHI node. + // + std::map PHIValues; + + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + MachineBasicBlock *PredMBB = MBBMap[PN->getIncomingBlock(i)]; + unsigned ValReg; + std::map::iterator EntryIt = + PHIValues.lower_bound(PredMBB); + + if (EntryIt != PHIValues.end() && EntryIt->first == PredMBB) { + // We already inserted an initialization of the register for this + // predecessor. Recycle it. + ValReg = EntryIt->second; + + } else { + // Get the incoming value into a virtual register. + // + Value *Val = PN->getIncomingValue(i); + + // If this is a constant or GlobalValue, we may have to insert code + // into the basic block to compute it into a virtual register. + if (isa(Val) || isa(Val)) { + // Because we don't want to clobber any values which might be in + // physical registers with the computation of this constant (which + // might be arbitrarily complex if it is a constant expression), + // just insert the computation at the top of the basic block. + MachineBasicBlock::iterator PI = PredMBB->begin(); + + // Skip over any PHI nodes though! + while (PI != PredMBB->end() && PI->getOpcode() == X86::PHI) + ++PI; + + ValReg = getReg(Val, PredMBB, PI); + } else { + ValReg = getReg(Val); + } + + // Remember that we inserted a value for this PHI for this predecessor + PHIValues.insert(EntryIt, std::make_pair(PredMBB, ValReg)); + } + + PhiMI->addRegOperand(ValReg); + PhiMI->addMachineBasicBlockOperand(PredMBB); + if (LongPhiMI) { + LongPhiMI->addRegOperand(ValReg+1); + LongPhiMI->addMachineBasicBlockOperand(PredMBB); + } + } + + // Now that we emitted all of the incoming values for the PHI node, make + // sure to reposition the InsertPoint after the PHI that we just added. + // This is needed because we might have inserted a constant into this + // block, right after the PHI's which is before the old insert point! + PHIInsertPoint = LongPhiMI ? LongPhiMI : PhiMI; + ++PHIInsertPoint; + } + } + } + + /// RequiresFPRegKill - The floating point stackifier pass cannot insert + /// compensation code on critical edges. As such, it requires that we kill all + /// FP registers on the exit from any blocks that either ARE critical edges, or + /// branch to a block that has incoming critical edges. + /// + /// Note that this kill instruction will eventually be eliminated when + /// restrictions in the stackifier are relaxed. + /// + static bool RequiresFPRegKill(const BasicBlock *BB) { + #if 0 + for (succ_const_iterator SI = succ_begin(BB), E = succ_end(BB); SI!=E; ++SI) { + const BasicBlock *Succ = *SI; + pred_const_iterator PI = pred_begin(Succ), PE = pred_end(Succ); + ++PI; // Block have at least one predecessory + if (PI != PE) { // If it has exactly one, this isn't crit edge + // If this block has more than one predecessor, check all of the + // predecessors to see if they have multiple successors. If so, then the + // block we are analyzing needs an FPRegKill. + for (PI = pred_begin(Succ); PI != PE; ++PI) { + const BasicBlock *Pred = *PI; + succ_const_iterator SI2 = succ_begin(Pred); + ++SI2; // There must be at least one successor of this block. + if (SI2 != succ_end(Pred)) + return true; // Yes, we must insert the kill on this edge. + } + } + } + // If we got this far, there is no need to insert the kill instruction. + return false; + #else + return true; + #endif + } + + // InsertFPRegKills - Insert FP_REG_KILL instructions into basic blocks that + // need them. This only occurs due to the floating point stackifier not being + // aggressive enough to handle arbitrary global stackification. + // + // Currently we insert an FP_REG_KILL instruction into each block that uses or + // defines a floating point virtual register. + // + // When the global register allocators (like linear scan) finally update live + // variable analysis, we can keep floating point values in registers across + // portions of the CFG that do not involve critical edges. This will be a big + // win, but we are waiting on the global allocators before we can do this. + // + // With a bit of work, the floating point stackifier pass can be enhanced to + // break critical edges as needed (to make a place to put compensation code), + // but this will require some infrastructure improvements as well. + // + void ISel::InsertFPRegKills() { + SSARegMap &RegMap = *F->getSSARegMap(); + + for (MachineFunction::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); I!=E; ++I) + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + MachineOperand& MO = I->getOperand(i); + if (MO.isRegister() && MO.getReg()) { + unsigned Reg = MO.getReg(); + if (MRegisterInfo::isVirtualRegister(Reg)) + if (RegMap.getRegClass(Reg)->getSize() == 10) + goto UsesFPReg; + } + } + // If we haven't found an FP register use or def in this basic block, check + // to see if any of our successors has an FP PHI node, which will cause a + // copy to be inserted into this block. + for (succ_const_iterator SI = succ_begin(BB->getBasicBlock()), + E = succ_end(BB->getBasicBlock()); SI != E; ++SI) { + MachineBasicBlock *SBB = MBBMap[*SI]; + for (MachineBasicBlock::iterator I = SBB->begin(); + I != SBB->end() && I->getOpcode() == X86::PHI; ++I) { + if (RegMap.getRegClass(I->getOperand(0).getReg())->getSize() == 10) + goto UsesFPReg; + } + } + continue; + UsesFPReg: + // Okay, this block uses an FP register. If the block has successors (ie, + // it's not an unwind/return), insert the FP_REG_KILL instruction. + if (BB->getBasicBlock()->getTerminator()->getNumSuccessors() && + RequiresFPRegKill(BB->getBasicBlock())) { + BuildMI(*BB, BB->getFirstTerminator(), X86::FP_REG_KILL, 0); + ++NumFPKill; + } + } + } + + + // canFoldSetCCIntoBranch - Return the setcc instruction if we can fold it into + // the conditional branch instruction which is the only user of the cc + // instruction. This is the case if the conditional branch is the only user of + // the setcc, and if the setcc is in the same basic block as the conditional + // branch. We also don't handle long arguments below, so we reject them here as + // well. + // + static SetCondInst *canFoldSetCCIntoBranch(Value *V) { + if (SetCondInst *SCI = dyn_cast(V)) + if (SCI->hasOneUse() && isa(SCI->use_back()) && + SCI->getParent() == cast(SCI->use_back())->getParent()) { + const Type *Ty = SCI->getOperand(0)->getType(); + if (Ty != Type::LongTy && Ty != Type::ULongTy) + return SCI; + } + return 0; + } + + // Return a fixed numbering for setcc instructions which does not depend on the + // order of the opcodes. + // + static unsigned getSetCCNumber(unsigned Opcode) { + switch(Opcode) { + default: assert(0 && "Unknown setcc instruction!"); + case Instruction::SetEQ: return 0; + case Instruction::SetNE: return 1; + case Instruction::SetLT: return 2; + case Instruction::SetGE: return 3; + case Instruction::SetGT: return 4; + case Instruction::SetLE: return 5; + } + } + + // LLVM -> X86 signed X86 unsigned + // ----- ---------- ------------ + // seteq -> sete sete + // setne -> setne setne + // setlt -> setl setb + // setge -> setge setae + // setgt -> setg seta + // setle -> setle setbe + // ---- + // sets // Used by comparison with 0 optimization + // setns + static const unsigned SetCCOpcodeTab[2][8] = { + { X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAEr, X86::SETAr, X86::SETBEr, + 0, 0 }, + { X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGEr, X86::SETGr, X86::SETLEr, + X86::SETSr, X86::SETNSr }, + }; + + // EmitComparison - This function emits a comparison of the two operands, + // returning the extended setcc code to use. + unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, + MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP) { + // The arguments are already supposed to be of the same type. + const Type *CompTy = Op0->getType(); + unsigned Class = getClassB(CompTy); + unsigned Op0r = getReg(Op0, MBB, IP); + + // Special case handling of: cmp R, i + if (Class == cByte || Class == cShort || Class == cInt) + if (ConstantInt *CI = dyn_cast(Op1)) { + uint64_t Op1v = cast(CI)->getRawValue(); + + // Mask off any upper bits of the constant, if there are any... + Op1v &= (1ULL << (8 << Class)) - 1; + + // If this is a comparison against zero, emit more efficient code. We + // can't handle unsigned comparisons against zero unless they are == or + // !=. These should have been strength reduced already anyway. + if (Op1v == 0 && (CompTy->isSigned() || OpNum < 2)) { + static const unsigned TESTTab[] = { + X86::TEST8rr, X86::TEST16rr, X86::TEST32rr + }; + BuildMI(*MBB, IP, TESTTab[Class], 2).addReg(Op0r).addReg(Op0r); + + if (OpNum == 2) return 6; // Map jl -> js + if (OpNum == 3) return 7; // Map jg -> jns + return OpNum; + } + + static const unsigned CMPTab[] = { + X86::CMP8ri, X86::CMP16ri, X86::CMP32ri + }; + + BuildMI(*MBB, IP, CMPTab[Class], 2).addReg(Op0r).addImm(Op1v); + return OpNum; + } + + // Special case handling of comparison against +/- 0.0 + if (ConstantFP *CFP = dyn_cast(Op1)) + if (CFP->isExactlyValue(+0.0) || CFP->isExactlyValue(-0.0)) { + BuildMI(*MBB, IP, X86::FTST, 1).addReg(Op0r); + BuildMI(*MBB, IP, X86::FNSTSW8r, 0); + BuildMI(*MBB, IP, X86::SAHF, 1); + return OpNum; + } + + unsigned Op1r = getReg(Op1, MBB, IP); + switch (Class) { + default: assert(0 && "Unknown type class!"); + // Emit: cmp , (do the comparison). We can + // compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with + // 32-bit. + case cByte: + BuildMI(*MBB, IP, X86::CMP8rr, 2).addReg(Op0r).addReg(Op1r); + break; + case cShort: + BuildMI(*MBB, IP, X86::CMP16rr, 2).addReg(Op0r).addReg(Op1r); + break; + case cInt: + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r); + break; + case cFP: + BuildMI(*MBB, IP, X86::FpUCOM, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::FNSTSW8r, 0); + BuildMI(*MBB, IP, X86::SAHF, 1); + break; + + case cLong: + if (OpNum < 2) { // seteq, setne + unsigned LoTmp = makeAnotherReg(Type::IntTy); + unsigned HiTmp = makeAnotherReg(Type::IntTy); + unsigned FinalTmp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, X86::XOR32rr, 2, LoTmp).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, X86::XOR32rr, 2, HiTmp).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, X86::OR32rr, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + break; // Allow the sete or setne to be generated from flags set by OR + } else { + // Emit a sequence of code which compares the high and low parts once + // each, then uses a conditional move to handle the overflow case. For + // example, a setlt for long would generate code like this: + // + // AL = lo(op1) < lo(op2) // Signedness depends on operands + // BL = hi(op1) < hi(op2) // Always unsigned comparison + // dest = hi(op1) == hi(op2) ? AL : BL; + // + + // FIXME: This would be much better if we had hierarchical register + // classes! Until then, hardcode registers so that we can deal with their + // aliases (because we don't have conditional byte moves). + // + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, SetCCOpcodeTab[0][OpNum], 0, X86::AL); + BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, SetCCOpcodeTab[CompTy->isSigned()][OpNum], 0, X86::BL); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::BH); + BuildMI(*MBB, IP, X86::IMPLICIT_DEF, 0, X86::AH); + BuildMI(*MBB, IP, X86::CMOVE16rr, 2, X86::BX).addReg(X86::BX) + .addReg(X86::AX); + // NOTE: visitSetCondInst knows that the value is dumped into the BL + // register at this point for long values... + return OpNum; + } + } + return OpNum; + } + + + /// SetCC instructions - Here we just emit boilerplate code to set a byte-sized + /// register, then move it to wherever the result should be. + /// + void ISel::visitSetCondInst(SetCondInst &I) { + if (canFoldSetCCIntoBranch(&I)) return; // Fold this into a branch... + + unsigned DestReg = getReg(I); + MachineBasicBlock::iterator MII = BB->end(); + emitSetCCOperation(BB, MII, I.getOperand(0), I.getOperand(1), I.getOpcode(), + DestReg); + } + + /// emitSetCCOperation - Common code shared between visitSetCondInst and + /// constant expression support. + /// + void ISel::emitSetCCOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, unsigned Opcode, + unsigned TargetReg) { + unsigned OpNum = getSetCCNumber(Opcode); + OpNum = EmitComparison(OpNum, Op0, Op1, MBB, IP); + + const Type *CompTy = Op0->getType(); + unsigned CompClass = getClassB(CompTy); + bool isSigned = CompTy->isSigned() && CompClass != cFP; + + if (CompClass != cLong || OpNum < 2) { + // Handle normal comparisons with a setcc instruction... + BuildMI(*MBB, IP, SetCCOpcodeTab[isSigned][OpNum], 0, TargetReg); + } else { + // Handle long comparisons by copying the value which is already in BL into + // the register we want... + BuildMI(*MBB, IP, X86::MOV8rr, 1, TargetReg).addReg(X86::BL); + } + } + + + + + /// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide + /// operand, in the specified target register. + /// + void ISel::promote32(unsigned targetReg, const ValueRecord &VR) { + bool isUnsigned = VR.Ty->isUnsigned(); + + // Make sure we have the register number for this value... + unsigned Reg = VR.Val ? getReg(VR.Val) : VR.Reg; + + switch (getClassB(VR.Ty)) { + case cByte: + // Extend value into target register (8->32) + if (isUnsigned) + BuildMI(BB, X86::MOVZX32rr8, 1, targetReg).addReg(Reg); + else + BuildMI(BB, X86::MOVSX32rr8, 1, targetReg).addReg(Reg); + break; + case cShort: + // Extend value into target register (16->32) + if (isUnsigned) + BuildMI(BB, X86::MOVZX32rr16, 1, targetReg).addReg(Reg); + else + BuildMI(BB, X86::MOVSX32rr16, 1, targetReg).addReg(Reg); + break; + case cInt: + // Move value into target register (32->32) + BuildMI(BB, X86::MOV32rr, 1, targetReg).addReg(Reg); + break; + default: + assert(0 && "Unpromotable operand class in promote32"); + } + } + + /// 'ret' instruction - Here we are interested in meeting the x86 ABI. As such, + /// we have the following possibilities: + /// + /// ret void: No return value, simply emit a 'ret' instruction + /// ret sbyte, ubyte : Extend value into EAX and return + /// ret short, ushort: Extend value into EAX and return + /// ret int, uint : Move value into EAX and return + /// ret pointer : Move value into EAX and return + /// ret long, ulong : Move value into EAX/EDX and return + /// ret float/double : Top of FP stack + /// + void ISel::visitReturnInst(ReturnInst &I) { + if (I.getNumOperands() == 0) { + BuildMI(BB, X86::RET, 0); // Just emit a 'ret' instruction + return; + } + + Value *RetVal = I.getOperand(0); + unsigned RetReg = getReg(RetVal); + switch (getClassB(RetVal->getType())) { + case cByte: // integral return values: extend or move into EAX and return + case cShort: + case cInt: + promote32(X86::EAX, ValueRecord(RetReg, RetVal->getType())); + // Declare that EAX is live on exit + BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::EAX).addReg(X86::ESP); + break; + case cFP: // Floats & Doubles: Return in ST(0) + BuildMI(BB, X86::FpSETRESULT, 1).addReg(RetReg); + // Declare that top-of-stack is live on exit + BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::ST0).addReg(X86::ESP); + break; + case cLong: + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(RetReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDX).addReg(RetReg+1); + // Declare that EAX & EDX are live on exit + BuildMI(BB, X86::IMPLICIT_USE, 3).addReg(X86::EAX).addReg(X86::EDX) + .addReg(X86::ESP); + break; + default: + visitInstruction(I); + } + // Emit a 'ret' instruction + BuildMI(BB, X86::RET, 0); + } + + // getBlockAfter - Return the basic block which occurs lexically after the + // specified one. + static inline BasicBlock *getBlockAfter(BasicBlock *BB) { + Function::iterator I = BB; ++I; // Get iterator to next block + return I != BB->getParent()->end() ? &*I : 0; + } + + /// visitBranchInst - Handle conditional and unconditional branches here. Note + /// that since code layout is frozen at this point, that if we are trying to + /// jump to a block that is the immediate successor of the current block, we can + /// just make a fall-through (but we don't currently). + /// + void ISel::visitBranchInst(BranchInst &BI) { + BasicBlock *NextBB = getBlockAfter(BI.getParent()); // BB after current one + + if (!BI.isConditional()) { // Unconditional branch? + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0)); + return; + } + + // See if we can fold the setcc into the branch itself... + SetCondInst *SCI = canFoldSetCCIntoBranch(BI.getCondition()); + if (SCI == 0) { + // Nope, cannot fold setcc into this branch. Emit a branch on a condition + // computed some other way... + unsigned condReg = getReg(BI.getCondition()); + BuildMI(BB, X86::CMP8ri, 2).addReg(condReg).addImm(0); + if (BI.getSuccessor(1) == NextBB) { + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, X86::JNE, 1).addPCDisp(BI.getSuccessor(0)); + } else { + BuildMI(BB, X86::JE, 1).addPCDisp(BI.getSuccessor(1)); + + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0)); + } + return; + } + + unsigned OpNum = getSetCCNumber(SCI->getOpcode()); + MachineBasicBlock::iterator MII = BB->end(); + OpNum = EmitComparison(OpNum, SCI->getOperand(0), SCI->getOperand(1), BB,MII); + + const Type *CompTy = SCI->getOperand(0)->getType(); + bool isSigned = CompTy->isSigned() && getClassB(CompTy) != cFP; + + + // LLVM -> X86 signed X86 unsigned + // ----- ---------- ------------ + // seteq -> je je + // setne -> jne jne + // setlt -> jl jb + // setge -> jge jae + // setgt -> jg ja + // setle -> jle jbe + // ---- + // js // Used by comparison with 0 optimization + // jns + + static const unsigned OpcodeTab[2][8] = { + { X86::JE, X86::JNE, X86::JB, X86::JAE, X86::JA, X86::JBE, 0, 0 }, + { X86::JE, X86::JNE, X86::JL, X86::JGE, X86::JG, X86::JLE, + X86::JS, X86::JNS }, + }; + + if (BI.getSuccessor(0) != NextBB) { + BuildMI(BB, OpcodeTab[isSigned][OpNum], 1).addPCDisp(BI.getSuccessor(0)); + if (BI.getSuccessor(1) != NextBB) + BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(1)); + } else { + // Change to the inverse condition... + if (BI.getSuccessor(1) != NextBB) { + OpNum ^= 1; + BuildMI(BB, OpcodeTab[isSigned][OpNum], 1).addPCDisp(BI.getSuccessor(1)); + } + } + } + + + /// doCall - This emits an abstract call instruction, setting up the arguments + /// and the return value as appropriate. For the actual function call itself, + /// it inserts the specified CallMI instruction into the stream. + /// + void ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args) { + + // Count how many bytes are to be pushed on the stack... + unsigned NumBytes = 0; + + if (!Args.empty()) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) + switch (getClassB(Args[i].Ty)) { + case cByte: case cShort: case cInt: + NumBytes += 4; break; + case cLong: + NumBytes += 8; break; + case cFP: + NumBytes += Args[i].Ty == Type::FloatTy ? 4 : 8; + break; + default: assert(0 && "Unknown class!"); + } + + // Adjust the stack pointer for the new arguments... + BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addImm(NumBytes); + + // Arguments go on the stack in reverse order, as specified by the ABI. + unsigned ArgOffset = 0; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + unsigned ArgReg; + switch (getClassB(Args[i].Ty)) { + case cByte: + case cShort: + if (Args[i].Val && isa(Args[i].Val)) { + // Zero/Sign extend constant, then stuff into memory. + ConstantInt *Val = cast(Args[i].Val); + Val = cast(ConstantExpr::getCast(Val, Type::IntTy)); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), X86::ESP, ArgOffset) + .addImm(Val->getRawValue() & 0xFFFFFFFF); + } else { + // Promote arg to 32 bits wide into a temporary register... + ArgReg = makeAnotherReg(Type::UIntTy); + promote32(ArgReg, Args[i]); + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + } + break; + case cInt: + if (Args[i].Val && isa(Args[i].Val)) { + unsigned Val = cast(Args[i].Val)->getRawValue(); + addRegOffset(BuildMI(BB, X86::MOV32mi, 5), + X86::ESP, ArgOffset).addImm(Val); + } else { + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + } + break; + case cLong: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + addRegOffset(BuildMI(BB, X86::MOV32mr, 5), + X86::ESP, ArgOffset+4).addReg(ArgReg+1); + ArgOffset += 4; // 8 byte entry, not 4. + break; + + case cFP: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + if (Args[i].Ty == Type::FloatTy) { + addRegOffset(BuildMI(BB, X86::FST32m, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + } else { + assert(Args[i].Ty == Type::DoubleTy && "Unknown FP type!"); + addRegOffset(BuildMI(BB, X86::FST64m, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + ArgOffset += 4; // 8 byte entry, not 4. + } + break; + + default: assert(0 && "Unknown class!"); + } + ArgOffset += 4; + } + } else { + BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addImm(0); + } + + BB->push_back(CallMI); + + BuildMI(BB, X86::ADJCALLSTACKUP, 1).addImm(NumBytes); + + // If there is a return value, scavenge the result from the location the call + // leaves it in... + // + if (Ret.Ty != Type::VoidTy) { + unsigned DestClass = getClassB(Ret.Ty); + switch (DestClass) { + case cByte: + case cShort: + case cInt: { + // Integral results are in %eax, or the appropriate portion + // thereof. + static const unsigned regRegMove[] = { + X86::MOV8rr, X86::MOV16rr, X86::MOV32rr + }; + static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; + BuildMI(BB, regRegMove[DestClass], 1, Ret.Reg).addReg(AReg[DestClass]); + break; + } + case cFP: // Floating-point return values live in %ST(0) + BuildMI(BB, X86::FpGETRESULT, 1, Ret.Reg); + break; + case cLong: // Long values are left in EDX:EAX + BuildMI(BB, X86::MOV32rr, 1, Ret.Reg).addReg(X86::EAX); + BuildMI(BB, X86::MOV32rr, 1, Ret.Reg+1).addReg(X86::EDX); + break; + default: assert(0 && "Unknown class!"); + } + } + } + + + /// visitCallInst - Push args on stack and do a procedure call instruction. + void ISel::visitCallInst(CallInst &CI) { + MachineInstr *TheCall; + if (Function *F = CI.getCalledFunction()) { + // Is it an intrinsic function call? + if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) { + visitIntrinsicCall(ID, CI); // Special intrinsics are not handled here + return; + } + + // Emit a CALL instruction with PC-relative displacement. + TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true); + } else { // Emit an indirect call... + unsigned Reg = getReg(CI.getCalledValue()); + TheCall = BuildMI(X86::CALL32r, 1).addReg(Reg); + } + + std::vector Args; + for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) + Args.push_back(ValueRecord(CI.getOperand(i))); + + unsigned DestReg = CI.getType() != Type::VoidTy ? getReg(CI) : 0; + doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args); + } + + + /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the + /// function, lowering any calls to unknown intrinsic functions into the + /// equivalent LLVM code. + /// + void ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) { + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) + if (CallInst *CI = dyn_cast(I++)) + if (Function *F = CI->getCalledFunction()) + switch (F->getIntrinsicID()) { + case Intrinsic::not_intrinsic: + case Intrinsic::vastart: + case Intrinsic::vacopy: + case Intrinsic::vaend: + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + case Intrinsic::memcpy: + case Intrinsic::memset: + // We directly implement these intrinsics + break; + default: + // All other intrinsic calls we must lower. + Instruction *Before = CI->getPrev(); + TM.getIntrinsicLowering().LowerIntrinsicCall(CI); + if (Before) { // Move iterator to instruction after call + I = Before; ++I; + } else { + I = BB->begin(); + } + } + + } + + void ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) { + unsigned TmpReg1, TmpReg2; + switch (ID) { + case Intrinsic::vastart: + // Get the address of the first vararg value... + TmpReg1 = getReg(CI); + addFrameReference(BuildMI(BB, X86::LEA32r, 5, TmpReg1), VarArgsFrameIndex); + return; + + case Intrinsic::vacopy: + TmpReg1 = getReg(CI); + TmpReg2 = getReg(CI.getOperand(1)); + BuildMI(BB, X86::MOV32rr, 1, TmpReg1).addReg(TmpReg2); + return; + case Intrinsic::vaend: return; // Noop on X86 + + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + TmpReg1 = getReg(CI); + if (cast(CI.getOperand(1))->isNullValue()) { + if (ID == Intrinsic::returnaddress) { + // Just load the return address + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, TmpReg1), + ReturnAddressIndex); + } else { + addFrameReference(BuildMI(BB, X86::LEA32r, 4, TmpReg1), + ReturnAddressIndex, -4); + } + } else { + // Values other than zero are not implemented yet. + BuildMI(BB, X86::MOV32ri, 1, TmpReg1).addImm(0); + } + return; + + case Intrinsic::memcpy: { + assert(CI.getNumOperands() == 5 && "Illegal llvm.memcpy call!"); + unsigned Align = 1; + if (ConstantInt *AlignC = dyn_cast(CI.getOperand(4))) { + Align = AlignC->getRawValue(); + if (Align == 0) Align = 1; + } + + // Turn the byte code into # iterations + unsigned CountReg; + unsigned Opcode; + switch (Align & 3) { + case 2: // WORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg = getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/2)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(1); + } + Opcode = X86::REP_MOVSW; + break; + case 0: // DWORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg = getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/4)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(2); + } + Opcode = X86::REP_MOVSD; + break; + default: // BYTE aligned + CountReg = getReg(CI.getOperand(3)); + Opcode = X86::REP_MOVSB; + break; + } + + // No matter what the alignment is, we put the source in ESI, the + // destination in EDI, and the count in ECX. + TmpReg1 = getReg(CI.getOperand(1)); + TmpReg2 = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV32rr, 1, X86::ECX).addReg(CountReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDI).addReg(TmpReg1); + BuildMI(BB, X86::MOV32rr, 1, X86::ESI).addReg(TmpReg2); + BuildMI(BB, Opcode, 0); + return; + } + case Intrinsic::memset: { + assert(CI.getNumOperands() == 5 && "Illegal llvm.memset call!"); + unsigned Align = 1; + if (ConstantInt *AlignC = dyn_cast(CI.getOperand(4))) { + Align = AlignC->getRawValue(); + if (Align == 0) Align = 1; + } + + // Turn the byte code into # iterations + unsigned CountReg; + unsigned Opcode; + if (ConstantInt *ValC = dyn_cast(CI.getOperand(2))) { + unsigned Val = ValC->getRawValue() & 255; + + // If the value is a constant, then we can potentially use larger copies. + switch (Align & 3) { + case 2: // WORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg =getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/2)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(1); + } + BuildMI(BB, X86::MOV16ri, 1, X86::AX).addImm((Val << 8) | Val); + Opcode = X86::REP_STOSW; + break; + case 0: // DWORD aligned + if (ConstantInt *I = dyn_cast(CI.getOperand(3))) { + CountReg =getReg(ConstantUInt::get(Type::UIntTy, I->getRawValue()/4)); + } else { + CountReg = makeAnotherReg(Type::IntTy); + unsigned ByteReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::SHR32ri, 2, CountReg).addReg(ByteReg).addImm(2); + } + Val = (Val << 8) | Val; + BuildMI(BB, X86::MOV32ri, 1, X86::EAX).addImm((Val << 16) | Val); + Opcode = X86::REP_STOSD; + break; + default: // BYTE aligned + CountReg = getReg(CI.getOperand(3)); + BuildMI(BB, X86::MOV8ri, 1, X86::AL).addImm(Val); + Opcode = X86::REP_STOSB; + break; + } + } else { + // If it's not a constant value we are storing, just fall back. We could + // try to be clever to form 16 bit and 32 bit values, but we don't yet. + unsigned ValReg = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV8rr, 1, X86::AL).addReg(ValReg); + CountReg = getReg(CI.getOperand(3)); + Opcode = X86::REP_STOSB; + } + + // No matter what the alignment is, we put the source in ESI, the + // destination in EDI, and the count in ECX. + TmpReg1 = getReg(CI.getOperand(1)); + //TmpReg2 = getReg(CI.getOperand(2)); + BuildMI(BB, X86::MOV32rr, 1, X86::ECX).addReg(CountReg); + BuildMI(BB, X86::MOV32rr, 1, X86::EDI).addReg(TmpReg1); + BuildMI(BB, Opcode, 0); + return; + } + + default: assert(0 && "Error: unknown intrinsics should have been lowered!"); + } + } + + static bool isSafeToFoldLoadIntoInstruction(LoadInst &LI, Instruction &User) { + if (LI.getParent() != User.getParent()) + return false; + BasicBlock::iterator It = &LI; + // Check all of the instructions between the load and the user. We should + // really use alias analysis here, but for now we just do something simple. + for (++It; It != BasicBlock::iterator(&User); ++It) { + switch (It->getOpcode()) { + case Instruction::Store: + case Instruction::Call: + case Instruction::Invoke: + return false; + } + } + return true; + } + + + /// visitSimpleBinary - Implement simple binary operators for integral types... + /// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, 4 for + /// Xor. + /// + void ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) { + unsigned DestReg = getReg(B); + MachineBasicBlock::iterator MI = BB->end(); + Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1); + + // Special case: op Reg, load [mem] + if (isa(Op0) && !isa(Op1)) + if (!B.swapOperands()) + std::swap(Op0, Op1); // Make sure any loads are in the RHS. + + unsigned Class = getClassB(B.getType()); + if (isa(Op1) && Class < cFP && + isSafeToFoldLoadIntoInstruction(*cast(Op1), B)) { + + static const unsigned OpcodeTab[][3] = { + // Arithmetic operators + { X86::ADD8rm, X86::ADD16rm, X86::ADD32rm }, // ADD + { X86::SUB8rm, X86::SUB16rm, X86::SUB32rm }, // SUB + + // Bitwise operators + { X86::AND8rm, X86::AND16rm, X86::AND32rm }, // AND + { X86:: OR8rm, X86:: OR16rm, X86:: OR32rm }, // OR + { X86::XOR8rm, X86::XOR16rm, X86::XOR32rm }, // XOR + }; + + assert(Class < cFP && "General code handles 64-bit integer types!"); + unsigned Opcode = OpcodeTab[OperatorClass][Class]; + + unsigned BaseReg, Scale, IndexReg, Disp; + getAddressingMode(cast(Op1)->getOperand(0), BaseReg, + Scale, IndexReg, Disp); + + unsigned Op0r = getReg(Op0); + addFullAddress(BuildMI(BB, Opcode, 2, DestReg).addReg(Op0r), + BaseReg, Scale, IndexReg, Disp); + return; + } + + emitSimpleBinaryOperation(BB, MI, Op0, Op1, OperatorClass, DestReg); + } + + /// emitSimpleBinaryOperation - Implement simple binary operators for integral + /// types... OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for + /// Or, 4 for Xor. + /// + /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary + /// and constant expression support. + /// + void ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, + unsigned OperatorClass, unsigned DestReg) { + unsigned Class = getClassB(Op0->getType()); + + // sub 0, X -> neg X + if (OperatorClass == 1 && Class != cLong) + if (ConstantInt *CI = dyn_cast(Op0)) { + if (CI->isNullValue()) { + unsigned op1Reg = getReg(Op1, MBB, IP); + switch (Class) { + default: assert(0 && "Unknown class for this function!"); + case cByte: + BuildMI(*MBB, IP, X86::NEG8r, 1, DestReg).addReg(op1Reg); + return; + case cShort: + BuildMI(*MBB, IP, X86::NEG16r, 1, DestReg).addReg(op1Reg); + return; + case cInt: + BuildMI(*MBB, IP, X86::NEG32r, 1, DestReg).addReg(op1Reg); + return; + } + } + } else if (ConstantFP *CFP = dyn_cast(Op0)) + if (CFP->isExactlyValue(-0.0)) { + // -0.0 - X === -X + unsigned op1Reg = getReg(Op1, MBB, IP); + BuildMI(*MBB, IP, X86::FCHS, 1, DestReg).addReg(op1Reg); + return; + } + + // Special case: op Reg, + if (Class != cLong && isa(Op1)) { + ConstantInt *Op1C = cast(Op1); + unsigned Op0r = getReg(Op0, MBB, IP); + + // xor X, -1 -> not X + if (OperatorClass == 4 && Op1C->isAllOnesValue()) { + static unsigned const NOTTab[] = { X86::NOT8r, X86::NOT16r, X86::NOT32r }; + BuildMI(*MBB, IP, NOTTab[Class], 1, DestReg).addReg(Op0r); + return; + } + + // add X, -1 -> dec X + if (OperatorClass == 0 && Op1C->isAllOnesValue()) { + static unsigned const DECTab[] = { X86::DEC8r, X86::DEC16r, X86::DEC32r }; + BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); + return; + } + + // add X, 1 -> inc X + if (OperatorClass == 0 && Op1C->equalsInt(1)) { + static unsigned const DECTab[] = { X86::INC8r, X86::INC16r, X86::INC32r }; + BuildMI(*MBB, IP, DECTab[Class], 1, DestReg).addReg(Op0r); + return; + } + + static const unsigned OpcodeTab[][3] = { + // Arithmetic operators + { X86::ADD8ri, X86::ADD16ri, X86::ADD32ri }, // ADD + { X86::SUB8ri, X86::SUB16ri, X86::SUB32ri }, // SUB + + // Bitwise operators + { X86::AND8ri, X86::AND16ri, X86::AND32ri }, // AND + { X86:: OR8ri, X86:: OR16ri, X86:: OR32ri }, // OR + { X86::XOR8ri, X86::XOR16ri, X86::XOR32ri }, // XOR + }; + + assert(Class < cFP && "General code handles 64-bit integer types!"); + unsigned Opcode = OpcodeTab[OperatorClass][Class]; + + + uint64_t Op1v = cast(Op1C)->getRawValue(); + BuildMI(*MBB, IP, Opcode, 5, DestReg).addReg(Op0r).addImm(Op1v); + return; + } + + // Finally, handle the general case now. + static const unsigned OpcodeTab[][4] = { + // Arithmetic operators + { X86::ADD8rr, X86::ADD16rr, X86::ADD32rr, X86::FpADD }, // ADD + { X86::SUB8rr, X86::SUB16rr, X86::SUB32rr, X86::FpSUB }, // SUB + + // Bitwise operators + { X86::AND8rr, X86::AND16rr, X86::AND32rr, 0 }, // AND + { X86:: OR8rr, X86:: OR16rr, X86:: OR32rr, 0 }, // OR + { X86::XOR8rr, X86::XOR16rr, X86::XOR32rr, 0 }, // XOR + }; + + bool isLong = false; + if (Class == cLong) { + isLong = true; + Class = cInt; // Bottom 32 bits are handled just like ints + } + + unsigned Opcode = OpcodeTab[OperatorClass][Class]; + assert(Opcode && "Floating point arguments to logical inst?"); + unsigned Op0r = getReg(Op0, MBB, IP); + unsigned Op1r = getReg(Op1, MBB, IP); + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); + + if (isLong) { // Handle the upper 32 bits of long values... + static const unsigned TopTab[] = { + X86::ADC32rr, X86::SBB32rr, X86::AND32rr, X86::OR32rr, X86::XOR32rr + }; + BuildMI(*MBB, IP, TopTab[OperatorClass], 2, + DestReg+1).addReg(Op0r+1).addReg(Op1r+1); + } + } + + /// doMultiply - Emit appropriate instructions to multiply together the + /// registers op0Reg and op1Reg, and put the result in DestReg. The type of the + /// result should be given as DestTy. + /// + void ISel::doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI, + unsigned DestReg, const Type *DestTy, + unsigned op0Reg, unsigned op1Reg) { + unsigned Class = getClass(DestTy); + switch (Class) { + case cFP: // Floating point multiply + BuildMI(*MBB, MBBI, X86::FpMUL, 2, DestReg).addReg(op0Reg).addReg(op1Reg); + return; + case cInt: + case cShort: + BuildMI(*MBB, MBBI, Class == cInt ? X86::IMUL32rr:X86::IMUL16rr, 2, DestReg) + .addReg(op0Reg).addReg(op1Reg); + return; + case cByte: + // Must use the MUL instruction, which forces use of AL... + BuildMI(*MBB, MBBI, X86::MOV8rr, 1, X86::AL).addReg(op0Reg); + BuildMI(*MBB, MBBI, X86::MUL8r, 1).addReg(op1Reg); + BuildMI(*MBB, MBBI, X86::MOV8rr, 1, DestReg).addReg(X86::AL); + return; + default: + case cLong: assert(0 && "doMultiply cannot operate on LONG values!"); + } + } + + // ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N. It + // returns zero when the input is not exactly a power of two. + static unsigned ExactLog2(unsigned Val) { + if (Val == 0) return 0; + unsigned Count = 0; + while (Val != 1) { + if (Val & 1) return 0; + Val >>= 1; + ++Count; + } + return Count+1; + } + + void ISel::doMultiplyConst(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned DestReg, const Type *DestTy, + unsigned op0Reg, unsigned ConstRHS) { + unsigned Class = getClass(DestTy); + + // If the element size is exactly a power of 2, use a shift to get it. + if (unsigned Shift = ExactLog2(ConstRHS)) { + switch (Class) { + default: assert(0 && "Unknown class for this function!"); + case cByte: + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); + return; + case cShort: + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); + return; + case cInt: + BuildMI(*MBB, IP, X86::SHL32ri,2, DestReg).addReg(op0Reg).addImm(Shift-1); + return; + } + } + + if (Class == cShort) { + BuildMI(*MBB, IP, X86::IMUL16rri,2,DestReg).addReg(op0Reg).addImm(ConstRHS); + return; + } else if (Class == cInt) { + BuildMI(*MBB, IP, X86::IMUL32rri,2,DestReg).addReg(op0Reg).addImm(ConstRHS); + return; + } + + // Most general case, emit a normal multiply... + static const unsigned MOVriTab[] = { + X86::MOV8ri, X86::MOV16ri, X86::MOV32ri + }; + + unsigned TmpReg = makeAnotherReg(DestTy); + BuildMI(*MBB, IP, MOVriTab[Class], 1, TmpReg).addImm(ConstRHS); + + // Emit a MUL to multiply the register holding the index by + // elementSize, putting the result in OffsetReg. + doMultiply(MBB, IP, DestReg, DestTy, op0Reg, TmpReg); + } + + /// visitMul - Multiplies are not simple binary operators because they must deal + /// with the EAX register explicitly. + /// + void ISel::visitMul(BinaryOperator &I) { + unsigned Op0Reg = getReg(I.getOperand(0)); + unsigned DestReg = getReg(I); + + // Simple scalar multiply? + if (I.getType() != Type::LongTy && I.getType() != Type::ULongTy) { + if (ConstantInt *CI = dyn_cast(I.getOperand(1))) { + unsigned Val = (unsigned)CI->getRawValue(); // Cannot be 64-bit constant + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiplyConst(BB, MBBI, DestReg, I.getType(), Op0Reg, Val); + } else { + unsigned Op1Reg = getReg(I.getOperand(1)); + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiply(BB, MBBI, DestReg, I.getType(), Op0Reg, Op1Reg); + } + } else { + unsigned Op1Reg = getReg(I.getOperand(1)); + + // Long value. We have to do things the hard way... + // Multiply the two low parts... capturing carry into EDX + BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MUL32r, 1).addReg(Op1Reg); // AL*BL + + unsigned OverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOV32rr, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOV32rr, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + + MachineBasicBlock::iterator MBBI = BB->end(); + unsigned AHBLReg = makeAnotherReg(Type::UIntTy); // AH*BL + BuildMI(*BB, MBBI, X86::IMUL32rr,2,AHBLReg).addReg(Op0Reg+1).addReg(Op1Reg); + + unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AH*BL+(AL*BL >> 32) + AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + + MBBI = BB->end(); + unsigned ALBHReg = makeAnotherReg(Type::UIntTy); // AL*BH + BuildMI(*BB, MBBI, X86::IMUL32rr,2,ALBHReg).addReg(Op0Reg).addReg(Op1Reg+1); + + BuildMI(*BB, MBBI, X86::ADD32rr, 2, // AL*BH + AH*BL + (AL*BL >> 32) + DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); + } + } + + + /// visitDivRem - Handle division and remainder instructions... these + /// instruction both require the same instructions to be generated, they just + /// select the result from a different register. Note that both of these + /// instructions work differently for signed and unsigned operands. + /// + void ISel::visitDivRem(BinaryOperator &I) { + unsigned Op0Reg = getReg(I.getOperand(0)); + unsigned Op1Reg = getReg(I.getOperand(1)); + unsigned ResultReg = getReg(I); + + MachineBasicBlock::iterator IP = BB->end(); + emitDivRemOperation(BB, IP, Op0Reg, Op1Reg, I.getOpcode() == Instruction::Div, + I.getType(), ResultReg); + } + + void ISel::emitDivRemOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + unsigned Op0Reg, unsigned Op1Reg, bool isDiv, + const Type *Ty, unsigned ResultReg) { + unsigned Class = getClass(Ty); + switch (Class) { + case cFP: // Floating point divide + if (isDiv) { + BuildMI(*BB, IP, X86::FpDIV, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + } else { // Floating point remainder... + MachineInstr *TheCall = + BuildMI(X86::CALLpcrel32, 1).addExternalSymbol("fmod", true); + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::DoubleTy)); + Args.push_back(ValueRecord(Op1Reg, Type::DoubleTy)); + doCall(ValueRecord(ResultReg, Type::DoubleTy), TheCall, Args); + } + return; + case cLong: { + static const char *FnName[] = + { "__moddi3", "__divdi3", "__umoddi3", "__udivdi3" }; + + unsigned NameIdx = Ty->isUnsigned()*2 + isDiv; + MachineInstr *TheCall = + BuildMI(X86::CALLpcrel32, 1).addExternalSymbol(FnName[NameIdx], true); + + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::LongTy)); + Args.push_back(ValueRecord(Op1Reg, Type::LongTy)); + doCall(ValueRecord(ResultReg, Type::LongTy), TheCall, Args); + return; + } + case cByte: case cShort: case cInt: + break; // Small integrals, handled below... + default: assert(0 && "Unknown class!"); + } + + static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX }; + static const unsigned MovOpcode[]={ X86::MOV8rr, X86::MOV16rr, X86::MOV32rr }; + static const unsigned SarOpcode[]={ X86::SAR8ri, X86::SAR16ri, X86::SAR32ri }; + static const unsigned ClrOpcode[]={ X86::MOV8ri, X86::MOV16ri, X86::MOV32ri }; + static const unsigned ExtRegs[] ={ X86::AH , X86::DX , X86::EDX }; + + static const unsigned DivOpcode[][4] = { + { X86::DIV8r , X86::DIV16r , X86::DIV32r , 0 }, // Unsigned division + { X86::IDIV8r, X86::IDIV16r, X86::IDIV32r, 0 }, // Signed division + }; + + bool isSigned = Ty->isSigned(); + unsigned Reg = Regs[Class]; + unsigned ExtReg = ExtRegs[Class]; + + // Put the first operand into one of the A registers... + BuildMI(*BB, IP, MovOpcode[Class], 1, Reg).addReg(Op0Reg); + + if (isSigned) { + // Emit a sign extension instruction... + unsigned ShiftResult = makeAnotherReg(Ty); + BuildMI(*BB, IP, SarOpcode[Class], 2,ShiftResult).addReg(Op0Reg).addImm(31); + BuildMI(*BB, IP, MovOpcode[Class], 1, ExtReg).addReg(ShiftResult); + } else { + // If unsigned, emit a zeroing instruction... (reg = 0) + BuildMI(*BB, IP, ClrOpcode[Class], 2, ExtReg).addImm(0); + } + + // Emit the appropriate divide or remainder instruction... + BuildMI(*BB, IP, DivOpcode[isSigned][Class], 1).addReg(Op1Reg); + + // Figure out which register we want to pick the result out of... + unsigned DestReg = isDiv ? Reg : ExtReg; + + // Put the result into the destination register... + BuildMI(*BB, IP, MovOpcode[Class], 1, ResultReg).addReg(DestReg); + } + + + /// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here + /// for constant immediate shift values, and for constant immediate + /// shift values equal to 1. Even the general case is sort of special, + /// because the shift amount has to be in CL, not just any old register. + /// + void ISel::visitShiftInst(ShiftInst &I) { + MachineBasicBlock::iterator IP = BB->end (); + emitShiftOperation (BB, IP, I.getOperand (0), I.getOperand (1), + I.getOpcode () == Instruction::Shl, I.getType (), + getReg (I)); + } + + /// emitShiftOperation - Common code shared between visitShiftInst and + /// constant expression support. + void ISel::emitShiftOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op, Value *ShiftAmount, bool isLeftShift, + const Type *ResultTy, unsigned DestReg) { + unsigned SrcReg = getReg (Op, MBB, IP); + bool isSigned = ResultTy->isSigned (); + unsigned Class = getClass (ResultTy); + + static const unsigned ConstantOperand[][4] = { + { X86::SHR8ri, X86::SHR16ri, X86::SHR32ri, X86::SHRD32rri8 }, // SHR + { X86::SAR8ri, X86::SAR16ri, X86::SAR32ri, X86::SHRD32rri8 }, // SAR + { X86::SHL8ri, X86::SHL16ri, X86::SHL32ri, X86::SHLD32rri8 }, // SHL + { X86::SHL8ri, X86::SHL16ri, X86::SHL32ri, X86::SHLD32rri8 }, // SAL = SHL + }; + + static const unsigned NonConstantOperand[][4] = { + { X86::SHR8rCL, X86::SHR16rCL, X86::SHR32rCL }, // SHR + { X86::SAR8rCL, X86::SAR16rCL, X86::SAR32rCL }, // SAR + { X86::SHL8rCL, X86::SHL16rCL, X86::SHL32rCL }, // SHL + { X86::SHL8rCL, X86::SHL16rCL, X86::SHL32rCL }, // SAL = SHL + }; + + // Longs, as usual, are handled specially... + if (Class == cLong) { + // If we have a constant shift, we can generate much more efficient code + // than otherwise... + // + if (ConstantUInt *CUI = dyn_cast(ShiftAmount)) { + unsigned Amount = CUI->getValue(); + if (Amount < 32) { + const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; + if (isLeftShift) { + BuildMI(*MBB, IP, Opc[3], 3, + DestReg+1).addReg(SrcReg+1).addReg(SrcReg).addImm(Amount); + BuildMI(*MBB, IP, Opc[2], 2, DestReg).addReg(SrcReg).addImm(Amount); + } else { + BuildMI(*MBB, IP, Opc[3], 3, + DestReg).addReg(SrcReg ).addReg(SrcReg+1).addImm(Amount); + BuildMI(*MBB, IP, Opc[2],2,DestReg+1).addReg(SrcReg+1).addImm(Amount); + } + } else { // Shifting more than 32 bits + Amount -= 32; + if (isLeftShift) { + BuildMI(*MBB, IP, X86::SHL32ri, 2, + DestReg + 1).addReg(SrcReg).addImm(Amount); + BuildMI(*MBB, IP, X86::MOV32ri, 1, + DestReg).addImm(0); + } else { + unsigned Opcode = isSigned ? X86::SAR32ri : X86::SHR32ri; + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(SrcReg+1).addImm(Amount); + BuildMI(*MBB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); + } + } + } else { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + + if (!isLeftShift && isSigned) { + // If this is a SHR of a Long, then we need to do funny sign extension + // stuff. TmpReg gets the value to use as the high-part if we are + // shifting more than 32 bits. + BuildMI(*MBB, IP, X86::SAR32ri, 2, TmpReg).addReg(SrcReg).addImm(31); + } else { + // Other shifts use a fixed zero value if the shift is more than 32 + // bits. + BuildMI(*MBB, IP, X86::MOV32ri, 1, TmpReg).addImm(0); + } + + // Initialize CL with the shift amount... + unsigned ShiftAmountReg = getReg(ShiftAmount, MBB, IP); + BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(ShiftAmountReg); + + unsigned TmpReg2 = makeAnotherReg(Type::IntTy); + unsigned TmpReg3 = makeAnotherReg(Type::IntTy); + if (isLeftShift) { + // TmpReg2 = shld inHi, inLo + BuildMI(*MBB, IP, X86::SHLD32rrCL,2,TmpReg2).addReg(SrcReg+1) + .addReg(SrcReg); + // TmpReg3 = shl inLo, CL + BuildMI(*MBB, IP, X86::SHL32rCL, 1, TmpReg3).addReg(SrcReg); + + // Set the flags to indicate whether the shift was by more than 32 bits. + BuildMI(*MBB, IP, X86::TEST8ri, 2).addReg(X86::CL).addImm(32); + + // DestHi = (>32) ? TmpReg3 : TmpReg2; + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, + DestReg+1).addReg(TmpReg2).addReg(TmpReg3); + // DestLo = (>32) ? TmpReg : TmpReg3; + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, + DestReg).addReg(TmpReg3).addReg(TmpReg); + } else { + // TmpReg2 = shrd inLo, inHi + BuildMI(*MBB, IP, X86::SHRD32rrCL,2,TmpReg2).addReg(SrcReg) + .addReg(SrcReg+1); + // TmpReg3 = s[ah]r inHi, CL + BuildMI(*MBB, IP, isSigned ? X86::SAR32rCL : X86::SHR32rCL, 1, TmpReg3) + .addReg(SrcReg+1); + + // Set the flags to indicate whether the shift was by more than 32 bits. + BuildMI(*MBB, IP, X86::TEST8ri, 2).addReg(X86::CL).addImm(32); + + // DestLo = (>32) ? TmpReg3 : TmpReg2; + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, + DestReg).addReg(TmpReg2).addReg(TmpReg3); + + // DestHi = (>32) ? TmpReg : TmpReg3; + BuildMI(*MBB, IP, X86::CMOVNE32rr, 2, + DestReg+1).addReg(TmpReg3).addReg(TmpReg); + } + } + return; + } + + if (ConstantUInt *CUI = dyn_cast(ShiftAmount)) { + // The shift amount is constant, guaranteed to be a ubyte. Get its value. + assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); + + const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; + BuildMI(*MBB, IP, Opc[Class], 2, + DestReg).addReg(SrcReg).addImm(CUI->getValue()); + } else { // The shift amount is non-constant. + unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); + BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(ShiftAmountReg); + + const unsigned *Opc = NonConstantOperand[isLeftShift*2+isSigned]; + BuildMI(*MBB, IP, Opc[Class], 1, DestReg).addReg(SrcReg); + } + } + + + void ISel::getAddressingMode(Value *Addr, unsigned &BaseReg, unsigned &Scale, + unsigned &IndexReg, unsigned &Disp) { + BaseReg = 0; Scale = 1; IndexReg = 0; Disp = 0; + if (GetElementPtrInst *GEP = dyn_cast(Addr)) { + if (isGEPFoldable(BB, GEP->getOperand(0), GEP->op_begin()+1, GEP->op_end(), + BaseReg, Scale, IndexReg, Disp)) + return; + } else if (ConstantExpr *CE = dyn_cast(Addr)) { + if (CE->getOpcode() == Instruction::GetElementPtr) + if (isGEPFoldable(BB, CE->getOperand(0), CE->op_begin()+1, CE->op_end(), + BaseReg, Scale, IndexReg, Disp)) + return; + } + + // If it's not foldable, reset addr mode. + BaseReg = getReg(Addr); + Scale = 1; IndexReg = 0; Disp = 0; + } + + + /// visitLoadInst - Implement LLVM load instructions in terms of the x86 'mov' + /// instruction. The load and store instructions are the only place where we + /// need to worry about the memory layout of the target machine. + /// + void ISel::visitLoadInst(LoadInst &I) { + // Check to see if this load instruction is going to be folded into a binary + // instruction, like add. If so, we don't want to emit it. Wouldn't a real + // pattern matching instruction selector be nice? + if (I.hasOneUse() && getClassB(I.getType()) < cFP) { + Instruction *User = cast(I.use_back()); + switch (User->getOpcode()) { + default: User = 0; break; + case Instruction::Add: + case Instruction::Sub: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + break; + } + + if (User) { + // Okay, we found a user. If the load is the first operand and there is + // no second operand load, reverse the operand ordering. Note that this + // can fail for a subtract (ie, no change will be made). + if (!isa(User->getOperand(1))) + cast(User)->swapOperands(); + + // Okay, now that everything is set up, if this load is used by the second + // operand, and if there are no instructions that invalidate the load + // before the binary operator, eliminate the load. + if (User->getOperand(1) == &I && + isSafeToFoldLoadIntoInstruction(I, *User)) + return; // Eliminate the load! + } + } + + unsigned DestReg = getReg(I); + unsigned BaseReg = 0, Scale = 1, IndexReg = 0, Disp = 0; + getAddressingMode(I.getOperand(0), BaseReg, Scale, IndexReg, Disp); + + unsigned Class = getClassB(I.getType()); + if (Class == cLong) { + addFullAddress(BuildMI(BB, X86::MOV32rm, 4, DestReg), + BaseReg, Scale, IndexReg, Disp); + addFullAddress(BuildMI(BB, X86::MOV32rm, 4, DestReg+1), + BaseReg, Scale, IndexReg, Disp+4); + return; + } + + static const unsigned Opcodes[] = { + X86::MOV8rm, X86::MOV16rm, X86::MOV32rm, X86::FLD32m + }; + unsigned Opcode = Opcodes[Class]; + if (I.getType() == Type::DoubleTy) Opcode = X86::FLD64m; + addFullAddress(BuildMI(BB, Opcode, 4, DestReg), + BaseReg, Scale, IndexReg, Disp); + } + + /// visitStoreInst - Implement LLVM store instructions in terms of the x86 'mov' + /// instruction. + /// + void ISel::visitStoreInst(StoreInst &I) { + unsigned BaseReg, Scale, IndexReg, Disp; + getAddressingMode(I.getOperand(1), BaseReg, Scale, IndexReg, Disp); + + const Type *ValTy = I.getOperand(0)->getType(); + unsigned Class = getClassB(ValTy); + + if (ConstantInt *CI = dyn_cast(I.getOperand(0))) { + uint64_t Val = CI->getRawValue(); + if (Class == cLong) { + addFullAddress(BuildMI(BB, X86::MOV32mi, 5), + BaseReg, Scale, IndexReg, Disp).addImm(Val & ~0U); + addFullAddress(BuildMI(BB, X86::MOV32mi, 5), + BaseReg, Scale, IndexReg, Disp+4).addImm(Val>>32); + } else { + static const unsigned Opcodes[] = { + X86::MOV8mi, X86::MOV16mi, X86::MOV32mi + }; + unsigned Opcode = Opcodes[Class]; + addFullAddress(BuildMI(BB, Opcode, 5), + BaseReg, Scale, IndexReg, Disp).addImm(Val); + } + } else if (ConstantBool *CB = dyn_cast(I.getOperand(0))) { + addFullAddress(BuildMI(BB, X86::MOV8mi, 5), + BaseReg, Scale, IndexReg, Disp).addImm(CB->getValue()); + } else { + if (Class == cLong) { + unsigned ValReg = getReg(I.getOperand(0)); + addFullAddress(BuildMI(BB, X86::MOV32mr, 5), + BaseReg, Scale, IndexReg, Disp).addReg(ValReg); + addFullAddress(BuildMI(BB, X86::MOV32mr, 5), + BaseReg, Scale, IndexReg, Disp+4).addReg(ValReg+1); + } else { + unsigned ValReg = getReg(I.getOperand(0)); + static const unsigned Opcodes[] = { + X86::MOV8mr, X86::MOV16mr, X86::MOV32mr, X86::FST32m + }; + unsigned Opcode = Opcodes[Class]; + if (ValTy == Type::DoubleTy) Opcode = X86::FST64m; + addFullAddress(BuildMI(BB, Opcode, 1+4), + BaseReg, Scale, IndexReg, Disp).addReg(ValReg); + } + } + } + + + /// visitCastInst - Here we have various kinds of copying with or without sign + /// extension going on. + /// + void ISel::visitCastInst(CastInst &CI) { + Value *Op = CI.getOperand(0); + // If this is a cast from a 32-bit integer to a Long type, and the only uses + // of the case are GEP instructions, then the cast does not need to be + // generated explicitly, it will be folded into the GEP. + if (CI.getType() == Type::LongTy && + (Op->getType() == Type::IntTy || Op->getType() == Type::UIntTy)) { + bool AllUsesAreGEPs = true; + for (Value::use_iterator I = CI.use_begin(), E = CI.use_end(); I != E; ++I) + if (!isa(*I)) { + AllUsesAreGEPs = false; + break; + } + + // No need to codegen this cast if all users are getelementptr instrs... + if (AllUsesAreGEPs) return; + } + + unsigned DestReg = getReg(CI); + MachineBasicBlock::iterator MI = BB->end(); + emitCastOperation(BB, MI, Op, CI.getType(), DestReg); + } + + /// emitCastOperation - Common code shared between visitCastInst and constant + /// expression cast support. + /// + void ISel::emitCastOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Src, const Type *DestTy, + unsigned DestReg) { + unsigned SrcReg = getReg(Src, BB, IP); + const Type *SrcTy = Src->getType(); + unsigned SrcClass = getClassB(SrcTy); + unsigned DestClass = getClassB(DestTy); + + // Implement casts to bool by using compare on the operand followed by set if + // not zero on the result. + if (DestTy == Type::BoolTy) { + switch (SrcClass) { + case cByte: + BuildMI(*BB, IP, X86::TEST8rr, 2).addReg(SrcReg).addReg(SrcReg); + break; + case cShort: + BuildMI(*BB, IP, X86::TEST16rr, 2).addReg(SrcReg).addReg(SrcReg); + break; + case cInt: + BuildMI(*BB, IP, X86::TEST32rr, 2).addReg(SrcReg).addReg(SrcReg); + break; + case cLong: { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + BuildMI(*BB, IP, X86::OR32rr, 2, TmpReg).addReg(SrcReg).addReg(SrcReg+1); + break; + } + case cFP: + BuildMI(*BB, IP, X86::FTST, 1).addReg(SrcReg); + BuildMI(*BB, IP, X86::FNSTSW8r, 0); + BuildMI(*BB, IP, X86::SAHF, 1); + break; + } + + // If the zero flag is not set, then the value is true, set the byte to + // true. + BuildMI(*BB, IP, X86::SETNEr, 1, DestReg); + return; + } + + static const unsigned RegRegMove[] = { + X86::MOV8rr, X86::MOV16rr, X86::MOV32rr, X86::FpMOV, X86::MOV32rr + }; + + // Implement casts between values of the same type class (as determined by + // getClass) by using a register-to-register move. + if (SrcClass == DestClass) { + if (SrcClass <= cInt || (SrcClass == cFP && SrcTy == DestTy)) { + BuildMI(*BB, IP, RegRegMove[SrcClass], 1, DestReg).addReg(SrcReg); + } else if (SrcClass == cFP) { + if (SrcTy == Type::FloatTy) { // double -> float + assert(DestTy == Type::DoubleTy && "Unknown cFP member!"); + BuildMI(*BB, IP, X86::FpMOV, 1, DestReg).addReg(SrcReg); + } else { // float -> double + assert(SrcTy == Type::DoubleTy && DestTy == Type::FloatTy && + "Unknown cFP member!"); + // Truncate from double to float by storing to memory as short, then + // reading it back. + unsigned FltAlign = TM.getTargetData().getFloatAlignment(); + int FrameIdx = F->getFrameInfo()->CreateStackObject(4, FltAlign); + addFrameReference(BuildMI(*BB, IP, X86::FST32m, 5), FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, X86::FLD32m, 5, DestReg), FrameIdx); + } + } else if (SrcClass == cLong) { + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg+1).addReg(SrcReg+1); + } else { + assert(0 && "Cannot handle this type of cast instruction!"); + abort(); + } + return; + } + + // Handle cast of SMALLER int to LARGER int using a move with sign extension + // or zero extension, depending on whether the source type was signed. + if (SrcClass <= cInt && (DestClass <= cInt || DestClass == cLong) && + SrcClass < DestClass) { + bool isLong = DestClass == cLong; + if (isLong) DestClass = cInt; + + static const unsigned Opc[][4] = { + { X86::MOVSX16rr8, X86::MOVSX32rr8, X86::MOVSX32rr16, X86::MOV32rr }, // s + { X86::MOVZX16rr8, X86::MOVZX32rr8, X86::MOVZX32rr16, X86::MOV32rr } // u + }; + + bool isUnsigned = SrcTy->isUnsigned(); + BuildMI(*BB, IP, Opc[isUnsigned][SrcClass + DestClass - 1], 1, + DestReg).addReg(SrcReg); + + if (isLong) { // Handle upper 32 bits as appropriate... + if (isUnsigned) // Zero out top bits... + BuildMI(*BB, IP, X86::MOV32ri, 1, DestReg+1).addImm(0); + else // Sign extend bottom half... + BuildMI(*BB, IP, X86::SAR32ri, 2, DestReg+1).addReg(DestReg).addImm(31); + } + return; + } + + // Special case long -> int ... + if (SrcClass == cLong && DestClass == cInt) { + BuildMI(*BB, IP, X86::MOV32rr, 1, DestReg).addReg(SrcReg); + return; + } + + // Handle cast of LARGER int to SMALLER int using a move to EAX followed by a + // move out of AX or AL. + if ((SrcClass <= cInt || SrcClass == cLong) && DestClass <= cInt + && SrcClass > DestClass) { + static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX, 0, X86::EAX }; + BuildMI(*BB, IP, RegRegMove[SrcClass], 1, AReg[SrcClass]).addReg(SrcReg); + BuildMI(*BB, IP, RegRegMove[DestClass], 1, DestReg).addReg(AReg[DestClass]); + return; + } + + // Handle casts from integer to floating point now... + if (DestClass == cFP) { + // Promote the integer to a type supported by FLD. We do this because there + // are no unsigned FLD instructions, so we must promote an unsigned value to + // a larger signed value, then use FLD on the larger value. + // + const Type *PromoteType = 0; + unsigned PromoteOpcode; + unsigned RealDestReg = DestReg; + switch (SrcTy->getPrimitiveID()) { + case Type::BoolTyID: + case Type::SByteTyID: + // We don't have the facilities for directly loading byte sized data from + // memory (even signed). Promote it to 16 bits. + PromoteType = Type::ShortTy; + PromoteOpcode = X86::MOVSX16rr8; + break; + case Type::UByteTyID: + PromoteType = Type::ShortTy; + PromoteOpcode = X86::MOVZX16rr8; + break; + case Type::UShortTyID: + PromoteType = Type::IntTy; + PromoteOpcode = X86::MOVZX32rr16; + break; + case Type::UIntTyID: { + // Make a 64 bit temporary... and zero out the top of it... + unsigned TmpReg = makeAnotherReg(Type::LongTy); + BuildMI(*BB, IP, X86::MOV32rr, 1, TmpReg).addReg(SrcReg); + BuildMI(*BB, IP, X86::MOV32ri, 1, TmpReg+1).addImm(0); + SrcTy = Type::LongTy; + SrcClass = cLong; + SrcReg = TmpReg; + break; + } + case Type::ULongTyID: + // Don't fild into the read destination. + DestReg = makeAnotherReg(Type::DoubleTy); + break; + default: // No promotion needed... + break; + } + + if (PromoteType) { + unsigned TmpReg = makeAnotherReg(PromoteType); + unsigned Opc = SrcTy->isSigned() ? X86::MOVSX16rr8 : X86::MOVZX16rr8; + BuildMI(*BB, IP, Opc, 1, TmpReg).addReg(SrcReg); + SrcTy = PromoteType; + SrcClass = getClass(PromoteType); + SrcReg = TmpReg; + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); + + if (SrcClass == cLong) { + addFrameReference(BuildMI(*BB, IP, X86::MOV32mr, 5), + FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, X86::MOV32mr, 5), + FrameIdx, 4).addReg(SrcReg+1); + } else { + static const unsigned Op1[] = { X86::MOV8mr, X86::MOV16mr, X86::MOV32mr }; + addFrameReference(BuildMI(*BB, IP, Op1[SrcClass], 5), + FrameIdx).addReg(SrcReg); + } + + static const unsigned Op2[] = + { 0/*byte*/, X86::FILD16m, X86::FILD32m, 0/*FP*/, X86::FILD64m }; + addFrameReference(BuildMI(*BB, IP, Op2[SrcClass], 5, DestReg), FrameIdx); + + // We need special handling for unsigned 64-bit integer sources. If the + // input number has the "sign bit" set, then we loaded it incorrectly as a + // negative 64-bit number. In this case, add an offset value. + if (SrcTy == Type::ULongTy) { + // Emit a test instruction to see if the dynamic input value was signed. + BuildMI(*BB, IP, X86::TEST32rr, 2).addReg(SrcReg+1).addReg(SrcReg+1); + + // If the sign bit is set, get a pointer to an offset, otherwise get a + // pointer to a zero. + MachineConstantPool *CP = F->getConstantPool(); + unsigned Zero = makeAnotherReg(Type::IntTy); + Constant *Null = Constant::getNullValue(Type::UIntTy); + addConstantPoolReference(BuildMI(*BB, IP, X86::LEA32r, 5, Zero), + CP->getConstantPoolIndex(Null)); + unsigned Offset = makeAnotherReg(Type::IntTy); + Constant *OffsetCst = ConstantUInt::get(Type::UIntTy, 0x5f800000); + + addConstantPoolReference(BuildMI(*BB, IP, X86::LEA32r, 5, Offset), + CP->getConstantPoolIndex(OffsetCst)); + unsigned Addr = makeAnotherReg(Type::IntTy); + BuildMI(*BB, IP, X86::CMOVS32rr, 2, Addr).addReg(Zero).addReg(Offset); + + // Load the constant for an add. FIXME: this could make an 'fadd' that + // reads directly from memory, but we don't support these yet. + unsigned ConstReg = makeAnotherReg(Type::DoubleTy); + addDirectMem(BuildMI(*BB, IP, X86::FLD32m, 4, ConstReg), Addr); + + BuildMI(*BB, IP, X86::FpADD, 2, RealDestReg) + .addReg(ConstReg).addReg(DestReg); + } + + return; + } + + // Handle casts from floating point to integer now... + if (SrcClass == cFP) { + // Change the floating point control register to use "round towards zero" + // mode when truncating to an integer value. + // + int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2); + addFrameReference(BuildMI(*BB, IP, X86::FNSTCW16m, 4), CWFrameIdx); + + // Load the old value of the high byte of the control word... + unsigned HighPartOfCW = makeAnotherReg(Type::UByteTy); + addFrameReference(BuildMI(*BB, IP, X86::MOV8rm, 4, HighPartOfCW), + CWFrameIdx, 1); + + // Set the high part to be round to zero... + addFrameReference(BuildMI(*BB, IP, X86::MOV8mi, 5), + CWFrameIdx, 1).addImm(12); + + // Reload the modified control word now... + addFrameReference(BuildMI(*BB, IP, X86::FLDCW16m, 4), CWFrameIdx); + + // Restore the memory image of control word to original value + addFrameReference(BuildMI(*BB, IP, X86::MOV8mr, 5), + CWFrameIdx, 1).addReg(HighPartOfCW); + + // We don't have the facilities for directly storing byte sized data to + // memory. Promote it to 16 bits. We also must promote unsigned values to + // larger classes because we only have signed FP stores. + unsigned StoreClass = DestClass; + const Type *StoreTy = DestTy; + if (StoreClass == cByte || DestTy->isUnsigned()) + switch (StoreClass) { + case cByte: StoreTy = Type::ShortTy; StoreClass = cShort; break; + case cShort: StoreTy = Type::IntTy; StoreClass = cInt; break; + case cInt: StoreTy = Type::LongTy; StoreClass = cLong; break; + // The following treatment of cLong may not be perfectly right, + // but it survives chains of casts of the form + // double->ulong->double. + case cLong: StoreTy = Type::LongTy; StoreClass = cLong; break; + default: assert(0 && "Unknown store class!"); + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(StoreTy, TM.getTargetData()); + + static const unsigned Op1[] = + { 0, X86::FIST16m, X86::FIST32m, 0, X86::FISTP64m }; + addFrameReference(BuildMI(*BB, IP, Op1[StoreClass], 5), + FrameIdx).addReg(SrcReg); + + if (DestClass == cLong) { + addFrameReference(BuildMI(*BB, IP, X86::MOV32rm, 4, DestReg), FrameIdx); + addFrameReference(BuildMI(*BB, IP, X86::MOV32rm, 4, DestReg+1), + FrameIdx, 4); + } else { + static const unsigned Op2[] = { X86::MOV8rm, X86::MOV16rm, X86::MOV32rm }; + addFrameReference(BuildMI(*BB, IP, Op2[DestClass], 4, DestReg), FrameIdx); + } + + // Reload the original control word now... + addFrameReference(BuildMI(*BB, IP, X86::FLDCW16m, 4), CWFrameIdx); + return; + } + + // Anything we haven't handled already, we can't (yet) handle at all. + assert(0 && "Unhandled cast instruction!"); + abort(); + } + + /// visitVANextInst - Implement the va_next instruction... + /// + void ISel::visitVANextInst(VANextInst &I) { + unsigned VAList = getReg(I.getOperand(0)); + unsigned DestReg = getReg(I); + + unsigned Size; + switch (I.getArgType()->getPrimitiveID()) { + default: + std::cerr << I; + assert(0 && "Error: bad type for va_next instruction!"); + return; + case Type::PointerTyID: + case Type::UIntTyID: + case Type::IntTyID: + Size = 4; + break; + case Type::ULongTyID: + case Type::LongTyID: + case Type::DoubleTyID: + Size = 8; + break; + } + + // Increment the VAList pointer... + BuildMI(BB, X86::ADD32ri, 2, DestReg).addReg(VAList).addImm(Size); + } + + void ISel::visitVAArgInst(VAArgInst &I) { + unsigned VAList = getReg(I.getOperand(0)); + unsigned DestReg = getReg(I); + + switch (I.getType()->getPrimitiveID()) { + default: + std::cerr << I; + assert(0 && "Error: bad type for va_next instruction!"); + return; + case Type::PointerTyID: + case Type::UIntTyID: + case Type::IntTyID: + addDirectMem(BuildMI(BB, X86::MOV32rm, 4, DestReg), VAList); + break; + case Type::ULongTyID: + case Type::LongTyID: + addDirectMem(BuildMI(BB, X86::MOV32rm, 4, DestReg), VAList); + addRegOffset(BuildMI(BB, X86::MOV32rm, 4, DestReg+1), VAList, 4); + break; + case Type::DoubleTyID: + addDirectMem(BuildMI(BB, X86::FLD64m, 4, DestReg), VAList); + break; + } + } + + /// visitGetElementPtrInst - instruction-select GEP instructions + /// + void ISel::visitGetElementPtrInst(GetElementPtrInst &I) { + // If this GEP instruction will be folded into all of its users, we don't need + // to explicitly calculate it! + unsigned A, B, C, D; + if (isGEPFoldable(0, I.getOperand(0), I.op_begin()+1, I.op_end(), A,B,C,D)) { + // Check all of the users of the instruction to see if they are loads and + // stores. + bool AllWillFold = true; + for (Value::use_iterator UI = I.use_begin(), E = I.use_end(); UI != E; ++UI) + if (cast(*UI)->getOpcode() != Instruction::Load) + if (cast(*UI)->getOpcode() != Instruction::Store || + cast(*UI)->getOperand(0) == &I) { + AllWillFold = false; + break; + } + + // If the instruction is foldable, and will be folded into all users, don't + // emit it! + if (AllWillFold) return; + } + + unsigned outputReg = getReg(I); + emitGEPOperation(BB, BB->end(), I.getOperand(0), + I.op_begin()+1, I.op_end(), outputReg); + } + + /// getGEPIndex - Inspect the getelementptr operands specified with GEPOps and + /// GEPTypes (the derived types being stepped through at each level). On return + /// from this function, if some indexes of the instruction are representable as + /// an X86 lea instruction, the machine operands are put into the Ops + /// instruction and the consumed indexes are poped from the GEPOps/GEPTypes + /// lists. Otherwise, GEPOps.size() is returned. If this returns a an + /// addressing mode that only partially consumes the input, the BaseReg input of + /// the addressing mode must be left free. + /// + /// Note that there is one fewer entry in GEPTypes than there is in GEPOps. + /// + void ISel::getGEPIndex(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + std::vector &GEPOps, + std::vector &GEPTypes, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp) { + const TargetData &TD = TM.getTargetData(); + + // Clear out the state we are working with... + BaseReg = 0; // No base register + Scale = 1; // Unit scale + IndexReg = 0; // No index register + Disp = 0; // No displacement + + // While there are GEP indexes that can be folded into the current address, + // keep processing them. + while (!GEPTypes.empty()) { + if (const StructType *StTy = dyn_cast(GEPTypes.back())) { + // It's a struct access. CUI is the index into the structure, + // which names the field. This index must have unsigned type. + const ConstantUInt *CUI = cast(GEPOps.back()); + + // Use the TargetData structure to pick out what the layout of the + // structure is in memory. Since the structure index must be constant, we + // can get its value and use it to find the right byte offset from the + // StructLayout class's list of structure member offsets. + Disp += TD.getStructLayout(StTy)->MemberOffsets[CUI->getValue()]; + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); + } else { + // It's an array or pointer access: [ArraySize x ElementType]. + const SequentialType *SqTy = cast(GEPTypes.back()); + Value *idx = GEPOps.back(); + + // idx is the index into the array. Unlike with structure + // indices, we may not know its actual value at code-generation + // time. + assert(idx->getType() == Type::LongTy && "Bad GEP array index!"); + + // If idx is a constant, fold it into the offset. + unsigned TypeSize = TD.getTypeSize(SqTy->getElementType()); + if (ConstantSInt *CSI = dyn_cast(idx)) { + Disp += TypeSize*CSI->getValue(); + } else { + // If the index reg is already taken, we can't handle this index. + if (IndexReg) return; + + // If this is a size that we can handle, then add the index as + switch (TypeSize) { + case 1: case 2: case 4: case 8: + // These are all acceptable scales on X86. + Scale = TypeSize; + break; + default: + // Otherwise, we can't handle this scale + return; + } + + if (CastInst *CI = dyn_cast(idx)) + if (CI->getOperand(0)->getType() == Type::IntTy || + CI->getOperand(0)->getType() == Type::UIntTy) + idx = CI->getOperand(0); + + IndexReg = MBB ? getReg(idx, MBB, IP) : 1; + } + + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); + } + } + + // GEPTypes is empty, which means we have a single operand left. See if we + // can set it as the base register. + // + // FIXME: When addressing modes are more powerful/correct, we could load + // global addresses directly as 32-bit immediates. + assert(BaseReg == 0); + BaseReg = MBB ? getReg(GEPOps[0], MBB, IP) : 1; + GEPOps.pop_back(); // Consume the last GEP operand + } + + + /// isGEPFoldable - Return true if the specified GEP can be completely + /// folded into the addressing mode of a load/store or lea instruction. + bool ISel::isGEPFoldable(MachineBasicBlock *MBB, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned &BaseReg, + unsigned &Scale, unsigned &IndexReg, unsigned &Disp) { + if (ConstantPointerRef *CPR = dyn_cast(Src)) + Src = CPR->getValue(); + + std::vector GEPOps; + GEPOps.resize(IdxEnd-IdxBegin+1); + GEPOps[0] = Src; + std::copy(IdxBegin, IdxEnd, GEPOps.begin()+1); + + std::vector GEPTypes; + GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd), + gep_type_end(Src->getType(), IdxBegin, IdxEnd)); + + MachineBasicBlock::iterator IP; + if (MBB) IP = MBB->end(); + getGEPIndex(MBB, IP, GEPOps, GEPTypes, BaseReg, Scale, IndexReg, Disp); + + // We can fold it away iff the getGEPIndex call eliminated all operands. + return GEPOps.empty(); + } + + void ISel::emitGEPOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned TargetReg) { + const TargetData &TD = TM.getTargetData(); + if (ConstantPointerRef *CPR = dyn_cast(Src)) + Src = CPR->getValue(); + + std::vector GEPOps; + GEPOps.resize(IdxEnd-IdxBegin+1); + GEPOps[0] = Src; + std::copy(IdxBegin, IdxEnd, GEPOps.begin()+1); + + std::vector GEPTypes; + GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd), + gep_type_end(Src->getType(), IdxBegin, IdxEnd)); + + // Keep emitting instructions until we consume the entire GEP instruction. + while (!GEPOps.empty()) { + unsigned OldSize = GEPOps.size(); + unsigned BaseReg, Scale, IndexReg, Disp; + getGEPIndex(MBB, IP, GEPOps, GEPTypes, BaseReg, Scale, IndexReg, Disp); + + if (GEPOps.size() != OldSize) { + // getGEPIndex consumed some of the input. Build an LEA instruction here. + unsigned NextTarget = 0; + if (!GEPOps.empty()) { + assert(BaseReg == 0 && + "getGEPIndex should have left the base register open for chaining!"); + NextTarget = BaseReg = makeAnotherReg(Type::UIntTy); + } + + if (IndexReg == 0 && Disp == 0) + BuildMI(*MBB, IP, X86::MOV32rr, 1, TargetReg).addReg(BaseReg); + else + addFullAddress(BuildMI(*MBB, IP, X86::LEA32r, 5, TargetReg), + BaseReg, Scale, IndexReg, Disp); + --IP; + TargetReg = NextTarget; + } else if (GEPTypes.empty()) { + // The getGEPIndex operation didn't want to build an LEA. Check to see if + // all operands are consumed but the base pointer. If so, just load it + // into the register. + if (GlobalValue *GV = dyn_cast(GEPOps[0])) { + BuildMI(*MBB, IP, X86::MOV32ri, 1, TargetReg).addGlobalAddress(GV); + } else { + unsigned BaseReg = getReg(GEPOps[0], MBB, IP); + BuildMI(*MBB, IP, X86::MOV32rr, 1, TargetReg).addReg(BaseReg); + } + break; // we are now done + + } else { + // It's an array or pointer access: [ArraySize x ElementType]. + const SequentialType *SqTy = cast(GEPTypes.back()); + Value *idx = GEPOps.back(); + GEPOps.pop_back(); // Consume a GEP operand + GEPTypes.pop_back(); + + // idx is the index into the array. Unlike with structure + // indices, we may not know its actual value at code-generation + // time. + assert(idx->getType() == Type::LongTy && "Bad GEP array index!"); + + // Most GEP instructions use a [cast (int/uint) to LongTy] as their + // operand on X86. Handle this case directly now... + if (CastInst *CI = dyn_cast(idx)) + if (CI->getOperand(0)->getType() == Type::IntTy || + CI->getOperand(0)->getType() == Type::UIntTy) + idx = CI->getOperand(0); + + // We want to add BaseReg to(idxReg * sizeof ElementType). First, we + // must find the size of the pointed-to type (Not coincidentally, the next + // type is the type of the elements in the array). + const Type *ElTy = SqTy->getElementType(); + unsigned elementSize = TD.getTypeSize(ElTy); + + // If idxReg is a constant, we don't need to perform the multiply! + if (ConstantSInt *CSI = dyn_cast(idx)) { + if (!CSI->isNullValue()) { + unsigned Offset = elementSize*CSI->getValue(); + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32ri, 2, TargetReg) + .addReg(Reg).addImm(Offset); + --IP; // Insert the next instruction before this one. + TargetReg = Reg; // Codegen the rest of the GEP into this + } + } else if (elementSize == 1) { + // If the element size is 1, we don't have to multiply, just add + unsigned idxReg = getReg(idx, MBB, IP); + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32rr, 2,TargetReg).addReg(Reg).addReg(idxReg); + --IP; // Insert the next instruction before this one. + TargetReg = Reg; // Codegen the rest of the GEP into this + } else { + unsigned idxReg = getReg(idx, MBB, IP); + unsigned OffsetReg = makeAnotherReg(Type::UIntTy); + + // Make sure we can back the iterator up to point to the first + // instruction emitted. + MachineBasicBlock::iterator BeforeIt = IP; + if (IP == MBB->begin()) + BeforeIt = MBB->end(); + else + --BeforeIt; + doMultiplyConst(MBB, IP, OffsetReg, Type::IntTy, idxReg, elementSize); + + // Emit an ADD to add OffsetReg to the basePtr. + unsigned Reg = makeAnotherReg(Type::UIntTy); + BuildMI(*MBB, IP, X86::ADD32rr, 2, TargetReg) + .addReg(Reg).addReg(OffsetReg); + + // Step to the first instruction of the multiply. + if (BeforeIt == MBB->end()) + IP = MBB->begin(); + else + IP = ++BeforeIt; + + TargetReg = Reg; // Codegen the rest of the GEP into this + } + } + } + } + + + /// visitAllocaInst - If this is a fixed size alloca, allocate space from the + /// frame manager, otherwise do it the hard way. + /// + void ISel::visitAllocaInst(AllocaInst &I) { + // Find the data size of the alloca inst's getAllocatedType. + const Type *Ty = I.getAllocatedType(); + unsigned TySize = TM.getTargetData().getTypeSize(Ty); + + // If this is a fixed size alloca in the entry block for the function, + // statically stack allocate the space. + // + if (ConstantUInt *CUI = dyn_cast(I.getArraySize())) { + if (I.getParent() == I.getParent()->getParent()->begin()) { + TySize *= CUI->getValue(); // Get total allocated size... + unsigned Alignment = TM.getTargetData().getTypeAlignment(Ty); + + // Create a new stack object using the frame manager... + int FrameIdx = F->getFrameInfo()->CreateStackObject(TySize, Alignment); + addFrameReference(BuildMI(BB, X86::LEA32r, 5, getReg(I)), FrameIdx); + return; + } + } + + // Create a register to hold the temporary result of multiplying the type size + // constant by the variable amount. + unsigned TotalSizeReg = makeAnotherReg(Type::UIntTy); + unsigned SrcReg1 = getReg(I.getArraySize()); + + // TotalSizeReg = mul , + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiplyConst(BB, MBBI, TotalSizeReg, Type::UIntTy, SrcReg1, TySize); + + // AddedSize = add , 15 + unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::ADD32ri, 2, AddedSizeReg).addReg(TotalSizeReg).addImm(15); + + // AlignedSize = and , ~15 + unsigned AlignedSize = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::AND32ri, 2, AlignedSize).addReg(AddedSizeReg).addImm(~15); + + // Subtract size from stack pointer, thereby allocating some space. + BuildMI(BB, X86::SUB32rr, 2, X86::ESP).addReg(X86::ESP).addReg(AlignedSize); + + // Put a pointer to the space into the result register, by copying + // the stack pointer. + BuildMI(BB, X86::MOV32rr, 1, getReg(I)).addReg(X86::ESP); + + // Inform the Frame Information that we have just allocated a variable-sized + // object. + F->getFrameInfo()->CreateVariableSizedObject(); + } + + /// visitMallocInst - Malloc instructions are code generated into direct calls + /// to the library malloc. + /// + void ISel::visitMallocInst(MallocInst &I) { + unsigned AllocSize = TM.getTargetData().getTypeSize(I.getAllocatedType()); + unsigned Arg; + + if (ConstantUInt *C = dyn_cast(I.getOperand(0))) { + Arg = getReg(ConstantUInt::get(Type::UIntTy, C->getValue() * AllocSize)); + } else { + Arg = makeAnotherReg(Type::UIntTy); + unsigned Op0Reg = getReg(I.getOperand(0)); + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiplyConst(BB, MBBI, Arg, Type::UIntTy, Op0Reg, AllocSize); + } + + std::vector Args; + Args.push_back(ValueRecord(Arg, Type::UIntTy)); + MachineInstr *TheCall = BuildMI(X86::CALLpcrel32, + 1).addExternalSymbol("malloc", true); + doCall(ValueRecord(getReg(I), I.getType()), TheCall, Args); + } + + + /// visitFreeInst - Free instructions are code gen'd to call the free libc + /// function. + /// + void ISel::visitFreeInst(FreeInst &I) { + std::vector Args; + Args.push_back(ValueRecord(I.getOperand(0))); + MachineInstr *TheCall = BuildMI(X86::CALLpcrel32, + 1).addExternalSymbol("free", true); + doCall(ValueRecord(0, Type::VoidTy), TheCall, Args); + } + + /// createX86SimpleInstructionSelector - This pass converts an LLVM function + /// into a machine code representation is a very simple peep-hole fashion. The + /// generated code sucks but the implementation is nice and simple. + /// + FunctionPass *llvm::createX86ReallySimpleInstructionSelector(TargetMachine &TM) { + return new ISel(TM); + } + + #include "X86GenSimpInstrSelector.inc" From lattner at cs.uiuc.edu Tue Apr 6 14:49:03 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 14:49:03 2004 Subject: [llvm-commits] CVS: llvm/docs/ReleaseNotes.html Message-ID: <200404061948.OAA01432@zion.cs.uiuc.edu> Changes in directory llvm/docs: ReleaseNotes.html updated: 1.161 -> 1.162 --- Log message: Bugs fixed new features implemented --- Diffs of the changes: (+4 -1) Index: llvm/docs/ReleaseNotes.html diff -u llvm/docs/ReleaseNotes.html:1.161 llvm/docs/ReleaseNotes.html:1.162 --- llvm/docs/ReleaseNotes.html:1.161 Sun Apr 4 20:43:08 2004 +++ llvm/docs/ReleaseNotes.html Tue Apr 6 14:48:42 2004 @@ -89,6 +89,7 @@

        1. The LLVM select instruction is now fully implemented and supported by all targets.
        2. +
        3. Bugpoint can now narrow down code-generation bugs to a loop nest, where before it could only narrow them down to a function being miscompiled.
        @@ -127,6 +128,7 @@
        1. [vmcore] Code quality problem due to long operand of getelementptr
        2. +
        3. The X86 backend now generates substantially better code for 64-bit integer operations.
        @@ -140,6 +142,7 @@
        1. [loopsimplify] Loop simplify incorrectly updates dominator information
        2. [tailduplicate] DemoteRegToStack breaks SSA form
        3. +
        4. [X86] JIT miscompiles unsigned short to floating point cast
        @@ -559,7 +562,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" /> The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/04/05 01:43:08 $ + Last modified: $Date: 2004/04/06 19:48:42 $ From lattner at cs.uiuc.edu Tue Apr 6 14:49:23 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 14:49:23 2004 Subject: [llvm-commits] CVS: llvm-www/releases/1.2/docs/ReleaseNotes.html Message-ID: <200404061949.OAA01957@zion.cs.uiuc.edu> Changes in directory llvm-www/releases/1.2/docs: ReleaseNotes.html updated: 1.7 -> 1.8 --- Log message: Bug found! --- Diffs of the changes: (+4 -2) Index: llvm-www/releases/1.2/docs/ReleaseNotes.html diff -u llvm-www/releases/1.2/docs/ReleaseNotes.html:1.7 llvm-www/releases/1.2/docs/ReleaseNotes.html:1.8 --- llvm-www/releases/1.2/docs/ReleaseNotes.html:1.7 Sun Apr 4 20:43:27 2004 +++ llvm-www/releases/1.2/docs/ReleaseNotes.html Tue Apr 6 14:48:55 2004 @@ -593,8 +593,10 @@
        +Bugs in 1.2 fixed in 1.3:
        @@ -669,7 +671,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" /> The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/04/05 01:43:27 $ + Last modified: $Date: 2004/04/06 19:48:55 $ From lattner at cs.uiuc.edu Tue Apr 6 15:19:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue Apr 6 15:19:02 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp Message-ID: <200404062018.PAA14223@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++: moments.cpp updated: 1.1 -> 1.2 --- Log message: Since we don't have the data file to use with this benchmark, just input it manually. This prevents it from segfaulting on every execution! --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp diff -u llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp:1.1 llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp:1.2 --- llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp:1.1 Mon Oct 6 20:11:33 2003 +++ llvm/test/Programs/SingleSource/Benchmarks/Shootout-C++/moments.cpp Tue Apr 6 15:18:07 2004 @@ -69,7 +69,7 @@ vector v; double d; - while (scanf(" %lf", &d) == 1) v.push_back(d); + for (unsigned i = 0; i != 500; ++i) v.push_back(i); moments m(v.begin(), v.end()); printf("n: %d\n", v.end() - v.begin()); From criswell at cs.uiuc.edu Tue Apr 6 15:23:01 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:23:01 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/ Message-ID: <200404062022.PAA03762@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/kimwitu++ added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 15:24:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:24:02 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/ Message-ID: <200404062023.PAA03791@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++/doc: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/kimwitu++/doc added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 15:24:23 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:24:23 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/LICENSE.TXT Message-ID: <200404062022.PAA03774@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++: LICENSE.TXT added (r1.1) --- Log message: Adding Kimwitu++ license file. --- Diffs of the changes: (+41 -0) Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/LICENSE.TXT diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/LICENSE.TXT:1.1 *** /dev/null Tue Apr 6 15:22:57 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/LICENSE.TXT Tue Apr 6 15:22:47 2004 *************** *** 0 **** --- 1,41 ---- + Kimwitu++ + ------------------------------------------------------------------------------- + Kimwitu++ is distributed as an LLVM benchmark. The LLVM "no warranty" clause + applies. Please see llvm/LICENSE.TXT for further details. + + Kimwitu++, a system that supports the construction of programs that + use trees or terms as their main data structure. + Copyright (C) 1988-1997 Axel Belinfante, University of Twente + Copyright (C) 1997-2000 Michael Piefel, Humboldt-University Berlin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Kimwitu++ is based on Kimwitu. + + Output of Kimwitu (and of works based on Kimwitu) can be used without + restriction (even though this output may contain fragments from the + source code of Kimwitu (or of works based on Kimwitu)), with one nota- + ble exception (because Kimwitu is built using itself): The output + generated by Kimwitu (and by works based on Kimwitu) from the source + code of Kimwitu (and from the source code of works based on Kimwitu) + is covered by the GNU General Public License. + + The structure-file-io reading and writing code has been derived, in part, + from The Synthesizer Generator (tm), a product of GrammaTech, Inc, + copyright (C) 1991, GrammaTech, Inc. Used with permission. + + GrammaTech and Synthesizer Generator, are tradenames of GrammaTech, Inc., + One Hopkins Place, Ithaca, NY 14850, (607) 273-7340. + From criswell at cs.uiuc.edu Tue Apr 6 15:24:37 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:24:37 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/formatters/ Message-ID: <200404062023.PAA03805@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/formatters: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/formatters added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 15:24:54 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:24:54 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/figures/ Message-ID: <200404062023.PAA03800@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/figures: --- Log message: Directory /home/vadve/shared/PublicCVS/llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/figures added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Tue Apr 6 15:26:03 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:26:03 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/Makefile developers-reference.xml fdl.xml kc2kc++.tex kpp-cook.xml kpp-intro.xml kpp-main.xml kpp-manual.xml kpp-rpn.xml Message-ID: <200404062025.PAA03933@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++/doc: Makefile added (r1.1) developers-reference.xml added (r1.1) fdl.xml added (r1.1) kc2kc++.tex added (r1.1) kpp-cook.xml added (r1.1) kpp-intro.xml added (r1.1) kpp-main.xml added (r1.1) kpp-manual.xml added (r1.1) kpp-rpn.xml added (r1.1) --- Log message: Initial import of kimwitu++. This is based on version 2.3.8. Kimwitu++ is analagous to a midterm exam for LLVM C++ programs. If LLVM can handle kimwitu++, we're in pretty good shape. --- Diffs of the changes: (+4146 -0) Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/Makefile diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/Makefile:1.1 *** /dev/null Tue Apr 6 15:25:32 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/Makefile Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,101 ---- + # Kimwitu++ documentation Makefile + # Copyright (c) 2000 Michael Piefel, Humboldt-University Berlin + # This is GPLed, but who would want it? + + .PHONY: all pdf tex dvi force index clean html + + XMLs := kpp-main.xml kpp-intro.xml kpp-manual.xml kpp-cook.xml kpp-rpn.xml + FIGs := syntaxtreex.fig simplify.fig fprintdot.fig + FIGDIR:= figures + IMGDIR:= imagesgen + DEST:=manual + + EPSs := $(subst .fig,.eps,$(FIGs)) + PDFs := $(subst .fig,.pdf,$(FIGs)) + PNGs := $(subst .fig,.png,$(FIGs)) + PSTEXs := $(addprefix $(IMGDIR)/, $(subst .fig,.tex,$(FIGs))) + FIGs := $(addprefix $(FIGDIR)/,$(FIGs)) + EPSs := $(addprefix $(IMGDIR)/,$(EPSs)) + PDFs := $(addprefix $(IMGDIR)/,$(PDFs)) + PNGs := $(addprefix $(IMGDIR)/,$(PNGs)) + + all: + @echo "Call with pdf, tex or target document name" + + pdf: $(DEST).pdf + + tex: $(DEST).tex + + dvi: $(DEST).dvi + + html: $(DEST).html + + force: + touch $(DEST).tex + + index: + makeindex $(MIFLAGS) $(DEST) + + $(DEST).dvi: $(DEST).tex $(EPSs) $(PSTEXs) + %.dvi: %.tex + latex $< + + + #%.tex: %.xml + # xsltproc formatters/docbook2tex.xsl $< > $@ + + .PRECIOUS: kpp-main.fo + + %.fo: %.xml + xsltproc formatters/kimwitu++.xsl $< > $@ + + %.pdf: %.fo + # New FOP does not seem to need this adaption any more + # xsltproc formatters/fo2fop.xsl $< > $@-fop.fo + # fop $@-fop.fo $@ + fop $< -pdf $@ + + $(DEST).tex: $(XMLs) formatters/docbook2tex.xsl + formatters/docbook2tex.sh $< $@ + + %.tex: %.xml formatters/docbook2tex.xsl + formatters/docbook2tex.sh $< $@ + + $(DEST).html: $(XMLs) $(PNGs) + formatters/docbook2html.sh $< $@ + + $(IMGDIR)/%.eps:$(FIGDIR)/%.fig + if [ ! -d $(IMGDIR) ] ; then \ + mkdir $(IMGDIR) ; \ + fi + fig2dev -L pstex -b1 $? $@ + + $(IMGDIR)/%.pdf:$(FIGDIR)/%.fig + if [ ! -d $(IMGDIR) ] ; then \ + mkdir $(IMGDIR) ; \ + fi + fig2dev -L pdftex -b1 $? $@ + + $(IMGDIR)/%.png:$(FIGDIR)/%.fig + if [ ! -d $(IMGDIR) ] ; then \ + mkdir $(IMGDIR) ; \ + fi + fig2dev -L png -b1 -S4 $? $@ + + $(IMGDIR)/%.tex:$(FIGDIR)/%.fig + if [ ! -d $(IMGDIR) ] ; then \ + mkdir $(IMGDIR) ; \ + fi + fig2dev -L pstex_t -p $(basename $@) $? $@ + + $(DEST).pdf: $(DEST).tex $(PDFs) $(PSTEXs) + %.pdf: %.tex + pdflatex $< + + clean: + rm -f *.aux *.log *.toc *.dvi *.out *.idx *.ind *.loe *.ilg *.fot *.fo + rm -f .kkkk_eeee .kkkk_kkkk + rm -rf $(IMGDIR) + + veryclean: clean + rm -f manual.tex manual.pdf manual.html Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/developers-reference.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/developers-reference.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/developers-reference.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,219 ---- + + + ]> + + + + + + + Kimwitu++ developers reference + + Michael + Piefel + + Humboldt-University Berlin + Institute for Informatics + + + This document is $Id: developers-reference.xml,v 1.1 2004/04/06 20:25:22 criswell Exp $. + + + + + + Smart Pointers + Smart pointers were implemented by Gerd Kurzbach. Their usage is not + straightforward, because that is made impossible by a few challenges. + Usage + + + + + What are the pointer types called? + + + + + For a phylum called phylum there'll be the following + pointer types: + phylum, a simple C + pointer, + c_phylum, a simple constant C + pointer, + phylum_ptr, the normal smart + pointer, + weak_phylum_ptr, the weak smart + pointer (does increment reference count), + + + + + + + Implementation + TODO + + + + + Kimwitu++ Source Management + Formatting the Kimwitu++ source code + The input (<abbrev>ie.</abbrev> Kimwitu++ text) + Tabs have a width of 8, in words eight, which means they are exactly 8 characters + wide, not two (2), not 4 (four), but 23 characters. + The indentation however should be four characters, ie. + 22. + If you don't want to use tabs, but expand them to spaces, fine. However, recall it's + shorter. In a proper editor, it should be easy to get the desired behaviour, + eg. in Vim you can set set tabstop=8 softtabstop=4 + shiftwidth=4. + + The output (<abbrev>ie.</abbrev> generated text) + In general care should be taken to make the generated source code human readable. + It should always look according to the guidelines above. + Kimwitu++ features a smart printer. This means you don't have to worry about + spaces, tabs and alignment, the printer will do it automatically. It will even ignore + your spaces and tabs, so don't bother except for making the input more readable. + Occasionally the printer will fail (it's simple, and not a complete parser like + entity), so you have to use the following hints in the output strings: + + \b + The printer likes to elide superfluous spaces. Sometimes spaces + are important (most notably to avoid nested template specifications with + > > being interpreted as the + >> operator. The space following + \b will not be ignored. + + + \v + This causes the following text to be indented one additional level. + Mnemonic for vorw?rts, which is German for + forward. + + + \r + This causes the following text to one level of indenting less. + Mnemonic for r?ckw?rts, which is German for + backward. + + + + + + + CVS + All changes which have an influence on the user should be marked with a + USER: prefix in the CSV change log message. This allows to collect + all user visible changes in the CHANGELOG file on release. + + + + + Uniq Phyla + Hash Sets + + + Why are hash sets used? + + Performance. Red-Black trees are known to be always good, hash tables can have + poor performance. But usually they are fast. As very many casestrings are created + in common programs, we optimize for this. + + + Why another level of indirection? + + Performance (compute hash only once). + + + What are the preprocessor decisions for? + + Hash sets are not standardized yet. + There are different implementations. The three compilers I looked at (gcc and + Intel's compiler) use three different ways to implement it. (The two gccs only + differ in the location of the header file.) + The GNU compiler expects two functors: One doing a hash, one doing a test for + equality. Predefined tests are not suitable, of course. + The Intel compiler expects a single functor both unary and binary: A unary + function doing a hash, a binary function doing a test for lessness. Predefined + tests are not suitable, of course. + There is no knowing how other compilers might implement this. If a known + compiler is used, hash sets are employed by default, but can be deactivated by + defining DONT_USE_HASHSET. If an unknown compiler is used, hash sets are not + employed by default, but can be activated by defining USE_HASHSET (but then keep + fingers crossed we guess the right way to use them). + + + + + + + Patterns + Allowed patterns + Patterns over phyla are not allowed. Patterns over predefined operators (e. g. _Str) + are not allowed. + Patterns over predefined operators + It is not desirable to define new unparse and rewrite rules for the predefined phyla. + Predefined phyla are primitive, rewriting should not need to change them. + Different unparse behaviour can easily be implemented in the unparse function, should + it really be needed. + A pattern over a predefined operator might be useful in a with-statement. + However, this is not necessary or possible: All operators in a with-statement must + be of the same phylum, as patterns over phyla are (not yet) allowed. + Primitive phyla only have one operator, so a with-statement would have only one + alternative and is superfluous. + + Patterns over phyla + Patterns over phyla are not allowed. This should be changed, considering the + following. + In a pattern over a phylum, there cannot be any references to subphyla. + Therefore, they are a bit limited. One possible exception could be lists and + abstract_list, as they always have two children. + Patterns over phyla are useless in with-statements. They can equally well be + implemented with a switch-statement over prod_sel(). + + + Pattern sorting + The sorting of patterns is a difficult area. There are some obvious cases, and + some which are more twisted. + If, at a certain point, two patterns may match the current phylum, which one will + be chosen? Let us consider the following cases: + + A pattern that is truly more specific than another, i. e. all + terms that match it would also match the other, but not vice versa, should be + tested for before the other. + For two patterns that are disjunct, i. e. there cannot exist any + terms that match both, ordering does not matter. + Two patterns which cover the same terms should be considered an + error. Otherwise one would always be preferred over the other, probably not + what the user intended. This is not so when there is a guard condition on the + pattern (provided); it is difficult to decide for us what + the semantics of these are (except when there are two identical conditions, + verbatim). + For overlapping patterns, the situation is complex. There must + exist a pattern (or multiple patterns) that covers exactly the intersection. + In general, for each term, there must always be a most specific + pattern. + This condition is difficult to implement, and it is hoped to be rare. We + might focus on easy special cases (as one pattern + covering the intersection of two others) and give + warnings whenever we are not sure. + + In all other cases, the patterns have to be sorted, and a warning might be issued + to the user if that ordering is not obvious. Currently, pattern sorting in Kimwitu is + through an algorithm that is unintuitive. It frequently leads to an unexpected order. + A pattern is considered more specific if it is more specific further to the left; when + in doubt, the order of appearance in the input is taken. + To this end, Gerd proposed two different algorithms, both intuitive but already + fairly complex, which both resulted in different orderings. I believe this problem + cannot be solved. + Unfortunately, for some projects, Kimwitu++ issues many warnings, when order + doesn't matter or is indeed obvious. A way to silence this warnings selectively is on + the wishlist + + + + + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/fdl.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/fdl.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/fdl.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,466 ---- + + GNU Free Documentation License + + + + + + + Version 1.1, March 2000 + +
        + Copyright © 2000 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. +
        + + + Preamble + + The purpose of this License is to make a manual, textbook, + or other written document ‘free’ in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by + others. + + This License is a kind of ‘copyleft’, which means that + derivative works of the document must themselves be free in the + same sense. It complements the GNU General Public License, which + is a copyleft license designed for free software. + + We have designed this License in order to use it for manuals + for free software, because free software needs free documentation: + a free program should come with manuals providing the same + freedoms that the software does. But this License is not limited + to software manuals; it can be used for any textual work, + regardless of subject matter or whether it is published as a + printed book. We recommend this License principally for works + whose purpose is instruction or reference. + + + + Applicability and Definitions + + This License applies to any manual or other work that + contains a notice placed by the copyright holder saying it can be + distributed under the terms of this License. The ‘Document’, + below, refers to any such manual or work. Any member of the + public is a licensee, and is addressed as ‘you’. + + A ‘Modified Version’ of the Document means any work + containing the Document or a portion of it, either copied + verbatim, or with modifications and/or translated into another + language. + + A ‘Secondary Section’ is a named appendix or a front-matter + section of the Document that deals exclusively with the + relationship of the publishers or authors of the Document to the + Document's overall subject (or to related matters) and contains + nothing that could fall directly within that overall subject. + (For example, if the Document is in part a textbook of + mathematics, a Secondary Section may not explain any mathematics.) + The relationship could be a matter of historical connection with + the subject or with related matters, or of legal, commercial, + philosophical, ethical or political position regarding + them. + + The ‘Invariant Sections’ are certain Secondary Sections + whose titles are designated, as being those of Invariant Sections, + in the notice that says that the Document is released under this + License. + + The ‘Cover Texts’ are certain short passages of text that + are listed, as Front-Cover Texts or Back-Cover Texts, in the + notice that says that the Document is released under this + License. + + A ‘Transparent’ copy of the Document means a + machine-readable copy, represented in a format whose specification + is available to the general public, whose contents can be viewed + and edited directly and straightforwardly with generic text + editors or (for images composed of pixels) generic paint programs + or (for drawings) some widely available drawing editor, and that + is suitable for input to text formatters or for automatic + translation to a variety of formats suitable for input to text + formatters. A copy made in an otherwise Transparent file format + whose markup has been designed to thwart or discourage subsequent + modification by readers is not Transparent. A copy that is not + ‘Transparent’ is called ‘Opaque’. + + Examples of suitable formats for Transparent copies include + plain ASCII without markup, Texinfo input format, LaTeX input + format, SGML or XML using a publicly available DTD, and + standard-conforming simple HTML designed for human modification. + Opaque formats include PostScript, PDF, proprietary formats that + can be read and edited only by proprietary word processors, SGML + or XML for which the DTD and/or processing tools are not generally + available, and the machine-generated HTML produced by some word + processors for output purposes only. + + The ‘Title Page’ means, for a printed book, the title page + itself, plus such following pages as are needed to hold, legibly, + the material this License requires to appear in the title page. + For works in formats which do not have any title page as such, + ‘Title Page’ means the text near the most prominent appearance of + the work's title, preceding the beginning of the body of the + text. + + + + Verbatim Copying + + You may copy and distribute the Document in any medium, + either commercially or noncommercially, provided that this + License, the copyright notices, and the license notice saying this + License applies to the Document are reproduced in all copies, and + that you add no other conditions whatsoever to those of this + License. You may not use technical measures to obstruct or + control the reading or further copying of the copies you make or + distribute. However, you may accept compensation in exchange for + copies. If you distribute a large enough number of copies you + must also follow the conditions in section 3. + + You may also lend copies, under the same conditions stated + above, and you may publicly display copies. + + + + Copying in Quantity + + If you publish printed copies of the Document numbering more + than 100, and the Document's license notice requires Cover Texts, + you must enclose the copies in covers that carry, clearly and + legibly, all these Cover Texts: Front-Cover Texts on the front + cover, and Back-Cover Texts on the back cover. Both covers must + also clearly and legibly identify you as the publisher of these + copies. The front cover must present the full title with all + words of the title equally prominent and visible. You may add + other material on the covers in addition. Copying with changes + limited to the covers, as long as they preserve the title of the + Document and satisfy these conditions, can be treated as verbatim + copying in other respects. + + If the required texts for either cover are too voluminous to + fit legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a + machine-readable Transparent copy along with each Opaque copy, or + state in or with each Opaque copy a publicly-accessible + computer-network location containing a complete Transparent copy + of the Document, free of added material, which the general + network-using public has access to download anonymously at no + charge using public-standard network protocols. If you use the + latter option, you must take reasonably prudent steps, when you + begin distribution of Opaque copies in quantity, to ensure that + this Transparent copy will remain thus accessible at the stated + location until at least one year after the last time you + distribute an Opaque copy (directly or through your agents or + retailers) of that edition to the public. + + It is requested, but not required, that you contact the + authors of the Document well before redistributing any large + number of copies, to give them a chance to provide you with an + updated version of the Document. + + + + Modifications + + You may copy and distribute a Modified Version of the + Document under the conditions of sections 2 and 3 above, provided + that you release the Modified Version under precisely this + License, with the Modified Version filling the role of the + Document, thus licensing distribution and modification of the + Modified Version to whoever possesses a copy of it. In addition, + you must do these things in the Modified Version: + + + Use in the Title Page + (and on the covers, if any) a title distinct from that of the + Document, and from those of previous versions (which should, if + there were any, be listed in the History section of the + Document). You may use the same title as a previous version if + the original publisher of that version gives permission. + + + List on the Title Page, + as authors, one or more persons or entities responsible for + authorship of the modifications in the Modified Version, + together with at least five of the principal authors of the + Document (all of its principal authors, if it has less than + five). + + + State on the Title page + the name of the publisher of the Modified Version, as the + publisher. + + + Preserve all the + copyright notices of the Document. + + + Add an appropriate + copyright notice for your modifications adjacent to the other + copyright notices. + + + Include, immediately + after the copyright notices, a license notice giving the public + permission to use the Modified Version under the terms of this + License, in the form shown in the Addendum below. + + + Preserve in that license + notice the full lists of Invariant Sections and required Cover + Texts given in the Document's license notice. + + + Include an unaltered + copy of this License. + + + Preserve the section + entitled ‘History’, and its title, and add to it an item stating + at least the title, year, new authors, and publisher of the + Modified Version as given on the Title Page. If there is no + section entitled ‘History’ in the Document, create one stating + the title, year, authors, and publisher of the Document as given + on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. + + + Preserve the network + location, if any, given in the Document for public access to a + Transparent copy of the Document, and likewise the network + locations given in the Document for previous versions it was + based on. These may be placed in the ‘History’ section. You + may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. + + + In any section entitled + ‘Acknowledgements’ or ‘Dedications’, preserve the section's + title, and preserve in the section all the substance and tone of + each of the contributor acknowledgements and/or dedications + given therein. + + + Preserve all the + Invariant Sections of the Document, unaltered in their text and + in their titles. Section numbers or the equivalent are not + considered part of the section titles. + + + Delete any section + entitled ‘Endorsements’. Such a section may not be included in + the Modified Version. + + + Do not retitle any + existing section as ‘Endorsements’ or to conflict in title with + any Invariant Section. + + + + If the Modified Version includes new front-matter sections + or appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option + designate some or all of these sections as invariant. To do this, + add their titles to the list of Invariant Sections in the Modified + Version's license notice. These titles must be distinct from any + other section titles. + + You may add a section entitled ‘Endorsements’, provided it + contains nothing but endorsements of your Modified Version by + various parties--for example, statements of peer review or that + the text has been approved by an organization as the authoritative + definition of a standard. + + You may add a passage of up to five words as a Front-Cover + Text, and a passage of up to 25 words as a Back-Cover Text, to the + end of the list of Cover Texts in the Modified Version. Only one + passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. If the + Document already includes a cover text for the same cover, + previously added by you or by arrangement made by the same entity + you are acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one. + + The author(s) and publisher(s) of the Document do not by + this License give permission to use their names for publicity for + or to assert or imply endorsement of any Modified Version. + + + + Combining Documents + + You may combine the Document with other documents released + under this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination + all of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice. + + The combined work need only contain one copy of this + License, and multiple identical Invariant Sections may be replaced + with a single copy. If there are multiple Invariant Sections with + the same name but different contents, make the title of each such + section unique by adding at the end of it, in parentheses, the + name of the original author or publisher of that section if known, + or else a unique number. Make the same adjustment to the section + titles in the list of Invariant Sections in the license notice of + the combined work. + + In the combination, you must combine any sections entitled + ‘History’ in the various original documents, forming one section + entitled ‘History’; likewise combine any sections entitled + ‘Acknowledgements’, and any sections entitled ‘Dedications’. You + must delete all sections entitled ‘Endorsements.’ + + + + Collections of Documents + + You may make a collection consisting of the Document and + other documents released under this License, and replace the + individual copies of this License in the various documents with a + single copy that is included in the collection, provided that you + follow the rules of this License for verbatim copying of each of + the documents in all other respects. + + You may extract a single document from such a collection, + and distribute it individually under this License, provided you + insert a copy of this License into the extracted document, and + follow this License in all other respects regarding verbatim + copying of that document. + + + + Aggregation with Independent Works + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of + a storage or distribution medium, does not as a whole count as a + Modified Version of the Document, provided no compilation + copyright is claimed for the compilation. Such a compilation is + called an ‘aggregate’, and this License does not apply to the + other self-contained works thus compiled with the Document, on + account of their being thus compiled, if they are not themselves + derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to + these copies of the Document, then if the Document is less than + one quarter of the entire aggregate, the Document's Cover Texts + may be placed on covers that surround only the Document within the + aggregate. Otherwise they must appear on covers around the whole + aggregate. + + + + Translation + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires + special permission from their copyright holders, but you may + include translations of some or all Invariant Sections in addition + to the original versions of these Invariant Sections. You may + include a translation of this License provided that you also + include the original English version of this License. In case of + a disagreement between the translation and the original English + version of this License, the original English version will + prevail. + + + + Termination + + You may not copy, modify, sublicense, or distribute the + Document except as expressly provided for under this License. Any + other attempt to copy, modify, sublicense or distribute the + Document is void, and will automatically terminate your rights + under this License. However, parties who have received copies, or + rights, from you under this License will not have their licenses + terminated so long as such parties remain in full + compliance. + + + + Future Revisions of This License + + The Free Software Foundation may publish new, revised + versions of the GNU Free Documentation License from time to time. + Such new versions will be similar in spirit to the present + version, but may differ in detail to address new problems or + concerns. See http://www.gnu.org/copyleft/. + + Each version of the License is given a distinguishing + version number. If the Document specifies that a particular + numbered version of this License ‘or any later version’ applies to + it, you have the option of following the terms and conditions + either of that specified version or of any later version that has + been published (not as a draft) by the Free Software Foundation. + If the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by the + Free Software Foundation. + + + + How to use this License for your documents + + To use this License in a document you have written, include + a copy of the License in the document and put the following + copyright and license notices just after the title page: + +
        + Copyright © YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + A copy of the license is included in the section entitled "GNU + Free Documentation License". +
        + + If you have no Invariant Sections, write ‘with no Invariant + Sections’ instead of saying which ones are invariant. If you have + no Front-Cover Texts, write ‘no Front-Cover Texts’ instead of + ‘Front-Cover Texts being LIST’; likewise for Back-Cover + Texts. + + If your document contains nontrivial examples of program + code, we recommend releasing these examples in parallel under your + choice of free software license, such as the GNU General Public + License, to permit their use in free software. +
        + +
        + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kc2kc++.tex diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kc2kc++.tex:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kc2kc++.tex Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,88 ---- + \documentclass[a4paper,10pt]{article} + \usepackage{url,a4wide,newcent} + \usepackage[latin1]{inputenc} + + \newcommand{\programtext}[1]{\texttt{\textbf{#1}}} + + \begin{document} + \begin{center}\Huge From Kimwitu to Kimwitu++\end{center} + + This document is meant as a short guide for converting projects that employ + Kimwitu to use Kimwitu++ instead. It is probably not complete. Please mail + any comments to \url{piefel at informatik.hu-berlin.de}. % @ + + \begin{itemize} + \item Generally Kimwitu++ works together with C++, while Kimwitu worked with C. + This will possibly cause some of the usual C to C++ hassle. + + \item Kernighan \& Ritchie style for C functions is not allowed in *.k files. + Use proper ISO~C instead. + + \item There is no longer a predefined phylum called `\programtext{int}'. There + is, however, a phylum providing the same functionality called + `\programtext{integer}'. When converting, please note that `\programtext{integer + i; i=5;}' will be caught by the compiler, while `\programtext{i=0;}' will not. + This is nasty, I'm sorry. + + The right way to use them is `\programtext{integer i; i=mkinteger(5);} and + `\programtext{if (i->value==5) \dots}'. + + \item Similar things apply to `\programtext{float}' et.\,al., there is now a + phylum `\programtext{real}'. + + \item \programtext{Bool}, \programtext{True} and \programtext{False} disappeared and are + supplanted by their respective C++ counterparts. + + \item Phyla are classes or objects, respectively. Instead of + `\programtext{unparse\_completeSyntaxTree( synTree, printer, view );}' you can + use the more natural `\programtext{synTree->unparse( printer, view );}'. + + \item The keyword and typename `\programtext{\%view}' and `\programtext{view}' + are no longer available (they were deprecated anyway). Use + `\programtext{\%uview}' and `\programtext{uview}'. + + \item Printers are now by default not functions taking \programtext{(char*, + uview)}, but rather objects of a class with \programtext{operator()(const char*, + uview)} defined. This allows a printer to have its own state. You can also still + use functions if you want, they will be wrapped when calling + \programtext{unparse}. + + \item Everthing is in the namespace \programtext{kc}. If you put + \programtext{using namespace kc;} in your program, everthing else will continue + to work as it did. + + \item If you want to interface with flex and bison, not that the union + \programtext{YYSTYPE} is not generated automatically anymore. Instead, use the + command line option --yystype, which will create a seperate yystype.h containing + the type definition. + + \item CSGIO works a little different in two respects.\begin{itemize} + \item The old functions returned a string which indicated success or failure. + The new functions instead return \programtext{void}. Errors will be reported + by throwing exceptions of type \programtext{IO\_exception}; there is a + function \programtext{IO\_exception2char} turning that into a string. + \item While \programtext{CSGIOwrite} is a member function, + \programtext{CSGIOread} cannot be. The latter takes just the phylum type, not + a pointer to it---just write \programtext{CSGIOread(f, p)}. + \end{itemize} + \end{itemize} + \clearpage + \begin{center}\large New Features\end{center} + This is just a very brief list of some of the nicest new features, it is not + exhaustive. + \begin{itemize} + \item Everything can be unparsed. As long as the (somewhat limited) parser can + read it, it will be handed to a global unparse function (in namespace kc); define + your own function if it is needed. + \item All patterns (eg. for unparse rules) can have a guard condition; the + condition comes in parentheses after the pattern following the new keyword + \programtext{provided}. + \item New functions for phylum types can be defined, just write something like + \programtext{void foo::bar() \{ \dots~\}}. + \item There is a new (additional) syntax for defining attributes of phyla such as + \programtext{\%member int foo::baz}; when using \programtext{\%attr} instead, the + attribute will be written out and read in with CSGIO functions. + \item Likewise you can define additional constructors and destructors with + \programtext{\%ctor} and \programtext{\%dtor}. + \end{itemize} + \end{document} Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-cook.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-cook.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-cook.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,7 ---- + + + emptyempty Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-intro.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-intro.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-intro.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,683 ---- + + + What is &kpp;? + This chapter sketches out the field on which &kpp; is usefully employed and + explains important terms. It develops an example to outline the advantages + of this tool compared to conventional techniques. The example will be used + throughout the following chapters to introduce concept by concept. The + complete code to make it work can be found in appendix . + + What for is &kpp; used? + To illustratively explain what we can do with the help of &kpp; we + call upon an example. Let us imagine we want to write a computer game. + Neat example. Respectable programmers as we are we calculate + the overall costs of the new project in advance. It will take us, say, 30 + days, on each we need to have a pizza at 7 € and 3 beer at 2 € + each, but luckily meanwhile our grandma supports us with 100 €. We + get the expression 30*(8+3*2)-100 + + + and type it in postfix notation into our + RPNrpn-calculator. + You know, one of the antiquated devices knowing nothing about precedence + nor parentheses and expecting input in Reverse Polish Notation, where + operands precede their operator. + So we type 30 8 3 2 * + * 100 -. Er, we cannot. + I remember. The calculator gave up the ghost last week. But don't + despair. We quickly program a new one. + + + A Simple Example + What exactly should the new calculator be able to do? Anyhow, it + better + would accept also variables. Why? Just imagine a drastic shortage of pizza + and beer what would urge us to setup a new expression again. We better use + a flexible one which can be seen in example , in which x is the price of + a beer and we know the price of a pizza always to be 4 times a beer. + + Sample Expression + 30*(4*x+3*x)-100 + + + + (and resulting input in RPN: + 30 4 x * 3 x * + * 100 -) + + + We now list the requirements on the calculator in proper order. + + We want it to analyse an input expression (term) of + digits, arithmetical operators, and variables. + It should calculate the expression if possible or + simplify it at least. + It then should output a result. + + + + We assume the existence of a code component (a scanner) providing + us with syntactical tokens like operators, numbers and identifiers + (variables). We then need a description of + correct input, a grammargrammar. + Our example demands a valid arithmetical term + only to consist of numbers, identifiers, and the four arithmetical operators. + A formal notation as used by the parser generator &yacc; (see ) would look like in example . + &yacc; Grammar for Sample + + aritherm: simpleterm + | aritherm aritherm '+' + | aritherm aritherm '-' + | aritherm aritherm '*' + | aritherm aritherm '/'; + + simpleterm: NUMBER + | IDENT; + + + Such a grammar is made up of rules, each having two sides separated by + a colon. These rules describe how the left-hand side called + nonterminalnonterminal can be + composed of syntactical tokens called + terminalsterminal, which + are typed in upper + case letters or as single quoted characters. Different alternatives are + separated by bar. The right-hand side may also contain nonterminals which + there can be regarded to be an application of their respective composition + rule. + The first rule of this grammar defines an &aritherm; + to be a &simpleterm; or a composition of two &aritherm;s and an operator + sign. These &aritherm;s in turn may be composed according to the + &aritherm; rule. The second rule describes what an &aritherm; looks + like, if it is a &simpleterm;. + A common way to hold an input term internally is to + keep it as a syntax + treetreesyntax + tree, that is a hierarchical structure of + nodesnode (upside + down tree). A nonterminal can be regarded as a node + typenode type and every + alternative of the assigned right-hand side as one + &kind;&kind; of that type. + Every actual node thus is a &kind; of a node type with a specific number + of child nodes, which depends on the &kind;. For example + '+' is a &kind; of &aritherm; and it has 2 child + nodes, while NUMBER is a &kind; of &simpleterm; and + it has none. Figure shows a syntax tree + for our sample input term. Since every node is a + termterm itself such a tree is + more generally called a term + treetreeterm tree. +
        + Syntax tree representing sample term + + + + + +
        + To summarise the task identified: we want to build a tree from the + term + which has been typed in, walk over the tree nodes, and perform appropriate + actions like calculating, simplifying or printing some results. +
        + + Conventional Approach + In a programming language a node type is usually represented as + a structured data type, that is, as a class in object oriented languages + and as a sort of record in others. + A &kind;, then, may be a class + variant or a subclass, and a variant record respectively. The + code fragment in example illustrates a + possible implementation in &cpp; (the &kind; as a subclass). The classes + left out are to define similar. + Node Types as Classes with &cpp; + + class Aritherm { /* ... */ }; + class Simpleterm : Aritherm { /* ... */ }; + + class Plus : public Aritherm + { + public : + Plus( Aritherm *a, Aritherm *b ) : t1 ( a ), t2 ( b ) + { /* ... */ }; + private: + Aritherm *t1, *t2; + }; + + class Number : public Simpleterm + { + public : + Number( int a ) : n ( a ) + { /* ... */ }; + private: + int n; + }; + + + From these classes we can instantiate &cpp; objects to represent our + sample tree. We can navigate through it by accessing the child nodes of + nodes. Not really yet, if you look closely at it. The child nodes are + private members and thus they can not be accessed. We have to make them + public or to add methods for their access. But what about the next step, + simplifying parts of the tree? The subtree + 4*x+3*x + + + could be transformed to, right, + (4+3)*x + + + , by putting x outside the parentheses, + as illustrated in figure . + For &cpp; this may look like listed in example . + +
        + Simplification of a samples subtree + + + + + +
        + + Term Substitution with &cpp; + + ( A ) !=0 && + dynamic_cast ( dynamic_cast( A ) -> t1 ) !=0 && + dynamic_cast ( dynamic_cast( A ) -> t2 ) !=0 && + dynamic_cast ( dynamic_cast( A ) -> t1 ) -> t2 == + dynamic_cast ( dynamic_cast( A ) -> t2 ) -> t2 ) + { + + A = new Mul ( new Sum ( + dynamic_cast ( dynamic_cast( A ) -> t1 ) -> t1, + dynamic_cast ( dynamic_cast( A ) -> t2 ) -> t1 ), + dynamic_cast ( dynamic_cast( A ) -> t1 ) -> t2 ); + }; + ]]> + + + That seems quite complicated and it is even more so! Not only have we + to cast for every child node access, to avoid memory leaks we had to free + memory of unused nodes as old A and its child nodes. + Furthermore the equality check between t1 and + t2 will merely compare pointer values, instead of + checking whether the subtrees are structurally equal. Thus we additionally + need to overload the equality operators. What a lot of trouble for such + a simple example! +
        + + &kpp; Approach + &kpp;'s&kpp; name + is formed after Swahili while the ‘++’ + reminds on &cpp;. + + + + + witu + : + ‘tree’ + + m- + : + plural prefix + + ki- + : + adjectival prefix: ‘being like’ + + kimwitu + = + ‘tree-s-ish’ + + + + + Thus the name indicates affiliation to trees and to &cpp;. You + guessed it before, didn't you? More strictly spoken &kpp; is a tool which + allows to describe in an easy way how to manipulate and to evaluate a + given term tree. From these descriptions &cpp; code is + generated and compiled to a program which processes terms. That is why + &kpp; itself is called a term processor. + The code for building a tree, we have to write ourselves, or + we let preferably other tools generate it. + We use &yacc; to call term + creation routines which are generated from a &kpp; abstract grammar. + This we have to specify first. It is similar to the &yacc; grammar, but + its right-hand side alternatives are operators applied to nonterminals. An + abstract grammar for our sample can be seen in example . The nonterminals integer + and casestring are predefined in &kpp;. + Abstract Grammar for Sample + + aritherm: SimpleTerm ( simpleterm ) + | Plus ( aritherm aritherm ) + | Minus ( aritherm aritherm ) + | Mul ( aritherm aritherm ) + | Div ( aritherm aritherm ); + + simpleterm: Number ( integer ) + | Ident ( casestring ); + + + Next we have to complete the &yacc; grammar by adding + semantic actions in braces to every alternative. These recursively + create a term tree which has its root element assigned to the variable + root_term. Example + shows this grammar, in which $$ denotes the term + under construction and $1 and $2 + its first and its second subtermsubterm (child + node). + + Completed &yacc; Grammar for Sample + + aritherm: simpleterm + { root_term = $$ = SimpleTerm( $1 ); } + | aritherm aritherm '+' + { root_term = $$ = Plus( $1, $2 ); } + | aritherm aritherm '-' + { root_term = $$ = Minus( $1, $2 ); } + | aritherm aritherm '*' + { root_term = $$ = Mul( $1, $2 ); } + | aritherm aritherm '/' + { root_term = $$ = Div( $1, $2 ); }; + + simpleterm: NUMBER + { $$ = Number( $1 ); } + | IDENT + { $$ = Ident( $1 ); }; + + + That is it for building a tree. Everything else is left to the + automatic code generation. Modifying or evaluating the tree + needs its own rules (see chapter ). + + + Summary + The language &kpp; is an extension of &cpp; for handling of term trees. + It allows the definition of term typesterm + typenode type, creation of terms, and provides + mechanisms for transforming and traversing trees as well as saving and + restoring them. Besides creating it in static code a tree can dynamically + be obtained by interfacing with compiler generator &cpp; code (as from + &yacc;/&bison;). The &kpp; processor generates &cpp; code from the contents + of &kpp; input (.k-files). Compilation of that code + yields the term processing program. + +
        + + How to Define Term Types + This chapter describes possibilities to define term types, which make up + the &kpp; input. In &kpp; they are called + phylaphylaphylum (singular + phylum)phylum, and that + is what we will call them from now on. A phylum instance is called a + termterm. + + Definition + phylumdefinition + How are phyla defined? Example shows + that each phylum is defined as an enumeration of its &kind;s, each being + an operator applied to a number of phyla, maybe zero. So the operator + SimpleTerm takes one &simpleterm; phylum, + Plus takes two &aritherm; phyla. There are several + predefined phyla, of which integer and + casestring already have been mentioned. The latter + denotes a case sensitive character string. If a phylum is + defined more than once, all occurrences contribute to the first one. For + each phylum, a &cpp; class is generated. + + Lists<indexterm><primary>list</primary></indexterm> + list + We may want to define a phylum as a list of phyla. Imagine we wanted + not only to type one expression into our calculator but several ones at + once, separated in input by, say, a semicolon. The main phylum, + representing whole the input, would be a list of + &aritherm;s. This is a right-recursive definition of a list which may be a + nil (empty) list. The name of the list phylum prefixed by + NilNil and + ConsCons make up + common names for the two list operators. The other way to define a list + phylum is to use the built-in + list operator. This not + only looks more simple but causes the generation of additional list + functions. + Example shows both definitions. + + Recursive and built-in List Definition + + arithermlist: Nilarithermlist ( ) + | Consarithermlist( aritherm arithermlist ); + + arithermlist: list aritherm; + + + + + Attributes<indexterm id="intro_attributes" + class="startofrange"><primary>attributes</primary></indexterm> + + Each phylum definition can contain declarations of attributes of + phylum or arbitrary &cpp; types. They follow the operator + enumeration as a block enclosed in braces. What purpose do they serve? + With them, we can attach additional information to nodes, which otherwise + could only unfavourably be represented in the tree. In our example, we may + take advantage of attributes by saving intermediate results to support + the calculation. Therefore we extend the definition of &aritherm; from + example + to example . + Phylum Definition with Attributes + + aritherm: SimpleTerm ( simpleterm ) + | Plus ( aritherm aritherm ) + | Minus ( aritherm aritherm ) + | Mul ( aritherm aritherm ) + | Div ( aritherm aritherm ) + { int result = 0; + bool evaluated = false; + bool computable = true; + }; + + + Attribute result should hold the intermediate + result of an &aritherm;, if it already has been evaluated + (evaluated==true) and found + computable during the evaluation + (computable==true), that is the + subterms contain no variables. The attributes can be initialized at the + declaration or inside an additional braces block which may follow + the declarations and can contain arbitrary &cpp; code. Example shows an alternative to the initialization from + example . + + Alternative Attributes Initialization + + result = 0; + $0->evaluated = false; + $0->computable = true; } + };]]> + + + That &cpp; code is executed when a term of that phylum has been + created. It can be referred to as $0 and its + attributes can be accessed via the operator + ]]>. + + + + + Aid with Term Handling + This chapter describes techniques necessary and useful to traverse a + term structure: the application of term patterns and the + use of special &kpp; language constructs for term handling. + + Patterns<indexterm><primary>patterns</primary></indexterm> + Patterns are a means to select specific terms which can be associated + with a desired action. Example shows some + patterns and explains what terms they match. Patterns are used in special + statements and in rewrite and unparse rules (see + and respectively). + Patterns + + + + + + Special Statements + &kpp; provides two statements as extensions to &cpp; which make it + more comfortable to deal with terms. These are the &with;-statement and + the &foreach;-statement. They can be used in functions and in the &cpp; + parts of unparse rules (see ). + The &with;&with;-statement + can be considered as a + switch-statement for a phylum. It contains an + enumeration of patterns which must describe &kind;s of the specified + phylum. From these, the one is chosen which matches a given term best. + Then the &cpp; code is executed, which was assigned to that pattern. + + Example takes a term of the phylum + &aritherm; + and calculates the attribute result, if the term is a + sum or a difference, + by adding or subtracting the results of the subterms. The keyword + default serves as a special pattern in &with;, which + matches when none of the others does. + In the first case, the two subterms are assigned to the variables + a and b, which can be used in the + &cpp; part. The term itself is assigned to variable c + which thus refers to the same term as the variable at. + Variable at is visible throughout the entire &with; + body and it can be accessed in all &cpp; parts. It may get a new term + assigned as it is done in the second case whithin which the variable + at refers to the first subterm. + + &with;-statement + + result = a -> result + b -> result; } + Minus ( at, b ) : { c -> result = at -> result - b -> result; } + default : { } + }]]> + + + The second special construct is the + &foreach;&foreach;-statement, which + iterates over a term of a list phylum and performs the specified actions + for every list element. Example determines + the greatest result from the terms in the list + a. + + &foreach;-statement + + result > max ) max = a -> result; + }]]> + + + + + + Modifying and Evaluating Term Trees + This chapter describes how the tree of terms can be processed + once it has been created. On one hand we can change its structure and + hopefully simplify it by applying rewrite rules. On the other hand we + can step through it and create a formatted output by applying unparse + rules. + + Transforming + Rewritingrewriting denotes + the process of stepping through the tree, seeking + the terms that match a pattern and substituting them by the appropriate + substitution term. Rewrite rules consist of two parts, where the + left-hand side is a pattern (as described in ) and the right-hand side is a substitution term + enclosed by angle brackets. A term must always be substituted by a simpler + one, that is by one that is nearer to the desired form of result. + Otherwise the substitution process may never stop. + Let us try simplifying according to figure to demonstrate the usage of rewrite rules. What + would the rules look like in &kpp; to achieve a simplification of that + kind? + Example shows a solution using rewriting. It + is quite short in comparison with example , isn't + it? + + Term Substitution using &kpp; + + <: Plus( Mul( a, c ), b )> ;]]> + + + An equivalent part would cover the case that b + takes the first position in both subterms. The meaning of the colon will + be explained in . + + Traversing + Originally unparsing was meant to be a reverse parse, used to give a + formatted output of the tree built. In general it should better be + recognized + as a way to traverse the tree. Unparse rules have a structure similar to + that of rewrite rules. The left-hand side consists of a pattern, the + right-hand side of a + list of unparse items enclosed by square brackets. Some more common + unparse items are strings, pattern variables, attributes, and blocks of + arbitrary &cpp; code enclosed in braces. + Unparsing starts by calling the + unparseunparse()-method + of a term, usually the root term, + and when a rule matches a term the + specified items are ‘printed’. Only string items are really + delivered to the current printer. This printer has to be defined by the + user, and it usually writes to the standard output or into a file. + Variable items and attribute items are further unparsed, code fragments + are executed. If no pattern matches then the default rule is used, which + exists for every phylum operator and which simply unparses the + subterms. + We could do quite a lot of different things with the information saved + in the tree. It just depends on the rules we use. For example we choose to + print the input term in infix notation, because it is better readable to + humans. + + + [infix: "(" a "+" b ")" ];]]> + + + + For every Plus term this rule prints an opening + parenthesis, unparses the first subterm, prints a plus sign, unparses the + second subterm, and then prints the closing parenthesis. The other + operators are handled by similar rules. + We also may want to eventually compute the result of + expressions. This can be achieved with rules like this. + + + [: a b { c -> result = a -> result + b -> result; } ];]]> + + + Here the subterms are unparsed and then an attribute of the term gets + assigned the sum of the subterm results. This will work only if these do + not contain Idents. The meaning of the colon will be + explained in . + The &cpp; code is enclosed by braces, but can itself contain + braces in matching pairs. If a single brace is needed, as when + mixing code and variable items, it has to be escaped with the dollar + sign. Example shows an application. + If the function yields true the first branch + is taken, and + b is unparsed before a. + + Escaped Braces in Unparse Rule + + [ : { if( smaller_than( a, b ) ) } ${ + b "+" a $} + { else } ${ + a "+" b $} ];]]> + + + + + Views<indexterm class="startofrange" + id="idx:view"><primary>view</primary></indexterm> + The whole process of rewriting and unparsing as well as parts of it + can be executed under different views. Each rule contains a view list + between the respective opening brace and the colon, and it is used only + if the current view appears + in the list. This allows to specify different rules for a pattern. If a + term is visited twice under different views, different rules are + applied. These rules can be merged into one by listing all right-hand sides + after one left-hand side, separating them by a comma. + Example defines two rewrite views + (simplify and canonify) and + two rules, each of which will only be applied to a matching term if the + current view is among + the specified ones. The first rule replaces the quotient of the same two + identifiers by the number 1, the second expresses + the associativity of addition. Both change the tree. + + Views in Rewrite Rules + mkinteger + + < simplify: SimpleTerm( Number( mkinteger( 1 ) ) ) >; + + Plus( Plus( a, b ), c ) + -> < canonify: Plus( a, Plus( b, c ) ) >;]]> + + + Example defines two unparse views + (infix and postfix) and two + rules for the same pattern, the one of which is used which matches both + the term and the current view. It is possible to force a variable item to + be unparsed under a desired view by specifying it after the variable and + an intermediate colon. Subterm b is further + unparsed under the view check_zero instead of the + view infix. + + %uview + + [ infix : a "/" b : check_zero ]; + ]]> + + + + Views in Unparse Rules + + [ infix : a "+" b ], + [ postfix : a b "+" ];]]> + + + + + + + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-main.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-main.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-main.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,136 ---- + + --> + + + + + + + Kimwitu++"> + C++"> + Yacc"> + Bison"> + with"> + foreach"> + aritherm"> + simpleterm"> + + + ]> + + + + + + + &kpp; + A Term Processor + + Toby + Neumann + + Humboldt-Universit?t zu Berlin + Institute for Informatics + + + + Michael + Piefel + + Humboldt-Universit?t zu Berlin + Institute for Informatics + + + User's guide 1.01 + 2002 + + Initial version in December 2001 + First draft in February 2002 + Unamended version missing part III in May 2002 + Amended version missing part III in July 2002 + + This document is still missing its third part. + + Humboldt-Universit?t zu Berlin +
        + Unter den Linden 6 + 10099 Berlin + Germany +
        +
        + + 2001 + 2002 + Toby Neumann, Institut f?r Informatik, Humboldt-Universit?t zu Berlin + + + This document describes the term processor &kpp;. &kpp; is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either version 2 of the Licence, + or (at your option) any later version. + Likewise this documentation is free. Permission is granted to copy, distribute + and/or modify this document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software Foundation; with no + Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of + the license is included in the section entitled ‘GNU Free Documentation + License’. + + + The program &kpp; is based on Kimwitu (with its own web site), written by + Axel Belinfante (belinfan at utwente.nl). Kimwitu is also free software, + licensed under the GPL, since its 4.6.1 release. + +
        + + + + + + + Introduction to &kpp; + + This part explains what essentially &kpp; is and what advantages it + provides. It gives an overview of the functionality of + &kpp;, which is demonstrated with example. Detailed discussion of concepts + is left to the reference part later in this book. + + &kpp-intro; + + + + Reference Manual + + This part lists all concepts of &kpp; and explains them in detail. + It is meant as a complete documentation of all features and contains + advices of do's and don'ts. To the advanced user it should serve as + a programming reference. + + &kpp-manual; + + + + + + + &app-rpn; + &app-fdl; + +
        + + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-manual.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-manual.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-manual.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,2114 ---- + + + Definition of Phyla + Basic Definition + A phylum definition consists of two sides. The left-hand side + specifies the phylum name, the right-hand side, behind a colon, a set of + alternative operators, which are separated by bars. An operator is + followed by a matching pair of parentheses, which may enclose a list of + phyla as arguments. A nullary operator has an empty list. + Example presents a basic definition with + operators of different arity. + Before the semicolon closing the definition an attribute block may appear. + The definition of a phylum follows the general form: + + + + + + For the names of phyla and operators, the same restrictions hold as + for &cpp; identifiers. + Multiple definitions of of a phylum with the same name are interpreted + as additional alternative branches of the first definition. + There are some simple predefined phyla: + integerinteger, realreal, + casestringcasestring, + and nocasestringnocasestring, representing integer values, + real values, case sensitive + strings, and case insensitive strings respectively. Terms of these are not + created by calls of operators but of special generated functions: + mkinteger()mkinteger, + mkreal()mkreal, + mkcasestring()mkcasestring and + mknocasestring()mknocasestring. + + The phylum + abstract_phylum represents the direct base of all + phyla. Adding properties, like attributes or methods, to it makes them + available for all phyla. Other direct bases may be specified for a phylum + by using the keyword + %base%base. + One of them has to be derived from abstract_phylum, + not necessarily directly. Example makes phylum + math_expression to be derived from a phylum + expression and a user defined &cpp; class + counter_class. + + Definition of a Phylum + + + + + + Changing base of a phylum + %base + + + + + + + List Phyla<indexterm id="idx:list_man" significance="preferred" + class="startofrange"><primary>list</primary></indexterm> + phylumlistlist + A list phylum can be defined by using the basic form of phylum + definitions in a (right-) recursive way. The nullary operator constructs + a list which is empty, and the binary, a list which is concatenated of + a single list element and a list. + The other variant uses the predefined operator list + after which is specified the phylum of the list elements. The latter + notation is to prefer because it is concise and causes the generation of + additional list functions. That includes two operators which are named + according to the scheme which is used in the right-recursive definition + (prefixes Nil and + Const). Other names could be chosen as + well but this may cause some confusion. With either variants, a term is + created by calling one of the two operators. + The two definitions in example yield the + same list of elements of a phylum expression. + + + Alternative Definitions of one List + + + + + + + Attributes of Phyla<indexterm significance="preferred" class="startofrange" id="idx:attributes"><primary>attributes</primary></indexterm> + A phylum definition may have an attribute part attached which is + enclosed in braces. It contains declarations of attributes of phylum types + or other &cpp; types and optionally their initial value assignment. After + that arbitrary &cpp; code can follow again enclosed in braces. This is the + general form of the attribute part: + + + + + + In particular, the initialization of attributes can be done in the + &cpp; part too; though technically then it is not initialization, but + assignment. Attributes may also be defined outside the phylum + definition according to the general form beneath. + + + + + + Only attributes of phylum types can be defined with + %attr%attr. + This is because they are considered part of the enclosing phylum by &kpp;. + When a term is written to a file using the CSGIO functions (see ), its + attributes are saved and can thus be restored. + Using the keyword + %member%member + instead allows also &cpp; types to be used. The values of attributes + defined in this way will get lost when their term is written to a + file. Restoring a saved term will assign the initial values to all + %member attributes. + The &cpp; code is executed after the term creation and the attribute + initializations. Inside that code the newly created term can be referred + to as + $0$0. + Attributes are accessed via the operator + ]]>. Each predefined phylum has an + attribute which holds its value, which is value for + integerinteger + and + realreal, + and name for + casestringcasestring + and + nocasestringnocasestring. + Example shows three alternative ways to define + and initialize one attribute (of &cpp; type). + + Alternative Definitions of one Attribute + + is_valid = true; } }; + + expression: Div ( expression expression ); + %member bool expression::is_valid = true;]]> + + + + + Supplemental Definitions + It is possible to supplement the classes which will be generated from + phylum definitions with additional methods. These are defined as usual but + have as qualifier the name of either a phylum or of an operator. Such a + method is known for all terms of the phylum or only for those constructed + by the specified operator. Predefined phyla can get additional methods + too. + + Additional Methods Definitions + + + + + It may appear desirable to initialize + attributes attributes of a phylum + with non-default values immediately at term creation. This can be realized + by using the &kpp; keyword %ctor%ctor to define + own constructors which will replace the default ones. Additional + constructors are possible for phyla as well as for operators, but not for + predefined phyla. + + If these constructors are defined to have arguments then of some points + are to take note. First, when used with operators the arguments will be + added to those in the operator definition. Second, since the default + constructors are replaced but relied on by some internal mechanism, the + user has to define new ones or alternatively just provide default values + for all new arguments. The latter may cause performance loss in the case + of many or non-simple arguments. + The keyword %dtor%dtor allows + own destructor definitions for freeing memory of attributes or something + similar. It is applicable to phyla and operators but not to predefined + phyla. + + User provided Constructors and Destructors + + + + + + Phylum Storage Options + storage optionsstorage class + storage class + For every phylum a &cpp; class is generated, with one create-method for + every operator. A term is created by calling the appropriate method, which + returns a pointer to the object representing the term. As a default for + every such object a new cell is allocated in memory. But the user may + influence the memory management for optimization purposes. At phylum + definition time the phylum can be declared to use a special storage class. + There is one predefined storage class: uniquniq. + It is allowed to specify !uniq what is the same as + specifying nothing and results in usage of the default storage. + Subphyla of a phylum with storage class can not use the default storage, + but + must be defined with a storage class too. The completed + general form of a phylum definition is the following one. + + + + + + + Phylum with Storage Class + + + + + The first phylum in example declares + explicitly to use the default storage. All other phyla defined until now + got that implicitly. Memory of such terms can be freed individually, + terms of the second phylum can not. They are kept under + uniq storage. What does this mean? + Each storage class has a hashtables + hashtable assigned. All terms + of phyla with that class are stored there. If a term is to be created the + create routine does conditionally allocate new storage. It + checks first whether there is already stored an object created with the + same arguments. If found true, the routine will return a pointer to that + object in memory. Such every term is created only once. All predefined + phyla, such as integer, are declared + uniq. So the + example has the effect that if two &simpleterm;s are created from the + same int value they will both point to the same + memory cell. + It is possible to define additional storage classes, which each get + their own table. Tables also can be explicitly created and assigned to + storage classes, as well as cleared or freed (see ). + Example declares two additional storage + classes and defines two phyla using them. + + + Storage Class Definition and Application + + + + + + + + + + Processing phyla + + Pattern Matching<indexterm + significance="preferred"><primary>patterns</primary></indexterm> + Patterns make it easier to select terms and subterms and to + distinguish cases. They appear in rules for rewriting and unparsing and in + &with;- and &foreach;-statements. Here there are explained common features + while the slight differences will be mentioned in the appropriate place. + + The term ‘pattern’ can be defined through induction. + Each of the following is a pattern in the context of &kpp;: + + + the literal of a predefined phylum or the + asterisk sign, + the phylum operator with zero or more patterns as arguments, + + the assignment of a pattern to a variable, and + + the enumeration of patterns delimited by + commas. + + Additionally some restrictions hold regarding the use of patterns. The + patterns of item are not allowed as the + outermost pattern, while these of item + are allowed only as the outermost pattern. The assignment of an asterisk + to a variable can be abbreviated by stating only the variable. + If more than one pattern matches a term, the most specific pattern is + chosen. If there is no most specific one, the first of the matches is + chosen. The matched term can be accessed + as $0$0, + its first subtermsubterm as + $1, the second as $2 etc. (not in + rewrite rules). Table lists pattern + examples, which are in each group equally specific. &kpp; is + not yet able to decide between more + complex patterns (maybe partly overlapping each other) which to be most + specific, but chooses the first found. + Pattern groups increasingly specific + + + + + + + + + pattern + matches + + + + + * + any term; not allowed as the outermost pattern. + + + + + + + SimpleTerm + term SimpleTerm with an unspecified + number of subterms; only allowed as the outermost pattern. + + + SimpleTerm(*) + term SimpleTerm with a subterm. + + + a=SimpleTerm(b) + term SimpleTerm with a subterm; the term + is assigned to a variable a, the subterm, to + b. + + + Number(7) + term Number with an + integer subterm of value the + 7. + + + SimpleTerm(*),Mul(b,b) + either term SimpleTerm with a subterm or + term Mul with two subterms which are + structurally equal (the first of the two is assigned to + b). + + + + + + + SimpleTerm(Number(*)) + term SimpleTerm with a subterm being a + Number. + + + a=SimpleTerm(Number(b)) + term SimpleTerm with a subterm being a + Number; the term is + assigned to a and the sub-subterm to + b. + + + + + + + value!=0)]]> + term SimpleTerm with a subterm + being a Number, which is + assigned to b, but matches only if the + integer b is not zero. + + + + +
        +
        + + &kpp; Control Structures + &kpp; provides two control structures which help dealing with + terms: the + &with;&with;-statement and the + &foreach;&foreach;-statement. They appear in + different variants, fitting slightly different purposes. + Explicit + &with;<indexterm><primary>&with;</primary><secondary>explicit</secondary></indexterm> + The &with;-statement is similar to a &cpp; + switch + and decides for a given term which alternative branch to choose. The + alternatives are patterns describing &kind;s of one phylum and have + assigned a &cpp; block, maybe an empty one. + The example lists a code piece + containing an explicitly stated &with;. It decides whether the term + a is an identifier or a number and executes its code. + That term is accessable throughout the whole &with; body unless + an other term is assigned to the variable a, as it is + done in the second case. There, variable a gets + assigned the subterm of the Number. + The special pattern default matches when the + preceding patterns do not. Here this would never occur, because a + &simpleterm; is defined to be one of the two specified. + If no default case is specified and none of the patterns matches the + term a runtime exception is released (program execution aborted). + The pattern default is allowed in all + &with;-variants (implicit-, explicit-, and &foreach;-&with;). + + Explicit &with; + + computable = false; } + c=Number( a ) : { c -> computable = true; c -> result = a -> value; } + default : { // never reached, because simpleterm has only + // the above two ]]>&kind; + + + + Implicit + &with;<indexterm><primary>&with;</primary><secondary>implicit</secondary></indexterm> + If a function is defined to have a phylum argument whose variable + name begins with a dollar sign, the function body is assumed to be + the body of an implicitly given &with;-statement. Example presents a function which returns + true if the given &aritherm; + matches one of + the specified patterns, that is represents an arithmetic term. If the + term has the &kind; SimpleTerm, the default case + would catch. + + Implicit &with; + + + + + + Simple &foreach; + The &foreach;-statement is a loop which runs over all elements of a + term which is a list phylum and executes at every run the code which is + specified in the statement body. + The &foreach; in example counts + the appearances of arithmetic terms by calling the function + is_arithmetic_term for a + during each run. This variable holds the current list element. + + Simple foreach + + + + + + &foreach;-&with;<indexterm><primary>&foreach;-&with;</primary></indexterm> + This foreach variant also steps through a list, but performs a + &with; for every element. A dollar prefixed list variable is used + instead of a simple variable. The statement body contains patterns with + a &cpp; block assigned to each. + Example + demonstrates the usage. It counts the number of sums and differences + within the term list. + + &foreach;-&with; + + + + + + &foreach; with Pattern + This third variant of &foreach; allows to specify a pattern instead + of + a list variable. The action is executed only for those list elements + which match the pattern. Thus it combines &foreach; and an implicit + &with; containing only one pattern of interest. Example is similar to example but it counts only the number of sums in the + list. + + &foreach; with Pattern + + + + + + Multiple Patterns<indexterm><primary>multiple + patterns</primary></indexterm> + For every one of the preceding statements it is possible to specify + not only one but multiple variables or patterns respectively. Used with + &foreach;, multiple lists can be iterated over at one time. The + variables or patterns are separated by ampersand signs (&), the list + specifications by commas. Used with &with;, multiple terms can be + checked at one time whether matching complex patterns. Here, the + variables are separated by commas. + The complex patterns are made up by concatenating + single patterns by ampersand signs + (&)&, where the first + pattern has to match the first term, the second the second term (and so + on) to have the complex pattern to match. A complex pattern can also be + a grouping of patterns, but then it must be enclosed in + parentheses. + Example shows a &with; over two + variables. The statement simply prints out whether the two terms have + the same &kind;. + + + Multiple Patterns in &with; + + + + + + <constant>afterforeach</constant><indexterm><primary>afterforeach</primary></indexterm> + When a &foreach; iterates over more than one list at one time, the + execution will stop if one of the lists reaches its end, while the others + may still contain elements. The + afterforeach-statement is useful + if it is desired to iterate further over the remainders of the lists. The + variables of the afterforeach refer to the list + remainders. Their phyla are already known + from the preceding &foreach;. The + code fragment in example uses + &foreach;-&with; and + afterforeach to decide whether list + A is longer than list B, returning + true if it is. + + <constant>afterforeach</constant> in Length Test + + + + + + + + Rewriting<indexterm + significance="preferred" id="idx:rewriting" + class="startofrange"><primary>rewriting</primary></indexterm> + The process of rewriting transforms a term tree. The left-hand side of + each rewrite rule is a pattern specifying which term to substitute. The + right-hand side denotes the term to substitute by, which has to be of the + same phylum as the original one. This is done by calls of operators and + term returning functions. Variables from the left-hand side may be used. + Example simplifies terms by replacing every + sum of numbers by its evaluated result. A helper function is necessary + since it is not possible directly to use &cpp; operators in a + rewrite rule (except method calls, see ). + + Rewriting + + + <: SimpleTerm( Number( plus( a, b ) ) ) >; + + %{ KC_REWRITE /* code redirection */ + integer plus( integer a, integer b ){ + return mkinteger( a -> value + b -> value ); + } + %}]]> + + + To allow rewriting to end, each rule has to replace the + term in question by one which is really simpler, reduced, or closer to a + normal form. Since rewriting searches depth first, the + subtermssubterm are usually + already the result of a transformation. + Calling the + rewriterewrite() method of the root term + starts the transforming process for the tree. Choosing an arbitrary term + instead rewrites the subtree beneath. + + + + Unparsing<indexterm class="startofrange" significance="preferred" + id="idx:unparsing"><primary>unparsing</primary></indexterm> + The process of unparsing traverses a term tree and executes the + instructions for every term matching a pattern as specified in the unparse + rules. The left-hand side of a rule denotes a term pattern, the right-hand + side a list of unparse items which are evaluated for matching terms. The + various items allowed are listed below and appear all in example , which is completely nonsensically. + + + string + Text strings in double quotes are delivered to the + printer unchanged. + + + variable + The term denoted by this term variable will be + unparsed by calling its unparse-method. + + + attribute + The + attributeattributes of + a term will be unparsed by calling + its + unparseunparse()-method. If it is of non-phylum + type the user has to provide such a method. + + + &cpp; code + Inside a pair of braces arbitrary &cpp; code may be + placed. + + + escaped braces + ${ + $} + If a non-matching brace is needed it has to be escaped by a dollar sign. + + + + variable with view + A view can be specified if a variable should be + unparsed under other than the current view (see ). + + + + unparse view variable definition + Variables of user defined unparse view classes can be + defined inside a rule (see ). + + + + + + Unparse Items + + [: "zero" + a + b->result + { if (a->value == 0) } ${ + a:infix + $} + %uviewvar prefix p1; + a:p1 + ];]]> + + + For every operator, there is a default pattern which matches if + no other pattern does. Its associated rule unparses all subtermssubterm. + The unparse-method + generated for every phylum can also be called explicitly. It has 3 + arguments: the term to be unparsed, a printer and an + unparse view. The names kc_printerkc_printer and + kc_current_viewkc_current_view + respectively refer to the printer and the view + which are currently in use. + Printer + printer + The user himself has to provide a printer function which satisfies + his needs. Usually it prints to the standard output or into some file, + and may take actions dependent on the view. + + + + void printer( const char* the_string, uview the_view ) { ... }; + + + + Since several printer instances may be needed also a printer functor + can be + specified as the printer. The printer functor class must be derived + public from the class + printer_functor_class. + + + %{ HEADER /* redirection since no class definitions allowed in .k */ + class example_printer : public printer_functor_class { + public: + void operator( ) ( const char* the_string, uview the_view ) { ... }; + } + %} + + + + + + Language Options + language options + Often a term tree has to be pretty printed into different but + similar destination languages, which sometimes require only slightly + different output to be generated. To avoid whole rule sets to be + multiplied and to allow a more flexible choice concerning the + destination language, the concept of language options has been + introduced. + Every unparse item can be preceded by a language option, which is a + language name in angle brackets followed by a colon. That item will be + unparsed only if the language specified is active. Languages are + declared using the keyword + %language%language + and they are set by + calling + set_language(...)set_language(). The active language can + be checked by calling + is_language(...)is_language(). The + language names must satisfy the requirements for &cpp; identifiers. + Example + demonstrates the application of language + options. + Language Options + + + [: : "public " "class " name + : " extends " : " : " + base_name " {\n" class_body "}" + : ";" + "\n" + ]; + ]]> + + + + + + + View + Classes<indexterm significance="preferred" class="startofrange" + id="idx:view_man"><primary>view</primary></indexterm> + Rewriting and unparsing of each term is done under a certain view. The + view serves as a means to further differentiate between rules when + choosing one to apply. To be a match a rule must have the current view + to appear in its view list, which is the left part of the right-hand side + between the bracket and the colon. If no rule matches the rules with + empty list are considered. Below is shown the general form of rules with + views. + + + " "<" rview_list ":" {operator|function} ">;" + unparse_rule := pattern "->" "[" uview_list ":" unparse_items "];"]]> + + + Views are declared by enumerating them after the keyword + %rview%rview and + %uview%uview for + rewriting and unparsing respectively, separated by a space or + a comma. These declarations enable &kpp; to check for view consistency, + although it is possible to leave them out entirely. But that + should be avoided, because then even simple misspellings in a view list + cause the implicit introduction of new views. One view is predefined for + rewriting and unparsing respectively, + base_rviewbase_rview and + base_uviewbase_uview, + which is implicitly included in the empty view list. + The view can be changed for a term by calling its + rewrite/unparserewrite()-method + with a new view argument. In unparse rules there the same can also + be achieved by appending a colon and a new view name to a variable unparse + item. Thus a whole subtree can be rewritten/unparsed under a different + view, or even multiple times under changing views. Changing views allows + to interlock several tasks on a certain subtree. + + + <: a -> rewrite( demo1 ) >; + + %uview demo2 ; + + Plus( a, b ) -> [: a:demo2 { b->unparse( kc_printer, demo2 ); } ]; + // both subterms of Plus are further unparsed under view demo2;]]> + + + viewclassEvery + view introduced by the user actually causes the generation of a view + class and one view variable of the same name. Since the user cannot + distinguish them, the generalizing term ‘view’ is used. + For unparse views that may matter since the user can define his own + unparse view classes. These are declared by + enclosing the view name in parentheses. The user has + to provide a class view_class + derived from a generated class + view_baseclass. In particular, + that class may contain member variables to hold information persistent + over several rules. The base class provides an equality + operator (==) deciding whether two view variables + are of the same class and a + name-method returning the name of the view. + No global view variable of the same name is generated for a user + defined unparse view class. Variables of such a view are instantiated + inside of unparse rules by %uviewvar%uviewvar + and may bear the same name as their class. They can be used + like the implicitly created view variables, but + additionally provide all features of their class. Example shows the definition of an unparse view class and + demonstrates its usage. + + User defined Unparse View Class + + [: + %uviewvar number_count nc; // instantiate view variable + c:nc // and unparse c with it + { std::cout << "Numbers counted: " << nc.counter << std::endl; } + ]; + Plus( a, b ), Minus( a, b ), Mul( a, b ), Div( a, b ) + -> [ number_count: a b ]; + SimpleTerm( a ) -> [ number_count: a ]; + Number -> [ number_count: { kc_current_view.counter++; } ]; + Ident -> [ number_count: ];]]> + + + View lists contain names of view classes, all other occurrences of + views actually are view variables. The scope of an unparse view variable + ends with its defining rule. Since its + name is not known inside other rules there it can be accessed only by + means of the name kc_current_viewkc_current_view, which always + refers to the view variable currently used. + + + + Restrictions on &cpp; in &kpp; + There are many places + in a .k-file where &cpp; code can be used. But for + some of them, the &kpp; processor allows only restricted use of &cpp; + constructs. These places are listed in the following along with the + restrictions they impose. + + .k-file + Only function definitions are allowed. These + must have no types as arguments which have compound names + (for example no long int). &cpp; + commentscomments are + allowed everywhere in .k-files. + + + &cpp; unparse item + Almost arbitrary &cpp; code is allowed, that is, + everything which is allowed inside a local &cpp; block. + + + rewrite rule + Only simple function calls are allowed, that is, calls + which have as arguments only term variables and term literals, + phylum operators and other simple function calls; in particular no + &cpp; operators, except access of member functions. + + + code redirection + Arbitrary &cpp; code is allowed, but it has to be pure + &cpp; since redirection code is not evaluated by &kpp;. + + + + There is a way to get around the restrictions of the &kpp; processor + using macros. A macro is defined inside a code redirection, which the + processor does not evaluate. Therefore it can + be as complex as necessary, while the macro call inside the rewrite rule + looks as simple as &kpp; wishes. Example + defines a function for addition, which can be + avoided when using a macro as in example . + + + Macro Application in Rewriting + + + <: SimpleTerm( Number( PLUS( a, b ) ) ) >; + + %{ KC_REWRITE /* code redirection */ + #define PLUS( a, b ) mkinteger( ( a ) -> value + ( b ) -> value ) + %}]]> + + + Some generated functions return terms of the phylum + abstract_phylum which have to be cast to the + actual phylum. The &cpp; cast operators may be used also for phylum + conversionphylumconversion + but &kpp; provides + phylum_castphylum_cast, + a cast operator for phyla, which is better to use. + +
        + + Generated Code + From the &kpp; definitions, rules and &cpp; code pieces, several classes + and functions in pure &cpp; are generated and distributed over multiple + files. Compiled, they will perform the desired tree handling. + Additional code is needed to create the trees, probably created by scanner + and parser generators, for instance Flex and + &bison;. + Generated Classes and Types + The definition of phyla and operators result in generated &cpp; + classes. + But these should be of no further interest for the user since the phylum + names can be used in &cpp; code as if being pointer types of these + classes, the operators as if being &cpp; constructors. + Every phylum has a const counterpart of the same name + prefixed by c_, which is the only means to get a + const phylum variable. + Just for the sake of completeness, be it mentioned that every + phylum corresponds to a class + impl_phylum and every + operator to a subclass + impl_phylum_operator. + All the classes are derived from a common base class which can be referred + to as + abstract_phylum. By adding constructors, methods + or attributes to it, all phyla will be changed in that way. + + The interworking with &yacc;/&bison; requires a type + YYSTYPE which will be generated by &kpp; when the + option yystype is specified (see ) + Smart-pointer<indexterm><primary>smart + pointer</primary></indexterm> + Memory often leaks when phylum operators are used in expressions, + and that is sometimes hard to detect. + The option smart-pointer enables a smart memory + management which avoids unnecessary copying of terms and automatically + frees memory of unused terms. This is achieved + by using so called smart-pointers which do reference counting and + allow to free a term if it is no longer referenced. + An additional type is generated for every phylum with the suffix + _ptr. Variables of such types are unnecessary + ever to be freed. Avoid mixing them with variables of the usual types, + especially never assign between them, because that is likely to cause + memory access errors. + + + Weak-pointer<indexterm><primary>weak + pointer</primary></indexterm> + The option weak-pointer extends the + smart-pointer technique and supports a third + type for every phylum. It gets prefix weak_ and + suffix _ptr. Weak-pointer variables of a term will + not contribute to the reference counting, such that the term already is + freed if merely weak-pointers reference it yet. That is why they are + only usefully employed in conjunction with smart-pointers. + In contrast to usual variables, weak-pointers have their own + reference counting, which allows to determine whether such a pointer + dangles, that is points to a term already freed and thus is no longer + valid. + + + Generated Functions + &kpp; generates a number of functions which are available wherever + &cpp; code is allowed in .k-files. The table lists all these functions and the sections + which contain a more detailed description. + Generated Functions + + + + + + function + see section + + + + + append + + + + concat + + + + eq + + + + CSGIOread + + + + CSGIOwrite + + + + filter + + + + fprint + + + + fprintdot + + + + fprintdotepilogue + + + + fprintdotprologue + + + + free + + + + freelist + + + + ht_create_simple + + + + ht_assign + + + + ht_assigned + + + + ht_clear + + + + ht_delete + + + + is_nil + + + + + + + + + + function + see section + + + + + last + + + + length + + + + map + + + + merge + + + + mkcasestring + + + + mkinteger + + + + mknocasestring + + + + mkreal + + + + op_name + + + + phylum_name + + + + print + + + + reduce + + + + reverse + + + + rewrite + + + + set_subphylum + + + + subphylum + + + + unparse + + + + + +
        + Common Functions + Since abstract_phylum has an + unparse-method defined and all phyla are derived + from abstract_phylum all phyla have it. The same + is true for some other methods. + copy<indexterm><primary>copy()</primary></indexterm> + + + abstract_phylum copy( bool copy_attributes ) const; + + + The method copies this term completely, including its subterms. + Since the result is always abstract_phylum it + has to be casted to the phylum of this term. If + true is specified as argument, the attributes are + copied too. But beware! Merely the addresses are copied if the + attributes are phyla or &cpp; pointers, that is, the new term + references the attributes of the old one. + + eq<indexterm><primary>eq()</primary></indexterm> + + + bool eq( c_abstract_phylum c_p ) const; + + + The method returns true if this term is + structurally equal to the argument, that is, both terms have + equal subtrees. + + fprint<indexterm><primary>fprint()</primary></indexterm> + + + void fprint( FILE* file ); + + + The method prints a textual presentation of this term to + the specified file. This simple example produces the output + underneath. + + simpleterm a_number = SimpleTerm( mkinteger( 23 ) ); + a_number -> print( ); + + SimpleTerm( + Number( + 23 + ) + ) + + + fprintdot<indexterm><primary>fprintdot()</primary></indexterm> + + + void fprintdot( FILE *f, + const char *root_label_prefix, + const char *edge_label_prefix, + const char *edge_attributes, + bool print_node_labels, + bool use_context_when_sharing_leaves, + bool print_prologue_and_epilogue + ) const; + + + This function creates a representation of the term in a format + understood by the program dot, which is part + of the graphics package graphviz and draws + directed acyclic graphs in various output formats like PostScript or + GIF. The target of the operation is the file f, while + the other arguments control the details of the graphs appearence. + + + root_label_prefix + Adds a label to the graph denoting the root term. + The label has the name of the phylum of that term prefixed by + this string argument. + + + edge_label_prefix + Every edge in the graph is labelled with a number. + This string argument appears as the prefix of these labels. + + + + edge_attributes + For dot, the edges can + have attributes which specify additional features like font name + or edge colour (see dot manual for + attribute names and values). This string argument is a list of + attribute/value pairs + (attribute=value), + separated by commas. + + + print_node_labels + If this argument is set to true, + the names of the subterms phyla appear in the graph. Otherwise + they are suppressed and only the term names (operator names) are + printed. + + + + use_context_when_sharing_leaves + Terms which are shared in the tree usually appear + only once in the graph (terms of uniq + phyla). In particular, terms of predefined phyla are shared if + they are equal. They are always leaves since they have no + subphyla. If this argument is set to true, + the leaves appear shared in the graph only if they are subterms + of shared (uniq) terms. + + + + print_prologue_and_epilogue + This argument is usually set to + true since a certain prologue and epilogue + are necessary to frame the graph. This is set to + false if multiple graphs are to be grouped + into one figure. In that case the prologue function has to be + called explicitly, then some fprintdot + calls follow, and finally the epilogue call finishes the figure + creation. + + + + The following call of fprintdot writes a + a presentation of the term t to a file + exa. From that file dot + creates a graph like that in figure . + + aterm t = Plus( SimpleTerm( Number( mkinteger( 7 ) ) ), + SimpleTerm( Number( mkinteger( 7 ) ) ) ); + t -> fprintdot(exa, "root_", "edge", "style=dashed", true, false, true); + +
        + Dot Created Graph of an Example Term + + + + + +
        +
        + fprintdotprologue<indexterm><primary>fprintdotprologue()</primary></indexterm> + + + void fprintdotprologue ( FILE *f ); + + + This function writes the prologue to f, which + is needed to set up graphviz. + Usually, when the figure contains only one graph, this function will + be called implicitly by fprintdot; call this + function when you set print_prologue_and_epilogue + to false in the function call above. + + + fprintdotepilogue<indexterm><primary>fprintdotepilogue()</primary></indexterm> + + + void fprintdotepilogue ( FILE *f ); + + + This function writes the epilogue to f, which + is needed to finish the graph for graphviz. + Usually, when the figure contains only one graph, this function will + be called implicitly by fprintdot; call this + function when you set print_prologue_and_epilogue + to false in the function call above. + + + op_name<indexterm><primary>op_name()</primary></indexterm> + + + const char* op_name( ) const; + + + This function returns the name of the phylum operator which has + been used to create this term. + + phylum_name<indexterm><primary>phylum_name()</primary></indexterm> + + + const char* phylum_name( ) const; + + + This function returns the name of the phylum of this term. + + print<indexterm><primary>print()</primary></indexterm> + + + void print( ); + + + This function prints a textual presentation of this term to the + standard output. It is similar to the output of + fprint. + + set_subphylum<indexterm><primary>set_subphylum()</primary></indexterm> + + + void set_subphylum( int n, abstract_phylum p, bool=false ); + + + This function replaces the nth subterm of this term by term + p, which must be of a phylum castable to the phylum + of the appropriate subterm. Numbering starts with 0. + + + subphylum<indexterm><primary>subphylum()</primary></indexterm> + + + abstract_phylum subphylum( int n, bool=false ) const; + + + This function returns the nth subterm of this + term. Numbering starts with 0. + + unparse<indexterm significance= + "preferred"><primary>unparse()</primary></indexterm> + + + void unparse( printer_functor pf, uview uv); + void unparse( printer_function opf, uview uv ); + + + This function starts unparsing for this term. It is recursively + called for every subterm. Unparsing is processed under the specified + unparse view, and the strings to output are delivered to the printer + functor or function respectively. + + rewrite<indexterm><primary>rewrite()</primary></indexterm> + + + rewrite( rview rv ); + ]]> + + + This functions starts rewriting for this term. It returns a new term + of the actual phylum. Usually it is called at the root term whereupon + the entire tree is searched under the specified view. + +
        + CSGIO Functions + The generated files csgiok.h and + csgiok.cccsgiok.cc,h + provide means to write terms to files and + to reconstruct terms from such files. Whole term trees thus can be saved + and exchanged between different applications. Reading and writing + is performed by two functions. + The format of the files has once been designed to be compatible to + the structure files of the commercial tool Synthesizer + Generator. The format written now by &kpp; is somewhat + extended so that they are not compatible any more, but old structure + files are expected to be still understood. + CSGIOwrite<indexterm><primary>CSGIOwrite()</primary></indexterm> + + + + + + The methods writes this term to f, that is, the + entire subterm tree. The + attributes are ignored except they are phyla which have been defined + using the keyword %member. + + CSGIOread<indexterm><primary>CSGIOread()</primary></indexterm> + + + void + CSGIOread( FILE *f, P &p ) + ]]> + + + The function reads from f the presentation of a + term. The term is constructed by successively calling the appropriate + operators of the subterms. The operators initialize the attributes + according to the phylum definition; except the + %member-attributes which get their values from + the saved term. The created term is assigned to p + which has to be a variable of the correct phylum. + + + + Creation Functions + Terms of predefined phyla are created by functions. + mkcasestring<indexterm significance= + "preferred"><primary>mkcasestring()</primary></indexterm> + + + casestring mkcasestring( const char *str ); + casestring mkcasestring( const char *str, unsigned int length ); + + + The function creates a term of the phylum + casestring + from the specified string. Upper and lower case characters are + distinguished. The second variant uses only the first + length characters of the specified string. + + + mkinteger<indexterm significance= + "preferred"><primary>mkinteger()</primary></indexterm> + + + integer mkinteger( const INTEGER i ); + + + The function creates a term of the phylum + integer + from the specified value. INTEGER is a macro + which can be defined by the user as needed but defaults to + int. + + mknocasestring<indexterm significance= + "preferred"><primary>mknocasestring()</primary></indexterm> + + + nocasestring mknocasestring( const char *str ); + nocasestring mknocasestring( const char *str, unsigned int length ); + + + The function creates a term of the phylum + nocasestring + from the specified string. Upper and lower case characters are not + distinguished. The second variant uses only the first + length characters of the specified string. + + mkreal<indexterm significance= + "preferred"><primary>mkreal()</primary></indexterm> + + + real mkreal( const REAL r ); + + + The function creates a term of the phylum + real + from the specified value. REAL is a macro + which can be defined by the user as needed but defaults to + double. + + + Memory Management Functions + When terms, once constructed, are no longer needed it is usually + reasonable to free the memory they allocate, + especially when dealing with large numbers of + terms. + The same does not hold not for the use of smart-pointers, because + these keep track of allocated memory by their own. Never apply + free or freelist to + smart-pointers. The + &cpp; delete should never be applied to + any term, since that would get around some &kpp; mechanisms. + free<indexterm><primary>free()</primary></indexterm> + + + void free( bool recursive=true ); + + + The method frees the memory allocated by this term and by + default it frees also the subterms recursively. When it is applied to + a list term, the whole list and all its elements are freed. The + non-recursive form only separates the list into its first element and + the remainder of the list. Terms of phyla under non-default storage + management can not be freed individually, calling + free on them has no effect. + + freelist<indexterm><primary>freelist()</primary></indexterm> + + + void freelist( ); + + + The method frees the spine of this list term and leaves the list + elements untouched. + + + + Hashtable Functions + hashtables + The memory management of terms of storage class + uniquniq + or a user defined one can only be influenced by hashtable operations. + + + ht_create_simple<indexterm><primary>ht_create_simple()</primary></indexterm> + + + hashtable_t ht_create_simple ( int size ); + + + The function creates a new hashtable and returns it. The current + implementation ignores the size argument. + + + ht_assign<indexterm><primary>ht_assign()</primary></indexterm> + + + hashtable_t ht_assign ( hashtable_t ht, storageclass_t sc, + bool still_unique=false ); + + + The function assigns the hashtable ht to the + storage class sc and returns the hashtable which + has previously been assigned to sc. + + ht_assigned<indexterm><primary>ht_assigned()</primary></indexterm> + + + hashtable_t ht_assigned ( storageclass_t sc ); + + + The function returns the hashtable which is assigned to the + storageclass sc. + + ht_clear<indexterm><primary>ht_clear()</primary></indexterm> + + + void ht_clear ( hashtable_t ht ); + + + The function removes all entries from the hashtable + ht. + + ht_delete<indexterm><primary>ht_delete()</primary></indexterm> + + + void ht_delete ( hashtable_t ht ); + + + The function deletes the hashtable ht entirely. + + + + List Functions<indexterm id="idx:listfunc" + class="startofrange"><primary>list</primary></indexterm> + List phyla which have been defined using the + list keyword get some methods performing convenient + tasks. In the function signatures, the name + ]]> denotes the actual + list phylum, ]]> denotes the + phylum of the list elements. + append<indexterm><primary>append()</primary></indexterm> + + + append( p );]]> + + + The method appends the specified term to this list and returns + the tail of the new list, ie. the sublist that has + p as its only element. This make appending several + elements in a row more efficient. + + + concat<indexterm><primary>concat()</primary></indexterm> + + + concat( c_ l1, c_ l2 );]]> + + + The function constructs a new list from the terms of + l1 followed by the terms of l2 + and returns that list. + + + filter<indexterm><primary>filter()</primary></indexterm> + + + filter( bool (*fp) () );]]> + + + The method constructs a new list from the terms of this + list for which the function fp yields + true. + + + is_nil<indexterm><primary>is_nil()</primary></indexterm> + + + + + + The method returns true if this list is empty. + + + last<indexterm><primary>last()</primary></indexterm> + + + last( ) const;]]> + + + The method returns the remainder of this list which contains only + one, the last, element. If this list is empty the empty list is + returned. + + + length<indexterm><primary>length()</primary></indexterm> + + + + + + The method returns the number of elements in this list. + + + map<indexterm><primary>map()</primary></indexterm> + + + map( (*fp) () );]]> + + + The method constructs a new list containing the terms which are + returned by the fp which is called for every + element of this list. The new list is returned. + + + merge<indexterm><primary>merge()</primary></indexterm> + + + merge( l, (*fp) (, ) );]]> + + + The method constructs a new list containing the terms which are + returned by the fp which is called for every + element of this list taking the second argument from the specified + list. The new list is returned. + + + reduce<indexterm><primary>reduce()</primary></indexterm> + + + reduce( p, (*fp) (, ) );]]> + + + The method successively applies the function + fp to each element of this list and + fps last result which initially is the term + p. The final result is returned. + + + reverse<indexterm><primary>reverse()</primary></indexterm> + + + reverse( ) const;]]> + + + The method constructs a new list which contains the elements of + this list in reverse order. The new list is returned. + + + + + +
        + Generated Files + The generated code is spread over several files. The table lists these files and a description of their + contents. + Every file defines a macro symbol which can be used in preprocessor + instructions and in code redirectionsredirection. + These symbols are listed as well. From every &kpp; file + a &cpp; file and a header file are generated. The name + file in the table refers to such files. + Generated files + + + + + + + + + + file + symbol + contents + + + + + csgiok.cccsgiok.cc,h + KC_CSGIO + functions for saving and restoring of terms + + + csgiok.h + KC_CSGIO_HEADER + some definitions for saving and restoring of terms + + + k.cck.cc,h + KC_TYPES + implementation of all classes generated from phylum definitions + + + k.h + KC_TYPES_HEADER + all class declarations generated from phylum definitions; + included by all implicitly generated files + + + rk.ccrk.cc,h + KC_REWRITE + rewrite methods for all phyla + + + rk.h + KC_REWRITE_HEADER + rewrite view class definitions + + + unpk.ccunpk.cc,h + KC_UNPARSE + unparse methods for all phyla + + + unpk.h + KC_UNPARSE_HEADER + unparse view class definitions + + + file.cc + KC_FUNCTIONS_file or CODE + function definitions from file.k-file + + + file.h + KC_FUNCTIONS_file_HEADER or HEADER + declarations of functions from file.k-file + + + +
        + Code Redirection<indexterm significance="preferred"><primary>redirection</primary></indexterm> + A .k-file can contain pieces of arbitrary &cpp; + enclosed between a line + starting with + %{%{ and + one starting with + %}%}. + Since it will not be + parsed by &kpp; but copied directly into generated code, it can not + contain special &kpp; constructs, but merely pure &cpp;. It will go to + the matching .cc-file, if no redirection is + specified. Giving a list of + file symbols after %{ will copy the code each + of the specified files instead. The available redirection symbols + are listed in table . + + + // this be a file example.k + + %{ + // everything between the brace lines will be copied to example.cc + %} + + %{ HEADER KC_UNPARSE /* beware of //-comments here */ + // everything between the brace lines will be copied to example.h and unpk.cc + %} + + + +
        +
        + + Running &kpp; + The &kpp; processor is invoked with the command + kc++. It can be invoked on any number of + .k-files and will create a number of output files + as outlined above. A typical call looks like this: + + + kc++ abstr.k rpn.k main.k + + When used together with other tools (see + ) a makefile is helpful. + Be aware, though, that every source file may influence every + generated file (because of the code redirections). Thus multiple destination + files depend on multiple source files. That means the makefile becomes more + complicated in order to handle these dependencies. That is why an example makefile + is provided in appendix (see ). It is sufficient + for the RPN example and + may easily be adapted for many more. + Options<indexterm id="idx:options" + class="startofrange"><primary>options</primary></indexterm> + &kpp; recognizes a number of command line options which affect the + process of parsing and code generation, some rather drastically. Table + presents, in alphabetical order, + all available options and their explanation. In most environments, two + forms are provided, short and GNU style long options. + + Suppose you do not need CSGIO input/output, but want to interface with + your favourite compiler compiler, you might use: + + kc++ --no-csgio --yystype abstr.k rpn.k main.k + + Some vital options can be specified directly in &kpp; using the + keyword %option. Such specified options take higher + priority than command line options and thus override them. + Table lists them in alphabetical order. + They behave like their command line counterparts. + A line like this could be specified in a &kpp; file: + + + %option yystype smart-pointer + + + Command line options + + + + + + + + + + + option + explanation + + + + + + ???c + ??????no???csgio + do not generate phylum read/write functions + (csgiok.{h,cc}) + + + + ???r + ??????no???rewrite + do not generate code for rewrite rules + (rk.{h,cc}) + + + ???u + ??????no???unparse + do not generate code for unparse rules + (unpk.{h,cc}) + + + ???d + ??????no???printdot + no fprintdot functions are generated + + + ???t + ??????no???hashtables + do not generate code for hashtable operations + + + + + ???n + ??????covariant=C + use covariant return types: y|n|p (yes, no or generate both + and decide per preprocessor macro + NO_COVARIANT_RETURN) + + + + ??????stdafx[=FILE] + generate include for Microsoft precompiled header files + (default stdafx.h) + + + ???e + ??????dllexport=STRING + generates string between keyword class and the + class name of all operators and phyla + + + ???m + ??????smart???pointer + generates code for smart pointers (reference counting) + + + ???w + ??????weak???pointer + generates code for weak pointers (implies smart pointers) + + + + ???s + ??????suffix=EXT + extension for generated source files (default + .cc) + + + ???f + ??????file???prefix=PREF + prefix all generated files + + + ???o + ??????overwrite + always write generated files even if not changed + + + ???b + ??????yystype[=FILE] + generate file (default yystype.h) + containing YYSTYPE, for &yacc; and &bison; + + + + ???y + ??????yxxunion + generate file yxx_union.h) + for use with for Yacc++. + + + + + ???l + ??????no???linedirec + omit the line directives (#line) + altogether + + + + ??????comment???line + change line directives to mere comments + + + + ??????dir???line + prepends the current working directory to the file name + in line directives + + + ???p + ??????pipe=CMD + process all files while piping them through CMD + + + + ???M + ??????msg???format=PAT + specifies format of (error) messages, PAT can contain: + + %p (program name), + %s (severity), + %f (file name), + + %d (current working directory), + %l (line number), + %c (column); + + the actual message is appended + + + ???q + ??????quiet + quiet operation (is default) + + + ???v + ??????verbose + print additional status information while processing + + + ???h + ??????help + display the help and exit + + + ???V + ??????version + output version information and exit + + + +
        + Built-in options + + + + + + + no???csgio + no???hashtables + no???printdot + no???rewrite + no???unparse + smart???pointer + weak???pointer + yystype + + +
        + +
        + &yacc;/&bison; + Interfacing with a compiler generator is useful when a tree should be + build from some kind of input. &kpp; provides the + yystype-option (see ) + which causes the generation of a header file needed by &yacc; to + cooperate. For + every token found, the desired &kpp; operator is called to create a term. + If lex/flex is used too, &yacc; has to be + run with the option which causes the generation of an other header file + needed + by lex/flex (???d + for &bison;). Appropriate files for the example can be found in appendix + . The makefile uses implicit rules for + flex and &bison;. + +
        + + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-rpn.xml diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-rpn.xml:1.1 *** /dev/null Tue Apr 6 15:25:33 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/doc/kpp-rpn.xml Tue Apr 6 15:25:22 2004 *************** *** 0 **** --- 1,332 ---- + + Complete code of RPN example + main.k + + + #include "k.h" + #include "rk.h" + #include "unpk.h" + #include "csgiok.h" + + int yyparse( ); + aritherm root_term; + %} + + %{ KC_TYPES_HEADER + extern aritherm root_term; + %} + + %option yystype + + void + printer( const char *s, uview v ) { + std::cout << s; + } + + int + main( int argc, char** argv ) { + std::cout << "rpn calculator" << std::endl; + yyparse( ); + aritherm canon_term = root_term -> rewrite( canonify ); + aritherm simpl_term = canon_term -> rewrite( simplify ); + std::cout << "simplified term in infix notation" << endl; + simpl_term -> unparse( printer, infix ); + std::cout << std::endl; + } + ]]> + + + abstr.k + + + + + rpn.k + + 3 + Plus(SimpleTerm(Number(a)),SimpleTerm(Number(b)))-> + ; + // 1 + 3 + b -> 4 + b + Plus(SimpleTerm(Number(a)),Plus(SimpleTerm(Number(b)),rem))-> + ; + // 1 + 3 - b -> 4 - b + Plus(SimpleTerm(Number(a)),Minus(SimpleTerm(Number(b)),rem))-> + ; + // 6 - 2 -> 4 + Minus(SimpleTerm(Number(a)),SimpleTerm(Number(b)))-> + ; + // 6 - 4 - b -> 2 - b + Minus(SimpleTerm(Number(a)),Minus(SimpleTerm(Number(b)),rem))-> + ; + // 6 - 4 + b -> 2 + b + Minus(SimpleTerm(Number(a)),Plus(SimpleTerm(Number(b)),rem))-> + ; + // 3 * 2 * b -> 6 * b + Mul(SimpleTerm(Number(a)),Mul(SimpleTerm(Number(b)),rem))-> + ; + // 3 * 2 / b -> 6 / b + Mul(SimpleTerm(Number(a)),Div(SimpleTerm(Number(b)),rem))-> + ; + // 3 * 2 -> 6 + Mul(SimpleTerm(Number(a)),SimpleTerm(Number(b)))-> + ; + // 6 / 2 -> 3 + Div(SimpleTerm(Number(a)),SimpleTerm(Number(b)))-> + ; + // 6 / 2 / b -> 3 / b + Div(SimpleTerm(Number(a)),Div(SimpleTerm(Number(b)),rem))-> + ; + // 6 / 2 * b -> 3 * b + Div(SimpleTerm(Number(a)),Mul(SimpleTerm(Number(b)),rem))-> + ; + + // a + a -> 2 * a + Plus(b=SimpleTerm(Ident(a)),SimpleTerm(Ident(a)))-> + ; + // a - a -> 0 + Minus(SimpleTerm(Ident(a)),SimpleTerm(Ident(a)))-> + ; + // a / a -> 1 + Div(SimpleTerm(Ident(a)),SimpleTerm(Ident(a)))-> + ; + // 6 * a + a -> 7 * a + Plus(Mul(SimpleTerm(Number(a)),SimpleTerm(Ident(b))),c=SimpleTerm(Ident(b)))-> + ; + // 6 * a -a -> 5 * a + Minus(Mul(SimpleTerm(Number(a)),SimpleTerm(Ident(b))),c=SimpleTerm(Ident(b)))-> + ; + // 6 * a + 3 * a -> 9 * a + Plus(Mul(SimpleTerm(Number(a)),SimpleTerm(Ident(b))), + Mul(SimpleTerm(Number(d)),c=SimpleTerm(Ident(b))))-> + ; + // 6 * a - 2 * a -> 4 * a + Minus(Mul(SimpleTerm(Number(a)),SimpleTerm(Ident(b))), + Mul(SimpleTerm(Number(d)),c=SimpleTerm(Ident(b))))-> + ; + // a + (a + 2 * b) -> 2 * a + 2 * b + Plus(b=SimpleTerm(Ident(a)),Plus(SimpleTerm(Ident(a)),rem))-> + ; + // a - (a +- 2 * b) -> 2 * b + Minus(SimpleTerm(Ident(a)),Plus(SimpleTerm(Ident(a)),rem)), + Minus(SimpleTerm(Ident(a)),Minus(SimpleTerm(Ident(a)),rem))-> + ; + // a + (a - 2 * b) -> 2 * a - 2 * b + Plus(b=SimpleTerm(Ident(a)),Minus(SimpleTerm(Ident(a)),rem))-> + ; + + // (a + b) + c -> a + (b + c) + Plus( Plus(a, b), c) + -> < canonify: Plus(a, Plus(b, c))>; + // (a - b) + c -> c + (a - b) + Plus( Minus(a, b), c) + -> < canonify: Plus(c, Minus(a, b))>; + // (a + b) - c -> a + (b - c) + Minus( Plus(a, b), c) + -> < canonify: Plus(a, Minus(b, c))>; + // (a * b) * c -> a * (b * c) + Mul( Mul(a, b), c) + -> < canonify: Mul(a, Mul(b, c))>; + // a + 5 -> 5 + a + Plus( a=SimpleTerm(Ident(*)), b=SimpleTerm(Number(*)) ) + -> < canonify: Plus(b, a)>; + // a * 5 -> 5 * a + Mul( a=SimpleTerm(Ident(*)), b=SimpleTerm(Number(*)) ) + -> < canonify: Mul(b, a)>; + // a + (6 + b) -> 6 + (a + b) + Plus( a=SimpleTerm(Ident(*)), Plus(b=SimpleTerm(Number(*)), rest) ) + -> < canonify: Plus(b, Plus(a,rest))>; + // a * (6 * b) -> 6 * (a * b) + Mul( a=SimpleTerm(Ident(*)), Mul(b=SimpleTerm(Number(*)), rest) ) + -> < canonify: Mul(b, Mul(a,rest))>; + + %{ KC_REWRITE + inline integer plus(integer a, integer b){ + return mkinteger(a->value+b->value); + } + inline integer minus(integer a, integer b){ + return mkinteger(a->value-b->value); + } + inline integer mul(integer a, integer b){ + return mkinteger(a->value*b->value); + } + inline integer div(integer a, integer b){ + return mkinteger(b->value==0 ? 0 : a->value / b->value); + } + %} + + %uview infix,postfix; + + Plus(a,b)->[infix: "(" a "+" b ")"]; + Minus(a,b)->[infix: "(" a "-" b ")"]; + Mul(a,b)->[infix: "(" a "*" b ")"]; + Div(a,b)->[infix: "(" a "/" b ")"]; + ]]> + + + lexic.l + + + #include "k.h" + #include "yystype.h" + #include "syntax.h" + #include "rpn.h" + %} + + %option noyywrap + + %% + + -?[0-9]+ { yylval.yt_integer = mkinteger(atoi(yytext)); return NUMBER;} + [a-z]+ { yylval.yt_casestring = mkcasestring(yytext); return IDENT; } + [+*-/] { return yytext[0]; } + [\t ]+ { /*empty*/ } + \n { return EOF; } + . { std::cerr << "Unkown character: " << yytext[0] << std::endl; } + + %% + + extern void yyerror(const char *s) { + std::cerr << "Syntax error: " << s << std::endl; + } + + ]]> + + + syntax.y + + NUMBER + %token IDENT + %token NEWLINE + + %type aritherm + %type simpleterm + + %% + + + aritherm: + simpleterm + { root_term = $$ = SimpleTerm($1); } + | aritherm aritherm '+' + { root_term = $$ = Plus($1,$2); } + | aritherm aritherm '*' + { root_term = $$ = Mul($1,$2); } + | aritherm aritherm '-' + { root_term = $$ = Minus($1,$2); } + | aritherm aritherm '/' + { root_term = $$ = Div($1,$2); } + ; + + simpleterm: + NUMBER + { $$ = Number($1); } + | IDENT + { $$ = Ident($1); } + ; + ]]> + + + Makefile + + + + .PRECIOUS: lexic.c y.output + + # Tools + SHELL = /bin/sh + YACC = bison + LEX = flex + CC = ${CXX} + KC = kc++ + + #Flages + YFLAGS = -d -y + LFLAGS = -t + CXXFLAGS = -g -Wall -Wno-unused -DYYDEBUG -DYYERROR_VERBOSE + CFLAGS = ${CXXFLAGS} + + # Sources + KFILES = rpn.k main.k abstr.k + YFILES = syntax.y + LFILES = lexic.l + + + # Goals + PARSER = rpn-parser + + # Help files + + KC_TIME = .kc_time_stamp + + KC_OGEN = k.o csgiok.o unpk.o rk.o + KC_OSRC = $(KFILES:.k=.o) + OBJS = $(KC_OGEN) $(KC_OSRC) $(YFILES:.y=.o) $(LFILES:.l=.o) $(CFILES:.cc=.o) + + + # default rule + $(PARSER):: + + # include or make autodependencies + ifeq (.depend,$(wildcard .depend)) + include .depend + else + $(PARSER):: depend + endif + + # Rules + $(KC_TIME): $(KFILES) + $(KC) $(KFILES) + touch $(KC_TIME) + + $(PARSER):: $(KC_TIME) $(OBJS) + $(CXX) $(CFLAGS) $(OBJS) ${LIBS} -o $@ + + + syntax.h : y.tab.h + -cmp -s syntax.h y.tab.h || cp y.tab.h syntax.h + + y.tab.h : syntax.c + + depend dep: + @echo Make dependencies first + $(MAKE) $(KC_TIME) + $(MAKE) $(YFILES:.y=.c) + $(MAKE) $(LFILES:.l=.c) + $(MAKE) syntax.h + $(CC) -M *.cc > .depend + + clean: + -rm -f $(OBJS) core *~ *.bak $(KFILES:.k=.cc) $(KC_OGEN:.o=.cc) $(KC_TIME) .kc* \ + $(YFILES:.y=.c) $(LFILES:.l=.c) $(KC_OGEN:.o=.h) $(KFILES:.k=.h) out.* \ + y.tab.h syntax.h syntax.output syntax.tab.c yystype.h + ]]> + + + From criswell at cs.uiuc.edu Tue Apr 6 15:26:41 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue Apr 6 15:26:41 2004 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Applications/kimwitu++/AUTHORS CHANGES COPYING Makefile README abs.cc abs.h config.h defs.h defs.hh error.cc error.h gen.cc gen.h getopt.h gutil.cc gutil.h k.cc k.h kimwl.cc kimwy.cc kimwy.h main.cc main.h occur.cc occur.h parse.cc parse.h pat.cc pat.h rk.cc rk.h unpk.cc unpk.h util.cc util.h yystype.h Message-ID: <200404062025.PAA03909@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Applications/kimwitu++: AUTHORS added (r1.1) CHANGES added (r1.1) COPYING added (r1.1) Makefile added (r1.1) README added (r1.1) abs.cc added (r1.1) abs.h added (r1.1) config.h added (r1.1) defs.h added (r1.1) defs.hh added (r1.1) error.cc added (r1.1) error.h added (r1.1) gen.cc added (r1.1) gen.h added (r1.1) getopt.h added (r1.1) gutil.cc added (r1.1) gutil.h added (r1.1) k.cc added (r1.1) k.h added (r1.1) kimwl.cc added (r1.1) kimwy.cc added (r1.1) kimwy.h added (r1.1) main.cc added (r1.1) main.h added (r1.1) occur.cc added (r1.1) occur.h added (r1.1) parse.cc added (r1.1) parse.h added (r1.1) pat.cc added (r1.1) pat.h added (r1.1) rk.cc added (r1.1) rk.h added (r1.1) unpk.cc added (r1.1) unpk.h added (r1.1) util.cc added (r1.1) util.h added (r1.1) yystype.h added (r1.1) --- Log message: Initial import of kimwitu++. This is based on version 2.3.8. Kimwitu++ is analagous to a midterm exam for LLVM C++ programs. If LLVM can handle kimwitu++, we're in pretty good shape. --- Diffs of the changes: (+65971 -0) Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/AUTHORS diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/AUTHORS:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/AUTHORS Tue Apr 6 15:25:06 2004 *************** *** 0 **** --- 1,13 ---- + Authors of Kimwitu++. + + Axel Belinfante . Wrote the original + Kimwitu program. + The structure-file-io reading and writing code has been derived, in part, + from The Synthesizer Generator (tm), see the LICENSE file. + + Michael Piefel . Derived Kimwitu++. + + Various hacks and improvements written by Ralf Schr?der , Martin v. L?wis , Carsten + Dumke , Gerd Kurzbach . + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/CHANGES diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/CHANGES:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/CHANGES Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,129 ---- + This is the list of user-visible changes in kimwitu++. Please see + src/ChangeLog for a more detailed list. + + * Changes in kimwitu++ 2.3.7 + ** new option --operator-cast to have an operator_cast<>() just like + phylum_cast<>() or dynamic_cast<>() + ** support for named subphyla for greater type safety + + * Changes in kimwitu++ 2.3.6 + ** new option -W allows greater control of warning levels + ** new option --rw-loop generates iterative rewrite algorithm (instead of + recursive) and greater control (or hacking) + + * Changes in kimwitu++ 2.3.5 + ** New options for error reporting format + ** Allow {con,de}structors for any class (but give warning) + ** Add options to morph line directives into comments + + * Changes in kimwitu++ 2.3.1 + ** Version number of generating Kimwitu++ goes into the generated code as + a number of #define's (KIMWITUVERSIONMAJOR, *MINOR, *MICRO) + ** Rename kc_.views to .views (should have happened before). + ** Added a virtual default_unparse method to have replaceable default + unparse behaviour. There is not yet a Kimwitu++ syntax extension for it. + + * Changes in kimwitu++ 2.3.0 + ** Change back the semantic of append to return the element for the list + where we insert the value. + ** This warrants a version number bump 3.0: Give warnings for overlapping + patterns in unparse, rewrite and with. + ** Support for g++ 3.2 + ** --no-linedirec does not emit any line directives now. + + * Changes in kimwitu++ 2.2.0 + ** Removed the kc_ prefix in many places. There are some macros you can use + to get the old names, you just have to define DEPRECATED. + ** Renamed kc_tag_ to impl_; macros as above. + ** Changed language macros to is_language and set_language. + + * Changes in kimwitu++ 2.1.4 + ** Allow conversion operators in phyla. + + * Changes in kimwitu++ 2.1.3 + ** Lines can have arbitrary lengths now. + + * Changes in kimwitu++ 2.1.2 + ** User-defined member functions now possible for primitive phyla. This + is actually a bug fix, but since it never worked before it can be + considered a new feature. + + * Changes in kimwitu++ 2.1.0 + ** Some care is taken to allow unparsing of lists to be done iteratively + instead of recursively by default. Faster and leaner on stack space. + ** Some more lists in kimwitu++ itself unparsing iteratively even though not + using default unparsing. Now very large files can be processed. + ** If available, kimwitu++ now uses hash sets for storing casestrings. This can + speed up things dramatically. Use -DUSE_HASHSET while compiling k.cc + + * Changes in kimwitu++ 2.0.3 + ** Using getopt_long now, this make option parsing more robust + + * Changes in kimwitu++ 2.0.2 + ** Added terminator statement to attributeOf + ** Fixed some namespace-related bugs + + * Changes in kimwitu++ 2.0.0 + ** Brought Kimwitu++ in sync with Kimwitu 4.6 + ** Added option --overwrite to always overwrite generated files, even if they + did not change + ** Renamed the fprintdotheader and fprintdotfooter functions into ...prologue + and ...epilogue, because these names better reflect their use + + * Changes in kimwitu++ 1.3.12 + ** Note: This really is not a step from 1.3.5, but rather one from 2.0; I just + missed the chance to change to 1.9999 earlier + ** Added option --yystype (generates YYSTYPE in yystype.h) + ** Changed CSGIO functions (read takes reference, both throw exceptions) + ** Keywords `%member' and `%attr'; + the latter generates attributes which are handled by CSGIO + ** Keywords `%ctor' and `%dtor' (not really, they appeared in some + earlier version, but I forget which) + ** All in namespace kc + ** Keyword `%option' to specify fixed options in file instead of + on command line + + * Changes in kimwitu++ 1.3.5 + ** Added options --smart-pointer and --weak-pointer + ** Made rviews and uviews work the same way once more + + * Changes in kimwitu++ 1.3.4 + ** Changed a whole lot of type names for printer functions + ** Added real old-style printer function support + + * Changes in kimwitu++ 1.3.3 + ** Fixed old nullary operators bug + + * Changes in kimwitu++ 1.3.2 + ** Added keyword `provided' + ** made option `--verbose' work + + * Changes in kimwitu++ 1.2.3 + ** Prettied up print method + + * Changes in kimwitu++ 1.2.1 + ** Change kc_uviews::view to be a pointer type. + + * Changes in kimwitu++ 1.2 + ** Rename KC_UView and uview to uview_class and uview_enum; + introduce uview as uview_class &. + ** Change option names to use dashes instead of underscores. + ** Remove support for non-sharing CSGIO + (This was a feature to make kimwitu 4 compatible with earlier versions) + ** Add is_nil method to lists. + + * Changes in kimwitu++ 1.1.1 + ** Rename kc_view_count to kc_last_uview; add kc_last_rview. + ** Fix old kimwitu double-rewrite bug. + + * Changes in kimwitu++ 1.1 + ** Rename kc_view_names to kc_uviews + To access view objects, you can use the kc_uviews array. + ** The subphyla union has been removed; + the subphyla are now called _. + ** The KC_SUBPHYLUM data structurs have been removed; + access to subphyla is now possible via the subphylum method. + ** Lists now produce a single class only; + the Nillist is represented with two null subphyla. + ** Syntax for C++ operators and overloading is now recognized. + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/COPYING diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/COPYING:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/COPYING Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,340 ---- + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + convey the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Also add information on how to contact you by electronic and paper mail. + + If the program is interactive, make it output a short notice like this + when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + + The hypothetical commands `show w' and `show c' should show the appropriate + parts of the General Public License. Of course, the commands you use may + be called something other than `show w' and `show c'; they could even be + mouse-clicks or menu items--whatever suits your program. + + You should also get your employer (if you work as a programmer) or your + school, if any, to sign a "copyright disclaimer" for the program, if + necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your program into + proprietary programs. If your program is a subroutine library, you may + consider it more useful to permit linking proprietary applications with the + library. If this is what you want to do, use the GNU Library General + Public License instead of this License. Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/Makefile diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/Makefile:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/Makefile Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,7 ---- + LEVEL = ../../../../.. + PROG = kc + CPPFLAGS=-I$(BUILD_SRC_DIR) -DYYDEBUG=1 + LDFLAGS = -lstdc++ + LIBS += -lstdc++ + RUN_OPTIONS = -o -v $(BUILD_SRC_DIR)/inputs/rpn.k $(BUILD_SRC_DIR)/inputs/main.k $(BUILD_SRC_DIR)/inputs/abs.k + include ../../Makefile.multisrc Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/README diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/README:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/README Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,105 ---- + =-------------- + = + = The Term Processor Kimwitu++ + = + =-------------- + + + Kimwitu++ is a system that supports the construction of programs that use + trees or terms as their main data structure. + For the Kimwitu++ web site (including newest version) have a look at + its homepage on http://site.informatik.hu-berlin.de/kimwitu++. + Kimwitu++ is derived from Kimwitu 4.4, see http://purl.oclc.org/net/kimwitu. + + + + How is this distribution structured? + + Sources: + src/* + src/Gen.boot/* + + The Term Processor was made using itself. + The src directory contains the `real' *.k (Kimwitu++ input) sources. + The src/Gen.boot directory contains the *.{h,cc} kc++-generated files + that you need to bootstrap it. + A src/Gen.* directory, where * is your target architecture, will be + created while kc++ is being made. It will contain (links to) the + kc-generated files used for boot-strapping, the compiled .o files + and the linked binary executable kc++. + + Manual: + man/man/kc++.1 + + Tells you all you need to know to invoke kc++ (Kimwitu++). + + Documentation: + doc/* + + The documentation is not yet avaiable. You can use the documentation + for Kimwitu instead, using a short kc->kc++ transition guide. + + + How do I install Kimwitu? + + Please refer to INSTALL. + + + Which architectures are supported? + + Kimwitu++ just reads and writes text files, in principle it should run + on any architecture you can think of. + Development is done mainly on Solaris and GNU/Linux, these will be supported + best. Probably also Windows NT. + + + Do I need a running Kimwitu++ to install Kimwitu++? + + No, you don't. src directory contains everything needed to bootstrap + Kimwitu++. + + + Why do you bother me with all this non-sense about bootstrapping and all? + + If you ever need to apply a patch, you will need to know how to change + Kimwitu++, and you will need the `real' *.k sources of Kimwitu++, not the + generated *.{h,cc} stuff in src. + + + How do I make changes in Kimwitu++? + + You don't want to. You ask us to change Kimwitu++ if you find anything that + needs to be changed. + + But, if you need to change anything in the sources of Kimwitu++, you should + make your change in the src directory, *not* in the Gen.* directory, because + the contents of that directory will be overwritten during the making of the + new Kimwitu++. + Note that in this case you will *need* a running Kimwitu++ to build the new + one. After making your changes, execute `make' or `make s1' in the src + directory. If everything is ok, you will find a new binary src/Gen.*/kc++_s1. + + + Who should I contact if I find anything that needs to be changed? + (Or have other questions related to Kimwitu++.) + + For original Kimwitu it is: + Axel Belinfante tel. +31/53 4893774 + You can contact me for any question related to Kimwitu. + + For Kimwitu++, please contact: + Martin von L?wis or + Michael Piefel , + both from Humboldt-University, Berlin + + + What is the licence? + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the Licence, or + (at your option) any later version. + Please refer to the file GPL containing the GNU General Public License in + version 2. The terms of the licence allow the development of commercial + software with Kimwitu++. + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.cc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.cc:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.cc Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,54 ---- + /* translation of file "abs.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #define KC_FUNCTIONS_abs_ + + #include + #include "k.h" + #include "abs.h" + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + static char abs_kAccesSid[] = "@(#)$Id: abs.cc,v 1.1 2004/04/06 20:25:07 criswell Exp $"; + + /* end included stuff */ + + + namespace kc { + + #ifndef KC_TRACE_PROVIDED + #define KC_TRACE_PROVIDED(COND,FILE,LINE,NODE) COND + #endif + + impl_fileline_FileLine::impl_fileline_FileLine(casestring _file, int _line) + { + file = (_file!=0) ? _file : mkcasestring(""); + line=_line; + + } + + + } // namespace kc Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.h:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/abs.h Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,42 ---- + /* translation of file "abs.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #ifndef KC_FUNCTIONS_abs_HEADER + #define KC_FUNCTIONS_abs_HEADER + #include "k.h" /* in case a user forgets */ + + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + /* end included stuff */ + + + namespace kc { + + } // namespace kc + + #endif // ! KC_FUNCTIONS_abs_HEADER + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/config.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/config.h:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/config.h Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,69 ---- + /* src/config.h. Generated by configure. */ + /* src/config.h.in. Generated from configure.ac by autoheader. */ + + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ + #define HAVE_DOPRNT 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_EXT_HASH_SET 1 + + /* Define to 1 if you have the header file. */ + /* #undef HAVE_HASH_SET */ + + /* Define to 1 if you have the header file. */ + #define HAVE_INTTYPES_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_MEMORY_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_STDINT_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_STDLIB_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_STRINGS_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_STRING_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_SYS_STAT_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_SYS_TYPES_H 1 + + /* Define to 1 if you have the header file. */ + #define HAVE_UNISTD_H 1 + + /* Define to 1 if you have the `vprintf' function. */ + #define HAVE_VPRINTF 1 + + /* Define if your Python's _tkinter is builtin */ + /* #undef NEED_TKINTER */ + + /* Define to the address where bug reports for this package should be sent. */ + #define PACKAGE_BUGREPORT "piefel at informatik.hu-berlin.de" + + /* Define to the full name of this package. */ + #define PACKAGE_NAME "Kimwitu++" + + /* Define to the full name and version of this package. */ + #define PACKAGE_STRING "Kimwitu++ 2.3.8" + + /* Define to the one symbol short name of this package. */ + #define PACKAGE_TARNAME "kimwitu++" + + /* Define to the version of this package. */ + #define PACKAGE_VERSION "2.3.8" + + /* Define as the return type of signal handlers (`int' or `void'). */ + #define RETSIGTYPE void + + /* Define to 1 if you have the ANSI C header files. */ + #define STDC_HEADERS 1 + + /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ + #define YYTEXT_POINTER 1 Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.h:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.h Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,11 ---- + /* this file is automatically generated by 'make'; do not edit! */ + #ifndef DEFS_H + # define RCSMAKEID "@(#)$Id: defs.h,v 1.1 2004/04/06 20:25:07 criswell Exp $" + # define KIMWITUCOPYRIGHT "@(#)$Author: criswell $" + # define KC_USE_STAT + # define KIMWITURELEASE "@(#)RELEASE VERSION 2.3.8" + # define KIMWITUVERSIONSTRING "2.3.8" + # define METAKIMWITUVERSIONMAJOR 2 + # define METAKIMWITUVERSIONMINOR 3 + # define METAKIMWITUVERSIONMICRO 8 + #endif /* DEFS_H */ Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.hh diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.hh:1.1 *** /dev/null Tue Apr 6 15:25:25 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/defs.hh Tue Apr 6 15:25:07 2004 *************** *** 0 **** --- 1,11 ---- + /* this file is automatically generated by 'make'; do not edit! */ + #ifndef DEFS_H + # define RCSMAKEID "@(#)$Id: defs.hh,v 1.1 2004/04/06 20:25:07 criswell Exp $" + # define KIMWITUCOPYRIGHT "@(#)$Author: criswell $" + # define KC_USE_STAT + # define KIMWITURELEASE "@(#)RELEASE VERSION 2.3.8" + # define KIMWITUVERSIONSTRING "2.3.8" + # define METAKIMWITUVERSIONMAJOR 2 + # define METAKIMWITUVERSIONMINOR 3 + # define METAKIMWITUVERSIONMICRO 8 + #endif /* DEFS_H */ Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/error.cc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/error.cc:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/error.cc Tue Apr 6 15:25:10 2004 *************** *** 0 **** --- 1,427 ---- + /* translation of file "error.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #define KC_FUNCTIONS_error_ + + #include + #include "k.h" + #include "error.h" + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + static char error_kAccesSid[] = "@(#)$Id: error.cc,v 1.1 2004/04/06 20:25:10 criswell Exp $"; + + bool gp_no_fatal_problems; + + #define QUOTEDBACKSLASH '\\' + + #ifndef KC_MAX_STRING_LEN + # define KC_MAX_STRING_LEN 200 + #endif /* !KC_MAX_STRING_LEN */ + + viewnameoption ug_viewnameopt; + + int kc_filePrinter::indent_level = 4; + kc_filePrinter::kc_filePrinter(FILE* f):file(f) + { + lineno=0; + no_of_printed_string_chars=0; + doit=false; + lastChar='\n'; + indent=0; + bs_cnt=0; + inString=false; + inChar=false; + inComment=false; + inCppComment=false; + spacePending=false; + beginOfLine = false; + keyword=0; + indentKeyword=false; + inPreProStmt=false; + } + + kc_filePrinter v_stdout_printer(stdout); + kc_filePrinter v_hfile_printer; + kc_filePrinter v_ccfile_printer; + printer_functor_class v_null_printer; + + bool kc_filePrinter::check_keyword(const char* s) + { + bool res=false; + if(inPreProStmt) { // just to ignore #if and #else + if(!isspace(*s)) + inPreProStmt=false; + } + else if(!keyword) { + if(*s=='#') + inPreProStmt=true; + else if(*s=='i' || *s=='e' || *s=='d' || *s=='w') // 'if', 'else', 'do', 'while' + keyword=s; // 'for' not supported yet + } + else if(!isalnum(*s) && *s!='_') { // end of identifier + ptrdiff_t length=s-keyword; + if( + (length==2 && strncmp(keyword,"if",length)==0) || + (length==4 && strncmp(keyword,"else",length)==0) || + (length==2 && strncmp(keyword,"do",length)==0) || + (length==5 && strncmp(keyword,"while",length)==0)) + res=true; // keyword found + keyword=0; + } + return res; + } + + void kc_filePrinter::operator()(const char *s, uview v) + { + char c; + + assertCond(file != 0); + + switch(v) { + case view_no_of_printed_string_chars_reset_enum: + no_of_printed_string_chars = 0; + break; + case view_printer_outputfileline_enum: + fprintf( file, "\n" ); lineno = lineno +1; + if(g_options.linedirec) + fprintf( file, "%s %d \"%s%s\"\n", pg_line, lineno+1, g_options.dir_line.c_str(),filename.c_str() ); + lineno = lineno +1; + lastChar='\n'; + break; + default: + while((c=*s++)) { + switch( c ) { + case '\0': return; + case '\n': + /* if (*s == QUOTEDBACKSLASH) s++; */ + lineno = lineno +1; + beginOfLine = true; + /* FALLTHROUGH */ + default: + if (v == view_gen_unpstr_c) { + if (no_of_printed_string_chars >= KC_MAX_STRING_LEN) { + if (doit) { + fprintf( file, "\"), " ); + ug_viewnameopt->unparse( *this, view_gen_unparsedefs_other_c ); + fprintf( file, " );\n kc_printer(kc_t(\"" ); + lineno = lineno +1; + no_of_printed_string_chars = 0; + doit = false; + } else { + switch( c ) { + case '\\': + case '\n': + break; + default: + doit = true; + } + } + } + no_of_printed_string_chars = no_of_printed_string_chars +1; + } else if (v == view_filename) { + /* duplicate (= escape) backslashes in file names. + * we do this to help those that work on windows etc. + */ + if (c == QUOTEDBACKSLASH) { /* we have to quote it! */ + putc( c, file ); + } + } + if(inString) { + if(c=='"' && bs_cnt%2==0) + inString=false; + putc( c, file ); + lastChar=c; + } + else if(inChar) { + if(c=='\'' && bs_cnt%2==0) + inChar=false; + putc( c, file ); + lastChar=c; + } + else if(inComment) { + if(c=='/' && lastChar=='*') + inComment=false; /* C comments */ + switch(c) { + case '\v': case '\r': case '\b': break; + default: + putc( c, file ); + lastChar=c; + } + } + else if(inCppComment) { + if(c=='\n') + inCppComment=false; /* C++ comments */ + switch(c) { + case '\v': case '\r': case '\b': break; + default: + putc( c, file ); + lastChar=c; + } + } + else { + int indent_offset=0; + if(!indentKeyword) { + indentKeyword=check_keyword(s-1); + if(indentKeyword) + ++indent; + } + switch(c) { + case ';': + if(indentKeyword) { + --indent; + indentKeyword=false; + } + goto default_case; + case '{': + if(indentKeyword) { + --indent; + indentKeyword=false; + } + // no break + case '(': + indent_offset=1; + goto default_case; + case '\v': + ++indent; + break; + case '}': + case ')': + if(indent) --indent; + goto default_case; + case '\r': + if(indent) --indent; + break; + case '\b': + lastChar=c; + break; + case ' ': + case '\t': + if(lastChar=='\b' || !beginOfLine) + goto default_case; + if(isspace(lastChar)) + break; + if(isalnum(lastChar) || lastChar=='_' || lastChar=='"' || lastChar=='\'' || lastChar==')' || lastChar=='}') { + if(isalnum(*(s+1))|| *(s+1)=='_'|| *(s+1)=='"' || *(s+1)=='\'') { + c=' '; + goto default_case; + } + spacePending=true; + } + break; + default: + default_case: + if(lastChar=='\n' && c!='\n' && c!='#') { + for(int i=indent*indent_level;i>0;) + if(i>=8) { + putc('\t',file); + i-=8; + } else { + for(int k=0;kunparse( v_stderr_printer, v ); + } + else + e->unparse( v_stderr_printer, view_error ); + + } + + static void v_stderr_printer(const char *s, uview v) + { + fflush( stdout ); + fprintf( stderr, "%s", s ); + fflush( stderr ); + + } + + + } // namespace kc Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/error.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/error.h:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/error.h Tue Apr 6 15:25:10 2004 *************** *** 0 **** --- 1,163 ---- + /* translation of file "error.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #ifndef KC_FUNCTIONS_error_HEADER + #define KC_FUNCTIONS_error_HEADER + #include "k.h" /* in case a user forgets */ + + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + #include "unpk.h" /* for the definition of uview and printer_functor_class */ + extern bool gp_no_fatal_problems; + #include + #include + using std::string; + + // Cater for broken compilers (eg. MacOS gcc) + #ifndef isalpha + using std::isalpha; + using std::isalnum; + #endif + + + #include + + namespace kc { + + class view_error_format_class : public view_error_format_baseclass { + public: + view_error_format_class(const std::string& fmt): msg(fmt) { } + + void program(const char* p) { replace("%p",p); } + void file(const char* f) { replace("%f",f); } + void line(INTEGER l) { + char buf[30]; + sprintf(buf,"%d",l); + replace("%l",buf); + } + void column(INTEGER c) { + char buf[30]; + sprintf(buf,"%d",c); + replace("%c",buf); + } + void severity(const char* s) { replace("%s",s); } + + const char* get_msg() { + // discard unused patterns + program(""); + file(""); + replace("%l",""); + replace("%c",""); + char* buf; + replace("%d",buf=getcwd(NULL,0)); // current directory + free(buf); + severity(""); + return msg.c_str(); + } + + void replace(const char* s1, const char* s2) { + std::string::size_type pos; + while((pos=msg.find(s1)) != std::string::npos) { + msg.replace(pos,strlen(s1),s2); + } + } + private: + std::string msg; + }; + + } + + + class kc_filePrinter : public printer_functor_class { + public: + kc_filePrinter(FILE *f=0); + virtual void operator()(const char* s, uview v); + int fclose() + { + int temp=0; + if (file) + temp=::fclose(file); + file=0; + return temp; + } + void init(const char *name, const char *mode, const string &type); + bool check_keyword(const char*); + FILE *destination() { return file; } + private: + FILE *file; + int lineno; + string filename; + int no_of_printed_string_chars; /* to split long double-quoted strings */ + bool doit; + char lastChar; + int indent; + int bs_cnt; + bool inString; + bool inChar; + bool inComment; + bool inCppComment; + bool spacePending; + bool beginOfLine; + const char* keyword; + bool indentKeyword; + bool inPreProStmt; + static int indent_level; + }; + + extern kc_filePrinter v_stdout_printer; + extern kc_filePrinter v_hfile_printer; + extern kc_filePrinter v_ccfile_printer; + extern printer_functor_class v_null_printer; + + + /* end included stuff */ + + + namespace kc { + problem Problem1S (const char *s1); + problem Problem1S1we (const char *s1, withexpression we); + problem Problem1S1ID (const char *s1, ID id); + problem Problem1S1tID (const char *s1, ID id); + problem Problem1S1ID1S1ID (const char *s1, ID id1, const char *s2, ID id2); + problem Problem1S1t1S1ID (const char *s1, IDtype id1, const char *s2, ID id2); + problem Problem1S1INT (const char *s1, INT i1); + problem Problem1S1int1S (const char *s1, int i1, const char *s2); + problem Problem1S1INT1S1ID (const char *s1, INT i1, const char *s2, ID id2); + problem Problem1S1ID1S1ID1S1ID (const char *s1, ID id1, const char *s2, ID id2, const char *s3, ID id3); + problem Problem1S1INT1S1ID1S1ID (const char *s1, INT i1, const char *s2, ID id2, const char *s3, ID id3); + problem Problem1S1storageoption1S1ID (const char *s1, storageoption so, const char *s2, ID id); + problem Problem2S (const char *s1, const char *s2); + problem ProblemSC (const char *s1, casestring s2); + problem Problem3S (const char *s1, const char *s2, const char *s3); + problem Problem4S (const char *s1, const char *s2, const char *s3, const char *s4); + problem Problem3S1int1S (const char *s1, const char *s2, const char *s3, int i1, const char *s4); + void v_report (error e); + + } // namespace kc + + #endif // ! KC_FUNCTIONS_error_HEADER + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.cc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.cc:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.cc Tue Apr 6 15:25:11 2004 *************** *** 0 **** --- 1,189 ---- + /* translation of file "gen.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #define KC_FUNCTIONS_gen_ + + #include + #include "k.h" + #include "gen.h" + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + static char gen_kAccesSid[] = "@(#)$Id: gen.cc,v 1.1 2004/04/06 20:25:11 criswell Exp $"; + + /* end included stuff */ + + + namespace kc { + + #ifndef KC_TRACE_PROVIDED + #define KC_TRACE_PROVIDED(COND,FILE,LINE,NODE) COND + #endif + + enum_operators f_selofoperator(ID oid) + { + int kc_i, kc_end = one_before_first_operator; + kc_i=kc_end; + { + phylumdeclarations kc_fe_selvar_1 = Thephylumdeclarations ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consphylumdeclarations + ) { + phylumdeclaration kc_selvar_0_1 = kc_fe_selvar_1->phylumdeclaration_1; + { + { + { + const phylumdeclaration p = kc_selvar_0_1; + { + phylumdeclaration kc_selvar_1_1 = phylum_cast(p); + if ((kc_selvar_1_1->prod_sel() == sel_PhylumDeclaration) && (phylum_cast(kc_selvar_1_1)->productionblock_1->prod_sel() == sel_ListAlternatives)) { + const alternatives alts = phylum_cast(phylum_cast(kc_selvar_1_1)->productionblock_1)->alternatives_1; + + { + alternatives kc_fe_selvar_1 = alts ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consalternatives + ) { + alternative kc_selvar_2_1 = kc_fe_selvar_1->alternative_1; + { + { + if ((kc_selvar_2_1->prod_sel() == sel_Alternative)) { + const ID id = phylum_cast(kc_selvar_2_1)->ID_1; + + kc_end++; + if (oid->eq(id)) kc_i=kc_end; + + } else + {/* EMPTY */ /*skip: no matching pattern in foreach patterns*/} + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->alternatives_1; + + } + } + + } else + if ((kc_selvar_1_1->prod_sel() == sel_PhylumDeclaration) && (phylum_cast(kc_selvar_1_1)->productionblock_1->prod_sel() == sel_NonlistAlternatives)) { + const alternatives alts = phylum_cast(phylum_cast(kc_selvar_1_1)->productionblock_1)->alternatives_1; + + { + alternatives kc_fe_selvar_1 = alts ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consalternatives + ) { + alternative kc_selvar_2_1 = kc_fe_selvar_1->alternative_1; + { + { + if ((kc_selvar_2_1->prod_sel() == sel_Alternative)) { + const ID id = phylum_cast(kc_selvar_2_1)->ID_1; + + kc_end++; + if (oid->eq(id)) kc_i=kc_end; + + } else + {/* EMPTY */ /*skip: no matching pattern in foreach patterns*/} + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->alternatives_1; + + } + } + + } else + if ((kc_selvar_1_1->prod_sel() == sel_PhylumDeclaration) && (phylum_cast(kc_selvar_1_1)->productionblock_1->prod_sel() == sel_PredefinedAlternatives)) { + const alternatives alts = phylum_cast(phylum_cast(kc_selvar_1_1)->productionblock_1)->alternatives_1; + + { + alternatives kc_fe_selvar_1 = alts ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consalternatives + ) { + alternative kc_selvar_2_1 = kc_fe_selvar_1->alternative_1; + { + { + if ((kc_selvar_2_1->prod_sel() == sel_Alternative)) { + const ID id = phylum_cast(kc_selvar_2_1)->ID_1; + + kc_end++; + if (oid->eq(id)) kc_i=kc_end; + + } else + {/* EMPTY */ /*skip: no matching pattern in foreach patterns*/} + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->alternatives_1; + + } + } + + } else + { kc_no_default_in_with( "f_selofoperator", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->phylumdeclarations_1; + + } + } + return static_cast(kc_end-kc_i+1); + + } + + void freespineandelements(unparseviewsinfo a_unparseviewsinfo) + { + abstract_phylum kc_p = a_unparseviewsinfo; + while(kc_p) { + if (kc_p->subphylum(0)) kc_p->subphylum(0)->free(false); + kc_p = kc_p->subphylum(1); + }; + a_unparseviewsinfo->freelist(); + + } + + void freespineandelements(rewriteviewsinfo a_rewriteviewsinfo) + { + abstract_phylum kc_p = a_rewriteviewsinfo; + while(kc_p) { + if (kc_p->subphylum(0)) kc_p->subphylum(0)->free(false); + kc_p = kc_p->subphylum(1); + }; + a_rewriteviewsinfo->freelist(); + + } + + + } // namespace kc Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.h:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/gen.h Tue Apr 6 15:25:11 2004 *************** *** 0 **** --- 1,18 ---- + /* translation of file "gen.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #ifndef KC_FUNCTIONS_gen_HEADER + #define KC_FUNCTIONS_gen_HEADER + #include "k.h" /* in case a user forgets */ + + + namespace kc { + enum_operators f_selofoperator (ID oid); + void freespineandelements (unparseviewsinfo a_unparseviewsinfo); + void freespineandelements (rewriteviewsinfo a_rewriteviewsinfo); + + } // namespace kc + + #endif // ! KC_FUNCTIONS_gen_HEADER + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/getopt.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/getopt.h:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/getopt.h Tue Apr 6 15:25:11 2004 *************** *** 0 **** --- 1,182 ---- + /* Declarations for getopt. + Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + /* $Id: getopt.h,v 1.1 2004/04/06 20:25:11 criswell Exp $ + * Modified for kimwitu++ */ + + #ifndef _GETOPT_H + + #ifndef __need_getopt + # define _GETOPT_H 1 + #endif + + /* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include , but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include , which will pull in for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ + #if !defined __GNU_LIBRARY__ + # include + #endif + + #ifdef __cplusplus + extern "C" { + #endif + + /* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + + extern char *optarg; + + /* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + + extern int optind; + + /* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + + extern int opterr; + + /* Set to an option character which was unrecognized. */ + + extern int optopt; + + #ifndef __need_getopt + /* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + + struct option + { + # if (defined __STDC__ && __STDC__) || defined __cplusplus + const char *name; + # else + char *name; + # endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; + }; + + /* Names for the values of the `has_arg' field of `struct option'. */ + + # define no_argument 0 + # define required_argument 1 + # define optional_argument 2 + #endif /* need getopt */ + + + /* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + + #if (defined __STDC__ && __STDC__) || defined __cplusplus + # ifdef __GNU_LIBRARY__ + /* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ + /* extern int getopt (int argc, char *const *argv, const char *__shortopts); */ + # else /* not __GNU_LIBRARY__ */ + /* extern int getopt (); */ + # endif /* __GNU_LIBRARY__ */ + + # ifndef __need_getopt + extern int getopt_long (int argc, char *const *argv, const char *__shortopts, + const struct option *__longopts, int *__longind); + extern int getopt_long_only (int argc, char *const *argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + + /* Internal only. Users should not call this directly. */ + extern int _getopt_internal (int argc, char *const *argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); + # endif + #else /* not __STDC__ */ + extern int getopt (); + # ifndef __need_getopt + extern int getopt_long (); + extern int getopt_long_only (); + + extern int _getopt_internal (); + # endif + #endif /* __STDC__ */ + + #ifdef __cplusplus + } + #endif + + /* Make sure we later can get all the definitions and declarations. */ + #undef __need_getopt + + #endif /* getopt.h */ Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.cc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.cc:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.cc Tue Apr 6 15:25:11 2004 *************** *** 0 **** --- 1,1204 ---- + /* translation of file "gutil.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #define KC_FUNCTIONS_gutil_ + + #include + #include "k.h" + #include "gutil.h" + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + static char gutil_kAccesSid[] = "@(#)$Id: gutil.cc,v 1.1 2004/04/06 20:25:11 criswell Exp $"; + + /* string(s) stuff */ + #include + #include + + phylumdeclaration The_abstract_phylum_decl; + phylumdeclaration The_abstract_phylum_ref_decl; + phylumdeclaration The_abstract_list_decl; + + #include "util.h" + + #include "parse.h" + + #include "unpk.h" + + #define MKSELVARMAXINTREPR 30 + + #include + + static ID global_filterview; /* to be used by filteronview */ + + #include "rk.h" /* for the rewrite_withcasesinfo call below */ + + /* end included stuff */ + + + namespace kc { + + #ifndef KC_TRACE_PROVIDED + #define KC_TRACE_PROVIDED(COND,FILE,LINE,NODE) COND + #endif + + static bool f_attributes_to_initialize (attributes attr); + static bool f_constructors_in_members (fndeclarations dcl); + static bool f_destructors_in_members (fndeclarations dcl); + static bool f_post_create_in_members (fndeclarations dcl); + static bool f_rewrite_in_members (fndeclarations dcl); + static ac_parameter_declaration lookup_and_create_ac_parameter_declaration (ID a_fnarg, ac_declaration_list C_vardecls); + static bool filterrewriteruleinfoonview (rewriteruleinfo a_rewriteruleinfo); + static bool filterunparsedeclinfoonview (unparsedeclinfo a_unparsedeclinfo); + static bool is_viewname_in_rewriteruleinfo (ID a_view, rewriteruleinfo a_rewriteruleinfo); + static bool is_viewname_in_unparsedeclinfo (ID a_view, unparsedeclinfo a_unparsedeclinfo); + static bool is_viewname_in_viewnames (ID a_view, viewnames a_viewnames); + static ID f_operatorofelem_patternrepresentation (elem_patternrepresentation a_elem_patternrepresentation); + static ID f_operatorofpaths (paths a_paths); + static ID f_operatorofpath (path a_path); + static elem_patternrepresentation f_outmost_nl_preds_in_patternrepresentation (patternrepresentation p); + static bool f_outmost_nl_preds_in_elem_patternrepresentation (elem_patternrepresentation e_p); + static bool f_outmost_nl_preds_in_paths (paths p); + bool f_something_to_initialize(Ccode_option cco) + { + { + Ccode_option kc_selvar_0_1 = phylum_cast( cco ); + if ((kc_selvar_0_1->prod_sel() == sel_CcodeOption)) { + const attributes attr = phylum_cast(kc_selvar_0_1)->attributes_1; + const Ctexts ct = phylum_cast(kc_selvar_0_1)->Ctexts_1; + + return (f_attributes_to_initialize( attr ) || (! f_NilCtexts( ct ))); + + } else + { kc_no_default_in_with( "f_something_to_initialize", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + bool f_something_to_initialize(alternative a) + { + return false; + + } + + bool f_NilCtexts(Ctexts c) + { + { + Ctexts kc_selvar_0_1 = phylum_cast( c ); + if ((kc_selvar_0_1->prod_sel() == sel_ConsCtexts)) { + return false; + } else + if ((kc_selvar_0_1->prod_sel() == sel_NilCtexts)) { + return true; + } else + { kc_no_default_in_with( "f_NilCtexts", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static bool f_attributes_to_initialize(attributes attr) + { + { + attributes kc_fe_selvar_1 = attr ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consattributes + ) { + attribute kc_selvar_0_1 = kc_fe_selvar_1->attribute_1; + { + { + { + const attribute a = kc_selvar_0_1; + + { + attribute kc_selvar_1_1 = phylum_cast( a ); + if ((kc_selvar_1_1->prod_sel() == sel_Attribute) && (phylum_cast(kc_selvar_1_1)->attribute_initialisation_option_1->prod_sel() == sel_Yesattribute_initialisation)) { + + return true; + + } else + if ((kc_selvar_1_1->prod_sel() == sel_Attribute) && (phylum_cast(kc_selvar_1_1)->attribute_initialisation_option_1->prod_sel() == sel_Noattribute_initialisation)) { + /*EMPTY*/ + } else + { kc_no_default_in_with( "f_attributes_to_initialize", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->attributes_1; + + } + } + return false; + + } + + static bool f_constructors_in_members(fndeclarations dcl) + {{ + fndeclarations kc_selvar_0_1 = phylum_cast(dcl); + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations) && ((kc_selvar_0_1)->fndeclaration_1->prod_sel() == sel_FnAcDeclaration) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->fnclass_1->prod_sel() == sel_ConstructorFn)) { + return true; + } else + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations)) { + const fndeclarations tail = (kc_selvar_0_1)->fndeclarations_1; + return f_constructors_in_members(tail); + } else + { + return false; + } + } + + } + + bool f_constructors_in_operatordecl(alternative op) + { + return f_constructors_in_members(op->additional_members); + + } + + bool f_constructors_in_phylumdecl(phylumdeclaration ph) + { + return f_constructors_in_members(ph->additional_members); + + } + + static bool f_destructors_in_members(fndeclarations dcl) + {{ + fndeclarations kc_selvar_0_1 = phylum_cast(dcl); + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations) && ((kc_selvar_0_1)->fndeclaration_1->prod_sel() == sel_FnAcDeclaration) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->fnclass_1->prod_sel() == sel_DestructorFn)) { + return true; + } else + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations)) { + const fndeclarations tail = (kc_selvar_0_1)->fndeclarations_1; + return f_destructors_in_members(tail); + } else + { + return false; + } + } + + } + + bool f_destructors_in_operatordecl(alternative op) + { + return f_destructors_in_members(op->additional_members); + + } + + bool f_destructors_in_phylumdecl(phylumdeclaration ph) + { + return f_destructors_in_members(ph->additional_members); + + } + + bool f_no_params(ac_parameter_type_list p) + {{ + ac_parameter_type_list kc_selvar_0_1 = phylum_cast(p); + if ((kc_selvar_0_1->prod_sel() == sel_AcParList) && (phylum_cast(kc_selvar_0_1)->ac_parameter_list_1->prod_sel() == sel_Nilac_parameter_list)) { + return true; + } else + { + return false; + } + } + + } + + static bool f_post_create_in_members(fndeclarations dcl) + {{ + fndeclarations kc_selvar_0_1 = phylum_cast(dcl); + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations) && ((kc_selvar_0_1)->fndeclaration_1->prod_sel() == sel_FnAcDeclaration) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1->prod_sel() == sel_AcDeclarator) && (phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1->prod_sel() == sel_AcQualifiedDeclProto) && (phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1->prod_sel() == sel_AcDirectDeclId) && (phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1)->ID_1->prod_sel() == sel_Id) && (phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1)->ID_1)->uniqID_1->prod_sel() == sel_Str) && (kc_strcmp(phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_dir! ect_declarator_1)->ac_direct_declarator_1)->ID_1)->uniqID_1)->casestri ng_1->name, kc_t("post_create"))==0) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->fnclass_1->prod_sel() == sel_MemberFn)) { + return true; + } else + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations)) { + const fndeclarations tail = (kc_selvar_0_1)->fndeclarations_1; + return f_post_create_in_members(tail); + } else + { + return false; + } + } + + } + + bool f_post_create_in_operatordecl(alternative op) + { + return f_post_create_in_members(op->additional_members); + + } + + bool f_post_create_in_phylumdecl(phylumdeclaration ph) + { + return f_post_create_in_members(ph->additional_members); + + } + + static bool f_rewrite_in_members(fndeclarations dcl) + {{ + fndeclarations kc_selvar_0_1 = phylum_cast(dcl); + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations) && ((kc_selvar_0_1)->fndeclaration_1->prod_sel() == sel_FnAcDeclaration) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1->prod_sel() == sel_AcDeclarator) && (phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1->prod_sel() == sel_AcQualifiedDeclProto) && (phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1->prod_sel() == sel_AcDirectDeclId) && (phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1)->ID_1->prod_sel() == sel_Id) && (phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_direct_declarator_1)->ac_direct_declarator_1)->ID_1)->uniqID_1->prod_sel() == sel_Str) && (kc_strcmp(phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast(phylum_cast((kc_selvar_0_1)->fndeclaration_1)->ac_declarator_1)->ac_dir! ect_declarator_1)->ac_direct_declarator_1)->ID_1)->uniqID_1)->casestri ng_1->name, kc_t("rewrite"))==0) && (phylum_cast((kc_selvar_0_1)->fndeclaration_1)->fnclass_1->prod_sel() == sel_MemberFn)) { + return true; + } else + if ((kc_selvar_0_1->prod_sel() == sel_Consfndeclarations)) { + const fndeclarations tail = (kc_selvar_0_1)->fndeclarations_1; + return f_rewrite_in_members(tail); + } else + { + return false; + } + } + + } + + bool f_rewrite_in_phylumdecl(phylumdeclaration ph) + { + return f_rewrite_in_members(ph->additional_members); + + } + + bool f_rewrite_in_operatordecl(alternative op) + {{ + alternative kc_selvar_0_1 = phylum_cast(op); + if ((kc_selvar_0_1->prod_sel() == sel_Alternative)) { + const ID oid = phylum_cast(kc_selvar_0_1)->ID_1; + + if(f_rewrite_in_members(op->additional_members)) + return true; + return f_rewrite_in_phylumdecl(f_phylumdeclofid(f_phylumofoperator(oid))); + + } else + { + return false; + } + } + + } + + ID f_phylumofwithcasesinfo(withcasesinfo wcso) + { + ID id; + { + withcasesinfo kc_selvar_0_1 = phylum_cast( wcso ); + if ((kc_selvar_0_1->prod_sel() == sel_Conswithcasesinfo)) { + const withcaseinfo wco = (kc_selvar_0_1)->withcaseinfo_1; + const withcasesinfo r_wcso = (kc_selvar_0_1)->withcasesinfo_1; + + { + withcaseinfo kc_selvar_1_1 = phylum_cast( wco ); + if ((kc_selvar_1_1->prod_sel() == sel_Withcaseinfo)) { + const patternrepresentation patrep = phylum_cast(kc_selvar_1_1)->patternrepresentation_1; + + if ( (id = f_phylumofpatternrepresentation( patrep ))->eq( f_emptyId() )) { + return f_phylumofwithcasesinfo( r_wcso ); + } else { + return id; + } + } else + { kc_no_default_in_with( "f_phylumofwithcasesinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilwithcasesinfo)) { + + v_report(NonFatal( NoFileLine(), Problem1S( "Error: can not find type of with expression" ))); + return Id( Str( mkcasestring( "KC_ERRORunknownTYPE" ))); + + } else + { kc_no_default_in_with( "f_phylumofwithcasesinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + ID f_phylumofpatternrepresentation(patternrepresentation a_patrep) + { + { + patternrepresentation kc_selvar_0_1 = phylum_cast( a_patrep ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspatternrepresentation)) { + const elem_patternrepresentation a_patrep_elem = (kc_selvar_0_1)->elem_patternrepresentation_1; + const patternrepresentation r_patrep = (kc_selvar_0_1)->patternrepresentation_1; + + { + elem_patternrepresentation kc_selvar_1_1 = phylum_cast( a_patrep_elem ); + if ((kc_selvar_1_1->prod_sel() == sel_PROperPredicate)) { + const ID id = phylum_cast(kc_selvar_1_1)->ID_1; + + return f_phylumofoperator( id ); + + } else + { + + return f_phylumofpatternrepresentation( r_patrep ); + + } + } + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpatternrepresentation)) { + + return f_emptyId(); + + } else + { kc_no_default_in_with( "f_phylumofpatternrepresentation", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + ac_parameter_type_list sort_extend_parameter_type_list(ac_declaration_list C_vardecls, ac_declarator decl) + {{ + ac_declarator kc_selvar_0_1 = phylum_cast(decl); + if ((kc_selvar_0_1->prod_sel() == sel_AcDeclarator)) { + const ac_direct_declarator add = phylum_cast(kc_selvar_0_1)->ac_direct_declarator_1; + + { + ac_direct_declarator kc_selvar_1_1 = phylum_cast( add ); + if ((kc_selvar_1_1->prod_sel() == sel_AcQualifiedDeclProto)) { + const ac_parameter_type_list fn_proto = phylum_cast(kc_selvar_1_1)->ac_parameter_type_list_1; + return fn_proto; + } else + if ((kc_selvar_1_1->prod_sel() == sel_AcDirectDeclProto)) { + const ac_parameter_type_list fn_proto = phylum_cast(kc_selvar_1_1)->ac_parameter_type_list_1; + return fn_proto; + } else + if ((kc_selvar_1_1->prod_sel() == sel_AcDirectDeclArray)) { + return AcParList( Nilac_parameter_list() ); + } else + if ((kc_selvar_1_1->prod_sel() == sel_AcDirectDeclPack)) { + return AcParList( Nilac_parameter_list() ); + } else + if ((kc_selvar_1_1->prod_sel() == sel_AcDirectDeclId)) { + return AcParList( Nilac_parameter_list() ); + } else + { kc_no_default_in_with( "sort_extend_parameter_type_list", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } else + { kc_no_default_in_with( "sort_extend_parameter_type_list", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + ac_parameter_list t_sort_extend_parameter_list(ac_declaration_list C_vardecls, ac_identifier_list fn_args, ac_parameter_list temp) + { + { + ac_identifier_list kc_selvar_0_1 = phylum_cast( fn_args ); + if ((kc_selvar_0_1->prod_sel() == sel_Consac_identifier_list)) { + const ID a_fnarg = (kc_selvar_0_1)->ID_1; + const ac_identifier_list r_fnargs = (kc_selvar_0_1)->ac_identifier_list_1; + + temp = t_sort_extend_parameter_list( C_vardecls, r_fnargs, temp ); + return Consac_parameter_list( lookup_and_create_ac_parameter_declaration( a_fnarg, C_vardecls ), temp ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilac_identifier_list)) { + return temp; + } else + { kc_no_default_in_with( "t_sort_extend_parameter_list", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static ac_parameter_declaration lookup_and_create_ac_parameter_declaration(ID a_fnarg, ac_declaration_list C_vardecls) + { + ac_parameter_declaration result = 0; + int number_of_results = 0; + { + ac_declaration_list kc_fe_selvar_1 = C_vardecls ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consac_declaration_list + ) { + ac_declaration kc_selvar_0_1 = kc_fe_selvar_1->ac_declaration_1; + { + { + if ((kc_selvar_0_1->prod_sel() == sel_AcDeclaration)) { + const ac_declaration_specifiers type = phylum_cast(kc_selvar_0_1)->ac_declaration_specifiers_1; + const ac_init_declarator_list cvars = phylum_cast(kc_selvar_0_1)->ac_init_declarator_list_1; + + { + ac_init_declarator_list kc_fe_selvar_1 = cvars ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consac_init_declarator_list + ) { + ac_init_declarator kc_selvar_1_1 = kc_fe_selvar_1->ac_init_declarator_1; + { + { + if ((kc_selvar_1_1->prod_sel() == sel_AcInitDecl)) { + const ac_declarator decl = phylum_cast(kc_selvar_1_1)->ac_declarator_1; + + ID name = f_ID_of_declarator( decl ); + if (name->eq( a_fnarg ) ) { + result = AcParDeclDecl( type, decl, Noac_constant_expression()); + number_of_results++; + } + } else + {/* EMPTY */ /*skip: no matching pattern in foreach patterns*/} + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->ac_init_declarator_list_1; + + } + } + + } else + {/* EMPTY */ /*skip: no matching pattern in foreach patterns*/} + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->ac_declaration_list_1; + + } + } + if (number_of_results == 1) { + return result; + } else { + + if (number_of_results > 1) { + v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "more than one type defined for function argument:", a_fnarg ))); + } else { + v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "can not find type of function argument:", a_fnarg ))); + } + + return AcParDeclDecl( + Consac_declaration_specifiers( + AcDeclSpecTypeSpec( + AcTypeSpec( Id( Str( mkcasestring( "KC_ERRORunknownTYPE" ))))), + Nilac_declaration_specifiers()), + AcDeclarator( + Nopointer(), + AcNoRef(), + AcDirectDeclId( a_fnarg )), + Noac_constant_expression()); + } + + } + + void unparse(const char *s, printer_functor printer_fn, uview v) + { + printer_fn( s, v ); + + } + + charruns impl_charruns::set(int _n) + { number=_n; return this; + } + + ID f_mkselvar(const char *prefix, int level) + { + + + + char fixbuf[BUFSIZ] ; + char *dynbuf = 0; + char *buf = 0; + ID id; + if (strlen(prefix) + MKSELVARMAXINTREPR + 1 > BUFSIZ) { + dynbuf = new char[strlen(prefix) + MKSELVARMAXINTREPR + 1]; + buf = dynbuf; + } else { + buf = fixbuf; + } + strcpy( buf, prefix ); + sprintf( &buf[strlen(prefix)], "%d", level ); + id = Id( Str( mkcasestring( buf ))); + if (dynbuf != 0) { + delete[] dynbuf; + } + return id; + + } + + ID f_mkselvar2(const char *prefix, int level, int branch) + { + + + + + char fixbuf[BUFSIZ] ; + char *dynbuf = 0; + char *buf = 0; + ID id; + int constant_factor = MKSELVARMAXINTREPR + 1 + MKSELVARMAXINTREPR + 1; + if (strlen(prefix) + constant_factor > BUFSIZ) { + dynbuf = new char[strlen(prefix) + constant_factor]; + buf = dynbuf; + } else { + buf = fixbuf; + } + strcpy( buf, prefix ); + sprintf( &buf[strlen(prefix)], "%d_%d", level, branch ); + id = Id( Str( mkcasestring( buf ))); + if (dynbuf != 0) { + delete[] dynbuf; + } + return id; + + } + + char *f_mk_filename(casestring a_casestring, const char *suffix) + { + char const *basename; + + if ((basename = strrchr( a_casestring->name, '/' )) == 0) + basename = a_casestring->name; + if (*basename == '/') + basename++; + else if (*basename == '"') + basename++; + size_t baselen = strlen(basename); + + char *filename = new char[baselen+strlen(suffix)+1]; + strcpy( filename, basename ); + if (baselen > 0 && filename[baselen-1] == '"' ) { + filename[baselen-1] = '\0'; + baselen--; + } + if ( baselen > 1 && (filename[baselen-1] == 'k' && filename[baselen-2] == '.' )) + baselen-=2; + if (strlen(suffix)==0) { + filename[baselen]='\0'; + return filename; + } + filename[baselen] = '.'; + + char *eofn=filename+baselen+1; + while ((*eofn++=*suffix++)) ; + return filename; + + } + + char *f_mk_filename(casestring a_casestring, const string &suffix) + { + return f_mk_filename(a_casestring, suffix.c_str()); + + } + + char *f_make_identifier_basename(const char *fn) + { + char *nn; + + size_t len = strlen(fn); + assertCond(len >2); + nn = new char[len-2+1]; + strncpy(nn, fn, len-2); + nn[len-2] = '\0'; + for (unsigned i=0; i < len-2; i++) { + if (! isalnum(nn[i])) { + nn[i] = '_'; + } } + return nn; + + } + + rewriterulesinfo f_rewriterulesinfoofalternativeinview(alternative a_alternative, ID a_view) + { + global_filterview = a_view; + return a_alternative->rewriteinfo->filter( filterrewriteruleinfoonview ); + + } + + rewriteviewsinfo f_rewriteviewsinfo_of_alternative(alternative a_alternative, viewnames a_views) + { + rewriterulesinfo tmp_rulesinfo = a_alternative->rewriteinfo; + rewriteviewsinfo tmp_viewsinfo = Nilrewriteviewsinfo(); + { + viewnames kc_fe_selvar_1 = a_views ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consviewnames + ) { + ID kc_selvar_0_1 = kc_fe_selvar_1->ID_1; + { + { + { + const ID a_view = kc_selvar_0_1; + + global_filterview = a_view; + tmp_viewsinfo = Consrewriteviewsinfo( Rewriteviewinfo( a_view, tmp_rulesinfo->filter( filterrewriteruleinfoonview )), tmp_viewsinfo ); + + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->viewnames_1; + + } + } + return tmp_viewsinfo; + + } + + unparseviewsinfo f_unparseviewsinfo_of_alternative(alternative a_alternative, viewnames a_views) + { + unparsedeclsinfo tmp_declsinfo = a_alternative->unparseinfo; + unparseviewsinfo tmp_viewsinfo = Nilunparseviewsinfo(); + { + viewnames kc_fe_selvar_1 = a_views ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consviewnames + ) { + ID kc_selvar_0_1 = kc_fe_selvar_1->ID_1; + { + { + { + const ID a_view = kc_selvar_0_1; + + global_filterview = a_view; + tmp_viewsinfo = Consunparseviewsinfo( Unparseviewinfo( a_view, tmp_declsinfo->filter( filterunparsedeclinfoonview )), tmp_viewsinfo ); + + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->viewnames_1; + + } + } + return tmp_viewsinfo; + + } + + static bool filterrewriteruleinfoonview(rewriteruleinfo a_rewriteruleinfo) + { + return is_viewname_in_rewriteruleinfo( global_filterview, a_rewriteruleinfo ); + + } + + static bool filterunparsedeclinfoonview(unparsedeclinfo a_unparsedeclinfo) + { + return is_viewname_in_unparsedeclinfo( global_filterview, a_unparsedeclinfo ); + + } + + static bool is_viewname_in_rewriteruleinfo(ID a_view, rewriteruleinfo a_rewriteruleinfo) + { + { + rewriteruleinfo kc_selvar_0_1 = phylum_cast( a_rewriteruleinfo ); + if ((kc_selvar_0_1->prod_sel() == sel_Rewriteruleinfo) && (phylum_cast(kc_selvar_0_1)->rewriteclause_1->prod_sel() == sel_RewriteClause)) { + const viewnames a_viewnames = phylum_cast(phylum_cast(kc_selvar_0_1)->rewriteclause_1)->viewnames_1; + + return is_viewname_in_viewnames( a_view, a_viewnames ); + + } else + { kc_no_default_in_with( "is_viewname_in_rewriteruleinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static bool is_viewname_in_unparsedeclinfo(ID a_view, unparsedeclinfo a_unparsedeclinfo) + { + { + unparsedeclinfo kc_selvar_0_1 = phylum_cast( a_unparsedeclinfo ); + if ((kc_selvar_0_1->prod_sel() == sel_Unparsedeclinfo) && (phylum_cast(kc_selvar_0_1)->unparseclause_1->prod_sel() == sel_UnparseClause)) { + const viewnames a_viewnames = phylum_cast(phylum_cast(kc_selvar_0_1)->unparseclause_1)->viewnames_1; + + return is_viewname_in_viewnames( a_view, a_viewnames ); + + } else + { kc_no_default_in_with( "is_viewname_in_unparsedeclinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static bool is_viewname_in_viewnames(ID a_view, viewnames a_viewnames) + { + { + viewnames kc_fe_selvar_1 = a_viewnames ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consviewnames + ) { + ID kc_selvar_0_1 = kc_fe_selvar_1->ID_1; + { + { + { + const ID a_viewname = kc_selvar_0_1; + + if ( a_view->eq( a_viewname ) ) { + return true; + } + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->viewnames_1; + + } + } + return false; + + } + + ID f_typeof(path a_path) + { + if (a_path->id->eq(f_emptyId())) { + { + path kc_selvar_0_1 = phylum_cast( a_path ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspath)) { + const integer i = (kc_selvar_0_1)->integer_1; + const path r_path = (kc_selvar_0_1)->path_1; + + return f_subphylumofoperator( r_path->op, Int( i ) ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpath)) { + + return f_phylumofoperator( a_path->op ); + + } else + { kc_no_default_in_with( "f_typeof", __LINE__, __FILE__ ); + return static_cast(0); } + } + } else { + return a_path->id; + } + + } + + ID f_operatorofpatternrepresentation(patternrepresentation a_patternrepresentation) + { + { + patternrepresentation kc_selvar_0_1 = phylum_cast( a_patternrepresentation ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspatternrepresentation)) { + const elem_patternrepresentation e = (kc_selvar_0_1)->elem_patternrepresentation_1; + + return f_operatorofelem_patternrepresentation( e ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpatternrepresentation)) { + + return f_emptyId(); + + } else + { kc_no_default_in_with( "f_operatorofpatternrepresentation", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static ID f_operatorofelem_patternrepresentation(elem_patternrepresentation a_elem_patternrepresentation) + { + { + elem_patternrepresentation kc_selvar_0_1 = phylum_cast( a_elem_patternrepresentation ); + if ((kc_selvar_0_1->prod_sel() == sel_PRDefault)) { + return f_emptyId(); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRUserPredicate)) { + return f_emptyId(); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRIntLiteral)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRStringLiteral)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRWildcard)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRNonLeafBinding)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PROperPredicate)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRBinding)) { + const path p = phylum_cast(kc_selvar_0_1)->path_1; + return f_operatorofpath( p ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_PRVarPredicate)) { + const paths ps = phylum_cast(kc_selvar_0_1)->paths_1; + return f_operatorofpaths( ps ); + } else + { kc_no_default_in_with( "f_operatorofelem_patternrepresentation", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static ID f_operatorofpaths(paths a_paths) + { + { + paths kc_selvar_0_1 = phylum_cast( a_paths ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspaths)) { + const path p = (kc_selvar_0_1)->path_1; + + return f_operatorofpath( p ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpaths)) { + + return f_emptyId(); + + } else + { kc_no_default_in_with( "f_operatorofpaths", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static ID f_operatorofpath(path a_path) + { + { + path kc_selvar_0_1 = phylum_cast( a_path ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspath)) { + const path r_path = (kc_selvar_0_1)->path_1; + + return r_path->op; + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpath)) { + + return a_path->op; + + } else + { kc_no_default_in_with( "f_operatorofpath", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + ID f_typeofunpsubterm(unpsubterm a_unpsubterm, ID a_operator) + { + { + unpsubterm kc_selvar_0_1 = phylum_cast( a_unpsubterm ); + if ((kc_selvar_0_1->prod_sel() == sel_UnpCastedVariable)) { + const ID a_cast = phylum_cast(kc_selvar_0_1)->ID_1; + return a_cast; + } else + if ((kc_selvar_0_1->prod_sel() == sel_UnpDollarvarAttr)) { + const INT i = phylum_cast(kc_selvar_0_1)->INT_1; + const unpattributes a_unpattributes = phylum_cast(kc_selvar_0_1)->unpattributes_1; + return f_check_unpattributes_in_phylum( a_unpattributes, f_subphylumofoperator( a_operator, i ) ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_UnpSubAttr)) { + const ID an_id = phylum_cast(kc_selvar_0_1)->ID_1; + const unpattributes an_unpattributes = phylum_cast(kc_selvar_0_1)->unpattributes_1; + return f_check_unpattributes_in_phylum( an_unpattributes, f_phylumofpatternID( an_id ) ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_UnpDollarvarTerm)) { + const INT i = phylum_cast(kc_selvar_0_1)->INT_1; + return f_subphylumofoperator( a_operator, i ); + } else + if ((kc_selvar_0_1->prod_sel() == sel_UnpSubTerm)) { + const ID a_id = phylum_cast(kc_selvar_0_1)->ID_1; + return f_phylumofpatternID( a_id ); + } else + { kc_no_default_in_with( "f_typeofunpsubterm", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + elem_patternrepresentation f_outmost_nl_preds_in_rewriterulesinfo(rewriterulesinfo ri) + { + { + rewriterulesinfo kc_selvar_0_1 = phylum_cast( ri ); + if ((kc_selvar_0_1->prod_sel() == sel_Consrewriterulesinfo) && ((kc_selvar_0_1)->rewriteruleinfo_1->prod_sel() == sel_Rewriteruleinfo)) { + const patternrepresentation preds = phylum_cast((kc_selvar_0_1)->rewriteruleinfo_1)->patternrepresentation_1; + const rewriterulesinfo r_ri = (kc_selvar_0_1)->rewriterulesinfo_1; + + elem_patternrepresentation epr = + f_outmost_nl_preds_in_patternrepresentation( preds ); + return epr ? epr + : f_outmost_nl_preds_in_rewriterulesinfo( r_ri ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilrewriterulesinfo)) { + return 0; + } else + { kc_no_default_in_with( "f_outmost_nl_preds_in_rewriterulesinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + elem_patternrepresentation f_outmost_nl_preds_in_unparsedeclsinfo(unparsedeclsinfo ri) + { + { + unparsedeclsinfo kc_selvar_0_1 = phylum_cast( ri ); + if ((kc_selvar_0_1->prod_sel() == sel_Consunparsedeclsinfo) && ((kc_selvar_0_1)->unparsedeclinfo_1->prod_sel() == sel_Unparsedeclinfo)) { + const patternrepresentation preds = phylum_cast((kc_selvar_0_1)->unparsedeclinfo_1)->patternrepresentation_1; + const unparsedeclsinfo r_ri = (kc_selvar_0_1)->unparsedeclsinfo_1; + + elem_patternrepresentation epr = + f_outmost_nl_preds_in_patternrepresentation( preds ); + return epr ? epr + : f_outmost_nl_preds_in_unparsedeclsinfo( r_ri ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilunparsedeclsinfo)) { + return 0; + } else + { kc_no_default_in_with( "f_outmost_nl_preds_in_unparsedeclsinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static elem_patternrepresentation f_outmost_nl_preds_in_patternrepresentation(patternrepresentation p) + { + { + patternrepresentation kc_selvar_0_1 = phylum_cast( p ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspatternrepresentation)) { + const elem_patternrepresentation a_p = (kc_selvar_0_1)->elem_patternrepresentation_1; + const patternrepresentation r_p = (kc_selvar_0_1)->patternrepresentation_1; + + return f_outmost_nl_preds_in_elem_patternrepresentation( a_p ) ? a_p + : f_outmost_nl_preds_in_patternrepresentation( r_p ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpatternrepresentation)) { + return 0; + } else + { kc_no_default_in_with( "f_outmost_nl_preds_in_patternrepresentation", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + static bool f_outmost_nl_preds_in_elem_patternrepresentation(elem_patternrepresentation e_p) + { + { + elem_patternrepresentation kc_selvar_0_1 = phylum_cast( e_p ); + if ((kc_selvar_0_1->prod_sel() == sel_PRVarPredicate)) { + const paths a_p = phylum_cast(kc_selvar_0_1)->paths_1; + + return f_outmost_nl_preds_in_paths( a_p ); + + } else + { + return false; + } + } + + } + + static bool f_outmost_nl_preds_in_paths(paths p) + { + { + paths kc_selvar_0_1 = phylum_cast( p ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspaths) && ((kc_selvar_0_1)->path_1->prod_sel() == sel_Conspath)) { + const paths r_p = (kc_selvar_0_1)->paths_1; + + return f_outmost_nl_preds_in_paths( r_p ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Conspaths) && ((kc_selvar_0_1)->path_1->prod_sel() == sel_Nilpath)) { + return true; + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilpaths)) { + return false; + } else + { kc_no_default_in_with( "f_outmost_nl_preds_in_paths", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + bool f_is_known_ptr_type(ID id) + { + static phylumnames known = 0; + + if (! known ) { + known = Nilphylumnames(); + known = Consphylumnames( Id( Str( mkcasestring( "size_t" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "unsigned" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "enum_phyla" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "enum_operators" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "KC_UNIQ_INFO" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "bool" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "hashtable_t" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "KC_IO_STATUS" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "uview" ))), known ); + known = Consphylumnames( Id( Str( mkcasestring( "rview" ))), known ); + } + { + phylumnames kc_fe_selvar_1 = known ; + + while( + kc_fe_selvar_1->prod_sel() == sel_Consphylumnames + ) { + ID kc_selvar_0_1 = kc_fe_selvar_1->ID_1; + { + { + { + const ID pn = kc_selvar_0_1; + + if ( pn->eq( id )) { + return true; + } + } + } + + } + kc_fe_selvar_1 = kc_fe_selvar_1->phylumnames_1; + + } + } + return false; + + } + + withcasesinfo rewrite_withcasesinfo(withcasesinfo a_withcasesinfo) + {{ + withcasesinfo kc_selvar_0_1 = phylum_cast(a_withcasesinfo); + if ((kc_selvar_0_1->prod_sel() == sel_Conswithcasesinfo) && ((kc_selvar_0_1)->withcaseinfo_1->prod_sel() == sel_Withcaseinfo)) { + const patternrepresentation p = phylum_cast((kc_selvar_0_1)->withcaseinfo_1)->patternrepresentation_1; + const patternrepresentation b = phylum_cast((kc_selvar_0_1)->withcaseinfo_1)->patternrepresentation_2; + const Ctext ct = phylum_cast((kc_selvar_0_1)->withcaseinfo_1)->Ctext_1; + const withcasesinfo r = (kc_selvar_0_1)->withcasesinfo_1; + + return Conswithcasesinfo( + Withcaseinfo( p->rewrite(base_rview), b, ct ), + rewrite_withcasesinfo( r ) ); + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilwithcasesinfo)) { + return kc_selvar_0_1; + } else + { kc_no_default_in_with( "rewrite_withcasesinfo", __LINE__, __FILE__ ); + return static_cast(0); } + } + + } + + int pos_of_sole_dollar_or_pattern_in_patternchain(patternchain a_patternchain) + { + return t_pos_of_sole_dollar_or_pattern_in_patternchain(a_patternchain, -2, 1); + + } + + int t_pos_of_sole_dollar_or_pattern_in_patternchain(patternchain a_patternchain, int tmp_result, int pos) + { + if (tmp_result == -1) { + return tmp_result; + } + { + patternchain kc_selvar_0_1 = phylum_cast( a_patternchain ); + if ((kc_selvar_0_1->prod_sel() == sel_Conspatternchain)) { + const patternchainitem h = (kc_selvar_0_1)->patternchainitem_1; + const patternchain t = (kc_selvar_0_1)->patternchain_1; + + tmp_result = t_pos_of_sole_dollar_or_pattern_in_patternchain( t, tmp_result, pos+1 ); + if (tmp_result == -1) { + return tmp_result; + } + { + patternchainitem kc_selvar_1_1 = phylum_cast( h ); + if ((kc_selvar_1_1->prod_sel() == sel_PatternchainitemDollarid)) { + + return tmp_result >= 0 ? -1 : pos; + + } else + if ((kc_selvar_1_1->prod_sel() == sel_PatternchainitemOutmost)) { + const outmostpattern p = phylum_cast(kc_selvar_1_1)->outmostpattern_1; + + { + outmostpattern kc_selvar_2_1 = phylum_cast( p ); + if ((kc_selvar_2_1->prod_sel() == sel_OPOperatorWildcard) && (phylum_cast(kc_selvar_2_1)->ID_1->prod_sel() == sel_Id)) { + const uniqID uid = phylum_cast(phylum_cast(kc_selvar_2_1)->ID_1)->uniqID_1; + + { + IDtype kc_selvar_3_1 = phylum_cast( uid->type ); + if ((kc_selvar_3_1->prod_sel() == sel_ITUnknown)) { + + return tmp_result; + + } else + if ((kc_selvar_3_1->prod_sel() == sel_ITPatternVariable)) { + + return tmp_result; + + } else + { + + if (tmp_result >= 0) { + return -1; + } else { + return pos; + } + } + } + + } else + { + + return tmp_result >= 0 ? -1 : pos; + + } + } + + } else + { + + return -1; + + } + } + + } else + { + + return tmp_result; + + } + } + + } + + string f_getidentfromstring(const char **c) + { + string s=""; + if (isalnum(**c) || **c=='_') + while (isalnum(**c) || **c=='_') s+=*(*c)++; + else + while (!(isalnum(**c) || **c=='_' || **c=='\0')) s+=*(*c)++; + return s; + + } + + + } // namespace kc Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.h diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.h:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/gutil.h Tue Apr 6 15:25:12 2004 *************** *** 0 **** --- 1,81 ---- + /* translation of file "gutil.k" */ + /* generated by: + * @(#)$Author: criswell $ + */ + #ifndef KC_FUNCTIONS_gutil_HEADER + #define KC_FUNCTIONS_gutil_HEADER + #include "k.h" /* in case a user forgets */ + + namespace kc { } + using namespace kc; + /* included stuff */ + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + extern phylumdeclaration The_abstract_phylum_decl; + extern phylumdeclaration The_abstract_phylum_ref_decl; + extern phylumdeclaration The_abstract_list_decl; + + /* end included stuff */ + + + namespace kc { + bool f_something_to_initialize (Ccode_option cco); + bool f_something_to_initialize (alternative a); + bool f_NilCtexts (Ctexts c); + bool f_constructors_in_operatordecl (alternative op); + bool f_constructors_in_phylumdecl (phylumdeclaration ph); + bool f_destructors_in_operatordecl (alternative op); + bool f_destructors_in_phylumdecl (phylumdeclaration ph); + bool f_no_params (ac_parameter_type_list p); + bool f_post_create_in_operatordecl (alternative op); + bool f_post_create_in_phylumdecl (phylumdeclaration ph); + bool f_rewrite_in_phylumdecl (phylumdeclaration ph); + bool f_rewrite_in_operatordecl (alternative op); + ID f_phylumofwithcasesinfo (withcasesinfo wcso); + ID f_phylumofpatternrepresentation (patternrepresentation a_patrep); + ac_parameter_type_list sort_extend_parameter_type_list (ac_declaration_list C_vardecls, ac_declarator decl); + ac_parameter_list t_sort_extend_parameter_list (ac_declaration_list C_vardecls, ac_identifier_list fn_args, ac_parameter_list temp); + void unparse (const char *s, printer_functor printer_fn, uview v); + ID f_mkselvar (const char *prefix, int level); + ID f_mkselvar2 (const char *prefix, int level, int branch); + char *f_mk_filename (casestring a_casestring, const char *suffix); + char *f_mk_filename (casestring a_casestring, const string &suffix); + char *f_make_identifier_basename (const char *fn); + rewriterulesinfo f_rewriterulesinfoofalternativeinview (alternative a_alternative, ID a_view); + rewriteviewsinfo f_rewriteviewsinfo_of_alternative (alternative a_alternative, viewnames a_views); + unparseviewsinfo f_unparseviewsinfo_of_alternative (alternative a_alternative, viewnames a_views); + ID f_typeof (path a_path); + ID f_operatorofpatternrepresentation (patternrepresentation a_patternrepresentation); + ID f_typeofunpsubterm (unpsubterm a_unpsubterm, ID a_operator); + elem_patternrepresentation f_outmost_nl_preds_in_rewriterulesinfo (rewriterulesinfo ri); + elem_patternrepresentation f_outmost_nl_preds_in_unparsedeclsinfo (unparsedeclsinfo ri); + bool f_is_known_ptr_type (ID id); + withcasesinfo rewrite_withcasesinfo (withcasesinfo a_withcasesinfo); + int pos_of_sole_dollar_or_pattern_in_patternchain (patternchain a_patternchain); + int t_pos_of_sole_dollar_or_pattern_in_patternchain (patternchain a_patternchain, int tmp_result, int pos); + string f_getidentfromstring (const char **c); + + } // namespace kc + + #endif // ! KC_FUNCTIONS_gutil_HEADER + Index: llvm/test/Programs/MultiSource/Applications/kimwitu++/k.cc diff -c /dev/null llvm/test/Programs/MultiSource/Applications/kimwitu++/k.cc:1.1 *** /dev/null Tue Apr 6 15:25:26 2004 --- llvm/test/Programs/MultiSource/Applications/kimwitu++/k.cc Tue Apr 6 15:25:12 2004 *************** *** 0 **** --- 1,13440 ---- + /* translation of file(s) + "abs.k" + "main.k" + "parse.k" + "error.k" + "occur.k" + "util.k" + "gen.k" + "gutil.k" + "pat.k" + */ + /* generated by: + * @(#)$Author: criswell $ + */ + #define KC_TYPES + + #include "k.h" + #include + #include + #include + #include + #include + + #ifdef _MSC_VER + #pragma warning( disable : 4786 ) + #endif + #include + #include + #include + #include + + #if !defined(USE_HASHSET) && (defined(__GNUC__) || defined(__ICC) || defined(__ECC)) \ + && !defined(DONT_USE_HASHSET) + # define USE_HASHSET + #endif + #ifdef USE_HASHSET + # if defined(__GNUC__) && __GNUC__>2 + # include + # else + # include + # endif + #endif + + using namespace std; + + namespace kc { + + inline bool + ht_less(casestring p1, casestring p2){ + return kc_strcmp(p1->name, p2->name)<0; + } + + inline bool + ht_less(nocasestring p1, nocasestring p2){ + return kc_strcasecmp(p1->name, p2->name)<0; + } + + inline bool + ht_less(real p1, real p2){ + return p1->value < p2->value; + } + + inline bool + ht_less(integer p1, integer p2){ + return p1->value < p2->value; + } + + inline bool + ht_less(voidptr p1, voidptr p2){ + return p1->pointer < p2->pointer; + } + + bool + ht_less(abstract_phylum p1, abstract_phylum p2) + { + enum_operators prod_sel=p1->prod_sel(); + enum_operators prod_sel2=p2->prod_sel(); + if(prod_selprod_sel2) + return false; + switch(prod_sel) { + case sel_NoCaseStr: + return ht_less(static_cast(p1),static_cast(p2)); + case sel__Str: + return ht_less(static_cast(p1),static_cast(p2)); + case sel__Real: + return ht_less(static_cast(p1),static_cast(p2)); + case sel__Int: + return ht_less(static_cast(p1),static_cast(p2)); + case sel__VoidPtr: + return ht_less(static_cast(p1),static_cast(p2)); + default: { + int i=0; + bool still_unique = kc_storageclass_still_uniq[phylum_info[p1->phylum()].uniq_stored]; + abstract_phylum sub1=0; + do { + sub1=p1->subphylum(i); + abstract_phylum sub2=p2->subphylum(i); + if(still_unique) { + if(sub1 + class phylum_less : std::binary_function + { + public: + bool operator()(const T& X, const T& Y) const + { return ht_less(X,Y); } + }; + + inline void deletefun(c_abstract_phylum t){ + delete const_cast(t); + } + + + #ifdef USE_HASHSET + struct hashitem { + size_t hashvalue; + casestring contents; + hashitem(casestring cs): contents(cs) { + unsigned long h = 0; + kc_char const *s = cs->name; + for ( ; *s; ++s) + h = 5*h + *s; + hashvalue=(size_t)h; + } + }; + + inline void deletefunhashitem(hashitem t) { + delete t.contents; + } + + # ifdef __GNUC__ + struct eq_hashitem { bool operator()(hashitem hi1, hashitem hi2) const { + return kc_strcmp(hi1.contents->name, hi2.contents->name) == 0; } }; + + struct hash_hashitem { size_t operator()(hashitem hi) const { + return hi.hashvalue; } }; + + # else + struct comp_hashitem { + enum { bucket_size = 4, min_buckets = 8 }; + // bucket_size and min_buckets are just guesses + size_t operator()(const hashitem hi) const { + return hi.hashvalue; } + bool operator()(const hashitem hi1, const hashitem hi2) const { + return kc_strcmp(hi1.contents->name, hi2.contents->name) < 0; } + }; + # endif // Whether gcc or icc + #endif // Whether hash or not + + struct hashtable_level + { + hashtable_level(bool cod = true): clean_on_destruction(cod) { } + void clear(bool free_entries=true) { + if(free_entries) + clear_entries(); + _casestring.clear(); + _nocasestring.clear(); + _integer.clear(); + _real.clear(); + _voidptr.clear(); + _abstract_phylum.clear(); + } + void clear_entries() { + #ifdef USE_HASHSET + std::for_each(_casestring.begin(),_casestring.end(),deletefunhashitem); + #else + std::for_each(_casestring.begin(),_casestring.end(),deletefun); + #endif + std::for_each(_nocasestring.begin(),_nocasestring.end(),deletefun); + std::for_each(_integer.begin(),_integer.end(),deletefun); + std::for_each(_real.begin(),_real.end(),deletefun); + std::for_each(_voidptr.begin(),_voidptr.end(),deletefun); + std::for_each(_abstract_phylum.begin(),_abstract_phylum.end(),deletefun); + } + ~hashtable_level() { + clear(clean_on_destruction); + } + abstract_phylum check_insert(abstract_phylum t) { + return *_abstract_phylum.insert(t).first; + } + casestring check_insert(casestring t) { + #ifdef USE_HASHSET + return (*_casestring.insert(hashitem(t)).first).contents; + #else + return *_casestring.insert(t).first; + #endif + } + nocasestring check_insert(nocasestring t) { + return *_nocasestring.insert(t).first; + } + integer check_insert(integer t) { + return *_integer.insert(t).first; + } + real check_insert(real t) { + return *_real.insert(t).first; + } + voidptr check_insert(voidptr t) { + return *_voidptr.insert(t).first; + } + private: + bool clean_on_destruction; + #ifdef USE_HASHSET + # ifdef __GNUC__ + # if __GNUC__==2 || (__GNUC__==3 && __GNUC_MINOR__==0) + std::hash_set _casestring; + # else + __gnu_cxx::hash_set _casestring; + # endif + # else + std::hash_set _casestring; + # endif + #else + std::set > _casestring; + #endif + std::set > _nocasestring; + std::set > _integer; + std::set > _real; + std::set > _voidptr; + std::set > _abstract_phylum; + }; + + class hashtable_stack: public std::list { + public: + hashtable_stack(): _pos(begin()) { } + + void inc_level() { _pos=insert(_pos, hashtable_level()); } + void dec_level() { if(valid() && _pos!=end()) ++_pos; } + void free_level() { if(_pos!=begin()) { erase(begin(),_pos);_pos=begin(); } } + + bool valid() const { return !empty(); } + hashtable_level& get_level() { return *_pos; } + + template + T check_insert(T t) { + return dynamic_cast((*_pos).check_insert(t)); + } + private: + iterator _pos; + }; + + class hashtable_struct_t { + public: + // don't clean _static_level on destruction (program ends) + hashtable_struct_t(): _static_level(false), _to_be_freed(false), _dynamic(false) { } + + template + T ht_check_insert(T t) { + if(_dynamic && _dynamic_level.valid()) + return _dynamic_level.check_insert(t); + else + return dynamic_cast(_static_level.check_insert(t)); + } + void ht_static() {_dynamic=false; } + void ht_dynamic() { + _dynamic=true; + if(!_dynamic_level.valid()) + _dynamic_level.inc_level(); + } + void ht_inc_level() { _dynamic_level.inc_level(); } + void ht_dec_level() { _dynamic_level.dec_level(); } + void ht_free_level() { _dynamic_level.free_level(); } + void ht_clear() { _static_level.clear(); _dynamic_level.clear(); _dynamic=false; } + + bool to_be_freed() { return _to_be_freed; } + void set_to_be_freed(bool b=true) { _to_be_freed=b; } + private: + hashtable_level _static_level; + hashtable_stack _dynamic_level; + bool _to_be_freed; /* should be true for dynamic, false for statically allocated structures */ + bool _dynamic; + }; + + impl_nocasestring_NoCaseStr::impl_nocasestring_NoCaseStr(const kc_char* _name) : name(_name) { } + void impl_nocasestring_NoCaseStr::make_own(int length) { + kc_char *newname=new kc_char[length+1]; + for (int i=0; i < length && name[i]; ++i) + newname[i] = kc_tolower(name[i]); + newname[length]=0; + name=newname; + } + + impl_casestring__Str::impl_casestring__Str(const kc_char* _name) : name(_name) { } + void impl_casestring__Str::make_own(int length) { + kc_char *newname=kc_strncpy(new kc_char[length+1],name,length); + newname[length]=0; + name=newname; + } + abstract_phylum impl_bindingidmark_BindingIdMark::subphylum(int no) const + { + switch(no){ + case 0: return uniqID_1; + } + return 0; + } + abstract_phylum impl_bindingidmarks::subphylum(int no) const + { + switch(no){ + case 0: return bindingidmark_1; + case 1: return bindingidmarks_1; + } + return 0; + } + abstract_phylum impl_countedphylumdeclaration_CountedPhylumdeclaration::subphylum(int no) const + { + switch(no){ + case 0: return uniqID_1; + } + return 0; + } + abstract_phylum impl_countedphylumdeclarations::subphylum(int no) const + { + switch(no){ + case 0: return countedphylumdeclaration_1; + case 1: return countedphylumdeclarations_1; + } + return 0; + } + abstract_phylum impl_addedphylumdeclaration_AddedPhylumdeclaration::subphylum(int no) const + { + switch(no){ + case 0: return uniqID_1; + } + return 0; + } + abstract_phylum impl_addedphylumdeclarations::subphylum(int no) const + { + switch(no){ + case 0: return addedphylumdeclaration_1; + case 1: return addedphylumdeclarations_1; + } + return 0; + } + abstract_phylum impl_problem_Problem6::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + case 2: return casestring_3; + case 3: return casestring_4; + case 4: return casestring_5; + case 5: return casestring_6; + } + return 0; + } + abstract_phylum impl_problem_Problem5::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + case 2: return casestring_3; + case 3: return casestring_4; + case 4: return casestring_5; + } + return 0; + } + abstract_phylum impl_problem_Problem4::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + case 2: return casestring_3; + case 3: return casestring_4; + } + return 0; + } + abstract_phylum impl_problem_Problem3int1::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + case 2: return casestring_3; + case 3: return integer_1; + case 4: return casestring_4; + } + return 0; + } + abstract_phylum impl_problem_Problem3::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + case 2: return casestring_3; + } + return 0; + } + abstract_phylum impl_problem_Problem2::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return casestring_2; + } + return 0; + } + abstract_phylum impl_problem_Problem1storageoption1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return storageoption_1; + case 2: return casestring_2; + case 3: return ID_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1INT1ID1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return INT_1; + case 2: return casestring_2; + case 3: return ID_1; + case 4: return casestring_3; + case 5: return ID_2; + } + return 0; + } + abstract_phylum impl_problem_Problem1ID1ID1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return ID_1; + case 2: return casestring_2; + case 3: return ID_2; + case 4: return casestring_3; + case 5: return ID_3; + } + return 0; + } + abstract_phylum impl_problem_Problem1INT1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return INT_1; + case 2: return casestring_2; + case 3: return ID_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1int1::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return integer_1; + case 2: return casestring_2; + } + return 0; + } + abstract_phylum impl_problem_Problem1INT::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return INT_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1t1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return IDtype_1; + case 2: return casestring_2; + case 3: return ID_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1ID1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return ID_1; + case 2: return casestring_2; + case 3: return ID_2; + } + return 0; + } + abstract_phylum impl_problem_Problem1we::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return withexpression_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1tID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1ID::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_problem_Problem1::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_error_Warning::subphylum(int no) const + { + switch(no){ + case 0: return fileline_1; + case 1: return problem_1; + } + return 0; + } + abstract_phylum impl_error_NonFatal::subphylum(int no) const + { + switch(no){ + case 0: return fileline_1; + case 1: return problem_1; + } + return 0; + } + abstract_phylum impl_error_Fatal::subphylum(int no) const + { + switch(no){ + case 0: return fileline_1; + case 1: return problem_1; + } + return 0; + } + abstract_phylum impl_baseclass_list::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return baseclass_list_1; + } + return 0; + } + abstract_phylum impl_baseclass_decl_BaseClassDecl::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return baseclass_list_1; + } + return 0; + } + abstract_phylum impl_baseclass_declarations::subphylum(int no) const + { + switch(no){ + case 0: return baseclass_decl_1; + case 1: return baseclass_declarations_1; + } + return 0; + } + abstract_phylum impl_ac_base_init_AcBaseInit::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ac_constant_expression_1; + } + return 0; + } + abstract_phylum impl_ac_base_init_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_base_init_1; + case 1: return ac_base_init_list_1; + } + return 0; + } + abstract_phylum impl_ac_opt_base_init_list_AcYesBaseInit::subphylum(int no) const + { + switch(no){ + case 0: return ac_base_init_list_1; + } + return 0; + } + abstract_phylum impl_ac_constant_expression_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_constant_expression_1; + case 1: return ac_constant_expression_list_1; + } + return 0; + } + abstract_phylum impl_ac_constant_expression_AcConstExpr::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_ac_constant_expression_option_Yesac_constant_expression::subphylum(int no) const + { + switch(no){ + case 0: return ac_constant_expression_1; + } + return 0; + } + abstract_phylum impl_ac_direct_abstract_declarator_AcDirAbsdeclFn::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_abstract_declarator_option_1; + case 1: return ac_parameter_type_list_1; + } + return 0; + } + abstract_phylum impl_ac_direct_abstract_declarator_AcDirAbsdeclArray::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_abstract_declarator_option_1; + case 1: return ac_constant_expression_option_1; + } + return 0; + } + abstract_phylum impl_ac_direct_abstract_declarator_AcDirAbsdeclPack::subphylum(int no) const + { + switch(no){ + case 0: return ac_abstract_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_abstract_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_abstract_declarator_AcAbsdeclDirdecl::subphylum(int no) const + { + switch(no){ + case 0: return ac_pointer_option_1; + case 1: return ac_direct_abstract_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_abstract_declarator_AcAbsdeclPointer::subphylum(int no) const + { + switch(no){ + case 0: return ac_pointer_1; + } + return 0; + } + abstract_phylum impl_ac_identifier_list::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ac_identifier_list_1; + } + return 0; + } + abstract_phylum impl_ac_parameter_declaration_AcParDeclAbsdecl::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifiers_1; + case 1: return ac_abstract_declarator_1; + case 2: return ac_constant_expression_option_1; + } + return 0; + } + abstract_phylum impl_ac_parameter_declaration_AcParDeclDecl::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifiers_1; + case 1: return ac_declarator_1; + case 2: return ac_constant_expression_option_1; + } + return 0; + } + abstract_phylum impl_ac_parameter_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_parameter_declaration_1; + case 1: return ac_parameter_list_1; + } + return 0; + } + abstract_phylum impl_ac_parameter_type_list_AcParList3Dot::subphylum(int no) const + { + switch(no){ + case 0: return ac_parameter_list_1; + } + return 0; + } + abstract_phylum impl_ac_parameter_type_list_AcParList::subphylum(int no) const + { + switch(no){ + case 0: return ac_parameter_list_1; + } + return 0; + } + abstract_phylum impl_ac_type_qualifier_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_type_qualifier_1; + case 1: return ac_type_qualifier_list_1; + } + return 0; + } + abstract_phylum impl_ac_class_qualifier_list::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ac_class_qualifier_list_1; + } + return 0; + } + abstract_phylum impl_ac_class_qualifier_help_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_declarator_1; + case 1: return ac_class_qualifier_help_list_1; + } + return 0; + } + abstract_phylum impl_ac_operator_name_AcOperatorName::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_ac_pointer_AcPointerCons::subphylum(int no) const + { + switch(no){ + case 0: return ac_type_qualifier_list_1; + case 1: return ac_pointer_1; + } + return 0; + } + abstract_phylum impl_ac_pointer_AcPointerNil::subphylum(int no) const + { + switch(no){ + case 0: return ac_type_qualifier_list_1; + } + return 0; + } + abstract_phylum impl_ac_pointer_option_Yespointer::subphylum(int no) const + { + switch(no){ + case 0: return ac_pointer_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcOperatorDeclId::subphylum(int no) const + { + switch(no){ + case 0: return ac_operator_name_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcConvOperatorDecl::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ID_2; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcMemberDecl::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ID_2; + case 2: return ac_constant_expression_list_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcQualifiedDeclProto::subphylum(int no) const + { + switch(no){ + case 0: return ac_class_qualifier_list_1; + case 1: return ac_direct_declarator_1; + case 2: return ac_parameter_type_list_1; + case 3: return ac_type_qualifier_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcDirectDeclProto::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_declarator_1; + case 1: return ac_parameter_type_list_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcDirectDeclArray::subphylum(int no) const + { + switch(no){ + case 0: return ac_direct_declarator_1; + case 1: return ac_constant_expression_option_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcDirectDeclPack::subphylum(int no) const + { + switch(no){ + case 0: return ac_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_direct_declarator_AcDirectDeclId::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_ac_declarator_AcDeclarator::subphylum(int no) const + { + switch(no){ + case 0: return ac_pointer_option_1; + case 1: return ac_ref_option_1; + case 2: return ac_direct_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_init_declarator_AcInitDecl::subphylum(int no) const + { + switch(no){ + case 0: return ac_declarator_1; + } + return 0; + } + abstract_phylum impl_ac_init_declarator_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_init_declarator_1; + case 1: return ac_init_declarator_list_1; + } + return 0; + } + abstract_phylum impl_ac_type_specifier_AcTypeSpec::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_specifier_AcDeclSpecTypeQual::subphylum(int no) const + { + switch(no){ + case 0: return ac_type_qualifier_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_specifier_AcDeclSpecTypeSpec::subphylum(int no) const + { + switch(no){ + case 0: return ac_type_specifier_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_specifier_AcDeclSpecStorageSpec::subphylum(int no) const + { + switch(no){ + case 0: return ac_storage_class_specifier_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_specifiers::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifier_1; + case 1: return ac_declaration_specifiers_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_list::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_1; + case 1: return ac_declaration_list_1; + } + return 0; + } + abstract_phylum impl_ac_declaration_AcDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifiers_1; + case 1: return ac_init_declarator_list_1; + } + return 0; + } + abstract_phylum impl_unparsedeclinfo_Unparsedeclinfo::subphylum(int no) const + { + switch(no){ + case 0: return patternrepresentation_1; + case 1: return patternrepresentation_2; + case 2: return unparseclause_1; + } + return 0; + } + abstract_phylum impl_unparsedeclsinfo::subphylum(int no) const + { + switch(no){ + case 0: return unparsedeclinfo_1; + case 1: return unparsedeclsinfo_1; + } + return 0; + } + abstract_phylum impl_unparseviewinfo_Unparseviewinfo::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return unparsedeclsinfo_1; + } + return 0; + } + abstract_phylum impl_unparseviewsinfo::subphylum(int no) const + { + switch(no){ + case 0: return unparseviewinfo_1; + case 1: return unparseviewsinfo_1; + } + return 0; + } + abstract_phylum impl_rewriteviewinfo_Rewriteviewinfo::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return rewriterulesinfo_1; + } + return 0; + } + abstract_phylum impl_rewriteviewsinfo::subphylum(int no) const + { + switch(no){ + case 0: return rewriteviewinfo_1; + case 1: return rewriteviewsinfo_1; + } + return 0; + } + abstract_phylum impl_withcaseinfo_Withcaseinfo::subphylum(int no) const + { + switch(no){ + case 0: return patternrepresentation_1; + case 1: return patternrepresentation_2; + case 2: return Ctext_1; + } + return 0; + } + abstract_phylum impl_withcasesinfo::subphylum(int no) const + { + switch(no){ + case 0: return withcaseinfo_1; + case 1: return withcasesinfo_1; + } + return 0; + } + abstract_phylum impl_rewriteruleinfo_Rewriteruleinfo::subphylum(int no) const + { + switch(no){ + case 0: return patternrepresentation_1; + case 1: return patternrepresentation_2; + case 2: return rewriteclause_1; + } + return 0; + } + abstract_phylum impl_rewriterulesinfo::subphylum(int no) const + { + switch(no){ + case 0: return rewriteruleinfo_1; + case 1: return rewriterulesinfo_1; + } + return 0; + } + abstract_phylum impl_argsnumbers::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + case 1: return argsnumbers_1; + } + return 0; + } + abstract_phylum impl_paths::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return paths_1; + } + return 0; + } + abstract_phylum impl_path::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + case 1: return path_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRIntLiteral::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return INT_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRStringLiteral::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRWildcard::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRNonLeafBinding::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return ID_1; + case 2: return patternrepresentation_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRUserPredicate::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PROperPredicate::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRVarPredicate::subphylum(int no) const + { + switch(no){ + case 0: return paths_1; + case 1: return ID_1; + case 2: return patternrepresentation_1; + } + return 0; + } + abstract_phylum impl_elem_patternrepresentation_PRBinding::subphylum(int no) const + { + switch(no){ + case 0: return path_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_patternrepresentation::subphylum(int no) const + { + switch(no){ + case 0: return elem_patternrepresentation_1; + case 1: return patternrepresentation_1; + } + return 0; + } + abstract_phylum impl_patternrepresentations::subphylum(int no) const + { + switch(no){ + case 0: return patternrepresentation_1; + case 1: return patternrepresentations_1; + } + return 0; + } + abstract_phylum impl_variables::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return variables_1; + } + return 0; + } + abstract_phylum impl_phyla::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return phyla_1; + } + return 0; + } + abstract_phylum impl_operators::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return operators_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITLanguageName::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITPatternVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return integer_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITUserFunction::subphylum(int no) const + { + switch(no){ + case 0: return fnclass_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITUserOperator::subphylum(int no) const + { + switch(no){ + case 0: return alternative_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITPredefinedOperator::subphylum(int no) const + { + switch(no){ + case 0: return alternative_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITUserPhylum::subphylum(int no) const + { + switch(no){ + case 0: return phylumdeclaration_1; + } + return 0; + } + abstract_phylum impl_IDtype_ITPredefinedPhylum::subphylum(int no) const + { + switch(no){ + case 0: return phylumdeclaration_1; + } + return 0; + } + abstract_phylum impl_scopetypefileline_ScopeTypeFileLine::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + case 1: return IDtype_1; + case 2: return casestring_1; + case 3: return integer_2; + } + return 0; + } + abstract_phylum impl_scopetypefilelinestack::subphylum(int no) const + { + switch(no){ + case 0: return scopetypefileline_1; + case 1: return scopetypefilelinestack_1; + } + return 0; + } + abstract_phylum impl_languagenames::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return languagenames_1; + } + return 0; + } + abstract_phylum impl_languageoption_LanguageList::subphylum(int no) const + { + switch(no){ + case 0: return languagenames_1; + } + return 0; + } + abstract_phylum impl_viewnameoption_YesViewname::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_unpattributes::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return unpattributes_1; + } + return 0; + } + abstract_phylum impl_unpsubterm_UnpCastedVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ID_2; + } + return 0; + } + abstract_phylum impl_unpsubterm_UnpDollarvarAttr::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + case 1: return unpattributes_1; + } + return 0; + } + abstract_phylum impl_unpsubterm_UnpSubAttr::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return unpattributes_1; + } + return 0; + } + abstract_phylum impl_unpsubterm_UnpDollarvarTerm::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + } + return 0; + } + abstract_phylum impl_unpsubterm_UnpSubTerm::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_unparseitem_UViewVarDecl::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ID_2; + case 2: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_unparseitem_UnpBody::subphylum(int no) const + { + switch(no){ + case 0: return languageoption_1; + case 1: return unparseitems_1; + } + return 0; + } + abstract_phylum impl_unparseitem_UnpCtext::subphylum(int no) const + { + switch(no){ + case 0: return languageoption_1; + case 1: return Ctext_1; + } + return 0; + } + abstract_phylum impl_unparseitem_UnpSubexpr::subphylum(int no) const + { + switch(no){ + case 0: return languageoption_1; + case 1: return unpsubterm_1; + case 2: return viewnameoption_1; + } + return 0; + } + abstract_phylum impl_unparseitem_UnpStr::subphylum(int no) const + { + switch(no){ + case 0: return languageoption_1; + case 1: return CexpressionDQ_1; + case 2: return viewnameoption_1; + } + return 0; + } + abstract_phylum impl_unparseitems::subphylum(int no) const + { + switch(no){ + case 0: return unparseitem_1; + case 1: return unparseitems_1; + } + return 0; + } + abstract_phylum impl_viewnames::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return viewnames_1; + } + return 0; + } + abstract_phylum impl_unparseclause_UnparseClause::subphylum(int no) const + { + switch(no){ + case 0: return viewnames_1; + case 1: return unparseitems_1; + } + return 0; + } + abstract_phylum impl_unparseclauses::subphylum(int no) const + { + switch(no){ + case 0: return unparseclause_1; + case 1: return unparseclauses_1; + } + return 0; + } + abstract_phylum impl_unparsedeclaration_UnparseDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return outmostpatterns_1; + case 1: return unparseclauses_1; + } + return 0; + } + abstract_phylum impl_unparsedeclarations::subphylum(int no) const + { + switch(no){ + case 0: return unparsedeclaration_1; + case 1: return unparsedeclarations_1; + } + return 0; + } + abstract_phylum impl_withcase_Withcase::subphylum(int no) const + { + switch(no){ + case 0: return patternchains_1; + case 1: return Ctext_1; + } + return 0; + } + abstract_phylum impl_withcases::subphylum(int no) const + { + switch(no){ + case 0: return withcase_1; + case 1: return withcases_1; + } + return 0; + } + abstract_phylum impl_withexpression_WECexpression::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_withexpression_WEVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_withexpressions::subphylum(int no) const + { + switch(no){ + case 0: return withexpression_1; + case 1: return withexpressions_1; + } + return 0; + } + abstract_phylum impl_contextinfo_InForeachContext::subphylum(int no) const + { + switch(no){ + case 0: return patternchain_1; + } + return 0; + } + abstract_phylum impl_foreach_after_ForeachAfter::subphylum(int no) const + { + switch(no){ + case 0: return patternchain_1; + case 1: return idCexpressions_1; + case 2: return withexpressions_1; + case 3: return Ctext_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextWithexpression::subphylum(int no) const + { + switch(no){ + case 0: return withexpressions_1; + case 1: return withcases_1; + case 2: return contextinfo_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextForeachexpression::subphylum(int no) const + { + switch(no){ + case 0: return patternchain_1; + case 1: return idCexpressions_1; + case 2: return withexpressions_1; + case 3: return Ctext_1; + case 4: return foreach_after_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextCbody::subphylum(int no) const + { + switch(no){ + case 0: return Ctext_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextCexpressionSQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionSQ_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextCexpressionDQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextNl::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextDollarVar::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + } + return 0; + } + abstract_phylum impl_Ctext_elem_CTextLine::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_Ctext::subphylum(int no) const + { + switch(no){ + case 0: return Ctext_elem_1; + case 1: return Ctext_1; + } + return 0; + } + abstract_phylum impl_fnclass_StaticFn::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_fndeclaration_AcMemberDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifiers_1; + case 1: return ac_declarator_1; + case 2: return ac_constant_expression_option_1; + case 3: return fnclass_1; + } + return 0; + } + abstract_phylum impl_fndeclaration_FnAcDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return ac_declaration_specifiers_1; + case 1: return ac_declarator_1; + case 2: return ac_declaration_list_1; + case 3: return ac_opt_base_init_list_1; + case 4: return Ctext_1; + case 5: return ID_1; + case 6: return fnclass_1; + } + return 0; + } + abstract_phylum impl_fndeclarations::subphylum(int no) const + { + switch(no){ + case 0: return fndeclaration_1; + case 1: return fndeclarations_1; + } + return 0; + } + abstract_phylum impl_fnfile_FnFile::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_fnfiles::subphylum(int no) const + { + switch(no){ + case 0: return fnfile_1; + case 1: return fnfiles_1; + } + return 0; + } + abstract_phylum impl_terms::subphylum(int no) const + { + switch(no){ + case 0: return term_1; + case 1: return terms_1; + } + return 0; + } + abstract_phylum impl_term_TIntLiteral::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + } + return 0; + } + abstract_phylum impl_term_TStringLiteral::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_term_TCTerm::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionSQ_1; + } + return 0; + } + abstract_phylum impl_term_TMemberVarDot::subphylum(int no) const + { + switch(no){ + case 0: return term_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_term_TMemberVar::subphylum(int no) const + { + switch(no){ + case 0: return term_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_term_TMethodDot::subphylum(int no) const + { + switch(no){ + case 0: return term_1; + case 1: return ID_1; + case 2: return terms_1; + } + return 0; + } + abstract_phylum impl_term_TMethod::subphylum(int no) const + { + switch(no){ + case 0: return term_1; + case 1: return ID_1; + case 2: return terms_1; + } + return 0; + } + abstract_phylum impl_term_TOperator::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return terms_1; + } + return 0; + } + abstract_phylum impl_term_TVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_patterns::subphylum(int no) const + { + switch(no){ + case 0: return pattern_1; + case 1: return patterns_1; + } + return 0; + } + abstract_phylum impl_pattern_PIntLiteral::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + } + return 0; + } + abstract_phylum impl_pattern_PStringLiteral::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_pattern_PNonLeafVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return pattern_1; + } + return 0; + } + abstract_phylum impl_pattern_POperator::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return patterns_1; + } + return 0; + } + abstract_phylum impl_pattern_PVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_outmostpattern_OPDefault::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_outmostpattern_OPWildcard::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_outmostpattern_OPNonLeafVariable::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return outmostpattern_1; + } + return 0; + } + abstract_phylum impl_outmostpattern_OPOperator::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return patterns_1; + case 2: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_outmostpattern_OPOperatorWildcard::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_patternchainitem_PatternchainitemDollarid::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_patternchainitem_PatternchainitemGroup::subphylum(int no) const + { + switch(no){ + case 0: return patternchains_1; + } + return 0; + } + abstract_phylum impl_patternchainitem_PatternchainitemOutmost::subphylum(int no) const + { + switch(no){ + case 0: return outmostpattern_1; + } + return 0; + } + abstract_phylum impl_outmostpatterns::subphylum(int no) const + { + switch(no){ + case 0: return outmostpattern_1; + case 1: return outmostpatterns_1; + } + return 0; + } + abstract_phylum impl_patternchain::subphylum(int no) const + { + switch(no){ + case 0: return patternchainitem_1; + case 1: return patternchain_1; + } + return 0; + } + abstract_phylum impl_patternchains::subphylum(int no) const + { + switch(no){ + case 0: return patternchain_1; + case 1: return patternchains_1; + } + return 0; + } + abstract_phylum impl_rewriteclause_RewriteClause::subphylum(int no) const + { + switch(no){ + case 0: return viewnames_1; + case 1: return term_1; + } + return 0; + } + abstract_phylum impl_rewriteclauses::subphylum(int no) const + { + switch(no){ + case 0: return rewriteclause_1; + case 1: return rewriteclauses_1; + } + return 0; + } + abstract_phylum impl_rwdeclaration_RwDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return outmostpatterns_1; + case 1: return rewriteclauses_1; + } + return 0; + } + abstract_phylum impl_rwdeclarations::subphylum(int no) const + { + switch(no){ + case 0: return rwdeclaration_1; + case 1: return rwdeclarations_1; + } + return 0; + } + abstract_phylum impl_includedeclaration_IncludeDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_includedeclarations::subphylum(int no) const + { + switch(no){ + case 0: return includedeclaration_1; + case 1: return includedeclarations_1; + } + return 0; + } + abstract_phylum impl_includefile_IncludeFile::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_includefiles::subphylum(int no) const + { + switch(no){ + case 0: return includefile_1; + case 1: return includefiles_1; + } + return 0; + } + abstract_phylum impl_Ctexts::subphylum(int no) const + { + switch(no){ + case 0: return Ctext_1; + case 1: return Ctexts_1; + } + return 0; + } + abstract_phylum impl_idCexpression_IdCexpression::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_idCexpressions::subphylum(int no) const + { + switch(no){ + case 0: return idCexpression_1; + case 1: return idCexpressions_1; + } + return 0; + } + abstract_phylum impl_CexpressionSQ_elem_CExpressionSQPart::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_CexpressionSQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionSQ_elem_1; + case 1: return CexpressionSQ_1; + } + return 0; + } + abstract_phylum impl_CexpressionDQ_elem_CExpressionDQPart::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_CexpressionDQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionDQ_elem_1; + case 1: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionArray::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionPack::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionSQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionSQ_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionDQ::subphylum(int no) const + { + switch(no){ + case 0: return CexpressionDQ_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionDollarvar::subphylum(int no) const + { + switch(no){ + case 0: return INT_1; + } + return 0; + } + abstract_phylum impl_Cexpression_elem_CExpressionPart::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_Cexpression::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_elem_1; + case 1: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_attribute_initialisation_option_Yesattribute_initialisation::subphylum(int no) const + { + switch(no){ + case 0: return Cexpression_1; + } + return 0; + } + abstract_phylum impl_attribute_Attribute::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return ID_2; + case 2: return attribute_initialisation_option_1; + } + return 0; + } + abstract_phylum impl_attributes::subphylum(int no) const + { + switch(no){ + case 0: return attribute_1; + case 1: return attributes_1; + } + return 0; + } + abstract_phylum impl_Ccode_option_CcodeOption::subphylum(int no) const + { + switch(no){ + case 0: return attributes_1; + case 1: return Ctexts_1; + } + return 0; + } + abstract_phylum impl_argument_Argument::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return integer_1; + } + return 0; + } + abstract_phylum impl_arguments::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return arguments_1; + } + return 0; + } + abstract_phylum impl_alternative_Alternative::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return arguments_1; + } + return 0; + } + abstract_phylum impl_alternatives::subphylum(int no) const + { + switch(no){ + case 0: return alternative_1; + case 1: return alternatives_1; + } + return 0; + } + abstract_phylum impl_productionblock_PredefinedAlternatives::subphylum(int no) const + { + switch(no){ + case 0: return alternatives_1; + } + return 0; + } + abstract_phylum impl_productionblock_NonlistAlternatives::subphylum(int no) const + { + switch(no){ + case 0: return alternatives_1; + } + return 0; + } + abstract_phylum impl_productionblock_ListAlternatives::subphylum(int no) const + { + switch(no){ + case 0: return alternatives_1; + case 1: return ID_1; + } + return 0; + } + abstract_phylum impl_storageclasses::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return storageclasses_1; + } + return 0; + } + abstract_phylum impl_storageoption_PositiveStorageOption::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_storageoption_NegativeStorageOption::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + } + return 0; + } + abstract_phylum impl_phylumdeclaration_PhylumDeclaration::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return storageoption_1; + case 2: return productionblock_1; + case 3: return Ccode_option_1; + } + return 0; + } + abstract_phylum impl_phylumnames::subphylum(int no) const + { + switch(no){ + case 0: return ID_1; + case 1: return phylumnames_1; + } + return 0; + } + abstract_phylum impl_phylumdeclarations::subphylum(int no) const + { + switch(no){ + case 0: return phylumdeclaration_1; + case 1: return phylumdeclarations_1; + } + return 0; + } + abstract_phylum impl_phylumdeclarationsroot_PhylumDeclarations::subphylum(int no) const + { + switch(no){ + case 0: return phylumdeclarations_1; + } + return 0; + } + abstract_phylum impl_STRING_String::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + abstract_phylum impl_INT_Int::subphylum(int no) const + { + switch(no){ + case 0: return integer_1; + } + return 0; + } + abstract_phylum impl_ID_Id::subphylum(int no) const + { + switch(no){ + case 0: return uniqID_1; + } + return 0; + } + abstract_phylum impl_uniqID_Str::subphylum(int no) const + { + switch(no){ + case 0: return casestring_1; + } + return 0; + } + void impl_bindingidmark_BindingIdMark::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = uniqID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_bindingidmarks::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = bindingidmark_1 = dynamic_cast(val);break; + case 1: newval = bindingidmarks_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_countedphylumdeclaration_CountedPhylumdeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = uniqID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_countedphylumdeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = countedphylumdeclaration_1 = dynamic_cast(val);break; + case 1: newval = countedphylumdeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_addedphylumdeclaration_AddedPhylumdeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = uniqID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_addedphylumdeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = addedphylumdeclaration_1 = dynamic_cast(val);break; + case 1: newval = addedphylumdeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem6::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + case 2: newval = casestring_3 = dynamic_cast(val);break; + case 3: newval = casestring_4 = dynamic_cast(val);break; + case 4: newval = casestring_5 = dynamic_cast(val);break; + case 5: newval = casestring_6 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem5::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + case 2: newval = casestring_3 = dynamic_cast(val);break; + case 3: newval = casestring_4 = dynamic_cast(val);break; + case 4: newval = casestring_5 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem4::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + case 2: newval = casestring_3 = dynamic_cast(val);break; + case 3: newval = casestring_4 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem3int1::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + case 2: newval = casestring_3 = dynamic_cast(val);break; + case 3: newval = integer_1 = dynamic_cast(val);break; + case 4: newval = casestring_4 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem3::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + case 2: newval = casestring_3 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem2::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = casestring_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1storageoption1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = storageoption_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1INT1ID1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = INT_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_1 = dynamic_cast(val);break; + case 4: newval = casestring_3 = dynamic_cast(val);break; + case 5: newval = ID_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1ID1ID1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_2 = dynamic_cast(val);break; + case 4: newval = casestring_3 = dynamic_cast(val);break; + case 5: newval = ID_3 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1INT1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = INT_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1int1::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = integer_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1INT::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1t1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = IDtype_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1ID1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = casestring_2 = dynamic_cast(val);break; + case 3: newval = ID_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1we::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = withexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1tID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1ID::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_problem_Problem1::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_error_Warning::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fileline_1 = dynamic_cast(val);break; + case 1: newval = problem_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_error_NonFatal::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fileline_1 = dynamic_cast(val);break; + case 1: newval = problem_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_error_Fatal::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fileline_1 = dynamic_cast(val);break; + case 1: newval = problem_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_baseclass_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = baseclass_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_baseclass_decl_BaseClassDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = baseclass_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_baseclass_declarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = baseclass_decl_1 = dynamic_cast(val);break; + case 1: newval = baseclass_declarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_base_init_AcBaseInit::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ac_constant_expression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_base_init_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_base_init_1 = dynamic_cast(val);break; + case 1: newval = ac_base_init_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_opt_base_init_list_AcYesBaseInit::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_base_init_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_constant_expression_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_constant_expression_1 = dynamic_cast(val);break; + case 1: newval = ac_constant_expression_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_constant_expression_AcConstExpr::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_constant_expression_option_Yesac_constant_expression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_constant_expression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_abstract_declarator_AcDirAbsdeclFn::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_abstract_declarator_option_1 = dynamic_cast(val);break; + case 1: newval = ac_parameter_type_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_abstract_declarator_AcDirAbsdeclArray::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_abstract_declarator_option_1 = dynamic_cast(val);break; + case 1: newval = ac_constant_expression_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_abstract_declarator_AcDirAbsdeclPack::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_abstract_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_abstract_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_abstract_declarator_AcAbsdeclDirdecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_pointer_option_1 = dynamic_cast(val);break; + case 1: newval = ac_direct_abstract_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_abstract_declarator_AcAbsdeclPointer::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_pointer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_identifier_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ac_identifier_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_parameter_declaration_AcParDeclAbsdecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + case 1: newval = ac_abstract_declarator_1 = dynamic_cast(val);break; + case 2: newval = ac_constant_expression_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_parameter_declaration_AcParDeclDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + case 1: newval = ac_declarator_1 = dynamic_cast(val);break; + case 2: newval = ac_constant_expression_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_parameter_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_parameter_declaration_1 = dynamic_cast(val);break; + case 1: newval = ac_parameter_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_parameter_type_list_AcParList3Dot::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_parameter_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_parameter_type_list_AcParList::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_parameter_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_type_qualifier_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_type_qualifier_1 = dynamic_cast(val);break; + case 1: newval = ac_type_qualifier_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_class_qualifier_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ac_class_qualifier_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_class_qualifier_help_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_declarator_1 = dynamic_cast(val);break; + case 1: newval = ac_class_qualifier_help_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_operator_name_AcOperatorName::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_pointer_AcPointerCons::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_type_qualifier_list_1 = dynamic_cast(val);break; + case 1: newval = ac_pointer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_pointer_AcPointerNil::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_type_qualifier_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_pointer_option_Yespointer::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_pointer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcOperatorDeclId::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_operator_name_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcConvOperatorDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ID_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcMemberDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ID_2 = dynamic_cast(val);break; + case 2: newval = ac_constant_expression_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcQualifiedDeclProto::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_class_qualifier_list_1 = dynamic_cast(val);break; + case 1: newval = ac_direct_declarator_1 = dynamic_cast(val);break; + case 2: newval = ac_parameter_type_list_1 = dynamic_cast(val);break; + case 3: newval = ac_type_qualifier_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcDirectDeclProto::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_declarator_1 = dynamic_cast(val);break; + case 1: newval = ac_parameter_type_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcDirectDeclArray::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_direct_declarator_1 = dynamic_cast(val);break; + case 1: newval = ac_constant_expression_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcDirectDeclPack::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_direct_declarator_AcDirectDeclId::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declarator_AcDeclarator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_pointer_option_1 = dynamic_cast(val);break; + case 1: newval = ac_ref_option_1 = dynamic_cast(val);break; + case 2: newval = ac_direct_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_init_declarator_AcInitDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declarator_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_init_declarator_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_init_declarator_1 = dynamic_cast(val);break; + case 1: newval = ac_init_declarator_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_type_specifier_AcTypeSpec::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_specifier_AcDeclSpecTypeQual::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_type_qualifier_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_specifier_AcDeclSpecTypeSpec::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_type_specifier_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_specifier_AcDeclSpecStorageSpec::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_storage_class_specifier_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_specifiers::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifier_1 = dynamic_cast(val);break; + case 1: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_list::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_1 = dynamic_cast(val);break; + case 1: newval = ac_declaration_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ac_declaration_AcDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + case 1: newval = ac_init_declarator_list_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparsedeclinfo_Unparsedeclinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternrepresentation_1 = dynamic_cast(val);break; + case 1: newval = patternrepresentation_2 = dynamic_cast(val);break; + case 2: newval = unparseclause_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparsedeclsinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = unparsedeclinfo_1 = dynamic_cast(val);break; + case 1: newval = unparsedeclsinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseviewinfo_Unparseviewinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = unparsedeclsinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseviewsinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = unparseviewinfo_1 = dynamic_cast(val);break; + case 1: newval = unparseviewsinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriteviewinfo_Rewriteviewinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = rewriterulesinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriteviewsinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = rewriteviewinfo_1 = dynamic_cast(val);break; + case 1: newval = rewriteviewsinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withcaseinfo_Withcaseinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternrepresentation_1 = dynamic_cast(val);break; + case 1: newval = patternrepresentation_2 = dynamic_cast(val);break; + case 2: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withcasesinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = withcaseinfo_1 = dynamic_cast(val);break; + case 1: newval = withcasesinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriteruleinfo_Rewriteruleinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternrepresentation_1 = dynamic_cast(val);break; + case 1: newval = patternrepresentation_2 = dynamic_cast(val);break; + case 2: newval = rewriteclause_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriterulesinfo::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = rewriteruleinfo_1 = dynamic_cast(val);break; + case 1: newval = rewriterulesinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_argsnumbers::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + case 1: newval = argsnumbers_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_paths::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = paths_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_path::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + case 1: newval = path_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRIntLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRStringLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRWildcard::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRNonLeafBinding::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = patternrepresentation_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRUserPredicate::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PROperPredicate::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRVarPredicate::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = paths_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = patternrepresentation_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_elem_patternrepresentation_PRBinding::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = path_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternrepresentation::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = elem_patternrepresentation_1 = dynamic_cast(val);break; + case 1: newval = patternrepresentation_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternrepresentations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternrepresentation_1 = dynamic_cast(val);break; + case 1: newval = patternrepresentations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_variables::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = variables_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_phyla::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = phyla_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_operators::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = operators_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITLanguageName::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITPatternVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = integer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITUserFunction::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fnclass_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITUserOperator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternative_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITPredefinedOperator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternative_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITUserPhylum::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = phylumdeclaration_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_IDtype_ITPredefinedPhylum::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = phylumdeclaration_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_scopetypefileline_ScopeTypeFileLine::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + case 1: newval = IDtype_1 = dynamic_cast(val);break; + case 2: newval = casestring_1 = dynamic_cast(val);break; + case 3: newval = integer_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_scopetypefilelinestack::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = scopetypefileline_1 = dynamic_cast(val);break; + case 1: newval = scopetypefilelinestack_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_languagenames::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = languagenames_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_languageoption_LanguageList::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = languagenames_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_viewnameoption_YesViewname::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpattributes::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = unpattributes_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpsubterm_UnpCastedVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ID_2 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpsubterm_UnpDollarvarAttr::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + case 1: newval = unpattributes_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpsubterm_UnpSubAttr::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = unpattributes_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpsubterm_UnpDollarvarTerm::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unpsubterm_UnpSubTerm::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitem_UViewVarDecl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ID_2 = dynamic_cast(val);break; + case 2: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitem_UnpBody::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = languageoption_1 = dynamic_cast(val);break; + case 1: newval = unparseitems_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitem_UnpCtext::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = languageoption_1 = dynamic_cast(val);break; + case 1: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitem_UnpSubexpr::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = languageoption_1 = dynamic_cast(val);break; + case 1: newval = unpsubterm_1 = dynamic_cast(val);break; + case 2: newval = viewnameoption_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitem_UnpStr::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = languageoption_1 = dynamic_cast(val);break; + case 1: newval = CexpressionDQ_1 = dynamic_cast(val);break; + case 2: newval = viewnameoption_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseitems::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = unparseitem_1 = dynamic_cast(val);break; + case 1: newval = unparseitems_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_viewnames::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = viewnames_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseclause_UnparseClause::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = viewnames_1 = dynamic_cast(val);break; + case 1: newval = unparseitems_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparseclauses::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = unparseclause_1 = dynamic_cast(val);break; + case 1: newval = unparseclauses_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparsedeclaration_UnparseDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = outmostpatterns_1 = dynamic_cast(val);break; + case 1: newval = unparseclauses_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_unparsedeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = unparsedeclaration_1 = dynamic_cast(val);break; + case 1: newval = unparsedeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withcase_Withcase::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchains_1 = dynamic_cast(val);break; + case 1: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withcases::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = withcase_1 = dynamic_cast(val);break; + case 1: newval = withcases_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withexpression_WECexpression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withexpression_WEVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_withexpressions::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = withexpression_1 = dynamic_cast(val);break; + case 1: newval = withexpressions_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_contextinfo_InForeachContext::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchain_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_foreach_after_ForeachAfter::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchain_1 = dynamic_cast(val);break; + case 1: newval = idCexpressions_1 = dynamic_cast(val);break; + case 2: newval = withexpressions_1 = dynamic_cast(val);break; + case 3: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextWithexpression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = withexpressions_1 = dynamic_cast(val);break; + case 1: newval = withcases_1 = dynamic_cast(val);break; + case 2: newval = contextinfo_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextForeachexpression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchain_1 = dynamic_cast(val);break; + case 1: newval = idCexpressions_1 = dynamic_cast(val);break; + case 2: newval = withexpressions_1 = dynamic_cast(val);break; + case 3: newval = Ctext_1 = dynamic_cast(val);break; + case 4: newval = foreach_after_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextCbody::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextCexpressionSQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionSQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextCexpressionDQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextNl::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextDollarVar::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext_elem_CTextLine::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctext::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Ctext_elem_1 = dynamic_cast(val);break; + case 1: newval = Ctext_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fnclass_StaticFn::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fndeclaration_AcMemberDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + case 1: newval = ac_declarator_1 = dynamic_cast(val);break; + case 2: newval = ac_constant_expression_option_1 = dynamic_cast(val);break; + case 3: newval = fnclass_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fndeclaration_FnAcDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ac_declaration_specifiers_1 = dynamic_cast(val);break; + case 1: newval = ac_declarator_1 = dynamic_cast(val);break; + case 2: newval = ac_declaration_list_1 = dynamic_cast(val);break; + case 3: newval = ac_opt_base_init_list_1 = dynamic_cast(val);break; + case 4: newval = Ctext_1 = dynamic_cast(val);break; + case 5: newval = ID_1 = dynamic_cast(val);break; + case 6: newval = fnclass_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fndeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fndeclaration_1 = dynamic_cast(val);break; + case 1: newval = fndeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fnfile_FnFile::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_fnfiles::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = fnfile_1 = dynamic_cast(val);break; + case 1: newval = fnfiles_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_terms::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = term_1 = dynamic_cast(val);break; + case 1: newval = terms_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TIntLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TStringLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TCTerm::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionSQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TMemberVarDot::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = term_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TMemberVar::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = term_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TMethodDot::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = term_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = terms_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TMethod::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = term_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + case 2: newval = terms_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TOperator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = terms_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_term_TVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patterns::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = pattern_1 = dynamic_cast(val);break; + case 1: newval = patterns_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_pattern_PIntLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_pattern_PStringLiteral::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_pattern_PNonLeafVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = pattern_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_pattern_POperator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = patterns_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_pattern_PVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpattern_OPDefault::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpattern_OPWildcard::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpattern_OPNonLeafVariable::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = outmostpattern_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpattern_OPOperator::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = patterns_1 = dynamic_cast(val);break; + case 2: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpattern_OPOperatorWildcard::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternchainitem_PatternchainitemDollarid::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternchainitem_PatternchainitemGroup::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchains_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternchainitem_PatternchainitemOutmost::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = outmostpattern_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_outmostpatterns::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = outmostpattern_1 = dynamic_cast(val);break; + case 1: newval = outmostpatterns_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternchain::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchainitem_1 = dynamic_cast(val);break; + case 1: newval = patternchain_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_patternchains::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = patternchain_1 = dynamic_cast(val);break; + case 1: newval = patternchains_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriteclause_RewriteClause::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = viewnames_1 = dynamic_cast(val);break; + case 1: newval = term_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rewriteclauses::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = rewriteclause_1 = dynamic_cast(val);break; + case 1: newval = rewriteclauses_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rwdeclaration_RwDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = outmostpatterns_1 = dynamic_cast(val);break; + case 1: newval = rewriteclauses_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_rwdeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = rwdeclaration_1 = dynamic_cast(val);break; + case 1: newval = rwdeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_includedeclaration_IncludeDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_includedeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = includedeclaration_1 = dynamic_cast(val);break; + case 1: newval = includedeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_includefile_IncludeFile::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_includefiles::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = includefile_1 = dynamic_cast(val);break; + case 1: newval = includefiles_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ctexts::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Ctext_1 = dynamic_cast(val);break; + case 1: newval = Ctexts_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_idCexpression_IdCexpression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_idCexpressions::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = idCexpression_1 = dynamic_cast(val);break; + case 1: newval = idCexpressions_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_CexpressionSQ_elem_CExpressionSQPart::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_CexpressionSQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionSQ_elem_1 = dynamic_cast(val);break; + case 1: newval = CexpressionSQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_CexpressionDQ_elem_CExpressionDQPart::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_CexpressionDQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionDQ_elem_1 = dynamic_cast(val);break; + case 1: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionArray::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionPack::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionSQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionSQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionDQ::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = CexpressionDQ_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionDollarvar::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = INT_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression_elem_CExpressionPart::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Cexpression::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_elem_1 = dynamic_cast(val);break; + case 1: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_attribute_initialisation_option_Yesattribute_initialisation::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = Cexpression_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_attribute_Attribute::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = ID_2 = dynamic_cast(val);break; + case 2: newval = attribute_initialisation_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_attributes::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = attribute_1 = dynamic_cast(val);break; + case 1: newval = attributes_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_Ccode_option_CcodeOption::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = attributes_1 = dynamic_cast(val);break; + case 1: newval = Ctexts_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_argument_Argument::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = integer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_arguments::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = arguments_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_alternative_Alternative::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = arguments_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_alternatives::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternative_1 = dynamic_cast(val);break; + case 1: newval = alternatives_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_productionblock_PredefinedAlternatives::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternatives_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_productionblock_NonlistAlternatives::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternatives_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_productionblock_ListAlternatives::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = alternatives_1 = dynamic_cast(val);break; + case 1: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_storageclasses::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = storageclasses_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_storageoption_PositiveStorageOption::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_storageoption_NegativeStorageOption::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_phylumdeclaration_PhylumDeclaration::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = storageoption_1 = dynamic_cast(val);break; + case 2: newval = productionblock_1 = dynamic_cast(val);break; + case 3: newval = Ccode_option_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_phylumnames::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = ID_1 = dynamic_cast(val);break; + case 1: newval = phylumnames_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_phylumdeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = phylumdeclaration_1 = dynamic_cast(val);break; + case 1: newval = phylumdeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_phylumdeclarationsroot_PhylumDeclarations::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = phylumdeclarations_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_STRING_String::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_INT_Int::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = integer_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_ID_Id::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = uniqID_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + void impl_uniqID_Str::set_subphylum(int no, abstract_phylum val) + { + abstract_phylum newval=0; + switch(no) { + case 0: newval = casestring_1 = dynamic_cast(val);break; + } + assertNonNull(newval); + } + + void + copy_attributes(enum_phyla copyPhy, c_abstract_phylum kc_p1, abstract_phylum kc_p2) + { + switch(copyPhy) { + case phylum_uniqID: { + c_uniqID p1 = dynamic_cast(kc_p1); + uniqID p2 = dynamic_cast(kc_p2); + p2->type = p1->type; + p2->line = p1->line; + p2->file = p1->file; + p2->scopeinfo = p1->scopeinfo; + break; + } + case phylum_ID: { + c_ID p1 = dynamic_cast(kc_p1); + ID p2 = dynamic_cast(kc_p2); + p2->type = p1->type; + p2->named_subphylum = p1->named_subphylum; + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_INT: { + c_INT p1 = dynamic_cast(kc_p1); + INT p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_STRING: { + c_STRING p1 = dynamic_cast(kc_p1); + STRING p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_phylumdeclaration: { + c_phylumdeclaration p1 = dynamic_cast(kc_p1); + phylumdeclaration p2 = dynamic_cast(kc_p2); + p2->marked = p1->marked; + p2->additional_members = p1->additional_members; + p2->base_classes = p1->base_classes; + break; + } + case phylum_storageclasses: + dynamic_cast(kc_p2)->phyla = dynamic_cast(kc_p1)->phyla; + break; + case phylum_alternative: { + c_alternative p1 = dynamic_cast(kc_p1); + alternative p2 = dynamic_cast(kc_p2); + p2->rewriteinfo = p1->rewriteinfo; + p2->unparseinfo = p1->unparseinfo; + p2->additional_members = p1->additional_members; + p2->base_classes = p1->base_classes; + break; + } + case phylum_arguments: + dynamic_cast(kc_p2)->seqnr = dynamic_cast(kc_p1)->seqnr; + break; + case phylum_Cexpression: { + c_Cexpression p1 = dynamic_cast(kc_p1); + Cexpression p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_idCexpression: + dynamic_cast(kc_p2)->id = dynamic_cast(kc_p1)->id; + break; + case phylum_includefile: { + c_includefile p1 = dynamic_cast(kc_p1); + includefile p2 = dynamic_cast(kc_p2); + p2->inc_type = p1->inc_type; + p2->inc = p1->inc; + break; + } + case phylum_includedeclaration: { + c_includedeclaration p1 = dynamic_cast(kc_p1); + includedeclaration p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_patternchains: { + c_patternchains p1 = dynamic_cast(kc_p1); + patternchains p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_patternchain: { + c_patternchain p1 = dynamic_cast(kc_p1); + patternchain p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_patternchainitem: { + c_patternchainitem p1 = dynamic_cast(kc_p1); + patternchainitem p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + p2->type = p1->type; + break; + } + case phylum_outmostpattern: { + c_outmostpattern p1 = dynamic_cast(kc_p1); + outmostpattern p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + p2->type = p1->type; + break; + } + case phylum_term: { + c_term p1 = dynamic_cast(kc_p1); + term p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_fnfile: + dynamic_cast(kc_p2)->fns = dynamic_cast(kc_p1)->fns; + break; + case phylum_fndeclaration: { + c_fndeclaration p1 = dynamic_cast(kc_p1); + fndeclaration p2 = dynamic_cast(kc_p2); + p2->sorted = p1->sorted; + p2->last_line = p1->last_line; + p2->file = p1->file; + p2->is_attr = p1->is_attr; + break; + } + case phylum_Ctext: { + c_Ctext p1 = dynamic_cast(kc_p1); + Ctext p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_Ctext_elem: { + c_Ctext_elem p1 = dynamic_cast(kc_p1); + Ctext_elem p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_foreach_after: { + c_foreach_after p1 = dynamic_cast(kc_p1); + foreach_after p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_withexpressions: { + c_withexpressions p1 = dynamic_cast(kc_p1); + withexpressions p2 = dynamic_cast(kc_p2); + p2->type = p1->type; + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_withexpression: { + c_withexpression p1 = dynamic_cast(kc_p1); + withexpression p2 = dynamic_cast(kc_p2); + p2->type = p1->type; + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_withcases: + dynamic_cast(kc_p2)->wcinfo = dynamic_cast(kc_p1)->wcinfo; + break; + case phylum_withcase: + dynamic_cast(kc_p2)->wcinfo = dynamic_cast(kc_p1)->wcinfo; + break; + case phylum_unparsedeclaration: + dynamic_cast(kc_p2)->patternreps = dynamic_cast(kc_p1)->patternreps; + break; + case phylum_viewnames: + dynamic_cast(kc_p2)->is_extern = dynamic_cast(kc_p1)->is_extern; + break; + case phylum_unparseitem: + dynamic_cast(kc_p2)->text_nr = dynamic_cast(kc_p1)->text_nr; + break; + case phylum_fileline: { + c_fileline p1 = dynamic_cast(kc_p1); + fileline p2 = dynamic_cast(kc_p2); + p2->file = p1->file; + p2->line = p1->line; + break; + } + case phylum_elem_patternrepresentation: { + c_elem_patternrepresentation p1 = dynamic_cast(kc_p1); + elem_patternrepresentation p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + p2->type = p1->type; + break; + } + case phylum_path: { + c_path p1 = dynamic_cast(kc_p1); + path p2 = dynamic_cast(kc_p2); + p2->op = p1->op; + p2->id = p1->id; + break; + } + case phylum_ac_operator_name: { + c_ac_operator_name p1 = dynamic_cast(kc_p1); + ac_operator_name p2 = dynamic_cast(kc_p2); + p2->line = p1->line; + p2->file = p1->file; + break; + } + case phylum_addedphylumdeclaration: + dynamic_cast(kc_p2)->added = dynamic_cast(kc_p1)->added; + break; + case phylum_countedphylumdeclaration: + dynamic_cast(kc_p2)->count = dynamic_cast(kc_p1)->count; + break; + case phylum_charruns: + dynamic_cast(kc_p2)->number = dynamic_cast(kc_p1)->number; + break; + case phylum_bindingidmark: + dynamic_cast(kc_p2)->marked = dynamic_cast(kc_p1)->marked; + break; + case one_before_first_phylum: // just to avoid a warning about missing case if empty + default: + break; // it's alright, no attributes to copy + } + enum_operators copyOp=kc_p1->prod_sel(); + for (int i=operator_info[copyOp].no_attrs-1; i>=0; --i) + attributeOf(kc_p2, i)=attributeOf(const_cast(kc_p1), i); + } + + KC_PHYLUM_INFO phylum_info[] = { + { "", one_before_first_operator, one_before_first_operator, (kc_storageclass_t)0 }, /* dummy element */ + { "nocasestring", sel_NoCaseStr, sel_NoCaseStr, uniq }, + { "casestring", sel__Str, sel__Str, uniq }, + { "real", sel__Real, sel__Real, uniq }, + { "integer", sel__Int, sel__Int, uniq }, + { "voidptr", sel__VoidPtr, sel__VoidPtr, uniq }, + { "uniqID", sel_Str, sel_Str, uniq }, + { "ID", sel_Id, sel_Id, kc_not_uniq }, + { "INT", sel_Int, sel_Int, kc_not_uniq }, + { "STRING", sel_String, sel_String, kc_not_uniq }, + { "phylumdeclarationsroot", sel_PhylumDeclarations, sel_PhylumDeclarations, kc_not_uniq }, + { "phylumdeclarations", sel_Nilphylumdeclarations, sel_Consphylumdeclarations, kc_not_uniq }, + { "phylumnames", sel_Nilphylumnames, sel_Consphylumnames, kc_not_uniq }, + { "phylumdeclaration", sel_PhylumDeclaration, sel_PhylumDeclaration, kc_not_uniq }, + { "storageoption", sel_NoStorageOption, sel_PositiveStorageOption, kc_not_uniq }, + { "storageclasses", sel_Nilstorageclasses, sel_Consstorageclasses, kc_not_uniq }, + { "productionblock", sel_Emptyproductionblock, sel_PredefinedAlternatives, kc_not_uniq }, + { "alternatives", sel_Nilalternatives, sel_Consalternatives, kc_not_uniq }, + { "alternative", sel_Alternative, sel_Alternative, kc_not_uniq }, + { "arguments", sel_Nilarguments, sel_Consarguments, kc_not_uniq }, + { "argument", sel_Argument, sel_Argument, kc_not_uniq }, + { "Ccode_option", sel_CcodeOption, sel_CcodeOption, kc_not_uniq }, + { "attributes", sel_Nilattributes, sel_Consattributes, kc_not_uniq }, + { "attribute", sel_Attribute, sel_Attribute, kc_not_uniq }, + { "attribute_initialisation_option", sel_Noattribute_initialisation, sel_Yesattribute_initialisation, kc_not_uniq }, + { "Cexpression", sel_NilCexpression, sel_ConsCexpression, kc_not_uniq }, + { "Cexpression_elem", sel_CExpressionPart, sel_CExpressionArray, kc_not_uniq }, + { "CexpressionDQ", sel_NilCexpressionDQ, sel_ConsCexpressionDQ, kc_not_uniq }, + { "CexpressionDQ_elem", sel_CExpressionDQPart, sel_CExpressionDQNl, kc_not_uniq }, + { "CexpressionSQ", sel_NilCexpressionSQ, sel_ConsCexpressionSQ, kc_not_uniq }, + { "CexpressionSQ_elem", sel_CExpressionSQPart, sel_CExpressionSQNl, kc_not_uniq }, + { "idCexpressions", sel_NilidCexpressions, sel_ConsidCexpressions, kc_not_uniq }, + { "idCexpression", sel_IdCexpression, sel_IdCexpression, kc_not_uniq }, + { "Ctexts", sel_NilCtexts, sel_ConsCtexts, kc_not_uniq }, + { "includefiles", sel_Nilincludefiles, sel_Consincludefiles, kc_not_uniq }, + { "includefile", sel_IncludeFile, sel_IncludeFile, uniq }, + { "includedeclarations", sel_Nilincludedeclarations, sel_Consincludedeclarations, kc_not_uniq }, + { "includedeclaration", sel_IncludeDeclaration, sel_IncludeDeclaration, kc_not_uniq }, + { "rwdeclarations", sel_Nilrwdeclarations, sel_Consrwdeclarations, kc_not_uniq }, + { "rwdeclaration", sel_RwDeclaration, sel_RwDeclaration, kc_not_uniq }, + { "rewriteclauses", sel_Nilrewriteclauses, sel_Consrewriteclauses, kc_not_uniq }, + { "rewriteclause", sel_RewriteClause, sel_RewriteClause, kc_not_uniq }, + { "patternchains", sel_Nilpatternchains, sel_Conspatternchains, kc_not_uniq }, + { "patternchain", sel_Nilpatternchain, sel_Conspatternchain, kc_not_uniq }, + { "outmostpatterns", sel_Niloutmostpatterns, sel_Consoutmostpatterns, kc_not_uniq }, + { "patternchainitem", sel_PatternchainitemOutmost, sel_PatternchainitemDollarid, kc_not_uniq }, + { "outmostpattern", sel_OPOperatorWildcard, sel_OPDefault, kc_not_uniq }, + { "pattern", sel_PVariable, sel_PIntLiteral, kc_not_uniq }, + { "patterns", sel_Nilpatterns, sel_Conspatterns, kc_not_uniq }, + { "term", sel_TVariable, sel_TIntLiteral, kc_not_uniq }, + { "terms", sel_Nilterms, sel_Consterms, kc_not_uniq }, + { "fnfiles", sel_Nilfnfiles, sel_Consfnfiles, kc_not_uniq }, + { "fnfile", sel_FnFile, sel_FnFile, uniq }, + { "fndeclarations", sel_Nilfndeclarations, sel_Consfndeclarations, kc_not_uniq }, + { "fndeclaration", sel_FnAcDeclaration, sel_AcMemberDeclaration, kc_not_uniq }, + { "fnclass", sel_GlobalFn, sel_ConvOperatorFn, kc_not_uniq }, + { "Ctext", sel_NilCtext, sel_ConsCtext, kc_not_uniq }, + { "Ctext_elem", sel_CTextLine, sel_CTextWithexpression, kc_not_uniq }, + { "foreach_after", sel_NoForeachAfter, sel_ForeachAfter, kc_not_uniq }, + { "contextinfo", sel_InForeachContext, sel_NotInForeachContext, kc_not_uniq }, + { "withexpressions", sel_Nilwithexpressions, sel_Conswithexpressions, kc_not_uniq }, + { "withexpression", sel_WEVariable, sel_WECexpression, kc_not_uniq }, + { "withcases", sel_Nilwithcases, sel_Conswithcases, kc_not_uniq }, + { "withcase", sel_Withcase, sel_Withcase, kc_not_uniq }, + { "unparsedeclarations", sel_Nilunparsedeclarations, sel_Consunparsedeclarations, kc_not_uniq }, + { "unparsedeclaration", sel_UnparseDeclaration, sel_UnparseDeclaration, kc_not_uniq }, + { "unparseclauses", sel_Nilunparseclauses, sel_Consunparseclauses, kc_not_uniq }, + { "unparseclause", sel_UnparseClause, sel_UnparseClause, kc_not_uniq }, + { "viewnames", sel_Nilviewnames, sel_Consviewnames, kc_not_uniq }, + { "unparseitems", sel_Nilunparseitems, sel_Consunparseitems, kc_not_uniq }, + { "unparseitem", sel_UnpStr, sel_UViewVarDecl, kc_not_uniq }, + { "unpsubterm", sel_UnpSubTerm, sel_UnpCastedVariable, kc_not_uniq }, + { "unpattributes", sel_Nilunpattributes, sel_Consunpattributes, kc_not_uniq }, + { "viewnameoption", sel_NoViewname, sel_YesViewname, kc_not_uniq }, + { "languageoption", sel_NoLanguagename, sel_LanguageList, kc_not_uniq }, + { "languagenames", sel_Nillanguagenames, sel_Conslanguagenames, kc_not_uniq }, + { "fileline", sel_FileLine, sel_PosNoFileLine, kc_not_uniq }, + { "scopetypefilelinestack", sel_Nilscopetypefilelinestack, sel_Consscopetypefilelinestack, kc_not_uniq }, + { "scopetypefileline", sel_ScopeTypeFileLine, sel_ScopeTypeFileLine, kc_not_uniq }, + { "IDtype", sel_ITUnknown, sel_ITLanguageName, kc_not_uniq }, + { "operators", sel_Niloperators, sel_Consoperators, kc_not_uniq }, + { "phyla", sel_Nilphyla, sel_Consphyla, kc_not_uniq }, + { "variables", sel_Nilvariables, sel_Consvariables, kc_not_uniq }, + { "dollarvarstatus", sel_DVAllowed, sel_DVDisallowed, kc_not_uniq }, + { "tribool", sel_Equal, sel_Bigger, kc_not_uniq }, + { "patternrepresentations", sel_Nilpatternrepresentations, sel_Conspatternrepresentations, kc_not_uniq }, + { "patternrepresentation", sel_Nilpatternrepresentation, sel_Conspatternrepresentation, kc_not_uniq }, + { "elem_patternrepresentation", sel_PRBinding, sel_PRIntLiteral, kc_not_uniq }, + { "path", sel_Nilpath, sel_Conspath, kc_not_uniq }, + { "paths", sel_Nilpaths, sel_Conspaths, kc_not_uniq }, + { "argsnumbers", sel_Nilargsnumbers, sel_Consargsnumbers, kc_not_uniq }, + { "rewriterulesinfo", sel_Nilrewriterulesinfo, sel_Consrewriterulesinfo, kc_not_uniq }, + { "rewriteruleinfo", sel_Rewriteruleinfo, sel_Rewriteruleinfo, kc_not_uniq }, + { "withcasesinfo", sel_Nilwithcasesinfo, sel_Conswithcasesinfo, kc_not_uniq }, + { "withcaseinfo", sel_Withcaseinfo, sel_Withcaseinfo, kc_not_uniq }, + { "rewriteviewsinfo", sel_Nilrewriteviewsinfo, sel_Consrewriteviewsinfo, kc_not_uniq }, + { "rewriteviewinfo", sel_Rewriteviewinfo, sel_Rewriteviewinfo, kc_not_uniq }, + { "unparseviewsinfo", sel_Nilunparseviewsinfo, sel_Consunparseviewsinfo, kc_not_uniq }, + { "unparseviewinfo", sel_Unparseviewinfo, sel_Unparseviewinfo, kc_not_uniq }, + { "unparsedeclsinfo", sel_Nilunparsedeclsinfo, sel_Consunparsedeclsinfo, kc_not_uniq }, + { "unparsedeclinfo", sel_Unparsedeclinfo, sel_Unparsedeclinfo, kc_not_uniq }, + { "ac_declaration", sel_AcDeclaration, sel_AcDeclaration, kc_not_uniq }, + { "ac_declaration_list", sel_Nilac_declaration_list, sel_Consac_declaration_list, kc_not_uniq }, + { "ac_declaration_specifiers", sel_Nilac_declaration_specifiers, sel_Consac_declaration_specifiers, kc_not_uniq }, + { "ac_declaration_specifier", sel_AcDeclSpecStorageSpec, sel_AcDeclSpecTypeQual, kc_not_uniq }, + { "ac_storage_class_specifier", sel_AcAuto, sel_AcVirtual, kc_not_uniq }, + { "ac_type_specifier", sel_AcTypeSpec, sel_AcTypeSpec, kc_not_uniq }, + { "ac_type_qualifier", sel_AcConst, sel_AcNoQualifier, kc_not_uniq }, + { "ac_init_declarator_list", sel_Nilac_init_declarator_list, sel_Consac_init_declarator_list, kc_not_uniq }, + { "ac_init_declarator", sel_AcInitDecl, sel_AcInitDecl, kc_not_uniq }, + { "ac_declarator", sel_AcDeclarator, sel_AcDeclarator, kc_not_uniq }, + { "ac_direct_declarator", sel_AcDirectDeclId, sel_AcOperatorDeclId, kc_not_uniq }, + { "ac_pointer_option", sel_Nopointer, sel_Yespointer, kc_not_uniq }, + { "ac_pointer", sel_AcPointerNil, sel_AcPointerCons, kc_not_uniq }, + { "ac_ref_option", sel_AcNoRef, sel_AcRef, kc_not_uniq }, + { "ac_operator_name", sel_AcOperatorName, sel_AcOperatorName, kc_not_uniq }, + { "ac_class_qualifier_help_list", sel_Nilac_class_qualifier_help_list, sel_Consac_class_qualifier_help_list, kc_not_uniq }, + { "ac_class_qualifier_list", sel_Nilac_class_qualifier_list, sel_Consac_class_qualifier_list, kc_not_uniq }, + { "ac_type_qualifier_list", sel_Nilac_type_qualifier_list, sel_Consac_type_qualifier_list, kc_not_uniq }, + { "ac_parameter_type_list", sel_AcParList, sel_AcParList3Dot, kc_not_uniq }, + { "ac_parameter_list", sel_Nilac_parameter_list, sel_Consac_parameter_list, kc_not_uniq }, + { "ac_parameter_declaration", sel_AcParDeclDecl, sel_AcParDeclAbsdecl, kc_not_uniq }, + { "ac_identifier_list", sel_Nilac_identifier_list, sel_Consac_identifier_list, kc_not_uniq }, + { "ac_abstract_declarator", sel_AcAbsdeclPointer, sel_AcAbsdeclDirdecl, kc_not_uniq }, + { "ac_direct_abstract_declarator_option", sel_Noac_direct_abstract_declarator, sel_Yesac_direct_abstract_declarator, kc_not_uniq }, + { "ac_direct_abstract_declarator", sel_AcDirAbsdeclPack, sel_AcDirAbsdeclFn, kc_not_uniq }, + { "ac_constant_expression_option", sel_Yesac_constant_expression, sel_Noac_constant_expression, kc_not_uniq }, + { "ac_constant_expression", sel_AcConstExpr, sel_AcConstExpr, kc_not_uniq }, + { "ac_constant_expression_list", sel_Nilac_constant_expression_list, sel_Consac_constant_expression_list, kc_not_uniq }, + { "ac_opt_base_init_list", sel_AcNoBaseInit, sel_AcYesBaseInit, kc_not_uniq }, + { "ac_base_init_list", sel_Nilac_base_init_list, sel_Consac_base_init_list, kc_not_uniq }, + { "ac_base_init", sel_AcBaseInit, sel_AcBaseInit, kc_not_uniq }, + { "baseclass_declarations", sel_Nilbaseclass_declarations, sel_Consbaseclass_declarations, kc_not_uniq }, + { "baseclass_decl", sel_BaseClassDecl, sel_BaseClassDecl, kc_not_uniq }, + { "baseclass_list", sel_Nilbaseclass_list, sel_Consbaseclass_list, kc_not_uniq }, + { "error", sel_Fatal, sel_Warning, kc_not_uniq }, + { "problem", sel_Problem1, sel_Problem6, kc_not_uniq }, + { "addedphylumdeclarations", sel_Niladdedphylumdeclarations, sel_Consaddedphylumdeclarations, kc_not_uniq }, + { "addedphylumdeclaration", sel_AddedPhylumdeclaration, sel_AddedPhylumdeclaration, kc_not_uniq }, + { "countedphylumdeclarations", sel_Nilcountedphylumdeclarations, sel_Conscountedphylumdeclarations, kc_not_uniq }, + { "countedphylumdeclaration", sel_CountedPhylumdeclaration, sel_CountedPhylumdeclaration, uniq }, + { "charruns", sel_Newlines, sel_Stars, uniq }, + { "bindingidmarks", sel_Nilbindingidmarks, sel_Consbindingidmarks, uniq }, + { "bindingidmark", sel_BindingIdMark, sel_BindingIdMark, uniq }, + { "", one_before_first_operator, one_before_first_operator, (kc_storageclass_t)0 } /* last element */ + }; + + static enum_phyla kc_subphyla_Str[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Id[] = { phylum_uniqID }; + static enum_phyla kc_subphyla_Int[] = { phylum_integer }; + static enum_phyla kc_subphyla_String[] = { phylum_casestring }; + static enum_phyla kc_subphyla_PhylumDeclarations[] = { phylum_phylumdeclarations }; + static enum_phyla kc_subphyla_Consphylumdeclarations[] = { phylum_phylumdeclaration, phylum_phylumdeclarations }; + static enum_phyla kc_subphyla_Consphylumnames[] = { phylum_ID, phylum_phylumnames }; + static enum_phyla kc_subphyla_PhylumDeclaration[] = { phylum_ID, phylum_storageoption, phylum_productionblock, phylum_Ccode_option }; + static enum_phyla kc_subphyla_NegativeStorageOption[] = { phylum_ID }; + static enum_phyla kc_subphyla_PositiveStorageOption[] = { phylum_ID }; + static enum_phyla kc_subphyla_Consstorageclasses[] = { phylum_ID, phylum_storageclasses }; + static enum_phyla kc_subphyla_ListAlternatives[] = { phylum_alternatives, phylum_ID }; + static enum_phyla kc_subphyla_NonlistAlternatives[] = { phylum_alternatives }; + static enum_phyla kc_subphyla_PredefinedAlternatives[] = { phylum_alternatives }; + static enum_phyla kc_subphyla_Consalternatives[] = { phylum_alternative, phylum_alternatives }; + static enum_phyla kc_subphyla_Alternative[] = { phylum_ID, phylum_arguments }; + static enum_phyla kc_subphyla_Consarguments[] = { phylum_ID, phylum_arguments }; + static enum_phyla kc_subphyla_Argument[] = { phylum_ID, phylum_integer }; + static enum_phyla kc_subphyla_CcodeOption[] = { phylum_attributes, phylum_Ctexts }; + static enum_phyla kc_subphyla_Consattributes[] = { phylum_attribute, phylum_attributes }; + static enum_phyla kc_subphyla_Attribute[] = { phylum_ID, phylum_ID, phylum_attribute_initialisation_option }; + static enum_phyla kc_subphyla_Yesattribute_initialisation[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_ConsCexpression[] = { phylum_Cexpression_elem, phylum_Cexpression }; + static enum_phyla kc_subphyla_CExpressionPart[] = { phylum_casestring }; + static enum_phyla kc_subphyla_CExpressionDollarvar[] = { phylum_INT }; + static enum_phyla kc_subphyla_CExpressionDQ[] = { phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_CExpressionSQ[] = { phylum_CexpressionSQ }; + static enum_phyla kc_subphyla_CExpressionPack[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_CExpressionArray[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_ConsCexpressionDQ[] = { phylum_CexpressionDQ_elem, phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_CExpressionDQPart[] = { phylum_casestring }; + static enum_phyla kc_subphyla_ConsCexpressionSQ[] = { phylum_CexpressionSQ_elem, phylum_CexpressionSQ }; + static enum_phyla kc_subphyla_CExpressionSQPart[] = { phylum_casestring }; + static enum_phyla kc_subphyla_ConsidCexpressions[] = { phylum_idCexpression, phylum_idCexpressions }; + static enum_phyla kc_subphyla_IdCexpression[] = { phylum_ID, phylum_Cexpression }; + static enum_phyla kc_subphyla_ConsCtexts[] = { phylum_Ctext, phylum_Ctexts }; + static enum_phyla kc_subphyla_Consincludefiles[] = { phylum_includefile, phylum_includefiles }; + static enum_phyla kc_subphyla_IncludeFile[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Consincludedeclarations[] = { phylum_includedeclaration, phylum_includedeclarations }; + static enum_phyla kc_subphyla_IncludeDeclaration[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Consrwdeclarations[] = { phylum_rwdeclaration, phylum_rwdeclarations }; + static enum_phyla kc_subphyla_RwDeclaration[] = { phylum_outmostpatterns, phylum_rewriteclauses }; + static enum_phyla kc_subphyla_Consrewriteclauses[] = { phylum_rewriteclause, phylum_rewriteclauses }; + static enum_phyla kc_subphyla_RewriteClause[] = { phylum_viewnames, phylum_term }; + static enum_phyla kc_subphyla_Conspatternchains[] = { phylum_patternchain, phylum_patternchains }; + static enum_phyla kc_subphyla_Conspatternchain[] = { phylum_patternchainitem, phylum_patternchain }; + static enum_phyla kc_subphyla_Consoutmostpatterns[] = { phylum_outmostpattern, phylum_outmostpatterns }; + static enum_phyla kc_subphyla_PatternchainitemOutmost[] = { phylum_outmostpattern }; + static enum_phyla kc_subphyla_PatternchainitemGroup[] = { phylum_patternchains }; + static enum_phyla kc_subphyla_PatternchainitemDollarid[] = { phylum_ID }; + static enum_phyla kc_subphyla_OPOperatorWildcard[] = { phylum_ID, phylum_Cexpression }; + static enum_phyla kc_subphyla_OPOperator[] = { phylum_ID, phylum_patterns, phylum_Cexpression }; + static enum_phyla kc_subphyla_OPNonLeafVariable[] = { phylum_ID, phylum_outmostpattern }; + static enum_phyla kc_subphyla_OPWildcard[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_OPDefault[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_PVariable[] = { phylum_ID }; + static enum_phyla kc_subphyla_POperator[] = { phylum_ID, phylum_patterns }; + static enum_phyla kc_subphyla_PNonLeafVariable[] = { phylum_ID, phylum_pattern }; + static enum_phyla kc_subphyla_PStringLiteral[] = { phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_PIntLiteral[] = { phylum_INT }; + static enum_phyla kc_subphyla_Conspatterns[] = { phylum_pattern, phylum_patterns }; + static enum_phyla kc_subphyla_TVariable[] = { phylum_ID }; + static enum_phyla kc_subphyla_TOperator[] = { phylum_ID, phylum_terms }; + static enum_phyla kc_subphyla_TMethod[] = { phylum_term, phylum_ID, phylum_terms }; + static enum_phyla kc_subphyla_TMethodDot[] = { phylum_term, phylum_ID, phylum_terms }; + static enum_phyla kc_subphyla_TMemberVar[] = { phylum_term, phylum_ID }; + static enum_phyla kc_subphyla_TMemberVarDot[] = { phylum_term, phylum_ID }; + static enum_phyla kc_subphyla_TCTerm[] = { phylum_CexpressionSQ }; + static enum_phyla kc_subphyla_TStringLiteral[] = { phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_TIntLiteral[] = { phylum_INT }; + static enum_phyla kc_subphyla_Consterms[] = { phylum_term, phylum_terms }; + static enum_phyla kc_subphyla_Consfnfiles[] = { phylum_fnfile, phylum_fnfiles }; + static enum_phyla kc_subphyla_FnFile[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Consfndeclarations[] = { phylum_fndeclaration, phylum_fndeclarations }; + static enum_phyla kc_subphyla_FnAcDeclaration[] = { phylum_ac_declaration_specifiers, phylum_ac_declarator, phylum_ac_declaration_list, phylum_ac_opt_base_init_list, phylum_Ctext, phylum_ID, phylum_fnclass }; + static enum_phyla kc_subphyla_AcMemberDeclaration[] = { phylum_ac_declaration_specifiers, phylum_ac_declarator, phylum_ac_constant_expression_option, phylum_fnclass }; + static enum_phyla kc_subphyla_StaticFn[] = { phylum_casestring }; + static enum_phyla kc_subphyla_ConsCtext[] = { phylum_Ctext_elem, phylum_Ctext }; + static enum_phyla kc_subphyla_CTextLine[] = { phylum_casestring }; + static enum_phyla kc_subphyla_CTextDollarVar[] = { phylum_INT }; + static enum_phyla kc_subphyla_CTextNl[] = { phylum_integer }; + static enum_phyla kc_subphyla_CTextCexpressionDQ[] = { phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_CTextCexpressionSQ[] = { phylum_CexpressionSQ }; + static enum_phyla kc_subphyla_CTextCbody[] = { phylum_Ctext }; + static enum_phyla kc_subphyla_CTextForeachexpression[] = { phylum_patternchain, phylum_idCexpressions, phylum_withexpressions, phylum_Ctext, phylum_foreach_after }; + static enum_phyla kc_subphyla_CTextWithexpression[] = { phylum_withexpressions, phylum_withcases, phylum_contextinfo }; + static enum_phyla kc_subphyla_ForeachAfter[] = { phylum_patternchain, phylum_idCexpressions, phylum_withexpressions, phylum_Ctext }; + static enum_phyla kc_subphyla_InForeachContext[] = { phylum_patternchain }; + static enum_phyla kc_subphyla_Conswithexpressions[] = { phylum_withexpression, phylum_withexpressions }; + static enum_phyla kc_subphyla_WEVariable[] = { phylum_ID }; + static enum_phyla kc_subphyla_WECexpression[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_Conswithcases[] = { phylum_withcase, phylum_withcases }; + static enum_phyla kc_subphyla_Withcase[] = { phylum_patternchains, phylum_Ctext }; + static enum_phyla kc_subphyla_Consunparsedeclarations[] = { phylum_unparsedeclaration, phylum_unparsedeclarations }; + static enum_phyla kc_subphyla_UnparseDeclaration[] = { phylum_outmostpatterns, phylum_unparseclauses }; + static enum_phyla kc_subphyla_Consunparseclauses[] = { phylum_unparseclause, phylum_unparseclauses }; + static enum_phyla kc_subphyla_UnparseClause[] = { phylum_viewnames, phylum_unparseitems }; + static enum_phyla kc_subphyla_Consviewnames[] = { phylum_ID, phylum_viewnames }; + static enum_phyla kc_subphyla_Consunparseitems[] = { phylum_unparseitem, phylum_unparseitems }; + static enum_phyla kc_subphyla_UnpStr[] = { phylum_languageoption, phylum_CexpressionDQ, phylum_viewnameoption }; + static enum_phyla kc_subphyla_UnpSubexpr[] = { phylum_languageoption, phylum_unpsubterm, phylum_viewnameoption }; + static enum_phyla kc_subphyla_UnpCtext[] = { phylum_languageoption, phylum_Ctext }; + static enum_phyla kc_subphyla_UnpBody[] = { phylum_languageoption, phylum_unparseitems }; + static enum_phyla kc_subphyla_UViewVarDecl[] = { phylum_ID, phylum_ID, phylum_Cexpression }; + static enum_phyla kc_subphyla_UnpSubTerm[] = { phylum_ID }; + static enum_phyla kc_subphyla_UnpDollarvarTerm[] = { phylum_INT }; + static enum_phyla kc_subphyla_UnpSubAttr[] = { phylum_ID, phylum_unpattributes }; + static enum_phyla kc_subphyla_UnpDollarvarAttr[] = { phylum_INT, phylum_unpattributes }; + static enum_phyla kc_subphyla_UnpCastedVariable[] = { phylum_ID, phylum_ID }; + static enum_phyla kc_subphyla_Consunpattributes[] = { phylum_ID, phylum_unpattributes }; + static enum_phyla kc_subphyla_YesViewname[] = { phylum_ID }; + static enum_phyla kc_subphyla_LanguageList[] = { phylum_languagenames }; + static enum_phyla kc_subphyla_Conslanguagenames[] = { phylum_ID, phylum_languagenames }; + static enum_phyla kc_subphyla_Consscopetypefilelinestack[] = { phylum_scopetypefileline, phylum_scopetypefilelinestack }; + static enum_phyla kc_subphyla_ScopeTypeFileLine[] = { phylum_integer, phylum_IDtype, phylum_casestring, phylum_integer }; + static enum_phyla kc_subphyla_ITPredefinedPhylum[] = { phylum_phylumdeclaration }; + static enum_phyla kc_subphyla_ITUserPhylum[] = { phylum_phylumdeclaration }; + static enum_phyla kc_subphyla_ITPredefinedOperator[] = { phylum_alternative, phylum_ID }; + static enum_phyla kc_subphyla_ITUserOperator[] = { phylum_alternative, phylum_ID }; + static enum_phyla kc_subphyla_ITUserFunction[] = { phylum_fnclass }; + static enum_phyla kc_subphyla_ITPatternVariable[] = { phylum_ID, phylum_integer }; + static enum_phyla kc_subphyla_ITLanguageName[] = { phylum_integer }; + static enum_phyla kc_subphyla_Consoperators[] = { phylum_ID, phylum_operators }; + static enum_phyla kc_subphyla_Consphyla[] = { phylum_ID, phylum_phyla }; + static enum_phyla kc_subphyla_Consvariables[] = { phylum_ID, phylum_variables }; + static enum_phyla kc_subphyla_Conspatternrepresentations[] = { phylum_patternrepresentation, phylum_patternrepresentations }; + static enum_phyla kc_subphyla_Conspatternrepresentation[] = { phylum_elem_patternrepresentation, phylum_patternrepresentation }; + static enum_phyla kc_subphyla_PRBinding[] = { phylum_path, phylum_ID }; + static enum_phyla kc_subphyla_PRVarPredicate[] = { phylum_paths, phylum_ID, phylum_patternrepresentation }; + static enum_phyla kc_subphyla_PROperPredicate[] = { phylum_path, phylum_ID }; + static enum_phyla kc_subphyla_PRUserPredicate[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_PRNonLeafBinding[] = { phylum_path, phylum_ID, phylum_patternrepresentation }; + static enum_phyla kc_subphyla_PRWildcard[] = { phylum_path }; + static enum_phyla kc_subphyla_PRStringLiteral[] = { phylum_path, phylum_CexpressionDQ }; + static enum_phyla kc_subphyla_PRIntLiteral[] = { phylum_path, phylum_INT }; + static enum_phyla kc_subphyla_Conspath[] = { phylum_integer, phylum_path }; + static enum_phyla kc_subphyla_Conspaths[] = { phylum_path, phylum_paths }; + static enum_phyla kc_subphyla_Consargsnumbers[] = { phylum_integer, phylum_argsnumbers }; + static enum_phyla kc_subphyla_Consrewriterulesinfo[] = { phylum_rewriteruleinfo, phylum_rewriterulesinfo }; + static enum_phyla kc_subphyla_Rewriteruleinfo[] = { phylum_patternrepresentation, phylum_patternrepresentation, phylum_rewriteclause }; + static enum_phyla kc_subphyla_Conswithcasesinfo[] = { phylum_withcaseinfo, phylum_withcasesinfo }; + static enum_phyla kc_subphyla_Withcaseinfo[] = { phylum_patternrepresentation, phylum_patternrepresentation, phylum_Ctext }; + static enum_phyla kc_subphyla_Consrewriteviewsinfo[] = { phylum_rewriteviewinfo, phylum_rewriteviewsinfo }; + static enum_phyla kc_subphyla_Rewriteviewinfo[] = { phylum_ID, phylum_rewriterulesinfo }; + static enum_phyla kc_subphyla_Consunparseviewsinfo[] = { phylum_unparseviewinfo, phylum_unparseviewsinfo }; + static enum_phyla kc_subphyla_Unparseviewinfo[] = { phylum_ID, phylum_unparsedeclsinfo }; + static enum_phyla kc_subphyla_Consunparsedeclsinfo[] = { phylum_unparsedeclinfo, phylum_unparsedeclsinfo }; + static enum_phyla kc_subphyla_Unparsedeclinfo[] = { phylum_patternrepresentation, phylum_patternrepresentation, phylum_unparseclause }; + static enum_phyla kc_subphyla_AcDeclaration[] = { phylum_ac_declaration_specifiers, phylum_ac_init_declarator_list }; + static enum_phyla kc_subphyla_Consac_declaration_list[] = { phylum_ac_declaration, phylum_ac_declaration_list }; + static enum_phyla kc_subphyla_Consac_declaration_specifiers[] = { phylum_ac_declaration_specifier, phylum_ac_declaration_specifiers }; + static enum_phyla kc_subphyla_AcDeclSpecStorageSpec[] = { phylum_ac_storage_class_specifier }; + static enum_phyla kc_subphyla_AcDeclSpecTypeSpec[] = { phylum_ac_type_specifier }; + static enum_phyla kc_subphyla_AcDeclSpecTypeQual[] = { phylum_ac_type_qualifier }; + static enum_phyla kc_subphyla_AcTypeSpec[] = { phylum_ID }; + static enum_phyla kc_subphyla_Consac_init_declarator_list[] = { phylum_ac_init_declarator, phylum_ac_init_declarator_list }; + static enum_phyla kc_subphyla_AcInitDecl[] = { phylum_ac_declarator }; + static enum_phyla kc_subphyla_AcDeclarator[] = { phylum_ac_pointer_option, phylum_ac_ref_option, phylum_ac_direct_declarator }; + static enum_phyla kc_subphyla_AcDirectDeclId[] = { phylum_ID }; + static enum_phyla kc_subphyla_AcDirectDeclPack[] = { phylum_ac_declarator }; + static enum_phyla kc_subphyla_AcDirectDeclArray[] = { phylum_ac_direct_declarator, phylum_ac_constant_expression_option }; + static enum_phyla kc_subphyla_AcDirectDeclProto[] = { phylum_ac_direct_declarator, phylum_ac_parameter_type_list }; + static enum_phyla kc_subphyla_AcQualifiedDeclProto[] = { phylum_ac_class_qualifier_list, phylum_ac_direct_declarator, phylum_ac_parameter_type_list, phylum_ac_type_qualifier }; + static enum_phyla kc_subphyla_AcMemberDecl[] = { phylum_ID, phylum_ID, phylum_ac_constant_expression_list }; + static enum_phyla kc_subphyla_AcConvOperatorDecl[] = { phylum_ID, phylum_ID }; + static enum_phyla kc_subphyla_AcOperatorDeclId[] = { phylum_ac_operator_name }; + static enum_phyla kc_subphyla_Yespointer[] = { phylum_ac_pointer }; + static enum_phyla kc_subphyla_AcPointerNil[] = { phylum_ac_type_qualifier_list }; + static enum_phyla kc_subphyla_AcPointerCons[] = { phylum_ac_type_qualifier_list, phylum_ac_pointer }; + static enum_phyla kc_subphyla_AcOperatorName[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Consac_class_qualifier_help_list[] = { phylum_ac_direct_declarator, phylum_ac_class_qualifier_help_list }; + static enum_phyla kc_subphyla_Consac_class_qualifier_list[] = { phylum_ID, phylum_ac_class_qualifier_list }; + static enum_phyla kc_subphyla_Consac_type_qualifier_list[] = { phylum_ac_type_qualifier, phylum_ac_type_qualifier_list }; + static enum_phyla kc_subphyla_AcParList[] = { phylum_ac_parameter_list }; + static enum_phyla kc_subphyla_AcParList3Dot[] = { phylum_ac_parameter_list }; + static enum_phyla kc_subphyla_Consac_parameter_list[] = { phylum_ac_parameter_declaration, phylum_ac_parameter_list }; + static enum_phyla kc_subphyla_AcParDeclDecl[] = { phylum_ac_declaration_specifiers, phylum_ac_declarator, phylum_ac_constant_expression_option }; + static enum_phyla kc_subphyla_AcParDeclAbsdecl[] = { phylum_ac_declaration_specifiers, phylum_ac_abstract_declarator, phylum_ac_constant_expression_option }; + static enum_phyla kc_subphyla_Consac_identifier_list[] = { phylum_ID, phylum_ac_identifier_list }; + static enum_phyla kc_subphyla_AcAbsdeclPointer[] = { phylum_ac_pointer }; + static enum_phyla kc_subphyla_AcAbsdeclDirdecl[] = { phylum_ac_pointer_option, phylum_ac_direct_abstract_declarator }; + static enum_phyla kc_subphyla_Yesac_direct_abstract_declarator[] = { phylum_ac_direct_abstract_declarator }; + static enum_phyla kc_subphyla_AcDirAbsdeclPack[] = { phylum_ac_abstract_declarator }; + static enum_phyla kc_subphyla_AcDirAbsdeclArray[] = { phylum_ac_direct_abstract_declarator_option, phylum_ac_constant_expression_option }; + static enum_phyla kc_subphyla_AcDirAbsdeclFn[] = { phylum_ac_direct_abstract_declarator_option, phylum_ac_parameter_type_list }; + static enum_phyla kc_subphyla_Yesac_constant_expression[] = { phylum_ac_constant_expression }; + static enum_phyla kc_subphyla_AcConstExpr[] = { phylum_Cexpression }; + static enum_phyla kc_subphyla_Consac_constant_expression_list[] = { phylum_ac_constant_expression, phylum_ac_constant_expression_list }; + static enum_phyla kc_subphyla_AcYesBaseInit[] = { phylum_ac_base_init_list }; + static enum_phyla kc_subphyla_Consac_base_init_list[] = { phylum_ac_base_init, phylum_ac_base_init_list }; + static enum_phyla kc_subphyla_AcBaseInit[] = { phylum_ID, phylum_ac_constant_expression }; + static enum_phyla kc_subphyla_Consbaseclass_declarations[] = { phylum_baseclass_decl, phylum_baseclass_declarations }; + static enum_phyla kc_subphyla_BaseClassDecl[] = { phylum_ID, phylum_baseclass_list }; + static enum_phyla kc_subphyla_Consbaseclass_list[] = { phylum_ID, phylum_baseclass_list }; + static enum_phyla kc_subphyla_Fatal[] = { phylum_fileline, phylum_problem }; + static enum_phyla kc_subphyla_NonFatal[] = { phylum_fileline, phylum_problem }; + static enum_phyla kc_subphyla_Warning[] = { phylum_fileline, phylum_problem }; + static enum_phyla kc_subphyla_Problem1[] = { phylum_casestring }; + static enum_phyla kc_subphyla_Problem1ID[] = { phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1tID[] = { phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1we[] = { phylum_casestring, phylum_withexpression }; + static enum_phyla kc_subphyla_Problem1ID1ID[] = { phylum_casestring, phylum_ID, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1t1ID[] = { phylum_casestring, phylum_IDtype, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1INT[] = { phylum_casestring, phylum_INT }; + static enum_phyla kc_subphyla_Problem1int1[] = { phylum_casestring, phylum_integer, phylum_casestring }; + static enum_phyla kc_subphyla_Problem1INT1ID[] = { phylum_casestring, phylum_INT, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1ID1ID1ID[] = { phylum_casestring, phylum_ID, phylum_casestring, phylum_ID, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1INT1ID1ID[] = { phylum_casestring, phylum_INT, phylum_casestring, phylum_ID, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem1storageoption1ID[] = { phylum_casestring, phylum_storageoption, phylum_casestring, phylum_ID }; + static enum_phyla kc_subphyla_Problem2[] = { phylum_casestring, phylum_casestring }; + static enum_phyla kc_subphyla_Problem3[] = { phylum_casestring, phylum_casestring, phylum_casestring }; + static enum_phyla kc_subphyla_Problem3int1[] = { phylum_casestring, phylum_casestring, phylum_casestring, phylum_integer, phylum_casestring }; + static enum_phyla kc_subphyla_Problem4[] = { phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring }; + static enum_phyla kc_subphyla_Problem5[] = { phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring }; + static enum_phyla kc_subphyla_Problem6[] = { phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring, phylum_casestring }; + static enum_phyla kc_subphyla_Consaddedphylumdeclarations[] = { phylum_addedphylumdeclaration, phylum_addedphylumdeclarations }; + static enum_phyla kc_subphyla_AddedPhylumdeclaration[] = { phylum_uniqID }; + static enum_phyla kc_subphyla_Conscountedphylumdeclarations[] = { phylum_countedphylumdeclaration, phylum_countedphylumdeclarations }; + static enum_phyla kc_subphyla_CountedPhylumdeclaration[] = { phylum_uniqID }; + static enum_phyla kc_subphyla_Consbindingidmarks[] = { phylum_bindingidmark, phylum_bindingidmarks }; + static enum_phyla kc_subphyla_BindingIdMark[] = { phylum_uniqID }; + + + KC_OPERATOR_INFO operator_info[] = { + { "", 0, 0, one_before_first_phylum, 0, 0, 0, 0 }, /* dummy element */ + { "NoCaseStr", 0, true, phylum_nocasestring, 0, 0, 0, sizeof(impl_nocasestring_NoCaseStr) }, + { "_Str", 0, true, phylum_casestring, 0, 0, 0, sizeof(impl_casestring__Str) }, + { "_Real", 0, true, phylum_real, 0, 0, 0, sizeof(impl_real__Real) }, + { "_Int", 0, true, phylum_integer, 0, 0, 0, sizeof(impl_integer__Int) }, + { "_VoidPtr", 0, true, phylum_voidptr, 0, 0, 0, sizeof(impl_voidptr__VoidPtr) }, + { "Str", 1, false, phylum_uniqID, kc_subphyla_Str, 0, 0, sizeof(impl_uniqID_Str) }, + { "Id", 1, false, phylum_ID, kc_subphyla_Id, 0, 0, sizeof(impl_ID_Id) }, + { "Int", 1, false, phylum_INT, kc_subphyla_Int, 0, 0, sizeof(impl_INT_Int) }, + { "String", 1, false, phylum_STRING, kc_subphyla_String, 0, 0, sizeof(impl_STRING_String) }, + { "PhylumDeclarations", 1, false, phylum_phylumdeclarationsroot, kc_subphyla_PhylumDeclarations, 0, 0, sizeof(impl_phylumdeclarationsroot_PhylumDeclarations) }, + { "Nilphylumdeclarations", 0, false, phylum_phylumdeclarations, 0, 0, 0, sizeof(impl_phylumdeclarations) }, + { "Consphylumdeclarations", 2, false, phylum_phylumdeclarations, kc_subphyla_Consphylumdeclarations, 0, 0, sizeof(impl_phylumdeclarations) }, + { "Nilphylumnames", 0, false, phylum_phylumnames, 0, 0, 0, sizeof(impl_phylumnames) }, + { "Consphylumnames", 2, false, phylum_phylumnames, kc_subphyla_Consphylumnames, 0, 0, sizeof(impl_phylumnames) }, + { "PhylumDeclaration", 4, false, phylum_phylumdeclaration, kc_subphyla_PhylumDeclaration, 0, 0, sizeof(impl_phylumdeclaration_PhylumDeclaration) }, + { "NoStorageOption", 0, false, phylum_storageoption, 0, 0, 0, sizeof(impl_storageoption_NoStorageOption) }, + { "NegativeStorageOption", 1, false, phylum_storageoption, kc_subphyla_NegativeStorageOption, 0, 0, sizeof(impl_storageoption_NegativeStorageOption) }, + { "PositiveStorageOption", 1, false, phylum_storageoption, kc_subphyla_PositiveStorageOption, 0, 0, sizeof(impl_storageoption_PositiveStorageOption) }, + { "Nilstorageclasses", 0, false, phylum_storageclasses, 0, 0, 0, sizeof(impl_storageclasses) }, + { "Consstorageclasses", 2, false, phylum_storageclasses, kc_subphyla_Consstorageclasses, 0, 0, sizeof(impl_storageclasses) }, + { "Emptyproductionblock", 0, false, phylum_productionblock, 0, 0, 0, sizeof(impl_productionblock_Emptyproductionblock) }, + { "ListAlternatives", 2, false, phylum_productionblock, kc_subphyla_ListAlternatives, 0, 0, sizeof(impl_productionblock_ListAlternatives) }, + { "NonlistAlternatives", 1, false, phylum_productionblock, kc_subphyla_NonlistAlternatives, 0, 0, sizeof(impl_productionblock_NonlistAlternatives) }, + { "PredefinedAlternatives", 1, false, phylum_productionblock, kc_subphyla_PredefinedAlternatives, 0, 0, sizeof(impl_productionblock_PredefinedAlternatives) }, + { "Nilalternatives", 0, false, phylum_alternatives, 0, 0, 0, sizeof(impl_alternatives) }, + { "Consalternatives", 2, false, phylum_alternatives, kc_subphyla_Consalternatives, 0, 0, sizeof(impl_alternatives) }, + { "Alternative", 2, false, phylum_alternative, kc_subphyla_Alternative, 0, 0, sizeof(impl_alternative_Alternative) }, + { "Nilarguments", 0, false, phylum_arguments, 0, 0, 0, sizeof(impl_arguments) }, + { "Consarguments", 2, false, phylum_arguments, kc_subphyla_Consarguments, 0, 0, sizeof(impl_arguments) }, + { "Argument", 2, false, phylum_argument, kc_subphyla_Argument, 0, 0, sizeof(impl_argument_Argument) }, + { "CcodeOption", 2, false, phylum_Ccode_option, kc_subphyla_CcodeOption, 0, 0, sizeof(impl_Ccode_option_CcodeOption) }, + { "Nilattributes", 0, false, phylum_attributes, 0, 0, 0, sizeof(impl_attributes) }, + { "Consattributes", 2, false, phylum_attributes, kc_subphyla_Consattributes, 0, 0, sizeof(impl_attributes) }, + { "Attribute", 3, false, phylum_attribute, kc_subphyla_Attribute, 0, 0, sizeof(impl_attribute_Attribute) }, + { "Noattribute_initialisation", 0, false, phylum_attribute_initialisation_option, 0, 0, 0, sizeof(impl_attribute_initialisation_option_Noattribute_initialisation) }, + { "Yesattribute_initialisation", 1, false, phylum_attribute_initialisation_option, kc_subphyla_Yesattribute_initialisation, 0, 0, sizeof(impl_attribute_initialisation_option_Yesattribute_initialisation) }, + { "NilCexpression", 0, false, phylum_Cexpression, 0, 0, 0, sizeof(impl_Cexpression) }, + { "ConsCexpression", 2, false, phylum_Cexpression, kc_subphyla_ConsCexpression, 0, 0, sizeof(impl_Cexpression) }, + { "CExpressionPart", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionPart, 0, 0, sizeof(impl_Cexpression_elem_CExpressionPart) }, + { "CExpressionDollarvar", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionDollarvar, 0, 0, sizeof(impl_Cexpression_elem_CExpressionDollarvar) }, + { "CExpressionNl", 0, false, phylum_Cexpression_elem, 0, 0, 0, sizeof(impl_Cexpression_elem_CExpressionNl) }, + { "CExpressionDQ", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionDQ, 0, 0, sizeof(impl_Cexpression_elem_CExpressionDQ) }, + { "CExpressionSQ", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionSQ, 0, 0, sizeof(impl_Cexpression_elem_CExpressionSQ) }, + { "CExpressionPack", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionPack, 0, 0, sizeof(impl_Cexpression_elem_CExpressionPack) }, + { "CExpressionArray", 1, false, phylum_Cexpression_elem, kc_subphyla_CExpressionArray, 0, 0, sizeof(impl_Cexpression_elem_CExpressionArray) }, + { "NilCexpressionDQ", 0, false, phylum_CexpressionDQ, 0, 0, 0, sizeof(impl_CexpressionDQ) }, + { "ConsCexpressionDQ", 2, false, phylum_CexpressionDQ, kc_subphyla_ConsCexpressionDQ, 0, 0, sizeof(impl_CexpressionDQ) }, + { "CExpressionDQPart", 1, false, phylum_CexpressionDQ_elem, kc_subphyla_CExpressionDQPart, 0, 0, sizeof(impl_CexpressionDQ_elem_CExpressionDQPart) }, + { "CExpressionDQNl", 0, false, phylum_CexpressionDQ_elem, 0, 0, 0, sizeof(impl_CexpressionDQ_elem_CExpressionDQNl) }, + { "NilCexpressionSQ", 0, false, phylum_CexpressionSQ, 0, 0, 0, sizeof(impl_CexpressionSQ) }, + { "ConsCexpressionSQ", 2, false, phylum_CexpressionSQ, kc_subphyla_ConsCexpressionSQ, 0, 0, sizeof(impl_CexpressionSQ) }, + { "CExpressionSQPart", 1, false, phylum_CexpressionSQ_elem, kc_subphyla_CExpressionSQPart, 0, 0, sizeof(impl_CexpressionSQ_elem_CExpressionSQPart) }, + { "CExpressionSQNl", 0, false, phylum_CexpressionSQ_elem, 0, 0, 0, sizeof(impl_CexpressionSQ_elem_CExpressionSQNl) }, + { "NilidCexpressions", 0, false, phylum_idCexpressions, 0, 0, 0, sizeof(impl_idCexpressions) }, + { "ConsidCexpressions", 2, false, phylum_idCexpressions, kc_subphyla_ConsidCexpressions, 0, 0, sizeof(impl_idCexpressions) }, + { "IdCexpression", 2, false, phylum_idCexpression, kc_subphyla_IdCexpression, 0, 0, sizeof(impl_idCexpression_IdCexpression) }, + { "NilCtexts", 0, false, phylum_Ctexts, 0, 0, 0, sizeof(impl_Ctexts) }, + { "ConsCtexts", 2, false, phylum_Ctexts, kc_subphyla_ConsCtexts, 0, 0, sizeof(impl_Ctexts) }, + { "Nilincludefiles", 0, false, phylum_includefiles, 0, 0, 0, sizeof(impl_includefiles) }, + { "Consincludefiles", 2, false, phylum_includefiles, kc_subphyla_Consincludefiles, 0, 0, sizeof(impl_includefiles) }, + { "IncludeFile", 1, false, phylum_includefile, kc_subphyla_IncludeFile, 0, 0, sizeof(impl_includefile_IncludeFile) }, + { "Nilincludedeclarations", 0, false, phylum_includedeclarations, 0, 0, 0, sizeof(impl_includedeclarations) }, + { "Consincludedeclarations", 2, false, phylum_includedeclarations, kc_subphyla_Consincludedeclarations, 0, 0, sizeof(impl_includedeclarations) }, + { "IncludeDeclaration", 1, false, phylum_includedeclaration, kc_subphyla_IncludeDeclaration, 0, 0, sizeof(impl_includedeclaration_IncludeDeclaration) }, + { "Nilrwdeclarations", 0, false, phylum_rwdeclarations, 0, 0, 0, sizeof(impl_rwdeclarations) }, + { "Consrwdeclarations", 2, false, phylum_rwdeclarations, kc_subphyla_Consrwdeclarations, 0, 0, sizeof(impl_rwdeclarations) }, + { "RwDeclaration", 2, false, phylum_rwdeclaration, kc_subphyla_RwDeclaration, 0, 0, sizeof(impl_rwdeclaration_RwDeclaration) }, + { "Nilrewriteclauses", 0, false, phylum_rewriteclauses, 0, 0, 0, sizeof(impl_rewriteclauses) }, + { "Consrewriteclauses", 2, false, phylum_rewriteclauses, kc_subphyla_Consrewriteclauses, 0, 0, sizeof(impl_rewriteclauses) }, + { "RewriteClause", 2, false, phylum_rewriteclause, kc_subphyla_RewriteClause, 0, 0, sizeof(impl_rewriteclause_RewriteClause) }, + { "Nilpatternchains", 0, false, phylum_patternchains, 0, 0, 0, sizeof(impl_patternchains) }, + { "Conspatternchains", 2, false, phylum_patternchains, kc_subphyla_Conspatternchains, 0, 0, sizeof(impl_patternchains) }, + { "Nilpatternchain", 0, false, phylum_patternchain, 0, 0, 0, sizeof(impl_patternchain) }, + { "Conspatternchain", 2, false, phylum_patternchain, kc_subphyla_Conspatternchain, 0, 0, sizeof(impl_patternchain) }, + { "Niloutmostpatterns", 0, false, phylum_outmostpatterns, 0, 0, 0, sizeof(impl_outmostpatterns) }, + { "Consoutmostpatterns", 2, false, phylum_outmostpatterns, kc_subphyla_Consoutmostpatterns, 0, 0, sizeof(impl_outmostpatterns) }, + { "PatternchainitemOutmost", 1, false, phylum_patternchainitem, kc_subphyla_PatternchainitemOutmost, 0, 0, sizeof(impl_patternchainitem_PatternchainitemOutmost) }, + { "PatternchainitemGroup", 1, false, phylum_patternchainitem, kc_subphyla_PatternchainitemGroup, 0, 0, sizeof(impl_patternchainitem_PatternchainitemGroup) }, + { "PatternchainitemDollarid", 1, false, phylum_patternchainitem, kc_subphyla_PatternchainitemDollarid, 0, 0, sizeof(impl_patternchainitem_PatternchainitemDollarid) }, + { "OPOperatorWildcard", 2, false, phylum_outmostpattern, kc_subphyla_OPOperatorWildcard, 0, 0, sizeof(impl_outmostpattern_OPOperatorWildcard) }, + { "OPOperator", 3, false, phylum_outmostpattern, kc_subphyla_OPOperator, 0, 0, sizeof(impl_outmostpattern_OPOperator) }, + { "OPNonLeafVariable", 2, false, phylum_outmostpattern, kc_subphyla_OPNonLeafVariable, 0, 0, sizeof(impl_outmostpattern_OPNonLeafVariable) }, + { "OPWildcard", 1, false, phylum_outmostpattern, kc_subphyla_OPWildcard, 0, 0, sizeof(impl_outmostpattern_OPWildcard) }, + { "OPDefault", 1, false, phylum_outmostpattern, kc_subphyla_OPDefault, 0, 0, sizeof(impl_outmostpattern_OPDefault) }, + { "PVariable", 1, false, phylum_pattern, kc_subphyla_PVariable, 0, 0, sizeof(impl_pattern_PVariable) }, + { "POperator", 2, false, phylum_pattern, kc_subphyla_POperator, 0, 0, sizeof(impl_pattern_POperator) }, + { "PNonLeafVariable", 2, false, phylum_pattern, kc_subphyla_PNonLeafVariable, 0, 0, sizeof(impl_pattern_PNonLeafVariable) }, + { "PWildcard", 0, false, phylum_pattern, 0, 0, 0, sizeof(impl_pattern_PWildcard) }, + { "PStringLiteral", 1, false, phylum_pattern, kc_subphyla_PStringLiteral, 0, 0, sizeof(impl_pattern_PStringLiteral) }, + { "PIntLiteral", 1, false, phylum_pattern, kc_subphyla_PIntLiteral, 0, 0, sizeof(impl_pattern_PIntLiteral) }, + { "Nilpatterns", 0, false, phylum_patterns, 0, 0, 0, sizeof(impl_patterns) }, + { "Conspatterns", 2, false, phylum_patterns, kc_subphyla_Conspatterns, 0, 0, sizeof(impl_patterns) }, + { "TVariable", 1, false, phylum_term, kc_subphyla_TVariable, 0, 0, sizeof(impl_term_TVariable) }, + { "TOperator", 2, false, phylum_term, kc_subphyla_TOperator, 0, 0, sizeof(impl_term_TOperator) }, + { "TMethod", 3, false, phylum_term, kc_subphyla_TMethod, 0, 0, sizeof(impl_term_TMethod) }, + { "TMethodDot", 3, false, phylum_term, kc_subphyla_TMethodDot, 0, 0, sizeof(impl_term_TMethodDot) }, + { "TMemberVar", 2, false, phylum_term, kc_subphyla_TMemberVar, 0, 0, sizeof(impl_term_TMemberVar) }, + { "TMemberVarDot", 2, false, phylum_term, kc_subphyla_TMemberVarDot, 0, 0, sizeof(impl_term_TMemberVarDot) }, + { "TCTerm", 1, false, phylum_term, kc_subphyla_TCTerm, 0, 0, sizeof(impl_term_TCTerm) }, + { "TStringLiteral", 1, false, phylum_term, kc_subphyla_TStringLiteral, 0, 0, sizeof(impl_term_TStringLiteral) }, + { "TIntLiteral", 1, false, phylum_term, kc_subphyla_TIntLiteral, 0, 0, sizeof(impl_term_TIntLiteral) }, + { "Nilterms", 0, false, phylum_terms, 0, 0, 0, sizeof(impl_terms) }, + { "Consterms", 2, false, phylum_terms, kc_subphyla_Consterms, 0, 0, sizeof(impl_terms) }, + { "Nilfnfiles", 0, false, phylum_fnfiles, 0, 0, 0, sizeof(impl_fnfiles) }, + { "Consfnfiles", 2, false, phylum_fnfiles, kc_subphyla_Consfnfiles, 0, 0, sizeof(impl_fnfiles) }, + { "FnFile", 1, false, phylum_fnfile, kc_subphyla_FnFile, 0, 0, sizeof(impl_fnfile_FnFile) }, + { "Nilfndeclarations", 0, false, phylum_fndeclarations, 0, 0, 0, sizeof(impl_fndeclarations) }, + { "Consfndeclarations", 2, false, phylum_fndeclarations, kc_subphyla_Consfndeclarations, 0, 0, sizeof(impl_fndeclarations) }, + { "FnAcDeclaration", 7, false, phylum_fndeclaration, kc_subphyla_FnAcDeclaration, 0, 0, sizeof(impl_fndeclaration_FnAcDeclaration) }, + { "AcMemberDeclaration", 4, false, phylum_fndeclaration, kc_subphyla_AcMemberDeclaration, 0, 0, sizeof(impl_fndeclaration_AcMemberDeclaration) }, + { "GlobalFn", 0, false, phylum_fnclass, 0, 0, 0, sizeof(impl_fnclass_GlobalFn) }, + { "StaticFn", 1, false, phylum_fnclass, kc_subphyla_StaticFn, 0, 0, sizeof(impl_fnclass_StaticFn) }, + { "MemberFn", 0, false, phylum_fnclass, 0, 0, 0, sizeof(impl_fnclass_MemberFn) }, + { "ConstructorFn", 0, false, phylum_fnclass, 0, 0, 0, sizeof(impl_fnclass_ConstructorFn) }, + { "DestructorFn", 0, false, phylum_fnclass, 0, 0, 0, sizeof(impl_fnclass_DestructorFn) }, + { "ConvOperatorFn", 0, false, phylum_fnclass, 0, 0, 0, sizeof(impl_fnclass_ConvOperatorFn) }, + { "NilCtext", 0, false, phylum_Ctext, 0, 0, 0, sizeof(impl_Ctext) }, + { "ConsCtext", 2, false, phylum_Ctext, kc_subphyla_ConsCtext, 0, 0, sizeof(impl_Ctext) }, + { "CTextLine", 1, false, phylum_Ctext_elem, kc_subphyla_CTextLine, 0, 0, sizeof(impl_Ctext_elem_CTextLine) }, + { "CTextDollarVar", 1, false, phylum_Ctext_elem, kc_subphyla_CTextDollarVar, 0, 0, sizeof(impl_Ctext_elem_CTextDollarVar) }, + { "CTextNl", 1, false, phylum_Ctext_elem, kc_subphyla_CTextNl, 0, 0, sizeof(impl_Ctext_elem_CTextNl) }, + { "CTextCexpressionDQ", 1, false, phylum_Ctext_elem, kc_subphyla_CTextCexpressionDQ, 0, 0, sizeof(impl_Ctext_elem_CTextCexpressionDQ) }, + { "CTextCexpressionSQ", 1, false, phylum_Ctext_elem, kc_subphyla_CTextCexpressionSQ, 0, 0, sizeof(impl_Ctext_elem_CTextCexpressionSQ) }, + { "CTextCbody", 1, false, phylum_Ctext_elem, kc_subphyla_CTextCbody, 0, 0, sizeof(impl_Ctext_elem_CTextCbody) }, + { "CTextForeachexpression", 5, false, phylum_Ctext_elem, kc_subphyla_CTextForeachexpression, 0, 0, sizeof(impl_Ctext_elem_CTextForeachexpression) }, + { "CTextWithexpression", 3, false, phylum_Ctext_elem, kc_subphyla_CTextWithexpression, 0, 0, sizeof(impl_Ctext_elem_CTextWithexpression) }, + { "NoForeachAfter", 0, false, phylum_foreach_after, 0, 0, 0, sizeof(impl_foreach_after_NoForeachAfter) }, + { "ForeachAfter", 4, false, phylum_foreach_after, kc_subphyla_ForeachAfter, 0, 0, sizeof(impl_foreach_after_ForeachAfter) }, + { "InForeachContext", 1, false, phylum_contextinfo, kc_subphyla_InForeachContext, 0, 0, sizeof(impl_contextinfo_InForeachContext) }, + { "NotInForeachContext", 0, false, phylum_contextinfo, 0, 0, 0, sizeof(impl_contextinfo_NotInForeachContext) }, + { "Nilwithexpressions", 0, false, phylum_withexpressions, 0, 0, 0, sizeof(impl_withexpressions) }, + { "Conswithexpressions", 2, false, phylum_withexpressions, kc_subphyla_Conswithexpressions, 0, 0, sizeof(impl_withexpressions) }, + { "WEVariable", 1, false, phylum_withexpression, kc_subphyla_WEVariable, 0, 0, sizeof(impl_withexpression_WEVariable) }, + { "WECexpression", 1, false, phylum_withexpression, kc_subphyla_WECexpression, 0, 0, sizeof(impl_withexpression_WECexpression) }, + { "Nilwithcases", 0, false, phylum_withcases, 0, 0, 0, sizeof(impl_withcases) }, + { "Conswithcases", 2, false, phylum_withcases, kc_subphyla_Conswithcases, 0, 0, sizeof(impl_withcases) }, + { "Withcase", 2, false, phylum_withcase, kc_subphyla_Withcase, 0, 0, sizeof(impl_withcase_Withcase) }, + { "Nilunparsedeclarations", 0, false, phylum_unparsedeclarations, 0, 0, 0, sizeof(impl_unparsedeclarations) }, + { "Consunparsedeclarations", 2, false, phylum_unparsedeclarations, kc_subphyla_Consunparsedeclarations, 0, 0, sizeof(impl_unparsedeclarations) }, + { "UnparseDeclaration", 2, false, phylum_unparsedeclaration, kc_subphyla_UnparseDeclaration, 0, 0, sizeof(impl_unparsedeclaration_UnparseDeclaration) }, + { "Nilunparseclauses", 0, false, phylum_unparseclauses, 0, 0, 0, sizeof(impl_unparseclauses) }, + { "Consunparseclauses", 2, false, phylum_unparseclauses, kc_subphyla_Consunparseclauses, 0, 0, sizeof(impl_unparseclauses) }, + { "UnparseClause", 2, false, phylum_unparseclause, kc_subphyla_UnparseClause, 0, 0, sizeof(impl_unparseclause_UnparseClause) }, + { "Nilviewnames", 0, false, phylum_viewnames, 0, 0, 0, sizeof(impl_viewnames) }, + { "Consviewnames", 2, false, phylum_viewnames, kc_subphyla_Consviewnames, 0, 0, sizeof(impl_viewnames) }, + { "Nilunparseitems", 0, false, phylum_unparseitems, 0, 0, 0, sizeof(impl_unparseitems) }, + { "Consunparseitems", 2, false, phylum_unparseitems, kc_subphyla_Consunparseitems, 0, 0, sizeof(impl_unparseitems) }, + { "UnpStr", 3, false, phylum_unparseitem, kc_subphyla_UnpStr, 0, 0, sizeof(impl_unparseitem_UnpStr) }, + { "UnpSubexpr", 3, false, phylum_unparseitem, kc_subphyla_UnpSubexpr, 0, 0, sizeof(impl_unparseitem_UnpSubexpr) }, + { "UnpCtext", 2, false, phylum_unparseitem, kc_subphyla_UnpCtext, 0, 0, sizeof(impl_unparseitem_UnpCtext) }, + { "UnpBody", 2, false, phylum_unparseitem, kc_subphyla_UnpBody, 0, 0, sizeof(impl_unparseitem_UnpBody) }, + { "UViewVarDecl", 3, false, phylum_unparseitem, kc_subphyla_UViewVarDecl, 0, 0, sizeof(impl_unparseitem_UViewVarDecl) }, + { "UnpSubTerm", 1, false, phylum_unpsubterm, kc_subphyla_UnpSubTerm, 0, 0, sizeof(impl_unpsubterm_UnpSubTerm) }, + { "UnpDollarvarTerm", 1, false, phylum_unpsubterm, kc_subphyla_UnpDollarvarTerm, 0, 0, sizeof(impl_unpsubterm_UnpDollarvarTerm) }, + { "UnpSubAttr", 2, false, phylum_unpsubterm, kc_subphyla_UnpSubAttr, 0, 0, sizeof(impl_unpsubterm_UnpSubAttr) }, + { "UnpDollarvarAttr", 2, false, phylum_unpsubterm, kc_subphyla_UnpDollarvarAttr, 0, 0, sizeof(impl_unpsubterm_UnpDollarvarAttr) }, + { "UnpCastedVariable", 2, false, phylum_unpsubterm, kc_subphyla_UnpCastedVariable, 0, 0, sizeof(impl_unpsubterm_UnpCastedVariable) }, + { "Nilunpattributes", 0, false, phylum_unpattributes, 0, 0, 0, sizeof(impl_unpattributes) }, + { "Consunpattributes", 2, false, phylum_unpattributes, kc_subphyla_Consunpattributes, 0, 0, sizeof(impl_unpattributes) }, + { "NoViewname", 0, false, phylum_viewnameoption, 0, 0, 0, sizeof(impl_viewnameoption_NoViewname) }, + { "YesViewname", 1, false, phylum_viewnameoption, kc_subphyla_YesViewname, 0, 0, sizeof(impl_viewnameoption_YesViewname) }, + { "NoLanguagename", 0, false, phylum_languageoption, 0, 0, 0, sizeof(impl_languageoption_NoLanguagename) }, + { "LanguageList", 1, false, phylum_languageoption, kc_subphyla_LanguageList, 0, 0, sizeof(impl_languageoption_LanguageList) }, + { "Nillanguagenames", 0, false, phylum_languagenames, 0, 0, 0, sizeof(impl_languagenames) }, + { "Conslanguagenames", 2, false, phylum_languagenames, kc_subphyla_Conslanguagenames, 0, 0, sizeof(impl_languagenames) }, + { "FileLine", 0, false, phylum_fileline, 0, 0, 0, sizeof(impl_fileline_FileLine) }, + { "NoFileLine", 0, false, phylum_fileline, 0, 0, 0, sizeof(impl_fileline_NoFileLine) }, + { "PosNoFileLine", 0, false, phylum_fileline, 0, 0, 0, sizeof(impl_fileline_PosNoFileLine) }, + { "Nilscopetypefilelinestack", 0, false, phylum_scopetypefilelinestack, 0, 0, 0, sizeof(impl_scopetypefilelinestack) }, + { "Consscopetypefilelinestack", 2, false, phylum_scopetypefilelinestack, kc_subphyla_Consscopetypefilelinestack, 0, 0, sizeof(impl_scopetypefilelinestack) }, + { "ScopeTypeFileLine", 4, false, phylum_scopetypefileline, kc_subphyla_ScopeTypeFileLine, 0, 0, sizeof(impl_scopetypefileline_ScopeTypeFileLine) }, + { "ITUnknown", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITUnknown) }, + { "ITPredefinedPhylum", 1, false, phylum_IDtype, kc_subphyla_ITPredefinedPhylum, 0, 0, sizeof(impl_IDtype_ITPredefinedPhylum) }, + { "ITUserPhylum", 1, false, phylum_IDtype, kc_subphyla_ITUserPhylum, 0, 0, sizeof(impl_IDtype_ITUserPhylum) }, + { "ITPredefinedOperator", 2, false, phylum_IDtype, kc_subphyla_ITPredefinedOperator, 0, 0, sizeof(impl_IDtype_ITPredefinedOperator) }, + { "ITUserOperator", 2, false, phylum_IDtype, kc_subphyla_ITUserOperator, 0, 0, sizeof(impl_IDtype_ITUserOperator) }, + { "ITPredefinedStorageClass", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITPredefinedStorageClass) }, + { "ITStorageClass", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITStorageClass) }, + { "ITPredefinedUView", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITPredefinedUView) }, + { "ITUserUView", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITUserUView) }, + { "ITUViewVar", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITUViewVar) }, + { "ITPredefinedRView", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITPredefinedRView) }, + { "ITUserRView", 0, false, phylum_IDtype, 0, 0, 0, sizeof(impl_IDtype_ITUserRView) }, + { "ITUserFunction", 1, false, phylum_IDtype, kc_subphyla_ITUserFunction, 0, 0, sizeof(impl_IDtype_ITUserFunction) }, + { "ITPatternVariable", 2, false, phylum_IDtype, kc_subphyla_ITPatternVariable, 0, 0, sizeof(impl_IDtype_ITPatternVariable) }, + { "ITLanguageName", 1, false, phylum_IDtype, kc_subphyla_ITLanguageName, 0, 0, sizeof(impl_IDtype_ITLanguageName) }, + { "Niloperators", 0, false, phylum_operators, 0, 0, 0, sizeof(impl_operators) }, + { "Consoperators", 2, false, phylum_operators, kc_subphyla_Consoperators, 0, 0, sizeof(impl_operators) }, + { "Nilphyla", 0, false, phylum_phyla, 0, 0, 0, sizeof(impl_phyla) }, + { "Consphyla", 2, false, phylum_phyla, kc_subphyla_Consphyla, 0, 0, sizeof(impl_phyla) }, + { "Nilvariables", 0, false, phylum_variables, 0, 0, 0, sizeof(impl_variables) }, + { "Consvariables", 2, false, phylum_variables, kc_subphyla_Consvariables, 0, 0, sizeof(impl_variables) }, + { "DVAllowed", 0, false, phylum_dollarvarstatus, 0, 0, 0, sizeof(impl_dollarvarstatus_DVAllowed) }, + { "DVDisallowed", 0, false, phylum_dollarvarstatus, 0, 0, 0, sizeof(impl_dollarvarstatus_DVDisallowed) }, + { "Equal", 0, false, phylum_tribool, 0, 0, 0, sizeof(impl_tribool_Equal) }, + { "Smaller", 0, false, phylum_tribool, 0, 0, 0, sizeof(impl_tribool_Smaller) }, + { "Bigger", 0, false, phylum_tribool, 0, 0, 0, sizeof(impl_tribool_Bigger) }, + { "Nilpatternrepresentations", 0, false, phylum_patternrepresentations, 0, 0, 0, sizeof(impl_patternrepresentations) }, + { "Conspatternrepresentations", 2, false, phylum_patternrepresentations, kc_subphyla_Conspatternrepresentations, 0, 0, sizeof(impl_patternrepresentations) }, + { "Nilpatternrepresentation", 0, false, phylum_patternrepresentation, 0, 0, 0, sizeof(impl_patternrepresentation) }, + { "Conspatternrepresentation", 2, false, phylum_patternrepresentation, kc_subphyla_Conspatternrepresentation, 0, 0, sizeof(impl_patternrepresentation) }, + { "PRBinding", 2, false, phylum_elem_patternrepresentation, kc_subphyla_PRBinding, 0, 0, sizeof(impl_elem_patternrepresentation_PRBinding) }, + { "PRVarPredicate", 3, false, phylum_elem_patternrepresentation, kc_subphyla_PRVarPredicate, 0, 0, sizeof(impl_elem_patternrepresentation_PRVarPredicate) }, + { "PROperPredicate", 2, false, phylum_elem_patternrepresentation, kc_subphyla_PROperPredicate, 0, 0, sizeof(impl_elem_patternrepresentation_PROperPredicate) }, + { "PRUserPredicate", 1, false, phylum_elem_patternrepresentation, kc_subphyla_PRUserPredicate, 0, 0, sizeof(impl_elem_patternrepresentation_PRUserPredicate) }, + { "PRNonLeafBinding", 3, false, phylum_elem_patternrepresentation, kc_subphyla_PRNonLeafBinding, 0, 0, sizeof(impl_elem_patternrepresentation_PRNonLeafBinding) }, + { "PRWildcard", 1, false, phylum_elem_patternrepresentation, kc_subphyla_PRWildcard, 0, 0, sizeof(impl_elem_patternrepresentation_PRWildcard) }, + { "PRDefault", 0, false, phylum_elem_patternrepresentation, 0, 0, 0, sizeof(impl_elem_patternrepresentation_PRDefault) }, + { "PRStringLiteral", 2, false, phylum_elem_patternrepresentation, kc_subphyla_PRStringLiteral, 0, 0, sizeof(impl_elem_patternrepresentation_PRStringLiteral) }, + { "PRIntLiteral", 2, false, phylum_elem_patternrepresentation, kc_subphyla_PRIntLiteral, 0, 0, sizeof(impl_elem_patternrepresentation_PRIntLiteral) }, + { "Nilpath", 0, false, phylum_path, 0, 0, 0, sizeof(impl_path) }, + { "Conspath", 2, false, phylum_path, kc_subphyla_Conspath, 0, 0, sizeof(impl_path) }, + { "Nilpaths", 0, false, phylum_paths, 0, 0, 0, sizeof(impl_paths) }, + { "Conspaths", 2, false, phylum_paths, kc_subphyla_Conspaths, 0, 0, sizeof(impl_paths) }, + { "Nilargsnumbers", 0, false, phylum_argsnumbers, 0, 0, 0, sizeof(impl_argsnumbers) }, + { "Consargsnumbers", 2, false, phylum_argsnumbers, kc_subphyla_Consargsnumbers, 0, 0, sizeof(impl_argsnumbers) }, + { "Nilrewriterulesinfo", 0, false, phylum_rewriterulesinfo, 0, 0, 0, sizeof(impl_rewriterulesinfo) }, + { "Consrewriterulesinfo", 2, false, phylum_rewriterulesinfo, kc_subphyla_Consrewriterulesinfo, 0, 0, sizeof(impl_rewriterulesinfo) }, + { "Rewriteruleinfo", 3, false, phylum_rewriteruleinfo, kc_subphyla_Rewriteruleinfo, 0, 0, sizeof(impl_rewriteruleinfo_Rewriteruleinfo) }, + { "Nilwithcasesinfo", 0, false, phylum_withcasesinfo, 0, 0, 0, sizeof(impl_withcasesinfo) }, + { "Conswithcasesinfo", 2, false, phylum_withcasesinfo, kc_subphyla_Conswithcasesinfo, 0, 0, sizeof(impl_withcasesinfo) }, + { "Withcaseinfo", 3, false, phylum_withcaseinfo, kc_subphyla_Withcaseinfo, 0, 0, sizeof(impl_withcaseinfo_Withcaseinfo) }, + { "Nilrewriteviewsinfo", 0, false, phylum_rewriteviewsinfo, 0, 0, 0, sizeof(impl_rewriteviewsinfo) }, + { "Consrewriteviewsinfo", 2, false, phylum_rewriteviewsinfo, kc_subphyla_Consrewriteviewsinfo, 0, 0, sizeof(impl_rewriteviewsinfo) }, + { "Rewriteviewinfo", 2, false, phylum_rewriteviewinfo, kc_subphyla_Rewriteviewinfo, 0, 0, sizeof(impl_rewriteviewinfo_Rewriteviewinfo) }, + { "Nilunparseviewsinfo", 0, false, phylum_unparseviewsinfo, 0, 0, 0, sizeof(impl_unparseviewsinfo) }, + { "Consunparseviewsinfo", 2, false, phylum_unparseviewsinfo, kc_subphyla_Consunparseviewsinfo, 0, 0, sizeof(impl_unparseviewsinfo) }, + { "Unparseviewinfo", 2, false, phylum_unparseviewinfo, kc_subphyla_Unparseviewinfo, 0, 0, sizeof(impl_unparseviewinfo_Unparseviewinfo) }, + { "Nilunparsedeclsinfo", 0, false, phylum_unparsedeclsinfo, 0, 0, 0, sizeof(impl_unparsedeclsinfo) }, + { "Consunparsedeclsinfo", 2, false, phylum_unparsedeclsinfo, kc_subphyla_Consunparsedeclsinfo, 0, 0, sizeof(impl_unparsedeclsinfo) }, + { "Unparsedeclinfo", 3, false, phylum_unparsedeclinfo, kc_subphyla_Unparsedeclinfo, 0, 0, sizeof(impl_unparsedeclinfo_Unparsedeclinfo) }, + { "AcDeclaration", 2, false, phylum_ac_declaration, kc_subphyla_AcDeclaration, 0, 0, sizeof(impl_ac_declaration_AcDeclaration) }, + { "Nilac_declaration_list", 0, false, phylum_ac_declaration_list, 0, 0, 0, sizeof(impl_ac_declaration_list) }, + { "Consac_declaration_list", 2, false, phylum_ac_declaration_list, kc_subphyla_Consac_declaration_list, 0, 0, sizeof(impl_ac_declaration_list) }, + { "Nilac_declaration_specifiers", 0, false, phylum_ac_declaration_specifiers, 0, 0, 0, sizeof(impl_ac_declaration_specifiers) }, + { "Consac_declaration_specifiers", 2, false, phylum_ac_declaration_specifiers, kc_subphyla_Consac_declaration_specifiers, 0, 0, sizeof(impl_ac_declaration_specifiers) }, + { "AcDeclSpecStorageSpec", 1, false, phylum_ac_declaration_specifier, kc_subphyla_AcDeclSpecStorageSpec, 0, 0, sizeof(impl_ac_declaration_specifier_AcDeclSpecStorageSpec) }, + { "AcDeclSpecTypeSpec", 1, false, phylum_ac_declaration_specifier, kc_subphyla_AcDeclSpecTypeSpec, 0, 0, sizeof(impl_ac_declaration_specifier_AcDeclSpecTypeSpec) }, + { "AcDeclSpecTypeQual", 1, false, phylum_ac_declaration_specifier, kc_subphyla_AcDeclSpecTypeQual, 0, 0, sizeof(impl_ac_declaration_specifier_AcDeclSpecTypeQual) }, + { "AcAuto", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcAuto) }, + { "AcRegister", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcRegister) }, + { "AcStatic", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcStatic) }, + { "AcExtern", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcExtern) }, + { "AcTypedef", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcTypedef) }, + { "AcVirtual", 0, false, phylum_ac_storage_class_specifier, 0, 0, 0, sizeof(impl_ac_storage_class_specifier_AcVirtual) }, + { "AcTypeSpec", 1, false, phylum_ac_type_specifier, kc_subphyla_AcTypeSpec, 0, 0, sizeof(impl_ac_type_specifier_AcTypeSpec) }, + { "AcConst", 0, false, phylum_ac_type_qualifier, 0, 0, 0, sizeof(impl_ac_type_qualifier_AcConst) }, + { "AcVolatile", 0, false, phylum_ac_type_qualifier, 0, 0, 0, sizeof(impl_ac_type_qualifier_AcVolatile) }, + { "AcUnsigned", 0, false, phylum_ac_type_qualifier, 0, 0, 0, sizeof(impl_ac_type_qualifier_AcUnsigned) }, + { "AcNoQualifier", 0, false, phylum_ac_type_qualifier, 0, 0, 0, sizeof(impl_ac_type_qualifier_AcNoQualifier) }, + { "Nilac_init_declarator_list", 0, false, phylum_ac_init_declarator_list, 0, 0, 0, sizeof(impl_ac_init_declarator_list) }, + { "Consac_init_declarator_list", 2, false, phylum_ac_init_declarator_list, kc_subphyla_Consac_init_declarator_list, 0, 0, sizeof(impl_ac_init_declarator_list) }, + { "AcInitDecl", 1, false, phylum_ac_init_declarator, kc_subphyla_AcInitDecl, 0, 0, sizeof(impl_ac_init_declarator_AcInitDecl) }, + { "AcDeclarator", 3, false, phylum_ac_declarator, kc_subphyla_AcDeclarator, 0, 0, sizeof(impl_ac_declarator_AcDeclarator) }, + { "AcDirectDeclId", 1, false, phylum_ac_direct_declarator, kc_subphyla_AcDirectDeclId, 0, 0, sizeof(impl_ac_direct_declarator_AcDirectDeclId) }, + { "AcDirectDeclPack", 1, false, phylum_ac_direct_declarator, kc_subphyla_AcDirectDeclPack, 0, 0, sizeof(impl_ac_direct_declarator_AcDirectDeclPack) }, + { "AcDirectDeclArray", 2, false, phylum_ac_direct_declarator, kc_subphyla_AcDirectDeclArray, 0, 0, sizeof(impl_ac_direct_declarator_AcDirectDeclArray) }, + { "AcDirectDeclProto", 2, false, phylum_ac_direct_declarator, kc_subphyla_AcDirectDeclProto, 0, 0, sizeof(impl_ac_direct_declarator_AcDirectDeclProto) }, + { "AcQualifiedDeclProto", 4, false, phylum_ac_direct_declarator, kc_subphyla_AcQualifiedDeclProto, 0, 0, sizeof(impl_ac_direct_declarator_AcQualifiedDeclProto) }, + { "AcMemberDecl", 3, false, phylum_ac_direct_declarator, kc_subphyla_AcMemberDecl, 0, 0, sizeof(impl_ac_direct_declarator_AcMemberDecl) }, + { "AcConvOperatorDecl", 2, false, phylum_ac_direct_declarator, kc_subphyla_AcConvOperatorDecl, 0, 0, sizeof(impl_ac_direct_declarator_AcConvOperatorDecl) }, + { "AcOperatorDeclId", 1, false, phylum_ac_direct_declarator, kc_subphyla_AcOperatorDeclId, 0, 0, sizeof(impl_ac_direct_declarator_AcOperatorDeclId) }, + { "Nopointer", 0, false, phylum_ac_pointer_option, 0, 0, 0, sizeof(impl_ac_pointer_option_Nopointer) }, + { "Yespointer", 1, false, phylum_ac_pointer_option, kc_subphyla_Yespointer, 0, 0, sizeof(impl_ac_pointer_option_Yespointer) }, + { "AcPointerNil", 1, false, phylum_ac_pointer, kc_subphyla_AcPointerNil, 0, 0, sizeof(impl_ac_pointer_AcPointerNil) }, + { "AcPointerCons", 2, false, phylum_ac_pointer, kc_subphyla_AcPointerCons, 0, 0, sizeof(impl_ac_pointer_AcPointerCons) }, + { "AcNoRef", 0, false, phylum_ac_ref_option, 0, 0, 0, sizeof(impl_ac_ref_option_AcNoRef) }, + { "AcRef", 0, false, phylum_ac_ref_option, 0, 0, 0, sizeof(impl_ac_ref_option_AcRef) }, + { "AcOperatorName", 1, false, phylum_ac_operator_name, kc_subphyla_AcOperatorName, 0, 0, sizeof(impl_ac_operator_name_AcOperatorName) }, + { "Nilac_class_qualifier_help_list", 0, false, phylum_ac_class_qualifier_help_list, 0, 0, 0, sizeof(impl_ac_class_qualifier_help_list) }, + { "Consac_class_qualifier_help_list", 2, false, phylum_ac_class_qualifier_help_list, kc_subphyla_Consac_class_qualifier_help_list, 0, 0, sizeof(impl_ac_class_qualifier_help_list) }, + { "Nilac_class_qualifier_list", 0, false, phylum_ac_class_qualifier_list, 0, 0, 0, sizeof(impl_ac_class_qualifier_list) }, + { "Consac_class_qualifier_list", 2, false, phylum_ac_class_qualifier_list, kc_subphyla_Consac_class_qualifier_list, 0, 0, sizeof(impl_ac_class_qualifier_list) }, + { "Nilac_type_qualifier_list", 0, false, phylum_ac_type_qualifier_list, 0, 0, 0, sizeof(impl_ac_type_qualifier_list) }, + { "Consac_type_qualifier_list", 2, false, phylum_ac_type_qualifier_list, kc_subphyla_Consac_type_qualifier_list, 0, 0, sizeof(impl_ac_type_qualifier_list) }, + { "AcParList", 1, false, phylum_ac_parameter_type_list, kc_subphyla_AcParList, 0, 0, sizeof(impl_ac_parameter_type_list_AcParList) }, + { "AcParList3Dot", 1, false, phylum_ac_parameter_type_list, kc_subphyla_AcParList3Dot, 0, 0, sizeof(impl_ac_parameter_type_list_AcParList3Dot) }, + { "Nilac_parameter_list", 0, false, phylum_ac_parameter_list, 0, 0, 0, sizeof(impl_ac_parameter_list) }, + { "Consac_parameter_list", 2, false, phylum_ac_parameter_list, kc_subphyla_Consac_parameter_list, 0, 0, sizeof(impl_ac_parameter_list) }, + { "AcParDeclDecl", 3, false, phylum_ac_parameter_declaration, kc_subphyla_AcParDeclDecl, 0, 0, sizeof(impl_ac_parameter_declaration_AcParDeclDecl) }, + { "AcParDeclAbsdecl", 3, false, phylum_ac_parameter_declaration, kc_subphyla_AcParDeclAbsdecl, 0, 0, sizeof(impl_ac_parameter_declaration_AcParDeclAbsdecl) }, + { "Nilac_identifier_list", 0, false, phylum_ac_identifier_list, 0, 0, 0, sizeof(impl_ac_identifier_list) }, + { "Consac_identifier_list", 2, false, phylum_ac_identifier_list, kc_subphyla_Consac_identifier_list, 0, 0, sizeof(impl_ac_identifier_list) }, + { "AcAbsdeclPointer", 1, false, phylum_ac_abstract_declarator, kc_subphyla_AcAbsdeclPointer, 0, 0, sizeof(impl_ac_abstract_declarator_AcAbsdeclPointer) }, + { "AcAbsdeclDirdecl", 2, false, phylum_ac_abstract_declarator, kc_subphyla_AcAbsdeclDirdecl, 0, 0, sizeof(impl_ac_abstract_declarator_AcAbsdeclDirdecl) }, + { "Noac_direct_abstract_declarator", 0, false, phylum_ac_direct_abstract_declarator_option, 0, 0, 0, sizeof(impl_ac_direct_abstract_declarator_option_Noac_direct_abstract_declarator) }, + { "Yesac_direct_abstract_declarator", 1, false, phylum_ac_direct_abstract_declarator_option, kc_subphyla_Yesac_direct_abstract_declarator, 0, 0, sizeof(impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator) }, + { "AcDirAbsdeclPack", 1, false, phylum_ac_direct_abstract_declarator, kc_subphyla_AcDirAbsdeclPack, 0, 0, sizeof(impl_ac_direct_abstract_declarator_AcDirAbsdeclPack) }, + { "AcDirAbsdeclArray", 2, false, phylum_ac_direct_abstract_declarator, kc_subphyla_AcDirAbsdeclArray, 0, 0, sizeof(impl_ac_direct_abstract_declarator_AcDirAbsdeclArray) }, + { "AcDirAbsdeclFn", 2, false, phylum_ac_direct_abstract_declarator, kc_subphyla_AcDirAbsdeclFn, 0, 0, sizeof(impl_ac_direct_abstract_declarator_AcDirAbsdeclFn) }, + { "Yesac_constant_expression", 1, false, phylum_ac_constant_expression_option, kc_subphyla_Yesac_constant_expression, 0, 0, sizeof(impl_ac_constant_expression_option_Yesac_constant_expression) }, + { "Noac_constant_expression", 0, false, phylum_ac_constant_expression_option, 0, 0, 0, sizeof(impl_ac_constant_expression_option_Noac_constant_expression) }, + { "AcConstExpr", 1, false, phylum_ac_constant_expression, kc_subphyla_AcConstExpr, 0, 0, sizeof(impl_ac_constant_expression_AcConstExpr) }, + { "Nilac_constant_expression_list", 0, false, phylum_ac_constant_expression_list, 0, 0, 0, sizeof(impl_ac_constant_expression_list) }, + { "Consac_constant_expression_list", 2, false, phylum_ac_constant_expression_list, kc_subphyla_Consac_constant_expression_list, 0, 0, sizeof(impl_ac_constant_expression_list) }, + { "AcNoBaseInit", 0, false, phylum_ac_opt_base_init_list, 0, 0, 0, sizeof(impl_ac_opt_base_init_list_AcNoBaseInit) }, + { "AcYesBaseInit", 1, false, phylum_ac_opt_base_init_list, kc_subphyla_AcYesBaseInit, 0, 0, sizeof(impl_ac_opt_base_init_list_AcYesBaseInit) }, + { "Nilac_base_init_list", 0, false, phylum_ac_base_init_list, 0, 0, 0, sizeof(impl_ac_base_init_list) }, + { "Consac_base_init_list", 2, false, phylum_ac_base_init_list, kc_subphyla_Consac_base_init_list, 0, 0, sizeof(impl_ac_base_init_list) }, + { "AcBaseInit", 2, false, phylum_ac_base_init, kc_subphyla_AcBaseInit, 0, 0, sizeof(impl_ac_base_init_AcBaseInit) }, + { "Nilbaseclass_declarations", 0, false, phylum_baseclass_declarations, 0, 0, 0, sizeof(impl_baseclass_declarations) }, + { "Consbaseclass_declarations", 2, false, phylum_baseclass_declarations, kc_subphyla_Consbaseclass_declarations, 0, 0, sizeof(impl_baseclass_declarations) }, + { "BaseClassDecl", 2, false, phylum_baseclass_decl, kc_subphyla_BaseClassDecl, 0, 0, sizeof(impl_baseclass_decl_BaseClassDecl) }, + { "Nilbaseclass_list", 0, false, phylum_baseclass_list, 0, 0, 0, sizeof(impl_baseclass_list) }, + { "Consbaseclass_list", 2, false, phylum_baseclass_list, kc_subphyla_Consbaseclass_list, 0, 0, sizeof(impl_baseclass_list) }, + { "Fatal", 2, false, phylum_error, kc_subphyla_Fatal, 0, 0, sizeof(impl_error_Fatal) }, + { "NonFatal", 2, false, phylum_error, kc_subphyla_NonFatal, 0, 0, sizeof(impl_error_NonFatal) }, + { "Warning", 2, false, phylum_error, kc_subphyla_Warning, 0, 0, sizeof(impl_error_Warning) }, + { "Problem1", 1, false, phylum_problem, kc_subphyla_Problem1, 0, 0, sizeof(impl_problem_Problem1) }, + { "Problem1ID", 2, false, phylum_problem, kc_subphyla_Problem1ID, 0, 0, sizeof(impl_problem_Problem1ID) }, + { "Problem1tID", 2, false, phylum_problem, kc_subphyla_Problem1tID, 0, 0, sizeof(impl_problem_Problem1tID) }, + { "Problem1we", 2, false, phylum_problem, kc_subphyla_Problem1we, 0, 0, sizeof(impl_problem_Problem1we) }, + { "Problem1ID1ID", 4, false, phylum_problem, kc_subphyla_Problem1ID1ID, 0, 0, sizeof(impl_problem_Problem1ID1ID) }, + { "Problem1t1ID", 4, false, phylum_problem, kc_subphyla_Problem1t1ID, 0, 0, sizeof(impl_problem_Problem1t1ID) }, + { "Problem1INT", 2, false, phylum_problem, kc_subphyla_Problem1INT, 0, 0, sizeof(impl_problem_Problem1INT) }, + { "Problem1int1", 3, false, phylum_problem, kc_subphyla_Problem1int1, 0, 0, sizeof(impl_problem_Problem1int1) }, + { "Problem1INT1ID", 4, false, phylum_problem, kc_subphyla_Problem1INT1ID, 0, 0, sizeof(impl_problem_Problem1INT1ID) }, + { "Problem1ID1ID1ID", 6, false, phylum_problem, kc_subphyla_Problem1ID1ID1ID, 0, 0, sizeof(impl_problem_Problem1ID1ID1ID) }, + { "Problem1INT1ID1ID", 6, false, phylum_problem, kc_subphyla_Problem1INT1ID1ID, 0, 0, sizeof(impl_problem_Problem1INT1ID1ID) }, + { "Problem1storageoption1ID", 4, false, phylum_problem, kc_subphyla_Problem1storageoption1ID, 0, 0, sizeof(impl_problem_Problem1storageoption1ID) }, + { "Problem2", 2, false, phylum_problem, kc_subphyla_Problem2, 0, 0, sizeof(impl_problem_Problem2) }, + { "Problem3", 3, false, phylum_problem, kc_subphyla_Problem3, 0, 0, sizeof(impl_problem_Problem3) }, + { "Problem3int1", 5, false, phylum_problem, kc_subphyla_Problem3int1, 0, 0, sizeof(impl_problem_Problem3int1) }, + { "Problem4", 4, false, phylum_problem, kc_subphyla_Problem4, 0, 0, sizeof(impl_problem_Problem4) }, + { "Problem5", 5, false, phylum_problem, kc_subphyla_Problem5, 0, 0, sizeof(impl_problem_Problem5) }, + { "Problem6", 6, false, phylum_problem, kc_subphyla_Problem6, 0, 0, sizeof(impl_problem_Problem6) }, + { "Niladdedphylumdeclarations", 0, false, phylum_addedphylumdeclarations, 0, 0, 0, sizeof(impl_addedphylumdeclarations) }, + { "Consaddedphylumdeclarations", 2, false, phylum_addedphylumdeclarations, kc_subphyla_Consaddedphylumdeclarations, 0, 0, sizeof(impl_addedphylumdeclarations) }, + { "AddedPhylumdeclaration", 1, false, phylum_addedphylumdeclaration, kc_subphyla_AddedPhylumdeclaration, 0, 0, sizeof(impl_addedphylumdeclaration_AddedPhylumdeclaration) }, + { "Nilcountedphylumdeclarations", 0, false, phylum_countedphylumdeclarations, 0, 0, 0, sizeof(impl_countedphylumdeclarations) }, + { "Conscountedphylumdeclarations", 2, false, phylum_countedphylumdeclarations, kc_subphyla_Conscountedphylumdeclarations, 0, 0, sizeof(impl_countedphylumdeclarations) }, + { "CountedPhylumdeclaration", 1, false, phylum_countedphylumdeclaration, kc_subphyla_CountedPhylumdeclaration, 0, 0, sizeof(impl_countedphylumdeclaration_CountedPhylumdeclaration) }, + { "Newlines", 0, false, phylum_charruns, 0, 0, 0, sizeof(impl_charruns_Newlines) }, + { "QuotedNewlines", 0, false, phylum_charruns, 0, 0, 0, sizeof(impl_charruns_QuotedNewlines) }, + { "Stars", 0, false, phylum_charruns, 0, 0, 0, sizeof(impl_charruns_Stars) }, + { "Nilbindingidmarks", 0, false, phylum_bindingidmarks, 0, 0, 0, sizeof(impl_bindingidmarks) }, + { "Consbindingidmarks", 2, false, phylum_bindingidmarks, kc_subphyla_Consbindingidmarks, 0, 0, sizeof(impl_bindingidmarks) }, + { "BindingIdMark", 1, false, phylum_bindingidmark, kc_subphyla_BindingIdMark, 0, 0, sizeof(impl_bindingidmark_BindingIdMark) }, + { "", 0, 0, one_before_first_phylum, 0, 0, 0, 0 } /* last element */ + }; + + static enum_phyla phylumstorageclass_uniq[] = { one_before_first_phylum, phylum_nocasestring, phylum_casestring, phylum_real, phylum_integer, phylum_voidptr, phylum_uniqID, phylum_includefile, phylum_fnfile, phylum_countedphylumdeclaration, phylum_charruns, phylum_bindingidmarks, phylum_bindingidmark, last_phylum }; + + KC_UNIQ_INFO kc_UniqInfo[] = { + (KC_UNIQ_INFO)0, + phylumstorageclass_uniq + }; + + } // namespace kc + namespace kc { } + using namespace kc; + /* included stuff */ + #include "gutil.h" + + // + // The Termprocessor Kimwitu++ + // + // Copyright (C) 1991 University of Twente, Dept TIOS. + // Copyright (C) 1998-2003 Humboldt-University of Berlin, Institute of Informatics + // All rights reserved. + // + // Kimwitu++ is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // Kimwitu++ 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 Kimwitu++; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + + /* end included stuff */ + + + namespace kc { + + void + kc_no_default_in_with( const char *kc_func, int kc_line, const char *kc_file ) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=A2CT(KC_NO_DEFAULT_IN_WITH); + const _TCHAR* tkc_func=A2CT(kc_func); + const _TCHAR* tkc_file=A2CT(kc_file); + TRACE( format, tkc_func, tkc_file, kc_line ); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_file, kc_line)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, KC_NO_DEFAULT_IN_WITH, kc_func, kc_file, kc_line ); + #ifndef KC_NODEFAULT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void + kc_returnless_function( const char *kc_func, int kc_line, const char *kc_file ) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: function %s does not return a value, at %s:%d"); + const _TCHAR* tkc_func=A2CT(kc_func); + const _TCHAR* tkc_file=A2CT(kc_file); + TRACE( format, tkc_func, tkc_file, kc_line ); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_file, kc_line)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, "Internal Error: function %s does not return a value, at %s:%d", kc_func, kc_file, kc_line ); + #ifndef KC_NODEFAULT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void + kc_assertionFailed(const char *kc_fn, int kc_l) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: Assertion failed at %s:%d\n"); + const _TCHAR* tkc_func=A2CT(kc_fn); + TRACE( format, tkc_func, kc_l ); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_fn, kc_l)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, "Internal Error: Assertion failed at %s:%d\n", kc_fn, kc_l ); + #ifndef KC_ASSERT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void + kc_assertionReasonFailed(const char *kc_fn, int kc_l, const char *kc_s) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: Assertion failed at file %s:%d: %s\n"); + const _TCHAR* tkc_func=A2CT(kc_fn); + const _TCHAR* tkc_s=A2CT(kc_s); + TRACE( format, tkc_func, kc_l, tkc_s ); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_fn, kc_l)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, "Internal Error: Assertion failed at file %s:%d: %s\n", kc_fn, kc_l, kc_s ); + #ifndef KC_ASSERT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void + kc_assertionNonNullFailed(const char *kc_fn, int kc_l, const char *kc_str) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: Assertion failed at %s:%d: pointer %s is NULL\n"); + const _TCHAR* tkc_func=A2CT(kc_fn); + const _TCHAR* tkc_s=A2CT(kc_str); + TRACE( format , tkc_func, kc_l, tkc_s); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_fn, kc_l)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, "Internal Error: Assertion failed at %s:%d: pointer %s is NULL\n", kc_fn, kc_l, kc_str ); + #ifndef KC_ASSERT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void + kc_assertionOperatorInPhylumFailed(int kc_op, const char *kc_str1, const char *kc_str2, const char *kc_phy, const char *kc_fn, int kc_l) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: Assertion failed at %s:%d: illegal value for (%s) %s%s: %d not a valid operator\n"); + const _TCHAR* tkc_func=A2CT(kc_fn); + const _TCHAR* tkc_s1=A2CT(kc_str1); + const _TCHAR* tkc_s2=A2CT(kc_str2); + const _TCHAR* tname=A2CT(kc_phy); + if ((kc_op <= one_before_first_operator) || (kc_op >= last_operator)) { + TRACE (format, tkc_func, kc_l, tname, tkc_s1, tkc_s2, kc_op ); + } else { + format=_T("Internal Error: Assertion failed at %s:%d: illegal value for (%s) %s%s: %s (%d) is a value of %s\n"); + const _TCHAR* tname2=A2CT(operator_info[kc_op].name); + const _TCHAR* tname3=A2CT(phylum_info[operator_info[kc_op].phylum].name); + TRACE(format,tkc_func, kc_l, tname, tkc_s1, tkc_s2, tname2, kc_op, tname3 ); + } + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_fn, kc_l)) + #endif + AfxDebugBreak(); + #else + if ((kc_op <= one_before_first_operator) || (kc_op >= last_operator)) { + fprintf( stderr, "Internal Error: Assertion failed at %s:%d: illegal value for (%s) %s%s: %d not a valid operator\n", + kc_fn, kc_l, kc_phy, kc_str1, kc_str2, kc_op ); + } else { + fprintf( stderr, "Internal Error: Assertion failed at %s:%d: illegal value for (%s) %s%s: %s (%d) is a value of %s\n", + kc_fn, kc_l, kc_phy, kc_str1, kc_str2, operator_info[kc_op].name, kc_op, phylum_info[operator_info[kc_op].phylum].name ); + } + #ifndef KC_ASSERT_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + + void kc_invalid_operator( const char *kc_func_prefix, enum_phyla kc_phy, int kc_line, const char *kc_file, enum_operators kc_oper ) + { + fflush(stdout); + #ifdef _AFX + USES_CONVERSION; + const _TCHAR* format=_T("Internal Error: invalid operator code in %s%s at %s:%d: %s\n"); + const _TCHAR* tkc_func=A2CT(kc_func_prefix); + const _TCHAR* tkc_file=A2CT(kc_file); + const _TCHAR* ts1=A2CT(phylumname_or_error( kc_phy )); + const _TCHAR* ts2=A2CT(kc_operatorname_or_error( kc_oper )); + TRACE( format, tkc_func, ts1, tkc_file, kc_line, ts2); + #ifdef _DEBUG + if (AfxAssertFailedLine(kc_file, kc_line)) + #endif + AfxDebugBreak(); + #else + fprintf( stderr, "Internal Error: invalid operator code in %s%s at %s:%d: %s\n", kc_func_prefix, phylumname_or_error( kc_phy ), kc_file, kc_line, kc_operatorname_or_error( kc_oper )); + #ifndef KC_INVALID_OPERATOR_NO_ABORT + abort(); + #else + exit( 1 ); + #endif + #endif + } + const enum_phyla impl_nocasestring::phylum_sel_ = phylum_nocasestring; + const enum_phyla impl_casestring::phylum_sel_ = phylum_casestring; + const enum_phyla impl_real::phylum_sel_ = phylum_real; + impl_real__Real::impl_real__Real(REAL _value) + : value(_value) { } + const enum_phyla impl_integer::phylum_sel_ = phylum_integer; + impl_integer__Int::impl_integer__Int(INTEGER _value) + : value(_value) { } + const enum_phyla impl_voidptr::phylum_sel_ = phylum_voidptr; + impl_voidptr__VoidPtr::impl_voidptr__VoidPtr(void* _pointer) + : pointer(_pointer) { } + const enum_phyla impl_uniqID::phylum_sel_ = phylum_uniqID; + impl_uniqID_Str::impl_uniqID_Str(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_ID::phylum_sel_ = phylum_ID; + impl_ID_Id::impl_ID_Id(uniqID _uniqID_1) + : uniqID_1(_uniqID_1) { } + const enum_phyla impl_INT::phylum_sel_ = phylum_INT; + impl_INT_Int::impl_INT_Int(integer _integer_1) + : integer_1(_integer_1) { } + const enum_phyla impl_STRING::phylum_sel_ = phylum_STRING; + impl_STRING_String::impl_STRING_String(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_phylumdeclarationsroot::phylum_sel_ = phylum_phylumdeclarationsroot; + impl_phylumdeclarationsroot_PhylumDeclarations::impl_phylumdeclarationsroot_PhylumDeclarations(phylumdeclarations _phylumdeclarations_1) + : phylumdeclarations_1(_phylumdeclarations_1) { } + const enum_phyla impl_phylumdeclarations::phylum_sel_ = phylum_phylumdeclarations; + impl_phylumdeclarations::impl_phylumdeclarations(phylumdeclaration p1 , phylumdeclarations p2) + : phylumdeclaration_1(p1), phylumdeclarations_1(p2) { } + const enum_phyla impl_phylumnames::phylum_sel_ = phylum_phylumnames; + impl_phylumnames::impl_phylumnames(ID p1 , phylumnames p2) + : ID_1(p1), phylumnames_1(p2) { } + const enum_phyla impl_phylumdeclaration::phylum_sel_ = phylum_phylumdeclaration; + impl_phylumdeclaration_PhylumDeclaration::impl_phylumdeclaration_PhylumDeclaration(ID _ID_1, storageoption _storageoption_1, productionblock _productionblock_1, Ccode_option _Ccode_option_1) + : ID_1(_ID_1), storageoption_1(_storageoption_1), productionblock_1(_productionblock_1), Ccode_option_1(_Ccode_option_1) { } + const enum_phyla impl_storageoption::phylum_sel_ = phylum_storageoption; + impl_storageoption_PositiveStorageOption::impl_storageoption_PositiveStorageOption(ID _ID_1) + : ID_1(_ID_1) { } + impl_storageoption_NegativeStorageOption::impl_storageoption_NegativeStorageOption(ID _ID_1) + : ID_1(_ID_1) { } + impl_storageoption_NoStorageOption::impl_storageoption_NoStorageOption() + { } + const enum_phyla impl_storageclasses::phylum_sel_ = phylum_storageclasses; + impl_storageclasses::impl_storageclasses(ID p1 , storageclasses p2) + : ID_1(p1), storageclasses_1(p2) { } + const enum_phyla impl_productionblock::phylum_sel_ = phylum_productionblock; + impl_productionblock_PredefinedAlternatives::impl_productionblock_PredefinedAlternatives(alternatives _alternatives_1) + : alternatives_1(_alternatives_1) { } + impl_productionblock_NonlistAlternatives::impl_productionblock_NonlistAlternatives(alternatives _alternatives_1) + : alternatives_1(_alternatives_1) { } + impl_productionblock_ListAlternatives::impl_productionblock_ListAlternatives(alternatives _alternatives_1, ID _ID_1) + : alternatives_1(_alternatives_1), ID_1(_ID_1) { } + impl_productionblock_Emptyproductionblock::impl_productionblock_Emptyproductionblock() + { } + const enum_phyla impl_alternatives::phylum_sel_ = phylum_alternatives; + impl_alternatives::impl_alternatives(alternative p1 , alternatives p2) + : alternative_1(p1), alternatives_1(p2) { } + const enum_phyla impl_alternative::phylum_sel_ = phylum_alternative; + impl_alternative_Alternative::impl_alternative_Alternative(ID _ID_1, arguments _arguments_1) + : ID_1(_ID_1), arguments_1(_arguments_1) { } + const enum_phyla impl_arguments::phylum_sel_ = phylum_arguments; + impl_arguments::impl_arguments(ID p1 , arguments p2) + : ID_1(p1), arguments_1(p2) { } + const enum_phyla impl_argument::phylum_sel_ = phylum_argument; + impl_argument_Argument::impl_argument_Argument(ID _ID_1, integer _integer_1) + : ID_1(_ID_1), integer_1(_integer_1) { } + const enum_phyla impl_Ccode_option::phylum_sel_ = phylum_Ccode_option; + impl_Ccode_option_CcodeOption::impl_Ccode_option_CcodeOption(attributes _attributes_1, Ctexts _Ctexts_1) + : attributes_1(_attributes_1), Ctexts_1(_Ctexts_1) { } + const enum_phyla impl_attributes::phylum_sel_ = phylum_attributes; + impl_attributes::impl_attributes(attribute p1 , attributes p2) + : attribute_1(p1), attributes_1(p2) { } + const enum_phyla impl_attribute::phylum_sel_ = phylum_attribute; + impl_attribute_Attribute::impl_attribute_Attribute(ID _ID_1, ID _ID_2, attribute_initialisation_option _attribute_initialisation_option_1) + : ID_1(_ID_1), ID_2(_ID_2), attribute_initialisation_option_1(_attribute_initialisation_option_1) { } + const enum_phyla impl_attribute_initialisation_option::phylum_sel_ = phylum_attribute_initialisation_option; + impl_attribute_initialisation_option_Yesattribute_initialisation::impl_attribute_initialisation_option_Yesattribute_initialisation(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_attribute_initialisation_option_Noattribute_initialisation::impl_attribute_initialisation_option_Noattribute_initialisation() + { } + const enum_phyla impl_Cexpression::phylum_sel_ = phylum_Cexpression; + impl_Cexpression::impl_Cexpression(Cexpression_elem p1 , Cexpression p2) + : Cexpression_elem_1(p1), Cexpression_1(p2) { } + const enum_phyla impl_Cexpression_elem::phylum_sel_ = phylum_Cexpression_elem; + impl_Cexpression_elem_CExpressionArray::impl_Cexpression_elem_CExpressionArray(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_Cexpression_elem_CExpressionPack::impl_Cexpression_elem_CExpressionPack(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_Cexpression_elem_CExpressionSQ::impl_Cexpression_elem_CExpressionSQ(CexpressionSQ _CexpressionSQ_1) + : CexpressionSQ_1(_CexpressionSQ_1) { } + impl_Cexpression_elem_CExpressionDQ::impl_Cexpression_elem_CExpressionDQ(CexpressionDQ _CexpressionDQ_1) + : CexpressionDQ_1(_CexpressionDQ_1) { } + impl_Cexpression_elem_CExpressionNl::impl_Cexpression_elem_CExpressionNl() + { } + impl_Cexpression_elem_CExpressionDollarvar::impl_Cexpression_elem_CExpressionDollarvar(INT _INT_1) + : INT_1(_INT_1) { } + impl_Cexpression_elem_CExpressionPart::impl_Cexpression_elem_CExpressionPart(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_CexpressionDQ::phylum_sel_ = phylum_CexpressionDQ; + impl_CexpressionDQ::impl_CexpressionDQ(CexpressionDQ_elem p1 , CexpressionDQ p2) + : CexpressionDQ_elem_1(p1), CexpressionDQ_1(p2) { } + const enum_phyla impl_CexpressionDQ_elem::phylum_sel_ = phylum_CexpressionDQ_elem; + impl_CexpressionDQ_elem_CExpressionDQNl::impl_CexpressionDQ_elem_CExpressionDQNl() + { } + impl_CexpressionDQ_elem_CExpressionDQPart::impl_CexpressionDQ_elem_CExpressionDQPart(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_CexpressionSQ::phylum_sel_ = phylum_CexpressionSQ; + impl_CexpressionSQ::impl_CexpressionSQ(CexpressionSQ_elem p1 , CexpressionSQ p2) + : CexpressionSQ_elem_1(p1), CexpressionSQ_1(p2) { } + const enum_phyla impl_CexpressionSQ_elem::phylum_sel_ = phylum_CexpressionSQ_elem; + impl_CexpressionSQ_elem_CExpressionSQNl::impl_CexpressionSQ_elem_CExpressionSQNl() + { } + impl_CexpressionSQ_elem_CExpressionSQPart::impl_CexpressionSQ_elem_CExpressionSQPart(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_idCexpressions::phylum_sel_ = phylum_idCexpressions; + impl_idCexpressions::impl_idCexpressions(idCexpression p1 , idCexpressions p2) + : idCexpression_1(p1), idCexpressions_1(p2) { } + const enum_phyla impl_idCexpression::phylum_sel_ = phylum_idCexpression; + impl_idCexpression_IdCexpression::impl_idCexpression_IdCexpression(ID _ID_1, Cexpression _Cexpression_1) + : ID_1(_ID_1), Cexpression_1(_Cexpression_1) { } + const enum_phyla impl_Ctexts::phylum_sel_ = phylum_Ctexts; + impl_Ctexts::impl_Ctexts(Ctext p1 , Ctexts p2) + : Ctext_1(p1), Ctexts_1(p2) { } + const enum_phyla impl_includefiles::phylum_sel_ = phylum_includefiles; + impl_includefiles::impl_includefiles(includefile p1 , includefiles p2) + : includefile_1(p1), includefiles_1(p2) { } + const enum_phyla impl_includefile::phylum_sel_ = phylum_includefile; + impl_includefile_IncludeFile::impl_includefile_IncludeFile(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_includedeclarations::phylum_sel_ = phylum_includedeclarations; + impl_includedeclarations::impl_includedeclarations(includedeclaration p1 , includedeclarations p2) + : includedeclaration_1(p1), includedeclarations_1(p2) { } + const enum_phyla impl_includedeclaration::phylum_sel_ = phylum_includedeclaration; + impl_includedeclaration_IncludeDeclaration::impl_includedeclaration_IncludeDeclaration(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_rwdeclarations::phylum_sel_ = phylum_rwdeclarations; + impl_rwdeclarations::impl_rwdeclarations(rwdeclaration p1 , rwdeclarations p2) + : rwdeclaration_1(p1), rwdeclarations_1(p2) { } + const enum_phyla impl_rwdeclaration::phylum_sel_ = phylum_rwdeclaration; + impl_rwdeclaration_RwDeclaration::impl_rwdeclaration_RwDeclaration(outmostpatterns _outmostpatterns_1, rewriteclauses _rewriteclauses_1) + : outmostpatterns_1(_outmostpatterns_1), rewriteclauses_1(_rewriteclauses_1) { } + const enum_phyla impl_rewriteclauses::phylum_sel_ = phylum_rewriteclauses; + impl_rewriteclauses::impl_rewriteclauses(rewriteclause p1 , rewriteclauses p2) + : rewriteclause_1(p1), rewriteclauses_1(p2) { } + const enum_phyla impl_rewriteclause::phylum_sel_ = phylum_rewriteclause; + impl_rewriteclause_RewriteClause::impl_rewriteclause_RewriteClause(viewnames _viewnames_1, term _term_1) + : viewnames_1(_viewnames_1), term_1(_term_1) { } + const enum_phyla impl_patternchains::phylum_sel_ = phylum_patternchains; + impl_patternchains::impl_patternchains(patternchain p1 , patternchains p2) + : patternchain_1(p1), patternchains_1(p2) { } + const enum_phyla impl_patternchain::phylum_sel_ = phylum_patternchain; + impl_patternchain::impl_patternchain(patternchainitem p1 , patternchain p2) + : patternchainitem_1(p1), patternchain_1(p2) { } + const enum_phyla impl_outmostpatterns::phylum_sel_ = phylum_outmostpatterns; + impl_outmostpatterns::impl_outmostpatterns(outmostpattern p1 , outmostpatterns p2) + : outmostpattern_1(p1), outmostpatterns_1(p2) { } + const enum_phyla impl_patternchainitem::phylum_sel_ = phylum_patternchainitem; + impl_patternchainitem_PatternchainitemDollarid::impl_patternchainitem_PatternchainitemDollarid(ID _ID_1) + : ID_1(_ID_1) { } + impl_patternchainitem_PatternchainitemGroup::impl_patternchainitem_PatternchainitemGroup(patternchains _patternchains_1) + : patternchains_1(_patternchains_1) { } + impl_patternchainitem_PatternchainitemOutmost::impl_patternchainitem_PatternchainitemOutmost(outmostpattern _outmostpattern_1) + : outmostpattern_1(_outmostpattern_1) { } + const enum_phyla impl_outmostpattern::phylum_sel_ = phylum_outmostpattern; + impl_outmostpattern_OPDefault::impl_outmostpattern_OPDefault(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_outmostpattern_OPWildcard::impl_outmostpattern_OPWildcard(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_outmostpattern_OPNonLeafVariable::impl_outmostpattern_OPNonLeafVariable(ID _ID_1, outmostpattern _outmostpattern_1) + : ID_1(_ID_1), outmostpattern_1(_outmostpattern_1) { } + impl_outmostpattern_OPOperator::impl_outmostpattern_OPOperator(ID _ID_1, patterns _patterns_1, Cexpression _Cexpression_1) + : ID_1(_ID_1), patterns_1(_patterns_1), Cexpression_1(_Cexpression_1) { } + impl_outmostpattern_OPOperatorWildcard::impl_outmostpattern_OPOperatorWildcard(ID _ID_1, Cexpression _Cexpression_1) + : ID_1(_ID_1), Cexpression_1(_Cexpression_1) { } + const enum_phyla impl_pattern::phylum_sel_ = phylum_pattern; + impl_pattern_PIntLiteral::impl_pattern_PIntLiteral(INT _INT_1) + : INT_1(_INT_1) { } + impl_pattern_PStringLiteral::impl_pattern_PStringLiteral(CexpressionDQ _CexpressionDQ_1) + : CexpressionDQ_1(_CexpressionDQ_1) { } + impl_pattern_PWildcard::impl_pattern_PWildcard() + { } + impl_pattern_PNonLeafVariable::impl_pattern_PNonLeafVariable(ID _ID_1, pattern _pattern_1) + : ID_1(_ID_1), pattern_1(_pattern_1) { } + impl_pattern_POperator::impl_pattern_POperator(ID _ID_1, patterns _patterns_1) + : ID_1(_ID_1), patterns_1(_patterns_1) { } + impl_pattern_PVariable::impl_pattern_PVariable(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_patterns::phylum_sel_ = phylum_patterns; + impl_patterns::impl_patterns(pattern p1 , patterns p2) + : pattern_1(p1), patterns_1(p2) { } + const enum_phyla impl_term::phylum_sel_ = phylum_term; + impl_term_TIntLiteral::impl_term_TIntLiteral(INT _INT_1) + : INT_1(_INT_1) { } + impl_term_TStringLiteral::impl_term_TStringLiteral(CexpressionDQ _CexpressionDQ_1) + : CexpressionDQ_1(_CexpressionDQ_1) { } + impl_term_TCTerm::impl_term_TCTerm(CexpressionSQ _CexpressionSQ_1) + : CexpressionSQ_1(_CexpressionSQ_1) { } + impl_term_TMemberVarDot::impl_term_TMemberVarDot(term _term_1, ID _ID_1) + : term_1(_term_1), ID_1(_ID_1) { } + impl_term_TMemberVar::impl_term_TMemberVar(term _term_1, ID _ID_1) + : term_1(_term_1), ID_1(_ID_1) { } + impl_term_TMethodDot::impl_term_TMethodDot(term _term_1, ID _ID_1, terms _terms_1) + : term_1(_term_1), ID_1(_ID_1), terms_1(_terms_1) { } + impl_term_TMethod::impl_term_TMethod(term _term_1, ID _ID_1, terms _terms_1) + : term_1(_term_1), ID_1(_ID_1), terms_1(_terms_1) { } + impl_term_TOperator::impl_term_TOperator(ID _ID_1, terms _terms_1) + : ID_1(_ID_1), terms_1(_terms_1) { } + impl_term_TVariable::impl_term_TVariable(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_terms::phylum_sel_ = phylum_terms; + impl_terms::impl_terms(term p1 , terms p2) + : term_1(p1), terms_1(p2) { } + const enum_phyla impl_fnfiles::phylum_sel_ = phylum_fnfiles; + impl_fnfiles::impl_fnfiles(fnfile p1 , fnfiles p2) + : fnfile_1(p1), fnfiles_1(p2) { } + const enum_phyla impl_fnfile::phylum_sel_ = phylum_fnfile; + impl_fnfile_FnFile::impl_fnfile_FnFile(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_fndeclarations::phylum_sel_ = phylum_fndeclarations; + impl_fndeclarations::impl_fndeclarations(fndeclaration p1 , fndeclarations p2) + : fndeclaration_1(p1), fndeclarations_1(p2) { } + const enum_phyla impl_fndeclaration::phylum_sel_ = phylum_fndeclaration; + impl_fndeclaration_AcMemberDeclaration::impl_fndeclaration_AcMemberDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1, fnclass _fnclass_1) + : ac_declaration_specifiers_1(_ac_declaration_specifiers_1), ac_declarator_1(_ac_declarator_1), ac_constant_expression_option_1(_ac_constant_expression_option_1), fnclass_1(_fnclass_1) { } + impl_fndeclaration_FnAcDeclaration::impl_fndeclaration_FnAcDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_declaration_list _ac_declaration_list_1, ac_opt_base_init_list _ac_opt_base_init_list_1, Ctext _Ctext_1, ID _ID_1, fnclass _fnclass_1) + : ac_declaration_specifiers_1(_ac_declaration_specifiers_1), ac_declarator_1(_ac_declarator_1), ac_declaration_list_1(_ac_declaration_list_1), ac_opt_base_init_list_1(_ac_opt_base_init_list_1), Ctext_1(_Ctext_1), ID_1(_ID_1), fnclass_1(_fnclass_1) { } + const enum_phyla impl_fnclass::phylum_sel_ = phylum_fnclass; + impl_fnclass_ConvOperatorFn::impl_fnclass_ConvOperatorFn() + { } + impl_fnclass_DestructorFn::impl_fnclass_DestructorFn() + { } + impl_fnclass_ConstructorFn::impl_fnclass_ConstructorFn() + { } + impl_fnclass_MemberFn::impl_fnclass_MemberFn() + { } + impl_fnclass_StaticFn::impl_fnclass_StaticFn(casestring _casestring_1) + : casestring_1(_casestring_1) { } + impl_fnclass_GlobalFn::impl_fnclass_GlobalFn() + { } + const enum_phyla impl_Ctext::phylum_sel_ = phylum_Ctext; + impl_Ctext::impl_Ctext(Ctext_elem p1 , Ctext p2) + : Ctext_elem_1(p1), Ctext_1(p2) { } + const enum_phyla impl_Ctext_elem::phylum_sel_ = phylum_Ctext_elem; + impl_Ctext_elem_CTextWithexpression::impl_Ctext_elem_CTextWithexpression(withexpressions _withexpressions_1, withcases _withcases_1, contextinfo _contextinfo_1) + : withexpressions_1(_withexpressions_1), withcases_1(_withcases_1), contextinfo_1(_contextinfo_1) { } + impl_Ctext_elem_CTextForeachexpression::impl_Ctext_elem_CTextForeachexpression(patternchain _patternchain_1, idCexpressions _idCexpressions_1, withexpressions _withexpressions_1, Ctext _Ctext_1, foreach_after _foreach_after_1) + : patternchain_1(_patternchain_1), idCexpressions_1(_idCexpressions_1), withexpressions_1(_withexpressions_1), Ctext_1(_Ctext_1), foreach_after_1(_foreach_after_1) { } + impl_Ctext_elem_CTextCbody::impl_Ctext_elem_CTextCbody(Ctext _Ctext_1) + : Ctext_1(_Ctext_1) { } + impl_Ctext_elem_CTextCexpressionSQ::impl_Ctext_elem_CTextCexpressionSQ(CexpressionSQ _CexpressionSQ_1) + : CexpressionSQ_1(_CexpressionSQ_1) { } + impl_Ctext_elem_CTextCexpressionDQ::impl_Ctext_elem_CTextCexpressionDQ(CexpressionDQ _CexpressionDQ_1) + : CexpressionDQ_1(_CexpressionDQ_1) { } + impl_Ctext_elem_CTextNl::impl_Ctext_elem_CTextNl(integer _integer_1) + : integer_1(_integer_1) { } + impl_Ctext_elem_CTextDollarVar::impl_Ctext_elem_CTextDollarVar(INT _INT_1) + : INT_1(_INT_1) { } + impl_Ctext_elem_CTextLine::impl_Ctext_elem_CTextLine(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_foreach_after::phylum_sel_ = phylum_foreach_after; + impl_foreach_after_ForeachAfter::impl_foreach_after_ForeachAfter(patternchain _patternchain_1, idCexpressions _idCexpressions_1, withexpressions _withexpressions_1, Ctext _Ctext_1) + : patternchain_1(_patternchain_1), idCexpressions_1(_idCexpressions_1), withexpressions_1(_withexpressions_1), Ctext_1(_Ctext_1) { } + impl_foreach_after_NoForeachAfter::impl_foreach_after_NoForeachAfter() + { } + const enum_phyla impl_contextinfo::phylum_sel_ = phylum_contextinfo; + impl_contextinfo_NotInForeachContext::impl_contextinfo_NotInForeachContext() + { } + impl_contextinfo_InForeachContext::impl_contextinfo_InForeachContext(patternchain _patternchain_1) + : patternchain_1(_patternchain_1) { } + const enum_phyla impl_withexpressions::phylum_sel_ = phylum_withexpressions; + impl_withexpressions::impl_withexpressions(withexpression p1 , withexpressions p2) + : withexpression_1(p1), withexpressions_1(p2) { } + const enum_phyla impl_withexpression::phylum_sel_ = phylum_withexpression; + impl_withexpression_WECexpression::impl_withexpression_WECexpression(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_withexpression_WEVariable::impl_withexpression_WEVariable(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_withcases::phylum_sel_ = phylum_withcases; + impl_withcases::impl_withcases(withcase p1 , withcases p2) + : withcase_1(p1), withcases_1(p2) { } + const enum_phyla impl_withcase::phylum_sel_ = phylum_withcase; + impl_withcase_Withcase::impl_withcase_Withcase(patternchains _patternchains_1, Ctext _Ctext_1) + : patternchains_1(_patternchains_1), Ctext_1(_Ctext_1) { } + const enum_phyla impl_unparsedeclarations::phylum_sel_ = phylum_unparsedeclarations; + impl_unparsedeclarations::impl_unparsedeclarations(unparsedeclaration p1 , unparsedeclarations p2) + : unparsedeclaration_1(p1), unparsedeclarations_1(p2) { } + const enum_phyla impl_unparsedeclaration::phylum_sel_ = phylum_unparsedeclaration; + impl_unparsedeclaration_UnparseDeclaration::impl_unparsedeclaration_UnparseDeclaration(outmostpatterns _outmostpatterns_1, unparseclauses _unparseclauses_1) + : outmostpatterns_1(_outmostpatterns_1), unparseclauses_1(_unparseclauses_1) { } + const enum_phyla impl_unparseclauses::phylum_sel_ = phylum_unparseclauses; + impl_unparseclauses::impl_unparseclauses(unparseclause p1 , unparseclauses p2) + : unparseclause_1(p1), unparseclauses_1(p2) { } + const enum_phyla impl_unparseclause::phylum_sel_ = phylum_unparseclause; + impl_unparseclause_UnparseClause::impl_unparseclause_UnparseClause(viewnames _viewnames_1, unparseitems _unparseitems_1) + : viewnames_1(_viewnames_1), unparseitems_1(_unparseitems_1) { } + const enum_phyla impl_viewnames::phylum_sel_ = phylum_viewnames; + impl_viewnames::impl_viewnames(ID p1 , viewnames p2) + : ID_1(p1), viewnames_1(p2) { } + const enum_phyla impl_unparseitems::phylum_sel_ = phylum_unparseitems; + impl_unparseitems::impl_unparseitems(unparseitem p1 , unparseitems p2) + : unparseitem_1(p1), unparseitems_1(p2) { } + const enum_phyla impl_unparseitem::phylum_sel_ = phylum_unparseitem; + impl_unparseitem_UViewVarDecl::impl_unparseitem_UViewVarDecl(ID _ID_1, ID _ID_2, Cexpression _Cexpression_1) + : ID_1(_ID_1), ID_2(_ID_2), Cexpression_1(_Cexpression_1) { } + impl_unparseitem_UnpBody::impl_unparseitem_UnpBody(languageoption _languageoption_1, unparseitems _unparseitems_1) + : languageoption_1(_languageoption_1), unparseitems_1(_unparseitems_1) { } + impl_unparseitem_UnpCtext::impl_unparseitem_UnpCtext(languageoption _languageoption_1, Ctext _Ctext_1) + : languageoption_1(_languageoption_1), Ctext_1(_Ctext_1) { } + impl_unparseitem_UnpSubexpr::impl_unparseitem_UnpSubexpr(languageoption _languageoption_1, unpsubterm _unpsubterm_1, viewnameoption _viewnameoption_1) + : languageoption_1(_languageoption_1), unpsubterm_1(_unpsubterm_1), viewnameoption_1(_viewnameoption_1) { } + impl_unparseitem_UnpStr::impl_unparseitem_UnpStr(languageoption _languageoption_1, CexpressionDQ _CexpressionDQ_1, viewnameoption _viewnameoption_1) + : languageoption_1(_languageoption_1), CexpressionDQ_1(_CexpressionDQ_1), viewnameoption_1(_viewnameoption_1) { } + const enum_phyla impl_unpsubterm::phylum_sel_ = phylum_unpsubterm; + impl_unpsubterm_UnpCastedVariable::impl_unpsubterm_UnpCastedVariable(ID _ID_1, ID _ID_2) + : ID_1(_ID_1), ID_2(_ID_2) { } + impl_unpsubterm_UnpDollarvarAttr::impl_unpsubterm_UnpDollarvarAttr(INT _INT_1, unpattributes _unpattributes_1) + : INT_1(_INT_1), unpattributes_1(_unpattributes_1) { } + impl_unpsubterm_UnpSubAttr::impl_unpsubterm_UnpSubAttr(ID _ID_1, unpattributes _unpattributes_1) + : ID_1(_ID_1), unpattributes_1(_unpattributes_1) { } + impl_unpsubterm_UnpDollarvarTerm::impl_unpsubterm_UnpDollarvarTerm(INT _INT_1) + : INT_1(_INT_1) { } + impl_unpsubterm_UnpSubTerm::impl_unpsubterm_UnpSubTerm(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_unpattributes::phylum_sel_ = phylum_unpattributes; + impl_unpattributes::impl_unpattributes(ID p1 , unpattributes p2) + : ID_1(p1), unpattributes_1(p2) { } + const enum_phyla impl_viewnameoption::phylum_sel_ = phylum_viewnameoption; + impl_viewnameoption_YesViewname::impl_viewnameoption_YesViewname(ID _ID_1) + : ID_1(_ID_1) { } + impl_viewnameoption_NoViewname::impl_viewnameoption_NoViewname() + { } + const enum_phyla impl_languageoption::phylum_sel_ = phylum_languageoption; + impl_languageoption_LanguageList::impl_languageoption_LanguageList(languagenames _languagenames_1) + : languagenames_1(_languagenames_1) { } + impl_languageoption_NoLanguagename::impl_languageoption_NoLanguagename() + { } + const enum_phyla impl_languagenames::phylum_sel_ = phylum_languagenames; + impl_languagenames::impl_languagenames(ID p1 , languagenames p2) + : ID_1(p1), languagenames_1(p2) { } + const enum_phyla impl_fileline::phylum_sel_ = phylum_fileline; + impl_fileline_PosNoFileLine::impl_fileline_PosNoFileLine() + { } + impl_fileline_NoFileLine::impl_fileline_NoFileLine() + { } + const enum_phyla impl_scopetypefilelinestack::phylum_sel_ = phylum_scopetypefilelinestack; + impl_scopetypefilelinestack::impl_scopetypefilelinestack(scopetypefileline p1 , scopetypefilelinestack p2) + : scopetypefileline_1(p1), scopetypefilelinestack_1(p2) { } + const enum_phyla impl_scopetypefileline::phylum_sel_ = phylum_scopetypefileline; + impl_scopetypefileline_ScopeTypeFileLine::impl_scopetypefileline_ScopeTypeFileLine(integer _integer_1, IDtype _IDtype_1, casestring _casestring_1, integer _integer_2) + : integer_1(_integer_1), IDtype_1(_IDtype_1), casestring_1(_casestring_1), integer_2(_integer_2) { } + const enum_phyla impl_IDtype::phylum_sel_ = phylum_IDtype; + impl_IDtype_ITLanguageName::impl_IDtype_ITLanguageName(integer _integer_1) + : integer_1(_integer_1) { } + impl_IDtype_ITPatternVariable::impl_IDtype_ITPatternVariable(ID _ID_1, integer _integer_1) + : ID_1(_ID_1), integer_1(_integer_1) { } + impl_IDtype_ITUserFunction::impl_IDtype_ITUserFunction(fnclass _fnclass_1) + : fnclass_1(_fnclass_1) { } + impl_IDtype_ITUserRView::impl_IDtype_ITUserRView() + { } + impl_IDtype_ITPredefinedRView::impl_IDtype_ITPredefinedRView() + { } + impl_IDtype_ITUViewVar::impl_IDtype_ITUViewVar() + { } + impl_IDtype_ITUserUView::impl_IDtype_ITUserUView() + { } + impl_IDtype_ITPredefinedUView::impl_IDtype_ITPredefinedUView() + { } + impl_IDtype_ITStorageClass::impl_IDtype_ITStorageClass() + { } + impl_IDtype_ITPredefinedStorageClass::impl_IDtype_ITPredefinedStorageClass() + { } + impl_IDtype_ITUserOperator::impl_IDtype_ITUserOperator(alternative _alternative_1, ID _ID_1) + : alternative_1(_alternative_1), ID_1(_ID_1) { } + impl_IDtype_ITPredefinedOperator::impl_IDtype_ITPredefinedOperator(alternative _alternative_1, ID _ID_1) + : alternative_1(_alternative_1), ID_1(_ID_1) { } + impl_IDtype_ITUserPhylum::impl_IDtype_ITUserPhylum(phylumdeclaration _phylumdeclaration_1) + : phylumdeclaration_1(_phylumdeclaration_1) { } + impl_IDtype_ITPredefinedPhylum::impl_IDtype_ITPredefinedPhylum(phylumdeclaration _phylumdeclaration_1) + : phylumdeclaration_1(_phylumdeclaration_1) { } + impl_IDtype_ITUnknown::impl_IDtype_ITUnknown() + { } + const enum_phyla impl_operators::phylum_sel_ = phylum_operators; + impl_operators::impl_operators(ID p1 , operators p2) + : ID_1(p1), operators_1(p2) { } + const enum_phyla impl_phyla::phylum_sel_ = phylum_phyla; + impl_phyla::impl_phyla(ID p1 , phyla p2) + : ID_1(p1), phyla_1(p2) { } + const enum_phyla impl_variables::phylum_sel_ = phylum_variables; + impl_variables::impl_variables(ID p1 , variables p2) + : ID_1(p1), variables_1(p2) { } + const enum_phyla impl_dollarvarstatus::phylum_sel_ = phylum_dollarvarstatus; + impl_dollarvarstatus_DVDisallowed::impl_dollarvarstatus_DVDisallowed() + { } + impl_dollarvarstatus_DVAllowed::impl_dollarvarstatus_DVAllowed() + { } + const enum_phyla impl_tribool::phylum_sel_ = phylum_tribool; + impl_tribool_Bigger::impl_tribool_Bigger() + { } + impl_tribool_Smaller::impl_tribool_Smaller() + { } + impl_tribool_Equal::impl_tribool_Equal() + { } + const enum_phyla impl_patternrepresentations::phylum_sel_ = phylum_patternrepresentations; + impl_patternrepresentations::impl_patternrepresentations(patternrepresentation p1 , patternrepresentations p2) + : patternrepresentation_1(p1), patternrepresentations_1(p2) { } + const enum_phyla impl_patternrepresentation::phylum_sel_ = phylum_patternrepresentation; + impl_patternrepresentation::impl_patternrepresentation(elem_patternrepresentation p1 , patternrepresentation p2) + : elem_patternrepresentation_1(p1), patternrepresentation_1(p2) { } + const enum_phyla impl_elem_patternrepresentation::phylum_sel_ = phylum_elem_patternrepresentation; + impl_elem_patternrepresentation_PRIntLiteral::impl_elem_patternrepresentation_PRIntLiteral(path _path_1, INT _INT_1) + : path_1(_path_1), INT_1(_INT_1) { } + impl_elem_patternrepresentation_PRStringLiteral::impl_elem_patternrepresentation_PRStringLiteral(path _path_1, CexpressionDQ _CexpressionDQ_1) + : path_1(_path_1), CexpressionDQ_1(_CexpressionDQ_1) { } + impl_elem_patternrepresentation_PRDefault::impl_elem_patternrepresentation_PRDefault() + { } + impl_elem_patternrepresentation_PRWildcard::impl_elem_patternrepresentation_PRWildcard(path _path_1) + : path_1(_path_1) { } + impl_elem_patternrepresentation_PRNonLeafBinding::impl_elem_patternrepresentation_PRNonLeafBinding(path _path_1, ID _ID_1, patternrepresentation _patternrepresentation_1) + : path_1(_path_1), ID_1(_ID_1), patternrepresentation_1(_patternrepresentation_1) { } + impl_elem_patternrepresentation_PRUserPredicate::impl_elem_patternrepresentation_PRUserPredicate(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + impl_elem_patternrepresentation_PROperPredicate::impl_elem_patternrepresentation_PROperPredicate(path _path_1, ID _ID_1) + : path_1(_path_1), ID_1(_ID_1) { } + impl_elem_patternrepresentation_PRVarPredicate::impl_elem_patternrepresentation_PRVarPredicate(paths _paths_1, ID _ID_1, patternrepresentation _patternrepresentation_1) + : paths_1(_paths_1), ID_1(_ID_1), patternrepresentation_1(_patternrepresentation_1) { } + impl_elem_patternrepresentation_PRBinding::impl_elem_patternrepresentation_PRBinding(path _path_1, ID _ID_1) + : path_1(_path_1), ID_1(_ID_1) { } + const enum_phyla impl_path::phylum_sel_ = phylum_path; + impl_path::impl_path(integer p1 , path p2) + : integer_1(p1), path_1(p2) { } + const enum_phyla impl_paths::phylum_sel_ = phylum_paths; + impl_paths::impl_paths(path p1 , paths p2) + : path_1(p1), paths_1(p2) { } + const enum_phyla impl_argsnumbers::phylum_sel_ = phylum_argsnumbers; + impl_argsnumbers::impl_argsnumbers(integer p1 , argsnumbers p2) + : integer_1(p1), argsnumbers_1(p2) { } + const enum_phyla impl_rewriterulesinfo::phylum_sel_ = phylum_rewriterulesinfo; + impl_rewriterulesinfo::impl_rewriterulesinfo(rewriteruleinfo p1 , rewriterulesinfo p2) + : rewriteruleinfo_1(p1), rewriterulesinfo_1(p2) { } + const enum_phyla impl_rewriteruleinfo::phylum_sel_ = phylum_rewriteruleinfo; + impl_rewriteruleinfo_Rewriteruleinfo::impl_rewriteruleinfo_Rewriteruleinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, rewriteclause _rewriteclause_1) + : patternrepresentation_1(_patternrepresentation_1), patternrepresentation_2(_patternrepresentation_2), rewriteclause_1(_rewriteclause_1) { } + const enum_phyla impl_withcasesinfo::phylum_sel_ = phylum_withcasesinfo; + impl_withcasesinfo::impl_withcasesinfo(withcaseinfo p1 , withcasesinfo p2) + : withcaseinfo_1(p1), withcasesinfo_1(p2) { } + const enum_phyla impl_withcaseinfo::phylum_sel_ = phylum_withcaseinfo; + impl_withcaseinfo_Withcaseinfo::impl_withcaseinfo_Withcaseinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, Ctext _Ctext_1) + : patternrepresentation_1(_patternrepresentation_1), patternrepresentation_2(_patternrepresentation_2), Ctext_1(_Ctext_1) { } + const enum_phyla impl_rewriteviewsinfo::phylum_sel_ = phylum_rewriteviewsinfo; + impl_rewriteviewsinfo::impl_rewriteviewsinfo(rewriteviewinfo p1 , rewriteviewsinfo p2) + : rewriteviewinfo_1(p1), rewriteviewsinfo_1(p2) { } + const enum_phyla impl_rewriteviewinfo::phylum_sel_ = phylum_rewriteviewinfo; + impl_rewriteviewinfo_Rewriteviewinfo::impl_rewriteviewinfo_Rewriteviewinfo(ID _ID_1, rewriterulesinfo _rewriterulesinfo_1) + : ID_1(_ID_1), rewriterulesinfo_1(_rewriterulesinfo_1) { } + const enum_phyla impl_unparseviewsinfo::phylum_sel_ = phylum_unparseviewsinfo; + impl_unparseviewsinfo::impl_unparseviewsinfo(unparseviewinfo p1 , unparseviewsinfo p2) + : unparseviewinfo_1(p1), unparseviewsinfo_1(p2) { } + const enum_phyla impl_unparseviewinfo::phylum_sel_ = phylum_unparseviewinfo; + impl_unparseviewinfo_Unparseviewinfo::impl_unparseviewinfo_Unparseviewinfo(ID _ID_1, unparsedeclsinfo _unparsedeclsinfo_1) + : ID_1(_ID_1), unparsedeclsinfo_1(_unparsedeclsinfo_1) { } + const enum_phyla impl_unparsedeclsinfo::phylum_sel_ = phylum_unparsedeclsinfo; + impl_unparsedeclsinfo::impl_unparsedeclsinfo(unparsedeclinfo p1 , unparsedeclsinfo p2) + : unparsedeclinfo_1(p1), unparsedeclsinfo_1(p2) { } + const enum_phyla impl_unparsedeclinfo::phylum_sel_ = phylum_unparsedeclinfo; + impl_unparsedeclinfo_Unparsedeclinfo::impl_unparsedeclinfo_Unparsedeclinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, unparseclause _unparseclause_1) + : patternrepresentation_1(_patternrepresentation_1), patternrepresentation_2(_patternrepresentation_2), unparseclause_1(_unparseclause_1) { } + const enum_phyla impl_ac_declaration::phylum_sel_ = phylum_ac_declaration; + impl_ac_declaration_AcDeclaration::impl_ac_declaration_AcDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_init_declarator_list _ac_init_declarator_list_1) + : ac_declaration_specifiers_1(_ac_declaration_specifiers_1), ac_init_declarator_list_1(_ac_init_declarator_list_1) { } + const enum_phyla impl_ac_declaration_list::phylum_sel_ = phylum_ac_declaration_list; + impl_ac_declaration_list::impl_ac_declaration_list(ac_declaration p1 , ac_declaration_list p2) + : ac_declaration_1(p1), ac_declaration_list_1(p2) { } + const enum_phyla impl_ac_declaration_specifiers::phylum_sel_ = phylum_ac_declaration_specifiers; + impl_ac_declaration_specifiers::impl_ac_declaration_specifiers(ac_declaration_specifier p1 , ac_declaration_specifiers p2) + : ac_declaration_specifier_1(p1), ac_declaration_specifiers_1(p2) { } + const enum_phyla impl_ac_declaration_specifier::phylum_sel_ = phylum_ac_declaration_specifier; + impl_ac_declaration_specifier_AcDeclSpecTypeQual::impl_ac_declaration_specifier_AcDeclSpecTypeQual(ac_type_qualifier _ac_type_qualifier_1) + : ac_type_qualifier_1(_ac_type_qualifier_1) { } + impl_ac_declaration_specifier_AcDeclSpecTypeSpec::impl_ac_declaration_specifier_AcDeclSpecTypeSpec(ac_type_specifier _ac_type_specifier_1) + : ac_type_specifier_1(_ac_type_specifier_1) { } + impl_ac_declaration_specifier_AcDeclSpecStorageSpec::impl_ac_declaration_specifier_AcDeclSpecStorageSpec(ac_storage_class_specifier _ac_storage_class_specifier_1) + : ac_storage_class_specifier_1(_ac_storage_class_specifier_1) { } + const enum_phyla impl_ac_storage_class_specifier::phylum_sel_ = phylum_ac_storage_class_specifier; + impl_ac_storage_class_specifier_AcVirtual::impl_ac_storage_class_specifier_AcVirtual() + { } + impl_ac_storage_class_specifier_AcTypedef::impl_ac_storage_class_specifier_AcTypedef() + { } + impl_ac_storage_class_specifier_AcExtern::impl_ac_storage_class_specifier_AcExtern() + { } + impl_ac_storage_class_specifier_AcStatic::impl_ac_storage_class_specifier_AcStatic() + { } + impl_ac_storage_class_specifier_AcRegister::impl_ac_storage_class_specifier_AcRegister() + { } + impl_ac_storage_class_specifier_AcAuto::impl_ac_storage_class_specifier_AcAuto() + { } + const enum_phyla impl_ac_type_specifier::phylum_sel_ = phylum_ac_type_specifier; + impl_ac_type_specifier_AcTypeSpec::impl_ac_type_specifier_AcTypeSpec(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_ac_type_qualifier::phylum_sel_ = phylum_ac_type_qualifier; + impl_ac_type_qualifier_AcNoQualifier::impl_ac_type_qualifier_AcNoQualifier() + { } + impl_ac_type_qualifier_AcUnsigned::impl_ac_type_qualifier_AcUnsigned() + { } + impl_ac_type_qualifier_AcVolatile::impl_ac_type_qualifier_AcVolatile() + { } + impl_ac_type_qualifier_AcConst::impl_ac_type_qualifier_AcConst() + { } + const enum_phyla impl_ac_init_declarator_list::phylum_sel_ = phylum_ac_init_declarator_list; + impl_ac_init_declarator_list::impl_ac_init_declarator_list(ac_init_declarator p1 , ac_init_declarator_list p2) + : ac_init_declarator_1(p1), ac_init_declarator_list_1(p2) { } + const enum_phyla impl_ac_init_declarator::phylum_sel_ = phylum_ac_init_declarator; + impl_ac_init_declarator_AcInitDecl::impl_ac_init_declarator_AcInitDecl(ac_declarator _ac_declarator_1) + : ac_declarator_1(_ac_declarator_1) { } + const enum_phyla impl_ac_declarator::phylum_sel_ = phylum_ac_declarator; + impl_ac_declarator_AcDeclarator::impl_ac_declarator_AcDeclarator(ac_pointer_option _ac_pointer_option_1, ac_ref_option _ac_ref_option_1, ac_direct_declarator _ac_direct_declarator_1) + : ac_pointer_option_1(_ac_pointer_option_1), ac_ref_option_1(_ac_ref_option_1), ac_direct_declarator_1(_ac_direct_declarator_1) { } + const enum_phyla impl_ac_direct_declarator::phylum_sel_ = phylum_ac_direct_declarator; + impl_ac_direct_declarator_AcOperatorDeclId::impl_ac_direct_declarator_AcOperatorDeclId(ac_operator_name _ac_operator_name_1) + : ac_operator_name_1(_ac_operator_name_1) { } + impl_ac_direct_declarator_AcConvOperatorDecl::impl_ac_direct_declarator_AcConvOperatorDecl(ID _ID_1, ID _ID_2) + : ID_1(_ID_1), ID_2(_ID_2) { } + impl_ac_direct_declarator_AcMemberDecl::impl_ac_direct_declarator_AcMemberDecl(ID _ID_1, ID _ID_2, ac_constant_expression_list _ac_constant_expression_list_1) + : ID_1(_ID_1), ID_2(_ID_2), ac_constant_expression_list_1(_ac_constant_expression_list_1) { } + impl_ac_direct_declarator_AcQualifiedDeclProto::impl_ac_direct_declarator_AcQualifiedDeclProto(ac_class_qualifier_list _ac_class_qualifier_list_1, ac_direct_declarator _ac_direct_declarator_1, ac_parameter_type_list _ac_parameter_type_list_1, ac_type_qualifier _ac_type_qualifier_1) + : ac_class_qualifier_list_1(_ac_class_qualifier_list_1), ac_direct_declarator_1(_ac_direct_declarator_1), ac_parameter_type_list_1(_ac_parameter_type_list_1), ac_type_qualifier_1(_ac_type_qualifier_1) { } + impl_ac_direct_declarator_AcDirectDeclProto::impl_ac_direct_declarator_AcDirectDeclProto(ac_direct_declarator _ac_direct_declarator_1, ac_parameter_type_list _ac_parameter_type_list_1) + : ac_direct_declarator_1(_ac_direct_declarator_1), ac_parameter_type_list_1(_ac_parameter_type_list_1) { } + impl_ac_direct_declarator_AcDirectDeclArray::impl_ac_direct_declarator_AcDirectDeclArray(ac_direct_declarator _ac_direct_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) + : ac_direct_declarator_1(_ac_direct_declarator_1), ac_constant_expression_option_1(_ac_constant_expression_option_1) { } + impl_ac_direct_declarator_AcDirectDeclPack::impl_ac_direct_declarator_AcDirectDeclPack(ac_declarator _ac_declarator_1) + : ac_declarator_1(_ac_declarator_1) { } + impl_ac_direct_declarator_AcDirectDeclId::impl_ac_direct_declarator_AcDirectDeclId(ID _ID_1) + : ID_1(_ID_1) { } + const enum_phyla impl_ac_pointer_option::phylum_sel_ = phylum_ac_pointer_option; + impl_ac_pointer_option_Yespointer::impl_ac_pointer_option_Yespointer(ac_pointer _ac_pointer_1) + : ac_pointer_1(_ac_pointer_1) { } + impl_ac_pointer_option_Nopointer::impl_ac_pointer_option_Nopointer() + { } + const enum_phyla impl_ac_pointer::phylum_sel_ = phylum_ac_pointer; + impl_ac_pointer_AcPointerCons::impl_ac_pointer_AcPointerCons(ac_type_qualifier_list _ac_type_qualifier_list_1, ac_pointer _ac_pointer_1) + : ac_type_qualifier_list_1(_ac_type_qualifier_list_1), ac_pointer_1(_ac_pointer_1) { } + impl_ac_pointer_AcPointerNil::impl_ac_pointer_AcPointerNil(ac_type_qualifier_list _ac_type_qualifier_list_1) + : ac_type_qualifier_list_1(_ac_type_qualifier_list_1) { } + const enum_phyla impl_ac_ref_option::phylum_sel_ = phylum_ac_ref_option; + impl_ac_ref_option_AcRef::impl_ac_ref_option_AcRef() + { } + impl_ac_ref_option_AcNoRef::impl_ac_ref_option_AcNoRef() + { } + const enum_phyla impl_ac_operator_name::phylum_sel_ = phylum_ac_operator_name; + impl_ac_operator_name_AcOperatorName::impl_ac_operator_name_AcOperatorName(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_ac_class_qualifier_help_list::phylum_sel_ = phylum_ac_class_qualifier_help_list; + impl_ac_class_qualifier_help_list::impl_ac_class_qualifier_help_list(ac_direct_declarator p1 , ac_class_qualifier_help_list p2) + : ac_direct_declarator_1(p1), ac_class_qualifier_help_list_1(p2) { } + const enum_phyla impl_ac_class_qualifier_list::phylum_sel_ = phylum_ac_class_qualifier_list; + impl_ac_class_qualifier_list::impl_ac_class_qualifier_list(ID p1 , ac_class_qualifier_list p2) + : ID_1(p1), ac_class_qualifier_list_1(p2) { } + const enum_phyla impl_ac_type_qualifier_list::phylum_sel_ = phylum_ac_type_qualifier_list; + impl_ac_type_qualifier_list::impl_ac_type_qualifier_list(ac_type_qualifier p1 , ac_type_qualifier_list p2) + : ac_type_qualifier_1(p1), ac_type_qualifier_list_1(p2) { } + const enum_phyla impl_ac_parameter_type_list::phylum_sel_ = phylum_ac_parameter_type_list; + impl_ac_parameter_type_list_AcParList3Dot::impl_ac_parameter_type_list_AcParList3Dot(ac_parameter_list _ac_parameter_list_1) + : ac_parameter_list_1(_ac_parameter_list_1) { } + impl_ac_parameter_type_list_AcParList::impl_ac_parameter_type_list_AcParList(ac_parameter_list _ac_parameter_list_1) + : ac_parameter_list_1(_ac_parameter_list_1) { } + const enum_phyla impl_ac_parameter_list::phylum_sel_ = phylum_ac_parameter_list; + impl_ac_parameter_list::impl_ac_parameter_list(ac_parameter_declaration p1 , ac_parameter_list p2) + : ac_parameter_declaration_1(p1), ac_parameter_list_1(p2) { } + const enum_phyla impl_ac_parameter_declaration::phylum_sel_ = phylum_ac_parameter_declaration; + impl_ac_parameter_declaration_AcParDeclAbsdecl::impl_ac_parameter_declaration_AcParDeclAbsdecl(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_abstract_declarator _ac_abstract_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) + : ac_declaration_specifiers_1(_ac_declaration_specifiers_1), ac_abstract_declarator_1(_ac_abstract_declarator_1), ac_constant_expression_option_1(_ac_constant_expression_option_1) { } + impl_ac_parameter_declaration_AcParDeclDecl::impl_ac_parameter_declaration_AcParDeclDecl(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) + : ac_declaration_specifiers_1(_ac_declaration_specifiers_1), ac_declarator_1(_ac_declarator_1), ac_constant_expression_option_1(_ac_constant_expression_option_1) { } + const enum_phyla impl_ac_identifier_list::phylum_sel_ = phylum_ac_identifier_list; + impl_ac_identifier_list::impl_ac_identifier_list(ID p1 , ac_identifier_list p2) + : ID_1(p1), ac_identifier_list_1(p2) { } + const enum_phyla impl_ac_abstract_declarator::phylum_sel_ = phylum_ac_abstract_declarator; + impl_ac_abstract_declarator_AcAbsdeclDirdecl::impl_ac_abstract_declarator_AcAbsdeclDirdecl(ac_pointer_option _ac_pointer_option_1, ac_direct_abstract_declarator _ac_direct_abstract_declarator_1) + : ac_pointer_option_1(_ac_pointer_option_1), ac_direct_abstract_declarator_1(_ac_direct_abstract_declarator_1) { } + impl_ac_abstract_declarator_AcAbsdeclPointer::impl_ac_abstract_declarator_AcAbsdeclPointer(ac_pointer _ac_pointer_1) + : ac_pointer_1(_ac_pointer_1) { } + const enum_phyla impl_ac_direct_abstract_declarator_option::phylum_sel_ = phylum_ac_direct_abstract_declarator_option; + impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator::impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator(ac_direct_abstract_declarator _ac_direct_abstract_declarator_1) + : ac_direct_abstract_declarator_1(_ac_direct_abstract_declarator_1) { } + impl_ac_direct_abstract_declarator_option_Noac_direct_abstract_declarator::impl_ac_direct_abstract_declarator_option_Noac_direct_abstract_declarator() + { } + const enum_phyla impl_ac_direct_abstract_declarator::phylum_sel_ = phylum_ac_direct_abstract_declarator; + impl_ac_direct_abstract_declarator_AcDirAbsdeclFn::impl_ac_direct_abstract_declarator_AcDirAbsdeclFn(ac_direct_abstract_declarator_option _ac_direct_abstract_declarator_option_1, ac_parameter_type_list _ac_parameter_type_list_1) + : ac_direct_abstract_declarator_option_1(_ac_direct_abstract_declarator_option_1), ac_parameter_type_list_1(_ac_parameter_type_list_1) { } + impl_ac_direct_abstract_declarator_AcDirAbsdeclArray::impl_ac_direct_abstract_declarator_AcDirAbsdeclArray(ac_direct_abstract_declarator_option _ac_direct_abstract_declarator_option_1, ac_constant_expression_option _ac_constant_expression_option_1) + : ac_direct_abstract_declarator_option_1(_ac_direct_abstract_declarator_option_1), ac_constant_expression_option_1(_ac_constant_expression_option_1) { } + impl_ac_direct_abstract_declarator_AcDirAbsdeclPack::impl_ac_direct_abstract_declarator_AcDirAbsdeclPack(ac_abstract_declarator _ac_abstract_declarator_1) + : ac_abstract_declarator_1(_ac_abstract_declarator_1) { } + const enum_phyla impl_ac_constant_expression_option::phylum_sel_ = phylum_ac_constant_expression_option; + impl_ac_constant_expression_option_Noac_constant_expression::impl_ac_constant_expression_option_Noac_constant_expression() + { } + impl_ac_constant_expression_option_Yesac_constant_expression::impl_ac_constant_expression_option_Yesac_constant_expression(ac_constant_expression _ac_constant_expression_1) + : ac_constant_expression_1(_ac_constant_expression_1) { } + const enum_phyla impl_ac_constant_expression::phylum_sel_ = phylum_ac_constant_expression; + impl_ac_constant_expression_AcConstExpr::impl_ac_constant_expression_AcConstExpr(Cexpression _Cexpression_1) + : Cexpression_1(_Cexpression_1) { } + const enum_phyla impl_ac_constant_expression_list::phylum_sel_ = phylum_ac_constant_expression_list; + impl_ac_constant_expression_list::impl_ac_constant_expression_list(ac_constant_expression p1 , ac_constant_expression_list p2) + : ac_constant_expression_1(p1), ac_constant_expression_list_1(p2) { } + const enum_phyla impl_ac_opt_base_init_list::phylum_sel_ = phylum_ac_opt_base_init_list; + impl_ac_opt_base_init_list_AcYesBaseInit::impl_ac_opt_base_init_list_AcYesBaseInit(ac_base_init_list _ac_base_init_list_1) + : ac_base_init_list_1(_ac_base_init_list_1) { } + impl_ac_opt_base_init_list_AcNoBaseInit::impl_ac_opt_base_init_list_AcNoBaseInit() + { } + const enum_phyla impl_ac_base_init_list::phylum_sel_ = phylum_ac_base_init_list; + impl_ac_base_init_list::impl_ac_base_init_list(ac_base_init p1 , ac_base_init_list p2) + : ac_base_init_1(p1), ac_base_init_list_1(p2) { } + const enum_phyla impl_ac_base_init::phylum_sel_ = phylum_ac_base_init; + impl_ac_base_init_AcBaseInit::impl_ac_base_init_AcBaseInit(ID _ID_1, ac_constant_expression _ac_constant_expression_1) + : ID_1(_ID_1), ac_constant_expression_1(_ac_constant_expression_1) { } + const enum_phyla impl_baseclass_declarations::phylum_sel_ = phylum_baseclass_declarations; + impl_baseclass_declarations::impl_baseclass_declarations(baseclass_decl p1 , baseclass_declarations p2) + : baseclass_decl_1(p1), baseclass_declarations_1(p2) { } + const enum_phyla impl_baseclass_decl::phylum_sel_ = phylum_baseclass_decl; + impl_baseclass_decl_BaseClassDecl::impl_baseclass_decl_BaseClassDecl(ID _ID_1, baseclass_list _baseclass_list_1) + : ID_1(_ID_1), baseclass_list_1(_baseclass_list_1) { } + const enum_phyla impl_baseclass_list::phylum_sel_ = phylum_baseclass_list; + impl_baseclass_list::impl_baseclass_list(ID p1 , baseclass_list p2) + : ID_1(p1), baseclass_list_1(p2) { } + const enum_phyla impl_error::phylum_sel_ = phylum_error; + impl_error_Warning::impl_error_Warning(fileline _fileline_1, problem _problem_1) + : fileline_1(_fileline_1), problem_1(_problem_1) { } + impl_error_NonFatal::impl_error_NonFatal(fileline _fileline_1, problem _problem_1) + : fileline_1(_fileline_1), problem_1(_problem_1) { } + impl_error_Fatal::impl_error_Fatal(fileline _fileline_1, problem _problem_1) + : fileline_1(_fileline_1), problem_1(_problem_1) { } + const enum_phyla impl_problem::phylum_sel_ = phylum_problem; + impl_problem_Problem6::impl_problem_Problem6(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4, casestring _casestring_5, casestring _casestring_6) + : casestring_1(_casestring_1), casestring_2(_casestring_2), casestring_3(_casestring_3), casestring_4(_casestring_4), casestring_5(_casestring_5), casestring_6(_casestring_6) { } + impl_problem_Problem5::impl_problem_Problem5(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4, casestring _casestring_5) + : casestring_1(_casestring_1), casestring_2(_casestring_2), casestring_3(_casestring_3), casestring_4(_casestring_4), casestring_5(_casestring_5) { } + impl_problem_Problem4::impl_problem_Problem4(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4) + : casestring_1(_casestring_1), casestring_2(_casestring_2), casestring_3(_casestring_3), casestring_4(_casestring_4) { } + impl_problem_Problem3int1::impl_problem_Problem3int1(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, integer _integer_1, casestring _casestring_4) + : casestring_1(_casestring_1), casestring_2(_casestring_2), casestring_3(_casestring_3), integer_1(_integer_1), casestring_4(_casestring_4) { } + impl_problem_Problem3::impl_problem_Problem3(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3) + : casestring_1(_casestring_1), casestring_2(_casestring_2), casestring_3(_casestring_3) { } + impl_problem_Problem2::impl_problem_Problem2(casestring _casestring_1, casestring _casestring_2) + : casestring_1(_casestring_1), casestring_2(_casestring_2) { } + impl_problem_Problem1storageoption1ID::impl_problem_Problem1storageoption1ID(casestring _casestring_1, storageoption _storageoption_1, casestring _casestring_2, ID _ID_1) + : casestring_1(_casestring_1), storageoption_1(_storageoption_1), casestring_2(_casestring_2), ID_1(_ID_1) { } + impl_problem_Problem1INT1ID1ID::impl_problem_Problem1INT1ID1ID(casestring _casestring_1, INT _INT_1, casestring _casestring_2, ID _ID_1, casestring _casestring_3, ID _ID_2) + : casestring_1(_casestring_1), INT_1(_INT_1), casestring_2(_casestring_2), ID_1(_ID_1), casestring_3(_casestring_3), ID_2(_ID_2) { } + impl_problem_Problem1ID1ID1ID::impl_problem_Problem1ID1ID1ID(casestring _casestring_1, ID _ID_1, casestring _casestring_2, ID _ID_2, casestring _casestring_3, ID _ID_3) + : casestring_1(_casestring_1), ID_1(_ID_1), casestring_2(_casestring_2), ID_2(_ID_2), casestring_3(_casestring_3), ID_3(_ID_3) { } + impl_problem_Problem1INT1ID::impl_problem_Problem1INT1ID(casestring _casestring_1, INT _INT_1, casestring _casestring_2, ID _ID_1) + : casestring_1(_casestring_1), INT_1(_INT_1), casestring_2(_casestring_2), ID_1(_ID_1) { } + impl_problem_Problem1int1::impl_problem_Problem1int1(casestring _casestring_1, integer _integer_1, casestring _casestring_2) + : casestring_1(_casestring_1), integer_1(_integer_1), casestring_2(_casestring_2) { } + impl_problem_Problem1INT::impl_problem_Problem1INT(casestring _casestring_1, INT _INT_1) + : casestring_1(_casestring_1), INT_1(_INT_1) { } + impl_problem_Problem1t1ID::impl_problem_Problem1t1ID(casestring _casestring_1, IDtype _IDtype_1, casestring _casestring_2, ID _ID_1) + : casestring_1(_casestring_1), IDtype_1(_IDtype_1), casestring_2(_casestring_2), ID_1(_ID_1) { } + impl_problem_Problem1ID1ID::impl_problem_Problem1ID1ID(casestring _casestring_1, ID _ID_1, casestring _casestring_2, ID _ID_2) + : casestring_1(_casestring_1), ID_1(_ID_1), casestring_2(_casestring_2), ID_2(_ID_2) { } + impl_problem_Problem1we::impl_problem_Problem1we(casestring _casestring_1, withexpression _withexpression_1) + : casestring_1(_casestring_1), withexpression_1(_withexpression_1) { } + impl_problem_Problem1tID::impl_problem_Problem1tID(casestring _casestring_1, ID _ID_1) + : casestring_1(_casestring_1), ID_1(_ID_1) { } + impl_problem_Problem1ID::impl_problem_Problem1ID(casestring _casestring_1, ID _ID_1) + : casestring_1(_casestring_1), ID_1(_ID_1) { } + impl_problem_Problem1::impl_problem_Problem1(casestring _casestring_1) + : casestring_1(_casestring_1) { } + const enum_phyla impl_addedphylumdeclarations::phylum_sel_ = phylum_addedphylumdeclarations; + impl_addedphylumdeclarations::impl_addedphylumdeclarations(addedphylumdeclaration p1 , addedphylumdeclarations p2) + : addedphylumdeclaration_1(p1), addedphylumdeclarations_1(p2) { } + const enum_phyla impl_addedphylumdeclaration::phylum_sel_ = phylum_addedphylumdeclaration; + impl_addedphylumdeclaration_AddedPhylumdeclaration::impl_addedphylumdeclaration_AddedPhylumdeclaration(uniqID _uniqID_1) + : uniqID_1(_uniqID_1) { } + const enum_phyla impl_countedphylumdeclarations::phylum_sel_ = phylum_countedphylumdeclarations; + impl_countedphylumdeclarations::impl_countedphylumdeclarations(countedphylumdeclaration p1 , countedphylumdeclarations p2) + : countedphylumdeclaration_1(p1), countedphylumdeclarations_1(p2) { } + const enum_phyla impl_countedphylumdeclaration::phylum_sel_ = phylum_countedphylumdeclaration; + impl_countedphylumdeclaration_CountedPhylumdeclaration::impl_countedphylumdeclaration_CountedPhylumdeclaration(uniqID _uniqID_1) + : uniqID_1(_uniqID_1) { } + const enum_phyla impl_charruns::phylum_sel_ = phylum_charruns; + impl_charruns_Stars::impl_charruns_Stars() + { } + impl_charruns_QuotedNewlines::impl_charruns_QuotedNewlines() + { } + impl_charruns_Newlines::impl_charruns_Newlines() + { } + const enum_phyla impl_bindingidmarks::phylum_sel_ = phylum_bindingidmarks; + impl_bindingidmarks::impl_bindingidmarks(bindingidmark p1 , bindingidmarks p2) + : bindingidmark_1(p1), bindingidmarks_1(p2) { } + const enum_phyla impl_bindingidmark::phylum_sel_ = phylum_bindingidmark; + impl_bindingidmark_BindingIdMark::impl_bindingidmark_BindingIdMark(uniqID _uniqID_1) + : uniqID_1(_uniqID_1) { } + + #ifdef KC_STATISTICS + KC_OPERATOR_STATISTICS operator_statistics[KC_NO_OF_OPERATORS]; + static int kc_casestring_strlen =0; + static int kc_nocasestring_strlen =0; + # define KC_COLLECT_STATS0(v) v + #else + # define KC_COLLECT_STATS0(v) + #endif + + #ifndef KC_CREATE_STATS + # define KC_CREATE_STATS(oper) operator_statistics[oper].created++; + #endif + #ifndef KC_EXISTINGNOTFOUND_STATS + # define KC_EXISTINGNOTFOUND_STATS(oper) operator_statistics[oper].existing_not_found++; + #endif + + #ifndef KC_FREE_CALLED_STATS + # define KC_FREE_CALLED_STATS(oper,rec) operator_statistics[oper].free_called[(rec?true:false)]++; + #endif + + #ifndef KC_FREED_STATS + # define KC_FREED_STATS(oper,rec) operator_statistics[oper].freed[(rec?true:false)]++; + #endif + static hashtable_struct_t kc_not_uniq_static_hashtable; + static hashtable_struct_t uniq_static_hashtable; + + bool kc_storageclass_still_uniq[] = { + true, true }; + + hashtable_t hashtables[] = { + &kc_not_uniq_static_hashtable, + &uniq_static_hashtable, + }; + + const char* kc_storageclassnames[] = { "kc_not_uniq", "uniq" }; + + namespace { // all local to k.cc + + uniqID kc_initialize_uniqID(uniqID kc_x) + { + kc_x->type = ITUnknown(); + kc_x->line = 0; + kc_x->file = mkcasestring(""); + kc_x->scopeinfo = Nilscopetypefilelinestack(); + + return kc_x; + } + + ID kc_initialize_ID(ID kc_x) + { + kc_x->type = ITUnknown(); + kc_x->named_subphylum = 0; + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + INT kc_initialize_INT(INT kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + STRING kc_initialize_STRING(STRING kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + phylumdeclaration kc_initialize_phylumdeclaration(phylumdeclaration kc_x) + { + kc_x->marked = 0; + kc_x->additional_members = Nilfndeclarations(); + kc_x->base_classes = Nilbaseclass_list(); + + return kc_x; + } + + storageclasses kc_initialize_storageclasses(storageclasses kc_x) + { + kc_x->phyla = Nilphylumnames(); + + return kc_x; + } + + alternative kc_initialize_alternative(alternative kc_x) + { + kc_x->rewriteinfo = Nilrewriterulesinfo(); + kc_x->unparseinfo = Nilunparsedeclsinfo(); + kc_x->additional_members = Nilfndeclarations(); + kc_x->base_classes = Nilbaseclass_list(); + + return kc_x; + } + + Cexpression kc_initialize_Cexpression(Cexpression kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + idCexpression kc_initialize_idCexpression(idCexpression kc_x) + { + kc_x->id = f_emptyId(); + + return kc_x; + } + + includefile kc_initialize_includefile(includefile kc_x) + { + kc_x->inc_type = include_unknown; + kc_x->inc[0] = Nilincludedeclarations(); + kc_x->inc[1] = Nilincludedeclarations(); + if (Theincludefiles == 0) { + Theincludefiles = Consincludefiles( kc_x, Nilincludefiles()); + } else { + Theincludefiles = Consincludefiles( kc_x, Theincludefiles); + } + + + return kc_x; + } + + includedeclaration kc_initialize_includedeclaration(includedeclaration kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + patternchains kc_initialize_patternchains(patternchains kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + patternchain kc_initialize_patternchain(patternchain kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + patternchainitem kc_initialize_patternchainitem(patternchainitem kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + kc_x->type = f_emptyId(); + + return kc_x; + } + + outmostpattern kc_initialize_outmostpattern(outmostpattern kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + kc_x->type = f_emptyId(); + + return kc_x; + } + + term kc_initialize_term(term kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + fnfile kc_initialize_fnfile(fnfile kc_x) + { + kc_x->fns = Nilfndeclarations(); + if (Thefnfiles == 0) { + Thefnfiles = Consfnfiles( kc_x, Nilfnfiles()); + } else { + Thefnfiles = Consfnfiles( kc_x, Thefnfiles); + } + + + return kc_x; + } + + fndeclaration kc_initialize_fndeclaration(fndeclaration kc_x) + { + kc_x->last_line = 0; + kc_x->file = mkcasestring(""); + { + fndeclaration kc_selvar_0_1 = phylum_cast(kc_x); + if ((kc_selvar_0_1->prod_sel() == sel_FnAcDeclaration)) { + const ac_declarator fn_args = phylum_cast(kc_selvar_0_1)->ac_declarator_1; + const ac_declaration_list C_vardecls = phylum_cast(kc_selvar_0_1)->ac_declaration_list_1; + + kc_selvar_0_1->sorted = sort_extend_parameter_type_list( C_vardecls, fn_args ); + + } else + { + kc_selvar_0_1->sorted = AcParList( Nilac_parameter_list() ); + } + } + + + return kc_x; + } + + Ctext kc_initialize_Ctext(Ctext kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + Ctext_elem kc_initialize_Ctext_elem(Ctext_elem kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + foreach_after kc_initialize_foreach_after(foreach_after kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + withexpressions kc_initialize_withexpressions(withexpressions kc_x) + { + kc_x->type = 0; + kc_x->line = 0; + kc_x->file = mkcasestring(""); + { + withexpressions kc_selvar_0_1 = phylum_cast(kc_x); + if ((kc_selvar_0_1->prod_sel() == sel_Conswithexpressions)) { + const withexpression h = (kc_selvar_0_1)->withexpression_1; + const withexpressions t = (kc_selvar_0_1)->withexpressions_1; + + kc_selvar_0_1->type = Consphylumnames( h->type, t->type ); + kc_selvar_0_1->line = h->line; + kc_selvar_0_1->file = h->file; + + } else + if ((kc_selvar_0_1->prod_sel() == sel_Nilwithexpressions)) { + + kc_selvar_0_1->type = Nilphylumnames(); + + } else + kc_no_default_in_with( "", __LINE__, __FILE__ ); + } + + + return kc_x; + } + + withexpression kc_initialize_withexpression(withexpression kc_x) + { + kc_x->type = f_emptyId(); + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + { + withexpression kc_selvar_0_1 = phylum_cast(kc_x); + if ((kc_selvar_0_1->prod_sel() == sel_WECexpression)) { + const Cexpression e = phylum_cast(kc_selvar_0_1)->Cexpression_1; + + kc_selvar_0_1->line = e->line; + kc_selvar_0_1->file = e->file; + + } else + if ((kc_selvar_0_1->prod_sel() == sel_WEVariable)) { + const ID id = phylum_cast(kc_selvar_0_1)->ID_1; + + kc_selvar_0_1->line = id->line; + kc_selvar_0_1->file = id->file; + + } else + kc_no_default_in_with( "", __LINE__, __FILE__ ); + } + + + return kc_x; + } + + viewnames kc_initialize_viewnames(viewnames kc_x) + { + kc_x->is_extern = false; + + return kc_x; + } + + unparseitem kc_initialize_unparseitem(unparseitem kc_x) + { + kc_x->text_nr = 0; + + return kc_x; + } + + elem_patternrepresentation kc_initialize_elem_patternrepresentation(elem_patternrepresentation kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + kc_x->type = f_emptyId(); + + return kc_x; + } + + path kc_initialize_path(path kc_x) + { + kc_x->op = f_emptyId(); + kc_x->id = f_emptyId(); + + return kc_x; + } + + ac_operator_name kc_initialize_ac_operator_name(ac_operator_name kc_x) + { + kc_x->line = 0; + kc_x->file = mkcasestring(""); + + return kc_x; + } + + addedphylumdeclaration kc_initialize_addedphylumdeclaration(addedphylumdeclaration kc_x) + { + kc_x->added = false; + if (!pl_addedphylumdeclarations) + pl_addedphylumdeclarations = + Consaddedphylumdeclarations( kc_x, Niladdedphylumdeclarations() ); + else + pl_addedphylumdeclarations = + Consaddedphylumdeclarations( kc_x, pl_addedphylumdeclarations ); + + + return kc_x; + } + + countedphylumdeclaration kc_initialize_countedphylumdeclaration(countedphylumdeclaration kc_x) + { + kc_x->count = 0; + if (!pl_countedphylumdeclarations) + pl_countedphylumdeclarations = + Conscountedphylumdeclarations( kc_x, Nilcountedphylumdeclarations() ); + else + pl_countedphylumdeclarations = + Conscountedphylumdeclarations( kc_x, pl_countedphylumdeclarations ); + + + return kc_x; + } + + bindingidmark kc_initialize_bindingidmark(bindingidmark kc_x) + { + kc_x->marked = false; + + if (! Thebindingidmarks) + Thebindingidmarks = Consbindingidmarks( kc_x, Nilbindingidmarks() ); + else + Thebindingidmarks = Consbindingidmarks( kc_x, Thebindingidmarks ); + + + return kc_x; + } + + + } // namespace + + enum_phyla + impl_abstract_phylum::phylum() const { + return operator_info[prod_sel()].phylum; + } + + const char* + impl_abstract_phylum::phylum_name() const { + return phylum_info[phylum()].name; + } + + const char* + impl_abstract_phylum::op_name() const { + return operator_info[prod_sel()].name; + } + + casestring + mkcasestring(const kc_char *kc_s, int length) + { + KC_COLLECT_STATS0(KC_CREATE_STATS(sel__Str)); + + casestring kc_x=new impl_casestring__Str(kc_s); + if(length>=0) + kc_x->make_own(length); + + casestring unique_kc_x=hashtables[uniq]->ht_check_insert((casestring)kc_x); + if(unique_kc_x!=kc_x) { + if(length<0) + kc_x->name=0; + + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel__Str)); + if(length<0) + kc_x->make_own(static_cast(kc_strlen(kc_s))); + + kc_x->post_create(); + } + return kc_x; + } + + nocasestring + mknocasestring(const kc_char *kc_s, int length) + { + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoCaseStr)); + + nocasestring kc_x=new impl_nocasestring_NoCaseStr(kc_s); + if(length>=0) + kc_x->make_own(length); + nocasestring unique_kc_x=hashtables[uniq]->ht_check_insert((nocasestring)kc_x); + if(unique_kc_x!=kc_x) { + if(length<0) + kc_x->name=0; + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoCaseStr)); + if(length<0) + kc_x->make_own(static_cast(kc_strlen(kc_s))); + kc_x->post_create(); + } + + return kc_x; + } + + integer + mkinteger(const INTEGER kc_i) + { + KC_COLLECT_STATS0(KC_CREATE_STATS(sel__Int)); + + integer kc_x =new impl_integer__Int(kc_i); + integer unique_kc_x=hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel__Int)); + kc_x->post_create(); + } + + return kc_x; + } + + real + mkreal(const REAL kc_r) + { + KC_COLLECT_STATS0(KC_CREATE_STATS(sel__Real)); + + real kc_x=new impl_real__Real(kc_r); + real unique_kc_x=hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel__Real)); + kc_x->post_create(); + } + + return kc_x; + } + + voidptr + mkvoidptr(void *kc_p) + { + KC_COLLECT_STATS0(KC_CREATE_STATS(sel__VoidPtr)); + voidptr kc_x=new impl_voidptr__VoidPtr(kc_p); + voidptr unique_kc_x=hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel__VoidPtr)); + kc_x->post_create(); + } + return kc_x; + } + + impl_uniqID_Str* + Str(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + uniqID kc_x=new impl_uniqID_Str(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Str)); + uniqID unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Str)); + kc_x->post_create(); + kc_x = kc_initialize_uniqID(kc_x); + } + return static_cast(kc_x); + } + + impl_ID_Id* + Id(uniqID _uniqID_1) { + assertPhylum(_uniqID_1, phylum_uniqID); + ID kc_x = new impl_ID_Id(_uniqID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Id)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Id)); + kc_x->post_create(); + kc_x = kc_initialize_ID(kc_x); + return static_cast(kc_x); + } + + impl_INT_Int* + Int(integer _integer_1) { + assertPhylum(_integer_1, phylum_integer); + INT kc_x = new impl_INT_Int(_integer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Int)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Int)); + kc_x->post_create(); + kc_x = kc_initialize_INT(kc_x); + return static_cast(kc_x); + } + + impl_STRING_String* + String(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + STRING kc_x = new impl_STRING_String(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_String)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_String)); + kc_x->post_create(); + kc_x = kc_initialize_STRING(kc_x); + return static_cast(kc_x); + } + + impl_phylumdeclarationsroot_PhylumDeclarations* + PhylumDeclarations(phylumdeclarations _phylumdeclarations_1) { + assertPhylum(_phylumdeclarations_1, phylum_phylumdeclarations); + phylumdeclarationsroot kc_x = new impl_phylumdeclarationsroot_PhylumDeclarations(_phylumdeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PhylumDeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PhylumDeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phylumdeclarations* + Nilphylumdeclarations() { + phylumdeclarations kc_x = new impl_phylumdeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phylumdeclarations* + Consphylumdeclarations(phylumdeclaration _phylumdeclaration_1, phylumdeclarations _phylumdeclarations_1) { + assertPhylum(_phylumdeclaration_1, phylum_phylumdeclaration); + assertPhylum(_phylumdeclarations_1, phylum_phylumdeclarations); + phylumdeclarations kc_x = new impl_phylumdeclarations(_phylumdeclaration_1, _phylumdeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phylumnames* + Nilphylumnames() { + phylumnames kc_x = new impl_phylumnames(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilphylumnames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilphylumnames)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phylumnames* + Consphylumnames(ID _ID_1, phylumnames _phylumnames_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_phylumnames_1, phylum_phylumnames); + phylumnames kc_x = new impl_phylumnames(_ID_1, _phylumnames_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consphylumnames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consphylumnames)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phylumdeclaration_PhylumDeclaration* + PhylumDeclaration(ID _ID_1, storageoption _storageoption_1, productionblock _productionblock_1, Ccode_option _Ccode_option_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_storageoption_1, phylum_storageoption); + assertPhylum(_productionblock_1, phylum_productionblock); + assertPhylum(_Ccode_option_1, phylum_Ccode_option); + phylumdeclaration kc_x = new impl_phylumdeclaration_PhylumDeclaration(_ID_1, _storageoption_1, _productionblock_1, _Ccode_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PhylumDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PhylumDeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_phylumdeclaration(kc_x); + return static_cast(kc_x); + } + + impl_storageoption_NoStorageOption* + NoStorageOption() { + storageoption kc_x = new impl_storageoption_NoStorageOption(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoStorageOption)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoStorageOption)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_storageoption_NegativeStorageOption* + NegativeStorageOption(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + storageoption kc_x = new impl_storageoption_NegativeStorageOption(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NegativeStorageOption)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NegativeStorageOption)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_storageoption_PositiveStorageOption* + PositiveStorageOption(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + storageoption kc_x = new impl_storageoption_PositiveStorageOption(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PositiveStorageOption)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PositiveStorageOption)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_storageclasses* + Nilstorageclasses() { + storageclasses kc_x = new impl_storageclasses(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilstorageclasses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilstorageclasses)); + kc_x->post_create(); + kc_x = kc_initialize_storageclasses(kc_x); + return static_cast(kc_x); + } + + impl_storageclasses* + Consstorageclasses(ID _ID_1, storageclasses _storageclasses_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_storageclasses_1, phylum_storageclasses); + storageclasses kc_x = new impl_storageclasses(_ID_1, _storageclasses_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consstorageclasses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consstorageclasses)); + kc_x->post_create(); + kc_x = kc_initialize_storageclasses(kc_x); + return static_cast(kc_x); + } + + impl_productionblock_Emptyproductionblock* + Emptyproductionblock() { + productionblock kc_x = new impl_productionblock_Emptyproductionblock(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Emptyproductionblock)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Emptyproductionblock)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_productionblock_ListAlternatives* + ListAlternatives(alternatives _alternatives_1, ID _ID_1) { + assertPhylum(_alternatives_1, phylum_alternatives); + assertPhylum(_ID_1, phylum_ID); + productionblock kc_x = new impl_productionblock_ListAlternatives(_alternatives_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ListAlternatives)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ListAlternatives)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_productionblock_NonlistAlternatives* + NonlistAlternatives(alternatives _alternatives_1) { + assertPhylum(_alternatives_1, phylum_alternatives); + productionblock kc_x = new impl_productionblock_NonlistAlternatives(_alternatives_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NonlistAlternatives)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NonlistAlternatives)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_productionblock_PredefinedAlternatives* + PredefinedAlternatives(alternatives _alternatives_1) { + assertPhylum(_alternatives_1, phylum_alternatives); + productionblock kc_x = new impl_productionblock_PredefinedAlternatives(_alternatives_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PredefinedAlternatives)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PredefinedAlternatives)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_alternatives* + Nilalternatives() { + alternatives kc_x = new impl_alternatives(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilalternatives)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilalternatives)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_alternatives* + Consalternatives(alternative _alternative_1, alternatives _alternatives_1) { + assertPhylum(_alternative_1, phylum_alternative); + assertPhylum(_alternatives_1, phylum_alternatives); + alternatives kc_x = new impl_alternatives(_alternative_1, _alternatives_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consalternatives)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consalternatives)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_alternative_Alternative* + Alternative(ID _ID_1, arguments _arguments_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_arguments_1, phylum_arguments); + alternative kc_x = new impl_alternative_Alternative(_ID_1, _arguments_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Alternative)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Alternative)); + kc_x->post_create(); + kc_x = kc_initialize_alternative(kc_x); + return static_cast(kc_x); + } + + impl_arguments* + Nilarguments() { + arguments kc_x = new impl_arguments(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilarguments)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilarguments)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_arguments* + Consarguments(ID _ID_1, arguments _arguments_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_arguments_1, phylum_arguments); + arguments kc_x = new impl_arguments(_ID_1, _arguments_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consarguments)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consarguments)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_argument_Argument* + Argument(ID _ID_1, integer _integer_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_integer_1, phylum_integer); + argument kc_x = new impl_argument_Argument(_ID_1, _integer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Argument)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Argument)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Ccode_option_CcodeOption* + CcodeOption(attributes _attributes_1, Ctexts _Ctexts_1) { + assertPhylum(_attributes_1, phylum_attributes); + assertPhylum(_Ctexts_1, phylum_Ctexts); + Ccode_option kc_x = new impl_Ccode_option_CcodeOption(_attributes_1, _Ctexts_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CcodeOption)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CcodeOption)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_attributes* + Nilattributes() { + attributes kc_x = new impl_attributes(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilattributes)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilattributes)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_attributes* + Consattributes(attribute _attribute_1, attributes _attributes_1) { + assertPhylum(_attribute_1, phylum_attribute); + assertPhylum(_attributes_1, phylum_attributes); + attributes kc_x = new impl_attributes(_attribute_1, _attributes_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consattributes)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consattributes)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_attribute_Attribute* + Attribute(ID _ID_1, ID _ID_2, attribute_initialisation_option _attribute_initialisation_option_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ID_2, phylum_ID); + assertPhylum(_attribute_initialisation_option_1, phylum_attribute_initialisation_option); + attribute kc_x = new impl_attribute_Attribute(_ID_1, _ID_2, _attribute_initialisation_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Attribute)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Attribute)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_attribute_initialisation_option_Noattribute_initialisation* + Noattribute_initialisation() { + attribute_initialisation_option kc_x = new impl_attribute_initialisation_option_Noattribute_initialisation(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Noattribute_initialisation)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Noattribute_initialisation)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_attribute_initialisation_option_Yesattribute_initialisation* + Yesattribute_initialisation(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + attribute_initialisation_option kc_x = new impl_attribute_initialisation_option_Yesattribute_initialisation(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Yesattribute_initialisation)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Yesattribute_initialisation)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression* + NilCexpression() { + Cexpression kc_x = new impl_Cexpression(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilCexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilCexpression)); + kc_x->post_create(); + kc_x = kc_initialize_Cexpression(kc_x); + return static_cast(kc_x); + } + + impl_Cexpression* + ConsCexpression(Cexpression_elem _Cexpression_elem_1, Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_elem_1, phylum_Cexpression_elem); + assertPhylum(_Cexpression_1, phylum_Cexpression); + Cexpression kc_x = new impl_Cexpression(_Cexpression_elem_1, _Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsCexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsCexpression)); + kc_x->post_create(); + kc_x = kc_initialize_Cexpression(kc_x); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionPart* + CExpressionPart(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionPart(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionPart)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionPart)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionDollarvar* + CExpressionDollarvar(INT _INT_1) { + assertPhylum(_INT_1, phylum_INT); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionDollarvar(_INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionDollarvar)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionDollarvar)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionNl* + CExpressionNl() { + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionNl(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionNl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionNl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionDQ* + CExpressionDQ(CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionDQ(_CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionDQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionDQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionSQ* + CExpressionSQ(CexpressionSQ _CexpressionSQ_1) { + assertPhylum(_CexpressionSQ_1, phylum_CexpressionSQ); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionSQ(_CexpressionSQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionSQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionSQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionPack* + CExpressionPack(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionPack(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionPack)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionPack)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Cexpression_elem_CExpressionArray* + CExpressionArray(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + Cexpression_elem kc_x = new impl_Cexpression_elem_CExpressionArray(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionArray)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionArray)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionDQ* + NilCexpressionDQ() { + CexpressionDQ kc_x = new impl_CexpressionDQ(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilCexpressionDQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilCexpressionDQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionDQ* + ConsCexpressionDQ(CexpressionDQ_elem _CexpressionDQ_elem_1, CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_CexpressionDQ_elem_1, phylum_CexpressionDQ_elem); + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + CexpressionDQ kc_x = new impl_CexpressionDQ(_CexpressionDQ_elem_1, _CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsCexpressionDQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsCexpressionDQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionDQ_elem_CExpressionDQPart* + CExpressionDQPart(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + CexpressionDQ_elem kc_x = new impl_CexpressionDQ_elem_CExpressionDQPart(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionDQPart)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionDQPart)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionDQ_elem_CExpressionDQNl* + CExpressionDQNl() { + CexpressionDQ_elem kc_x = new impl_CexpressionDQ_elem_CExpressionDQNl(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionDQNl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionDQNl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionSQ* + NilCexpressionSQ() { + CexpressionSQ kc_x = new impl_CexpressionSQ(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilCexpressionSQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilCexpressionSQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionSQ* + ConsCexpressionSQ(CexpressionSQ_elem _CexpressionSQ_elem_1, CexpressionSQ _CexpressionSQ_1) { + assertPhylum(_CexpressionSQ_elem_1, phylum_CexpressionSQ_elem); + assertPhylum(_CexpressionSQ_1, phylum_CexpressionSQ); + CexpressionSQ kc_x = new impl_CexpressionSQ(_CexpressionSQ_elem_1, _CexpressionSQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsCexpressionSQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsCexpressionSQ)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionSQ_elem_CExpressionSQPart* + CExpressionSQPart(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + CexpressionSQ_elem kc_x = new impl_CexpressionSQ_elem_CExpressionSQPart(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionSQPart)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionSQPart)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_CexpressionSQ_elem_CExpressionSQNl* + CExpressionSQNl() { + CexpressionSQ_elem kc_x = new impl_CexpressionSQ_elem_CExpressionSQNl(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CExpressionSQNl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CExpressionSQNl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_idCexpressions* + NilidCexpressions() { + idCexpressions kc_x = new impl_idCexpressions(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilidCexpressions)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilidCexpressions)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_idCexpressions* + ConsidCexpressions(idCexpression _idCexpression_1, idCexpressions _idCexpressions_1) { + assertPhylum(_idCexpression_1, phylum_idCexpression); + assertPhylum(_idCexpressions_1, phylum_idCexpressions); + idCexpressions kc_x = new impl_idCexpressions(_idCexpression_1, _idCexpressions_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsidCexpressions)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsidCexpressions)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_idCexpression_IdCexpression* + IdCexpression(ID _ID_1, Cexpression _Cexpression_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_Cexpression_1, phylum_Cexpression); + idCexpression kc_x = new impl_idCexpression_IdCexpression(_ID_1, _Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_IdCexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_IdCexpression)); + kc_x->post_create(); + kc_x = kc_initialize_idCexpression(kc_x); + return static_cast(kc_x); + } + + impl_Ctexts* + NilCtexts() { + Ctexts kc_x = new impl_Ctexts(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilCtexts)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilCtexts)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Ctexts* + ConsCtexts(Ctext _Ctext_1, Ctexts _Ctexts_1) { + assertPhylum(_Ctext_1, phylum_Ctext); + assertPhylum(_Ctexts_1, phylum_Ctexts); + Ctexts kc_x = new impl_Ctexts(_Ctext_1, _Ctexts_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsCtexts)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsCtexts)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_includefiles* + Nilincludefiles() { + includefiles kc_x = new impl_includefiles(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilincludefiles)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilincludefiles)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_includefiles* + Consincludefiles(includefile _includefile_1, includefiles _includefiles_1) { + assertPhylum(_includefile_1, phylum_includefile); + assertPhylum(_includefiles_1, phylum_includefiles); + includefiles kc_x = new impl_includefiles(_includefile_1, _includefiles_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consincludefiles)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consincludefiles)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_includefile_IncludeFile* + IncludeFile(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + includefile kc_x=new impl_includefile_IncludeFile(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_IncludeFile)); + includefile unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_IncludeFile)); + kc_x->post_create(); + kc_x = kc_initialize_includefile(kc_x); + } + return static_cast(kc_x); + } + + impl_includedeclarations* + Nilincludedeclarations() { + includedeclarations kc_x = new impl_includedeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilincludedeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilincludedeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_includedeclarations* + Consincludedeclarations(includedeclaration _includedeclaration_1, includedeclarations _includedeclarations_1) { + assertPhylum(_includedeclaration_1, phylum_includedeclaration); + assertPhylum(_includedeclarations_1, phylum_includedeclarations); + includedeclarations kc_x = new impl_includedeclarations(_includedeclaration_1, _includedeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consincludedeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consincludedeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_includedeclaration_IncludeDeclaration* + IncludeDeclaration(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + includedeclaration kc_x = new impl_includedeclaration_IncludeDeclaration(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_IncludeDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_IncludeDeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_includedeclaration(kc_x); + return static_cast(kc_x); + } + + impl_rwdeclarations* + Nilrwdeclarations() { + rwdeclarations kc_x = new impl_rwdeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilrwdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilrwdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rwdeclarations* + Consrwdeclarations(rwdeclaration _rwdeclaration_1, rwdeclarations _rwdeclarations_1) { + assertPhylum(_rwdeclaration_1, phylum_rwdeclaration); + assertPhylum(_rwdeclarations_1, phylum_rwdeclarations); + rwdeclarations kc_x = new impl_rwdeclarations(_rwdeclaration_1, _rwdeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consrwdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consrwdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rwdeclaration_RwDeclaration* + RwDeclaration(outmostpatterns _outmostpatterns_1, rewriteclauses _rewriteclauses_1) { + assertPhylum(_outmostpatterns_1, phylum_outmostpatterns); + assertPhylum(_rewriteclauses_1, phylum_rewriteclauses); + rwdeclaration kc_x = new impl_rwdeclaration_RwDeclaration(_outmostpatterns_1, _rewriteclauses_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_RwDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_RwDeclaration)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteclauses* + Nilrewriteclauses() { + rewriteclauses kc_x = new impl_rewriteclauses(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilrewriteclauses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilrewriteclauses)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteclauses* + Consrewriteclauses(rewriteclause _rewriteclause_1, rewriteclauses _rewriteclauses_1) { + assertPhylum(_rewriteclause_1, phylum_rewriteclause); + assertPhylum(_rewriteclauses_1, phylum_rewriteclauses); + rewriteclauses kc_x = new impl_rewriteclauses(_rewriteclause_1, _rewriteclauses_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consrewriteclauses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consrewriteclauses)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteclause_RewriteClause* + RewriteClause(viewnames _viewnames_1, term _term_1) { + assertPhylum(_viewnames_1, phylum_viewnames); + assertPhylum(_term_1, phylum_term); + rewriteclause kc_x = new impl_rewriteclause_RewriteClause(_viewnames_1, _term_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_RewriteClause)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_RewriteClause)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternchains* + Nilpatternchains() { + patternchains kc_x = new impl_patternchains(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpatternchains)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpatternchains)); + kc_x->post_create(); + kc_x = kc_initialize_patternchains(kc_x); + return static_cast(kc_x); + } + + impl_patternchains* + Conspatternchains(patternchain _patternchain_1, patternchains _patternchains_1) { + assertPhylum(_patternchain_1, phylum_patternchain); + assertPhylum(_patternchains_1, phylum_patternchains); + patternchains kc_x = new impl_patternchains(_patternchain_1, _patternchains_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspatternchains)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspatternchains)); + kc_x->post_create(); + kc_x = kc_initialize_patternchains(kc_x); + return static_cast(kc_x); + } + + impl_patternchain* + Nilpatternchain() { + patternchain kc_x = new impl_patternchain(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpatternchain)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpatternchain)); + kc_x->post_create(); + kc_x = kc_initialize_patternchain(kc_x); + return static_cast(kc_x); + } + + impl_patternchain* + Conspatternchain(patternchainitem _patternchainitem_1, patternchain _patternchain_1) { + assertPhylum(_patternchainitem_1, phylum_patternchainitem); + assertPhylum(_patternchain_1, phylum_patternchain); + patternchain kc_x = new impl_patternchain(_patternchainitem_1, _patternchain_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspatternchain)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspatternchain)); + kc_x->post_create(); + kc_x = kc_initialize_patternchain(kc_x); + return static_cast(kc_x); + } + + impl_outmostpatterns* + Niloutmostpatterns() { + outmostpatterns kc_x = new impl_outmostpatterns(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Niloutmostpatterns)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Niloutmostpatterns)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_outmostpatterns* + Consoutmostpatterns(outmostpattern _outmostpattern_1, outmostpatterns _outmostpatterns_1) { + assertPhylum(_outmostpattern_1, phylum_outmostpattern); + assertPhylum(_outmostpatterns_1, phylum_outmostpatterns); + outmostpatterns kc_x = new impl_outmostpatterns(_outmostpattern_1, _outmostpatterns_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consoutmostpatterns)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consoutmostpatterns)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternchainitem_PatternchainitemOutmost* + PatternchainitemOutmost(outmostpattern _outmostpattern_1) { + assertPhylum(_outmostpattern_1, phylum_outmostpattern); + patternchainitem kc_x = new impl_patternchainitem_PatternchainitemOutmost(_outmostpattern_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PatternchainitemOutmost)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PatternchainitemOutmost)); + kc_x->post_create(); + kc_x = kc_initialize_patternchainitem(kc_x); + return static_cast(kc_x); + } + + impl_patternchainitem_PatternchainitemGroup* + PatternchainitemGroup(patternchains _patternchains_1) { + assertPhylum(_patternchains_1, phylum_patternchains); + patternchainitem kc_x = new impl_patternchainitem_PatternchainitemGroup(_patternchains_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PatternchainitemGroup)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PatternchainitemGroup)); + kc_x->post_create(); + kc_x = kc_initialize_patternchainitem(kc_x); + return static_cast(kc_x); + } + + impl_patternchainitem_PatternchainitemDollarid* + PatternchainitemDollarid(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + patternchainitem kc_x = new impl_patternchainitem_PatternchainitemDollarid(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PatternchainitemDollarid)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PatternchainitemDollarid)); + kc_x->post_create(); + kc_x = kc_initialize_patternchainitem(kc_x); + return static_cast(kc_x); + } + + impl_outmostpattern_OPOperatorWildcard* + OPOperatorWildcard(ID _ID_1, Cexpression _Cexpression_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_Cexpression_1, phylum_Cexpression); + outmostpattern kc_x = new impl_outmostpattern_OPOperatorWildcard(_ID_1, _Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_OPOperatorWildcard)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_OPOperatorWildcard)); + kc_x->post_create(); + kc_x = kc_initialize_outmostpattern(kc_x); + return static_cast(kc_x); + } + + impl_outmostpattern_OPOperator* + OPOperator(ID _ID_1, patterns _patterns_1, Cexpression _Cexpression_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_patterns_1, phylum_patterns); + assertPhylum(_Cexpression_1, phylum_Cexpression); + outmostpattern kc_x = new impl_outmostpattern_OPOperator(_ID_1, _patterns_1, _Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_OPOperator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_OPOperator)); + kc_x->post_create(); + kc_x = kc_initialize_outmostpattern(kc_x); + return static_cast(kc_x); + } + + impl_outmostpattern_OPNonLeafVariable* + OPNonLeafVariable(ID _ID_1, outmostpattern _outmostpattern_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_outmostpattern_1, phylum_outmostpattern); + outmostpattern kc_x = new impl_outmostpattern_OPNonLeafVariable(_ID_1, _outmostpattern_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_OPNonLeafVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_OPNonLeafVariable)); + kc_x->post_create(); + kc_x = kc_initialize_outmostpattern(kc_x); + return static_cast(kc_x); + } + + impl_outmostpattern_OPWildcard* + OPWildcard(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + outmostpattern kc_x = new impl_outmostpattern_OPWildcard(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_OPWildcard)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_OPWildcard)); + kc_x->post_create(); + kc_x = kc_initialize_outmostpattern(kc_x); + return static_cast(kc_x); + } + + impl_outmostpattern_OPDefault* + OPDefault(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + outmostpattern kc_x = new impl_outmostpattern_OPDefault(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_OPDefault)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_OPDefault)); + kc_x->post_create(); + kc_x = kc_initialize_outmostpattern(kc_x); + return static_cast(kc_x); + } + + impl_pattern_PVariable* + PVariable(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + pattern kc_x = new impl_pattern_PVariable(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PVariable)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_pattern_POperator* + POperator(ID _ID_1, patterns _patterns_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_patterns_1, phylum_patterns); + pattern kc_x = new impl_pattern_POperator(_ID_1, _patterns_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_POperator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_POperator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_pattern_PNonLeafVariable* + PNonLeafVariable(ID _ID_1, pattern _pattern_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_pattern_1, phylum_pattern); + pattern kc_x = new impl_pattern_PNonLeafVariable(_ID_1, _pattern_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PNonLeafVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PNonLeafVariable)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_pattern_PWildcard* + PWildcard() { + pattern kc_x = new impl_pattern_PWildcard(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PWildcard)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PWildcard)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_pattern_PStringLiteral* + PStringLiteral(CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + pattern kc_x = new impl_pattern_PStringLiteral(_CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PStringLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PStringLiteral)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_pattern_PIntLiteral* + PIntLiteral(INT _INT_1) { + assertPhylum(_INT_1, phylum_INT); + pattern kc_x = new impl_pattern_PIntLiteral(_INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PIntLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PIntLiteral)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patterns* + Nilpatterns() { + patterns kc_x = new impl_patterns(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpatterns)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpatterns)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patterns* + Conspatterns(pattern _pattern_1, patterns _patterns_1) { + assertPhylum(_pattern_1, phylum_pattern); + assertPhylum(_patterns_1, phylum_patterns); + patterns kc_x = new impl_patterns(_pattern_1, _patterns_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspatterns)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspatterns)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_term_TVariable* + TVariable(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + term kc_x = new impl_term_TVariable(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TVariable)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TOperator* + TOperator(ID _ID_1, terms _terms_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_terms_1, phylum_terms); + term kc_x = new impl_term_TOperator(_ID_1, _terms_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TOperator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TOperator)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TMethod* + TMethod(term _term_1, ID _ID_1, terms _terms_1) { + assertPhylum(_term_1, phylum_term); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_terms_1, phylum_terms); + term kc_x = new impl_term_TMethod(_term_1, _ID_1, _terms_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TMethod)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TMethod)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TMethodDot* + TMethodDot(term _term_1, ID _ID_1, terms _terms_1) { + assertPhylum(_term_1, phylum_term); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_terms_1, phylum_terms); + term kc_x = new impl_term_TMethodDot(_term_1, _ID_1, _terms_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TMethodDot)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TMethodDot)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TMemberVar* + TMemberVar(term _term_1, ID _ID_1) { + assertPhylum(_term_1, phylum_term); + assertPhylum(_ID_1, phylum_ID); + term kc_x = new impl_term_TMemberVar(_term_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TMemberVar)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TMemberVar)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TMemberVarDot* + TMemberVarDot(term _term_1, ID _ID_1) { + assertPhylum(_term_1, phylum_term); + assertPhylum(_ID_1, phylum_ID); + term kc_x = new impl_term_TMemberVarDot(_term_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TMemberVarDot)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TMemberVarDot)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TCTerm* + TCTerm(CexpressionSQ _CexpressionSQ_1) { + assertPhylum(_CexpressionSQ_1, phylum_CexpressionSQ); + term kc_x = new impl_term_TCTerm(_CexpressionSQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TCTerm)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TCTerm)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TStringLiteral* + TStringLiteral(CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + term kc_x = new impl_term_TStringLiteral(_CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TStringLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TStringLiteral)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_term_TIntLiteral* + TIntLiteral(INT _INT_1) { + assertPhylum(_INT_1, phylum_INT); + term kc_x = new impl_term_TIntLiteral(_INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_TIntLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_TIntLiteral)); + kc_x->post_create(); + kc_x = kc_initialize_term(kc_x); + return static_cast(kc_x); + } + + impl_terms* + Nilterms() { + terms kc_x = new impl_terms(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilterms)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilterms)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_terms* + Consterms(term _term_1, terms _terms_1) { + assertPhylum(_term_1, phylum_term); + assertPhylum(_terms_1, phylum_terms); + terms kc_x = new impl_terms(_term_1, _terms_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consterms)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consterms)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnfiles* + Nilfnfiles() { + fnfiles kc_x = new impl_fnfiles(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilfnfiles)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilfnfiles)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnfiles* + Consfnfiles(fnfile _fnfile_1, fnfiles _fnfiles_1) { + assertPhylum(_fnfile_1, phylum_fnfile); + assertPhylum(_fnfiles_1, phylum_fnfiles); + fnfiles kc_x = new impl_fnfiles(_fnfile_1, _fnfiles_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consfnfiles)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consfnfiles)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnfile_FnFile* + FnFile(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + fnfile kc_x=new impl_fnfile_FnFile(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_FnFile)); + fnfile unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_FnFile)); + kc_x->post_create(); + kc_x = kc_initialize_fnfile(kc_x); + } + return static_cast(kc_x); + } + + impl_fndeclarations* + Nilfndeclarations() { + fndeclarations kc_x = new impl_fndeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilfndeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilfndeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fndeclarations* + Consfndeclarations(fndeclaration _fndeclaration_1, fndeclarations _fndeclarations_1) { + assertPhylum(_fndeclaration_1, phylum_fndeclaration); + assertPhylum(_fndeclarations_1, phylum_fndeclarations); + fndeclarations kc_x = new impl_fndeclarations(_fndeclaration_1, _fndeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consfndeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consfndeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fndeclaration_FnAcDeclaration* + FnAcDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_declaration_list _ac_declaration_list_1, ac_opt_base_init_list _ac_opt_base_init_list_1, Ctext _Ctext_1, ID _ID_1, fnclass _fnclass_1) { + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + assertPhylum(_ac_declarator_1, phylum_ac_declarator); + assertPhylum(_ac_declaration_list_1, phylum_ac_declaration_list); + assertPhylum(_ac_opt_base_init_list_1, phylum_ac_opt_base_init_list); + assertPhylum(_Ctext_1, phylum_Ctext); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_fnclass_1, phylum_fnclass); + fndeclaration kc_x = new impl_fndeclaration_FnAcDeclaration(_ac_declaration_specifiers_1, _ac_declarator_1, _ac_declaration_list_1, _ac_opt_base_init_list_1, _Ctext_1, _ID_1, _fnclass_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_FnAcDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_FnAcDeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_fndeclaration(kc_x); + return static_cast(kc_x); + } + + impl_fndeclaration_AcMemberDeclaration* + AcMemberDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1, fnclass _fnclass_1) { + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + assertPhylum(_ac_declarator_1, phylum_ac_declarator); + assertPhylum(_ac_constant_expression_option_1, phylum_ac_constant_expression_option); + assertPhylum(_fnclass_1, phylum_fnclass); + fndeclaration kc_x = new impl_fndeclaration_AcMemberDeclaration(_ac_declaration_specifiers_1, _ac_declarator_1, _ac_constant_expression_option_1, _fnclass_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcMemberDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcMemberDeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_fndeclaration(kc_x); + return static_cast(kc_x); + } + + impl_fnclass_GlobalFn* + GlobalFn() { + fnclass kc_x = new impl_fnclass_GlobalFn(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_GlobalFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_GlobalFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnclass_StaticFn* + StaticFn(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + fnclass kc_x = new impl_fnclass_StaticFn(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_StaticFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_StaticFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnclass_MemberFn* + MemberFn() { + fnclass kc_x = new impl_fnclass_MemberFn(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_MemberFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_MemberFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnclass_ConstructorFn* + ConstructorFn() { + fnclass kc_x = new impl_fnclass_ConstructorFn(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConstructorFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConstructorFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnclass_DestructorFn* + DestructorFn() { + fnclass kc_x = new impl_fnclass_DestructorFn(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_DestructorFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_DestructorFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fnclass_ConvOperatorFn* + ConvOperatorFn() { + fnclass kc_x = new impl_fnclass_ConvOperatorFn(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConvOperatorFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConvOperatorFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_Ctext* + NilCtext() { + Ctext kc_x = new impl_Ctext(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NilCtext)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NilCtext)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext(kc_x); + return static_cast(kc_x); + } + + impl_Ctext* + ConsCtext(Ctext_elem _Ctext_elem_1, Ctext _Ctext_1) { + assertPhylum(_Ctext_elem_1, phylum_Ctext_elem); + assertPhylum(_Ctext_1, phylum_Ctext); + Ctext kc_x = new impl_Ctext(_Ctext_elem_1, _Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ConsCtext)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ConsCtext)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextLine* + CTextLine(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + Ctext_elem kc_x = new impl_Ctext_elem_CTextLine(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextLine)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextLine)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextDollarVar* + CTextDollarVar(INT _INT_1) { + assertPhylum(_INT_1, phylum_INT); + Ctext_elem kc_x = new impl_Ctext_elem_CTextDollarVar(_INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextDollarVar)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextDollarVar)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextNl* + CTextNl(integer _integer_1) { + assertPhylum(_integer_1, phylum_integer); + Ctext_elem kc_x = new impl_Ctext_elem_CTextNl(_integer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextNl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextNl)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextCexpressionDQ* + CTextCexpressionDQ(CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + Ctext_elem kc_x = new impl_Ctext_elem_CTextCexpressionDQ(_CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextCexpressionDQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextCexpressionDQ)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextCexpressionSQ* + CTextCexpressionSQ(CexpressionSQ _CexpressionSQ_1) { + assertPhylum(_CexpressionSQ_1, phylum_CexpressionSQ); + Ctext_elem kc_x = new impl_Ctext_elem_CTextCexpressionSQ(_CexpressionSQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextCexpressionSQ)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextCexpressionSQ)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextCbody* + CTextCbody(Ctext _Ctext_1) { + assertPhylum(_Ctext_1, phylum_Ctext); + Ctext_elem kc_x = new impl_Ctext_elem_CTextCbody(_Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextCbody)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextCbody)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextForeachexpression* + CTextForeachexpression(patternchain _patternchain_1, idCexpressions _idCexpressions_1, withexpressions _withexpressions_1, Ctext _Ctext_1, foreach_after _foreach_after_1) { + assertPhylum(_patternchain_1, phylum_patternchain); + assertPhylum(_idCexpressions_1, phylum_idCexpressions); + assertPhylum(_withexpressions_1, phylum_withexpressions); + assertPhylum(_Ctext_1, phylum_Ctext); + assertPhylum(_foreach_after_1, phylum_foreach_after); + Ctext_elem kc_x = new impl_Ctext_elem_CTextForeachexpression(_patternchain_1, _idCexpressions_1, _withexpressions_1, _Ctext_1, _foreach_after_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextForeachexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextForeachexpression)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_Ctext_elem_CTextWithexpression* + CTextWithexpression(withexpressions _withexpressions_1, withcases _withcases_1, contextinfo _contextinfo_1) { + assertPhylum(_withexpressions_1, phylum_withexpressions); + assertPhylum(_withcases_1, phylum_withcases); + assertPhylum(_contextinfo_1, phylum_contextinfo); + Ctext_elem kc_x = new impl_Ctext_elem_CTextWithexpression(_withexpressions_1, _withcases_1, _contextinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CTextWithexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CTextWithexpression)); + kc_x->post_create(); + kc_x = kc_initialize_Ctext_elem(kc_x); + return static_cast(kc_x); + } + + impl_foreach_after_NoForeachAfter* + NoForeachAfter() { + foreach_after kc_x = new impl_foreach_after_NoForeachAfter(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoForeachAfter)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoForeachAfter)); + kc_x->post_create(); + kc_x = kc_initialize_foreach_after(kc_x); + return static_cast(kc_x); + } + + impl_foreach_after_ForeachAfter* + ForeachAfter(patternchain _patternchain_1, idCexpressions _idCexpressions_1, withexpressions _withexpressions_1, Ctext _Ctext_1) { + assertPhylum(_patternchain_1, phylum_patternchain); + assertPhylum(_idCexpressions_1, phylum_idCexpressions); + assertPhylum(_withexpressions_1, phylum_withexpressions); + assertPhylum(_Ctext_1, phylum_Ctext); + foreach_after kc_x = new impl_foreach_after_ForeachAfter(_patternchain_1, _idCexpressions_1, _withexpressions_1, _Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ForeachAfter)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ForeachAfter)); + kc_x->post_create(); + kc_x = kc_initialize_foreach_after(kc_x); + return static_cast(kc_x); + } + + impl_contextinfo_InForeachContext* + InForeachContext(patternchain _patternchain_1) { + assertPhylum(_patternchain_1, phylum_patternchain); + contextinfo kc_x = new impl_contextinfo_InForeachContext(_patternchain_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_InForeachContext)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_InForeachContext)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_contextinfo_NotInForeachContext* + NotInForeachContext() { + contextinfo kc_x = new impl_contextinfo_NotInForeachContext(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NotInForeachContext)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NotInForeachContext)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withexpressions* + Nilwithexpressions() { + withexpressions kc_x = new impl_withexpressions(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilwithexpressions)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilwithexpressions)); + kc_x->post_create(); + kc_x = kc_initialize_withexpressions(kc_x); + return static_cast(kc_x); + } + + impl_withexpressions* + Conswithexpressions(withexpression _withexpression_1, withexpressions _withexpressions_1) { + assertPhylum(_withexpression_1, phylum_withexpression); + assertPhylum(_withexpressions_1, phylum_withexpressions); + withexpressions kc_x = new impl_withexpressions(_withexpression_1, _withexpressions_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conswithexpressions)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conswithexpressions)); + kc_x->post_create(); + kc_x = kc_initialize_withexpressions(kc_x); + return static_cast(kc_x); + } + + impl_withexpression_WEVariable* + WEVariable(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + withexpression kc_x = new impl_withexpression_WEVariable(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_WEVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_WEVariable)); + kc_x->post_create(); + kc_x = kc_initialize_withexpression(kc_x); + return static_cast(kc_x); + } + + impl_withexpression_WECexpression* + WECexpression(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + withexpression kc_x = new impl_withexpression_WECexpression(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_WECexpression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_WECexpression)); + kc_x->post_create(); + kc_x = kc_initialize_withexpression(kc_x); + return static_cast(kc_x); + } + + impl_withcases* + Nilwithcases() { + withcases kc_x = new impl_withcases(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilwithcases)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilwithcases)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withcases* + Conswithcases(withcase _withcase_1, withcases _withcases_1) { + assertPhylum(_withcase_1, phylum_withcase); + assertPhylum(_withcases_1, phylum_withcases); + withcases kc_x = new impl_withcases(_withcase_1, _withcases_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conswithcases)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conswithcases)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withcase_Withcase* + Withcase(patternchains _patternchains_1, Ctext _Ctext_1) { + assertPhylum(_patternchains_1, phylum_patternchains); + assertPhylum(_Ctext_1, phylum_Ctext); + withcase kc_x = new impl_withcase_Withcase(_patternchains_1, _Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Withcase)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Withcase)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclarations* + Nilunparsedeclarations() { + unparsedeclarations kc_x = new impl_unparsedeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunparsedeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunparsedeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclarations* + Consunparsedeclarations(unparsedeclaration _unparsedeclaration_1, unparsedeclarations _unparsedeclarations_1) { + assertPhylum(_unparsedeclaration_1, phylum_unparsedeclaration); + assertPhylum(_unparsedeclarations_1, phylum_unparsedeclarations); + unparsedeclarations kc_x = new impl_unparsedeclarations(_unparsedeclaration_1, _unparsedeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunparsedeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunparsedeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclaration_UnparseDeclaration* + UnparseDeclaration(outmostpatterns _outmostpatterns_1, unparseclauses _unparseclauses_1) { + assertPhylum(_outmostpatterns_1, phylum_outmostpatterns); + assertPhylum(_unparseclauses_1, phylum_unparseclauses); + unparsedeclaration kc_x = new impl_unparsedeclaration_UnparseDeclaration(_outmostpatterns_1, _unparseclauses_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnparseDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnparseDeclaration)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseclauses* + Nilunparseclauses() { + unparseclauses kc_x = new impl_unparseclauses(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunparseclauses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunparseclauses)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseclauses* + Consunparseclauses(unparseclause _unparseclause_1, unparseclauses _unparseclauses_1) { + assertPhylum(_unparseclause_1, phylum_unparseclause); + assertPhylum(_unparseclauses_1, phylum_unparseclauses); + unparseclauses kc_x = new impl_unparseclauses(_unparseclause_1, _unparseclauses_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunparseclauses)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunparseclauses)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseclause_UnparseClause* + UnparseClause(viewnames _viewnames_1, unparseitems _unparseitems_1) { + assertPhylum(_viewnames_1, phylum_viewnames); + assertPhylum(_unparseitems_1, phylum_unparseitems); + unparseclause kc_x = new impl_unparseclause_UnparseClause(_viewnames_1, _unparseitems_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnparseClause)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnparseClause)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_viewnames* + Nilviewnames() { + viewnames kc_x = new impl_viewnames(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilviewnames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilviewnames)); + kc_x->post_create(); + kc_x = kc_initialize_viewnames(kc_x); + return static_cast(kc_x); + } + + impl_viewnames* + Consviewnames(ID _ID_1, viewnames _viewnames_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_viewnames_1, phylum_viewnames); + viewnames kc_x = new impl_viewnames(_ID_1, _viewnames_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consviewnames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consviewnames)); + kc_x->post_create(); + kc_x = kc_initialize_viewnames(kc_x); + return static_cast(kc_x); + } + + impl_unparseitems* + Nilunparseitems() { + unparseitems kc_x = new impl_unparseitems(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunparseitems)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunparseitems)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseitems* + Consunparseitems(unparseitem _unparseitem_1, unparseitems _unparseitems_1) { + assertPhylum(_unparseitem_1, phylum_unparseitem); + assertPhylum(_unparseitems_1, phylum_unparseitems); + unparseitems kc_x = new impl_unparseitems(_unparseitem_1, _unparseitems_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunparseitems)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunparseitems)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseitem_UnpStr* + UnpStr(languageoption _languageoption_1, CexpressionDQ _CexpressionDQ_1, viewnameoption _viewnameoption_1) { + assertPhylum(_languageoption_1, phylum_languageoption); + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + assertPhylum(_viewnameoption_1, phylum_viewnameoption); + unparseitem kc_x = new impl_unparseitem_UnpStr(_languageoption_1, _CexpressionDQ_1, _viewnameoption_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpStr)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpStr)); + kc_x->post_create(); + kc_x = kc_initialize_unparseitem(kc_x); + return static_cast(kc_x); + } + + impl_unparseitem_UnpSubexpr* + UnpSubexpr(languageoption _languageoption_1, unpsubterm _unpsubterm_1, viewnameoption _viewnameoption_1) { + assertPhylum(_languageoption_1, phylum_languageoption); + assertPhylum(_unpsubterm_1, phylum_unpsubterm); + assertPhylum(_viewnameoption_1, phylum_viewnameoption); + unparseitem kc_x = new impl_unparseitem_UnpSubexpr(_languageoption_1, _unpsubterm_1, _viewnameoption_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpSubexpr)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpSubexpr)); + kc_x->post_create(); + kc_x = kc_initialize_unparseitem(kc_x); + return static_cast(kc_x); + } + + impl_unparseitem_UnpCtext* + UnpCtext(languageoption _languageoption_1, Ctext _Ctext_1) { + assertPhylum(_languageoption_1, phylum_languageoption); + assertPhylum(_Ctext_1, phylum_Ctext); + unparseitem kc_x = new impl_unparseitem_UnpCtext(_languageoption_1, _Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpCtext)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpCtext)); + kc_x->post_create(); + kc_x = kc_initialize_unparseitem(kc_x); + return static_cast(kc_x); + } + + impl_unparseitem_UnpBody* + UnpBody(languageoption _languageoption_1, unparseitems _unparseitems_1) { + assertPhylum(_languageoption_1, phylum_languageoption); + assertPhylum(_unparseitems_1, phylum_unparseitems); + unparseitem kc_x = new impl_unparseitem_UnpBody(_languageoption_1, _unparseitems_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpBody)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpBody)); + kc_x->post_create(); + kc_x = kc_initialize_unparseitem(kc_x); + return static_cast(kc_x); + } + + impl_unparseitem_UViewVarDecl* + UViewVarDecl(ID _ID_1, ID _ID_2, Cexpression _Cexpression_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ID_2, phylum_ID); + assertPhylum(_Cexpression_1, phylum_Cexpression); + unparseitem kc_x = new impl_unparseitem_UViewVarDecl(_ID_1, _ID_2, _Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UViewVarDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UViewVarDecl)); + kc_x->post_create(); + kc_x = kc_initialize_unparseitem(kc_x); + return static_cast(kc_x); + } + + impl_unpsubterm_UnpSubTerm* + UnpSubTerm(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + unpsubterm kc_x = new impl_unpsubterm_UnpSubTerm(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpSubTerm)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpSubTerm)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpsubterm_UnpDollarvarTerm* + UnpDollarvarTerm(INT _INT_1) { + assertPhylum(_INT_1, phylum_INT); + unpsubterm kc_x = new impl_unpsubterm_UnpDollarvarTerm(_INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpDollarvarTerm)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpDollarvarTerm)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpsubterm_UnpSubAttr* + UnpSubAttr(ID _ID_1, unpattributes _unpattributes_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_unpattributes_1, phylum_unpattributes); + unpsubterm kc_x = new impl_unpsubterm_UnpSubAttr(_ID_1, _unpattributes_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpSubAttr)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpSubAttr)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpsubterm_UnpDollarvarAttr* + UnpDollarvarAttr(INT _INT_1, unpattributes _unpattributes_1) { + assertPhylum(_INT_1, phylum_INT); + assertPhylum(_unpattributes_1, phylum_unpattributes); + unpsubterm kc_x = new impl_unpsubterm_UnpDollarvarAttr(_INT_1, _unpattributes_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpDollarvarAttr)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpDollarvarAttr)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpsubterm_UnpCastedVariable* + UnpCastedVariable(ID _ID_1, ID _ID_2) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ID_2, phylum_ID); + unpsubterm kc_x = new impl_unpsubterm_UnpCastedVariable(_ID_1, _ID_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_UnpCastedVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_UnpCastedVariable)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpattributes* + Nilunpattributes() { + unpattributes kc_x = new impl_unpattributes(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunpattributes)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunpattributes)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unpattributes* + Consunpattributes(ID _ID_1, unpattributes _unpattributes_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_unpattributes_1, phylum_unpattributes); + unpattributes kc_x = new impl_unpattributes(_ID_1, _unpattributes_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunpattributes)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunpattributes)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_viewnameoption_NoViewname* + NoViewname() { + viewnameoption kc_x = new impl_viewnameoption_NoViewname(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoViewname)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoViewname)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_viewnameoption_YesViewname* + YesViewname(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + viewnameoption kc_x = new impl_viewnameoption_YesViewname(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_YesViewname)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_YesViewname)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_languageoption_NoLanguagename* + NoLanguagename() { + languageoption kc_x = new impl_languageoption_NoLanguagename(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoLanguagename)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoLanguagename)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_languageoption_LanguageList* + LanguageList(languagenames _languagenames_1) { + assertPhylum(_languagenames_1, phylum_languagenames); + languageoption kc_x = new impl_languageoption_LanguageList(_languagenames_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_LanguageList)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_LanguageList)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_languagenames* + Nillanguagenames() { + languagenames kc_x = new impl_languagenames(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nillanguagenames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nillanguagenames)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_languagenames* + Conslanguagenames(ID _ID_1, languagenames _languagenames_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_languagenames_1, phylum_languagenames); + languagenames kc_x = new impl_languagenames(_ID_1, _languagenames_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conslanguagenames)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conslanguagenames)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fileline_FileLine* + FileLine(casestring _file, int _line) { + fileline kc_x = new impl_fileline_FileLine(_file, _line); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_FileLine)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_FileLine)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fileline_NoFileLine* + NoFileLine() { + fileline kc_x = new impl_fileline_NoFileLine(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NoFileLine)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NoFileLine)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_fileline_PosNoFileLine* + PosNoFileLine() { + fileline kc_x = new impl_fileline_PosNoFileLine(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PosNoFileLine)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PosNoFileLine)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_scopetypefilelinestack* + Nilscopetypefilelinestack() { + scopetypefilelinestack kc_x = new impl_scopetypefilelinestack(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilscopetypefilelinestack)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilscopetypefilelinestack)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_scopetypefilelinestack* + Consscopetypefilelinestack(scopetypefileline _scopetypefileline_1, scopetypefilelinestack _scopetypefilelinestack_1) { + assertPhylum(_scopetypefileline_1, phylum_scopetypefileline); + assertPhylum(_scopetypefilelinestack_1, phylum_scopetypefilelinestack); + scopetypefilelinestack kc_x = new impl_scopetypefilelinestack(_scopetypefileline_1, _scopetypefilelinestack_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consscopetypefilelinestack)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consscopetypefilelinestack)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_scopetypefileline_ScopeTypeFileLine* + ScopeTypeFileLine(integer _integer_1, IDtype _IDtype_1, casestring _casestring_1, integer _integer_2) { + assertPhylum(_integer_1, phylum_integer); + assertPhylum(_IDtype_1, phylum_IDtype); + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_integer_2, phylum_integer); + scopetypefileline kc_x = new impl_scopetypefileline_ScopeTypeFileLine(_integer_1, _IDtype_1, _casestring_1, _integer_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ScopeTypeFileLine)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ScopeTypeFileLine)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUnknown* + ITUnknown() { + IDtype kc_x = new impl_IDtype_ITUnknown(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUnknown)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUnknown)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPredefinedPhylum* + ITPredefinedPhylum(phylumdeclaration _phylumdeclaration_1) { + assertPhylum(_phylumdeclaration_1, phylum_phylumdeclaration); + IDtype kc_x = new impl_IDtype_ITPredefinedPhylum(_phylumdeclaration_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPredefinedPhylum)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPredefinedPhylum)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUserPhylum* + ITUserPhylum(phylumdeclaration _phylumdeclaration_1) { + assertPhylum(_phylumdeclaration_1, phylum_phylumdeclaration); + IDtype kc_x = new impl_IDtype_ITUserPhylum(_phylumdeclaration_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUserPhylum)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUserPhylum)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPredefinedOperator* + ITPredefinedOperator(alternative _alternative_1, ID _ID_1) { + assertPhylum(_alternative_1, phylum_alternative); + assertPhylum(_ID_1, phylum_ID); + IDtype kc_x = new impl_IDtype_ITPredefinedOperator(_alternative_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPredefinedOperator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPredefinedOperator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUserOperator* + ITUserOperator(alternative _alternative_1, ID _ID_1) { + assertPhylum(_alternative_1, phylum_alternative); + assertPhylum(_ID_1, phylum_ID); + IDtype kc_x = new impl_IDtype_ITUserOperator(_alternative_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUserOperator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUserOperator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPredefinedStorageClass* + ITPredefinedStorageClass() { + IDtype kc_x = new impl_IDtype_ITPredefinedStorageClass(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPredefinedStorageClass)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPredefinedStorageClass)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITStorageClass* + ITStorageClass() { + IDtype kc_x = new impl_IDtype_ITStorageClass(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITStorageClass)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITStorageClass)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPredefinedUView* + ITPredefinedUView() { + IDtype kc_x = new impl_IDtype_ITPredefinedUView(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPredefinedUView)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPredefinedUView)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUserUView* + ITUserUView() { + IDtype kc_x = new impl_IDtype_ITUserUView(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUserUView)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUserUView)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUViewVar* + ITUViewVar() { + IDtype kc_x = new impl_IDtype_ITUViewVar(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUViewVar)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUViewVar)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPredefinedRView* + ITPredefinedRView() { + IDtype kc_x = new impl_IDtype_ITPredefinedRView(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPredefinedRView)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPredefinedRView)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUserRView* + ITUserRView() { + IDtype kc_x = new impl_IDtype_ITUserRView(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUserRView)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUserRView)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITUserFunction* + ITUserFunction(fnclass _fnclass_1) { + assertPhylum(_fnclass_1, phylum_fnclass); + IDtype kc_x = new impl_IDtype_ITUserFunction(_fnclass_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITUserFunction)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITUserFunction)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITPatternVariable* + ITPatternVariable(ID _ID_1, integer _integer_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_integer_1, phylum_integer); + IDtype kc_x = new impl_IDtype_ITPatternVariable(_ID_1, _integer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITPatternVariable)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITPatternVariable)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_IDtype_ITLanguageName* + ITLanguageName(integer _integer_1) { + assertPhylum(_integer_1, phylum_integer); + IDtype kc_x = new impl_IDtype_ITLanguageName(_integer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_ITLanguageName)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_ITLanguageName)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_operators* + Niloperators() { + operators kc_x = new impl_operators(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Niloperators)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Niloperators)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_operators* + Consoperators(ID _ID_1, operators _operators_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_operators_1, phylum_operators); + operators kc_x = new impl_operators(_ID_1, _operators_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consoperators)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consoperators)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phyla* + Nilphyla() { + phyla kc_x = new impl_phyla(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilphyla)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilphyla)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_phyla* + Consphyla(ID _ID_1, phyla _phyla_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_phyla_1, phylum_phyla); + phyla kc_x = new impl_phyla(_ID_1, _phyla_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consphyla)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consphyla)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_variables* + Nilvariables() { + variables kc_x = new impl_variables(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilvariables)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilvariables)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_variables* + Consvariables(ID _ID_1, variables _variables_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_variables_1, phylum_variables); + variables kc_x = new impl_variables(_ID_1, _variables_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consvariables)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consvariables)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_dollarvarstatus_DVAllowed* + DVAllowed() { + dollarvarstatus kc_x = new impl_dollarvarstatus_DVAllowed(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_DVAllowed)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_DVAllowed)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_dollarvarstatus_DVDisallowed* + DVDisallowed() { + dollarvarstatus kc_x = new impl_dollarvarstatus_DVDisallowed(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_DVDisallowed)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_DVDisallowed)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_tribool_Equal* + Equal() { + tribool kc_x = new impl_tribool_Equal(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Equal)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Equal)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_tribool_Smaller* + Smaller() { + tribool kc_x = new impl_tribool_Smaller(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Smaller)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Smaller)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_tribool_Bigger* + Bigger() { + tribool kc_x = new impl_tribool_Bigger(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Bigger)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Bigger)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternrepresentations* + Nilpatternrepresentations() { + patternrepresentations kc_x = new impl_patternrepresentations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpatternrepresentations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpatternrepresentations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternrepresentations* + Conspatternrepresentations(patternrepresentation _patternrepresentation_1, patternrepresentations _patternrepresentations_1) { + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + assertPhylum(_patternrepresentations_1, phylum_patternrepresentations); + patternrepresentations kc_x = new impl_patternrepresentations(_patternrepresentation_1, _patternrepresentations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspatternrepresentations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspatternrepresentations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternrepresentation* + Nilpatternrepresentation() { + patternrepresentation kc_x = new impl_patternrepresentation(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpatternrepresentation)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpatternrepresentation)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_patternrepresentation* + Conspatternrepresentation(elem_patternrepresentation _elem_patternrepresentation_1, patternrepresentation _patternrepresentation_1) { + assertPhylum(_elem_patternrepresentation_1, phylum_elem_patternrepresentation); + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + patternrepresentation kc_x = new impl_patternrepresentation(_elem_patternrepresentation_1, _patternrepresentation_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspatternrepresentation)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspatternrepresentation)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRBinding* + PRBinding(path _path_1, ID _ID_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_ID_1, phylum_ID); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRBinding(_path_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRBinding)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRBinding)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRVarPredicate* + PRVarPredicate(paths _paths_1, ID _ID_1, patternrepresentation _patternrepresentation_1) { + assertPhylum(_paths_1, phylum_paths); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRVarPredicate(_paths_1, _ID_1, _patternrepresentation_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRVarPredicate)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRVarPredicate)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PROperPredicate* + PROperPredicate(path _path_1, ID _ID_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_ID_1, phylum_ID); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PROperPredicate(_path_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PROperPredicate)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PROperPredicate)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRUserPredicate* + PRUserPredicate(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRUserPredicate(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRUserPredicate)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRUserPredicate)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRNonLeafBinding* + PRNonLeafBinding(path _path_1, ID _ID_1, patternrepresentation _patternrepresentation_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRNonLeafBinding(_path_1, _ID_1, _patternrepresentation_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRNonLeafBinding)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRNonLeafBinding)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRWildcard* + PRWildcard(path _path_1) { + assertPhylum(_path_1, phylum_path); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRWildcard(_path_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRWildcard)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRWildcard)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRDefault* + PRDefault() { + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRDefault(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRDefault)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRDefault)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRStringLiteral* + PRStringLiteral(path _path_1, CexpressionDQ _CexpressionDQ_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_CexpressionDQ_1, phylum_CexpressionDQ); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRStringLiteral(_path_1, _CexpressionDQ_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRStringLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRStringLiteral)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_elem_patternrepresentation_PRIntLiteral* + PRIntLiteral(path _path_1, INT _INT_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_INT_1, phylum_INT); + elem_patternrepresentation kc_x = new impl_elem_patternrepresentation_PRIntLiteral(_path_1, _INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_PRIntLiteral)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_PRIntLiteral)); + kc_x->post_create(); + kc_x = kc_initialize_elem_patternrepresentation(kc_x); + return static_cast(kc_x); + } + + impl_path* + Nilpath() { + path kc_x = new impl_path(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpath)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpath)); + kc_x->post_create(); + kc_x = kc_initialize_path(kc_x); + return static_cast(kc_x); + } + + impl_path* + Conspath(integer _integer_1, path _path_1) { + assertPhylum(_integer_1, phylum_integer); + assertPhylum(_path_1, phylum_path); + path kc_x = new impl_path(_integer_1, _path_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspath)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspath)); + kc_x->post_create(); + kc_x = kc_initialize_path(kc_x); + return static_cast(kc_x); + } + + impl_paths* + Nilpaths() { + paths kc_x = new impl_paths(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilpaths)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilpaths)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_paths* + Conspaths(path _path_1, paths _paths_1) { + assertPhylum(_path_1, phylum_path); + assertPhylum(_paths_1, phylum_paths); + paths kc_x = new impl_paths(_path_1, _paths_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conspaths)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conspaths)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_argsnumbers* + Nilargsnumbers() { + argsnumbers kc_x = new impl_argsnumbers(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilargsnumbers)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilargsnumbers)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_argsnumbers* + Consargsnumbers(integer _integer_1, argsnumbers _argsnumbers_1) { + assertPhylum(_integer_1, phylum_integer); + assertPhylum(_argsnumbers_1, phylum_argsnumbers); + argsnumbers kc_x = new impl_argsnumbers(_integer_1, _argsnumbers_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consargsnumbers)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consargsnumbers)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriterulesinfo* + Nilrewriterulesinfo() { + rewriterulesinfo kc_x = new impl_rewriterulesinfo(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilrewriterulesinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilrewriterulesinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriterulesinfo* + Consrewriterulesinfo(rewriteruleinfo _rewriteruleinfo_1, rewriterulesinfo _rewriterulesinfo_1) { + assertPhylum(_rewriteruleinfo_1, phylum_rewriteruleinfo); + assertPhylum(_rewriterulesinfo_1, phylum_rewriterulesinfo); + rewriterulesinfo kc_x = new impl_rewriterulesinfo(_rewriteruleinfo_1, _rewriterulesinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consrewriterulesinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consrewriterulesinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteruleinfo_Rewriteruleinfo* + Rewriteruleinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, rewriteclause _rewriteclause_1) { + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + assertPhylum(_patternrepresentation_2, phylum_patternrepresentation); + assertPhylum(_rewriteclause_1, phylum_rewriteclause); + rewriteruleinfo kc_x = new impl_rewriteruleinfo_Rewriteruleinfo(_patternrepresentation_1, _patternrepresentation_2, _rewriteclause_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Rewriteruleinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Rewriteruleinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withcasesinfo* + Nilwithcasesinfo() { + withcasesinfo kc_x = new impl_withcasesinfo(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilwithcasesinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilwithcasesinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withcasesinfo* + Conswithcasesinfo(withcaseinfo _withcaseinfo_1, withcasesinfo _withcasesinfo_1) { + assertPhylum(_withcaseinfo_1, phylum_withcaseinfo); + assertPhylum(_withcasesinfo_1, phylum_withcasesinfo); + withcasesinfo kc_x = new impl_withcasesinfo(_withcaseinfo_1, _withcasesinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conswithcasesinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conswithcasesinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_withcaseinfo_Withcaseinfo* + Withcaseinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, Ctext _Ctext_1) { + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + assertPhylum(_patternrepresentation_2, phylum_patternrepresentation); + assertPhylum(_Ctext_1, phylum_Ctext); + withcaseinfo kc_x = new impl_withcaseinfo_Withcaseinfo(_patternrepresentation_1, _patternrepresentation_2, _Ctext_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Withcaseinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Withcaseinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteviewsinfo* + Nilrewriteviewsinfo() { + rewriteviewsinfo kc_x = new impl_rewriteviewsinfo(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilrewriteviewsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilrewriteviewsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteviewsinfo* + Consrewriteviewsinfo(rewriteviewinfo _rewriteviewinfo_1, rewriteviewsinfo _rewriteviewsinfo_1) { + assertPhylum(_rewriteviewinfo_1, phylum_rewriteviewinfo); + assertPhylum(_rewriteviewsinfo_1, phylum_rewriteviewsinfo); + rewriteviewsinfo kc_x = new impl_rewriteviewsinfo(_rewriteviewinfo_1, _rewriteviewsinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consrewriteviewsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consrewriteviewsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_rewriteviewinfo_Rewriteviewinfo* + Rewriteviewinfo(ID _ID_1, rewriterulesinfo _rewriterulesinfo_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_rewriterulesinfo_1, phylum_rewriterulesinfo); + rewriteviewinfo kc_x = new impl_rewriteviewinfo_Rewriteviewinfo(_ID_1, _rewriterulesinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Rewriteviewinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Rewriteviewinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseviewsinfo* + Nilunparseviewsinfo() { + unparseviewsinfo kc_x = new impl_unparseviewsinfo(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunparseviewsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunparseviewsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseviewsinfo* + Consunparseviewsinfo(unparseviewinfo _unparseviewinfo_1, unparseviewsinfo _unparseviewsinfo_1) { + assertPhylum(_unparseviewinfo_1, phylum_unparseviewinfo); + assertPhylum(_unparseviewsinfo_1, phylum_unparseviewsinfo); + unparseviewsinfo kc_x = new impl_unparseviewsinfo(_unparseviewinfo_1, _unparseviewsinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunparseviewsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunparseviewsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparseviewinfo_Unparseviewinfo* + Unparseviewinfo(ID _ID_1, unparsedeclsinfo _unparsedeclsinfo_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_unparsedeclsinfo_1, phylum_unparsedeclsinfo); + unparseviewinfo kc_x = new impl_unparseviewinfo_Unparseviewinfo(_ID_1, _unparsedeclsinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Unparseviewinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Unparseviewinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclsinfo* + Nilunparsedeclsinfo() { + unparsedeclsinfo kc_x = new impl_unparsedeclsinfo(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilunparsedeclsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilunparsedeclsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclsinfo* + Consunparsedeclsinfo(unparsedeclinfo _unparsedeclinfo_1, unparsedeclsinfo _unparsedeclsinfo_1) { + assertPhylum(_unparsedeclinfo_1, phylum_unparsedeclinfo); + assertPhylum(_unparsedeclsinfo_1, phylum_unparsedeclsinfo); + unparsedeclsinfo kc_x = new impl_unparsedeclsinfo(_unparsedeclinfo_1, _unparsedeclsinfo_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consunparsedeclsinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consunparsedeclsinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_unparsedeclinfo_Unparsedeclinfo* + Unparsedeclinfo(patternrepresentation _patternrepresentation_1, patternrepresentation _patternrepresentation_2, unparseclause _unparseclause_1) { + assertPhylum(_patternrepresentation_1, phylum_patternrepresentation); + assertPhylum(_patternrepresentation_2, phylum_patternrepresentation); + assertPhylum(_unparseclause_1, phylum_unparseclause); + unparsedeclinfo kc_x = new impl_unparsedeclinfo_Unparsedeclinfo(_patternrepresentation_1, _patternrepresentation_2, _unparseclause_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Unparsedeclinfo)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Unparsedeclinfo)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_AcDeclaration* + AcDeclaration(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_init_declarator_list _ac_init_declarator_list_1) { + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + assertPhylum(_ac_init_declarator_list_1, phylum_ac_init_declarator_list); + ac_declaration kc_x = new impl_ac_declaration_AcDeclaration(_ac_declaration_specifiers_1, _ac_init_declarator_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDeclaration)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_list* + Nilac_declaration_list() { + ac_declaration_list kc_x = new impl_ac_declaration_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_declaration_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_declaration_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_list* + Consac_declaration_list(ac_declaration _ac_declaration_1, ac_declaration_list _ac_declaration_list_1) { + assertPhylum(_ac_declaration_1, phylum_ac_declaration); + assertPhylum(_ac_declaration_list_1, phylum_ac_declaration_list); + ac_declaration_list kc_x = new impl_ac_declaration_list(_ac_declaration_1, _ac_declaration_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_declaration_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_declaration_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_specifiers* + Nilac_declaration_specifiers() { + ac_declaration_specifiers kc_x = new impl_ac_declaration_specifiers(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_declaration_specifiers)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_declaration_specifiers)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_specifiers* + Consac_declaration_specifiers(ac_declaration_specifier _ac_declaration_specifier_1, ac_declaration_specifiers _ac_declaration_specifiers_1) { + assertPhylum(_ac_declaration_specifier_1, phylum_ac_declaration_specifier); + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + ac_declaration_specifiers kc_x = new impl_ac_declaration_specifiers(_ac_declaration_specifier_1, _ac_declaration_specifiers_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_declaration_specifiers)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_declaration_specifiers)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_specifier_AcDeclSpecStorageSpec* + AcDeclSpecStorageSpec(ac_storage_class_specifier _ac_storage_class_specifier_1) { + assertPhylum(_ac_storage_class_specifier_1, phylum_ac_storage_class_specifier); + ac_declaration_specifier kc_x = new impl_ac_declaration_specifier_AcDeclSpecStorageSpec(_ac_storage_class_specifier_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDeclSpecStorageSpec)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDeclSpecStorageSpec)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_specifier_AcDeclSpecTypeSpec* + AcDeclSpecTypeSpec(ac_type_specifier _ac_type_specifier_1) { + assertPhylum(_ac_type_specifier_1, phylum_ac_type_specifier); + ac_declaration_specifier kc_x = new impl_ac_declaration_specifier_AcDeclSpecTypeSpec(_ac_type_specifier_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDeclSpecTypeSpec)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDeclSpecTypeSpec)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declaration_specifier_AcDeclSpecTypeQual* + AcDeclSpecTypeQual(ac_type_qualifier _ac_type_qualifier_1) { + assertPhylum(_ac_type_qualifier_1, phylum_ac_type_qualifier); + ac_declaration_specifier kc_x = new impl_ac_declaration_specifier_AcDeclSpecTypeQual(_ac_type_qualifier_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDeclSpecTypeQual)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDeclSpecTypeQual)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcAuto* + AcAuto() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcAuto(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcAuto)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcAuto)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcRegister* + AcRegister() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcRegister(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcRegister)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcRegister)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcStatic* + AcStatic() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcStatic(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcStatic)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcStatic)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcExtern* + AcExtern() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcExtern(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcExtern)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcExtern)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcTypedef* + AcTypedef() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcTypedef(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcTypedef)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcTypedef)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_storage_class_specifier_AcVirtual* + AcVirtual() { + ac_storage_class_specifier kc_x = new impl_ac_storage_class_specifier_AcVirtual(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcVirtual)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcVirtual)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_specifier_AcTypeSpec* + AcTypeSpec(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + ac_type_specifier kc_x = new impl_ac_type_specifier_AcTypeSpec(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcTypeSpec)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcTypeSpec)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_AcConst* + AcConst() { + ac_type_qualifier kc_x = new impl_ac_type_qualifier_AcConst(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcConst)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcConst)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_AcVolatile* + AcVolatile() { + ac_type_qualifier kc_x = new impl_ac_type_qualifier_AcVolatile(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcVolatile)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcVolatile)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_AcUnsigned* + AcUnsigned() { + ac_type_qualifier kc_x = new impl_ac_type_qualifier_AcUnsigned(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcUnsigned)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcUnsigned)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_AcNoQualifier* + AcNoQualifier() { + ac_type_qualifier kc_x = new impl_ac_type_qualifier_AcNoQualifier(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcNoQualifier)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcNoQualifier)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_init_declarator_list* + Nilac_init_declarator_list() { + ac_init_declarator_list kc_x = new impl_ac_init_declarator_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_init_declarator_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_init_declarator_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_init_declarator_list* + Consac_init_declarator_list(ac_init_declarator _ac_init_declarator_1, ac_init_declarator_list _ac_init_declarator_list_1) { + assertPhylum(_ac_init_declarator_1, phylum_ac_init_declarator); + assertPhylum(_ac_init_declarator_list_1, phylum_ac_init_declarator_list); + ac_init_declarator_list kc_x = new impl_ac_init_declarator_list(_ac_init_declarator_1, _ac_init_declarator_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_init_declarator_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_init_declarator_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_init_declarator_AcInitDecl* + AcInitDecl(ac_declarator _ac_declarator_1) { + assertPhylum(_ac_declarator_1, phylum_ac_declarator); + ac_init_declarator kc_x = new impl_ac_init_declarator_AcInitDecl(_ac_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcInitDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcInitDecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_declarator_AcDeclarator* + AcDeclarator(ac_pointer_option _ac_pointer_option_1, ac_ref_option _ac_ref_option_1, ac_direct_declarator _ac_direct_declarator_1) { + assertPhylum(_ac_pointer_option_1, phylum_ac_pointer_option); + assertPhylum(_ac_ref_option_1, phylum_ac_ref_option); + assertPhylum(_ac_direct_declarator_1, phylum_ac_direct_declarator); + ac_declarator kc_x = new impl_ac_declarator_AcDeclarator(_ac_pointer_option_1, _ac_ref_option_1, _ac_direct_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDeclarator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDeclarator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcDirectDeclId* + AcDirectDeclId(ID _ID_1) { + assertPhylum(_ID_1, phylum_ID); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcDirectDeclId(_ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirectDeclId)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirectDeclId)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcDirectDeclPack* + AcDirectDeclPack(ac_declarator _ac_declarator_1) { + assertPhylum(_ac_declarator_1, phylum_ac_declarator); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcDirectDeclPack(_ac_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirectDeclPack)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirectDeclPack)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcDirectDeclArray* + AcDirectDeclArray(ac_direct_declarator _ac_direct_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) { + assertPhylum(_ac_direct_declarator_1, phylum_ac_direct_declarator); + assertPhylum(_ac_constant_expression_option_1, phylum_ac_constant_expression_option); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcDirectDeclArray(_ac_direct_declarator_1, _ac_constant_expression_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirectDeclArray)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirectDeclArray)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcDirectDeclProto* + AcDirectDeclProto(ac_direct_declarator _ac_direct_declarator_1, ac_parameter_type_list _ac_parameter_type_list_1) { + assertPhylum(_ac_direct_declarator_1, phylum_ac_direct_declarator); + assertPhylum(_ac_parameter_type_list_1, phylum_ac_parameter_type_list); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcDirectDeclProto(_ac_direct_declarator_1, _ac_parameter_type_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirectDeclProto)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirectDeclProto)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcQualifiedDeclProto* + AcQualifiedDeclProto(ac_class_qualifier_list _ac_class_qualifier_list_1, ac_direct_declarator _ac_direct_declarator_1, ac_parameter_type_list _ac_parameter_type_list_1, ac_type_qualifier _ac_type_qualifier_1) { + assertPhylum(_ac_class_qualifier_list_1, phylum_ac_class_qualifier_list); + assertPhylum(_ac_direct_declarator_1, phylum_ac_direct_declarator); + assertPhylum(_ac_parameter_type_list_1, phylum_ac_parameter_type_list); + assertPhylum(_ac_type_qualifier_1, phylum_ac_type_qualifier); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcQualifiedDeclProto(_ac_class_qualifier_list_1, _ac_direct_declarator_1, _ac_parameter_type_list_1, _ac_type_qualifier_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcQualifiedDeclProto)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcQualifiedDeclProto)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcMemberDecl* + AcMemberDecl(ID _ID_1, ID _ID_2, ac_constant_expression_list _ac_constant_expression_list_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ID_2, phylum_ID); + assertPhylum(_ac_constant_expression_list_1, phylum_ac_constant_expression_list); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcMemberDecl(_ID_1, _ID_2, _ac_constant_expression_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcMemberDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcMemberDecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcConvOperatorDecl* + AcConvOperatorDecl(ID _ID_1, ID _ID_2) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ID_2, phylum_ID); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcConvOperatorDecl(_ID_1, _ID_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcConvOperatorDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcConvOperatorDecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_declarator_AcOperatorDeclId* + AcOperatorDeclId(ac_operator_name _ac_operator_name_1) { + assertPhylum(_ac_operator_name_1, phylum_ac_operator_name); + ac_direct_declarator kc_x = new impl_ac_direct_declarator_AcOperatorDeclId(_ac_operator_name_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcOperatorDeclId)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcOperatorDeclId)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_pointer_option_Nopointer* + Nopointer() { + ac_pointer_option kc_x = new impl_ac_pointer_option_Nopointer(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nopointer)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nopointer)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_pointer_option_Yespointer* + Yespointer(ac_pointer _ac_pointer_1) { + assertPhylum(_ac_pointer_1, phylum_ac_pointer); + ac_pointer_option kc_x = new impl_ac_pointer_option_Yespointer(_ac_pointer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Yespointer)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Yespointer)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_pointer_AcPointerNil* + AcPointerNil(ac_type_qualifier_list _ac_type_qualifier_list_1) { + assertPhylum(_ac_type_qualifier_list_1, phylum_ac_type_qualifier_list); + ac_pointer kc_x = new impl_ac_pointer_AcPointerNil(_ac_type_qualifier_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcPointerNil)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcPointerNil)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_pointer_AcPointerCons* + AcPointerCons(ac_type_qualifier_list _ac_type_qualifier_list_1, ac_pointer _ac_pointer_1) { + assertPhylum(_ac_type_qualifier_list_1, phylum_ac_type_qualifier_list); + assertPhylum(_ac_pointer_1, phylum_ac_pointer); + ac_pointer kc_x = new impl_ac_pointer_AcPointerCons(_ac_type_qualifier_list_1, _ac_pointer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcPointerCons)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcPointerCons)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_ref_option_AcNoRef* + AcNoRef() { + ac_ref_option kc_x = new impl_ac_ref_option_AcNoRef(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcNoRef)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcNoRef)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_ref_option_AcRef* + AcRef() { + ac_ref_option kc_x = new impl_ac_ref_option_AcRef(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcRef)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcRef)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_operator_name_AcOperatorName* + AcOperatorName(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + ac_operator_name kc_x = new impl_ac_operator_name_AcOperatorName(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcOperatorName)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcOperatorName)); + kc_x->post_create(); + kc_x = kc_initialize_ac_operator_name(kc_x); + return static_cast(kc_x); + } + + impl_ac_class_qualifier_help_list* + Nilac_class_qualifier_help_list() { + ac_class_qualifier_help_list kc_x = new impl_ac_class_qualifier_help_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_class_qualifier_help_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_class_qualifier_help_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_class_qualifier_help_list* + Consac_class_qualifier_help_list(ac_direct_declarator _ac_direct_declarator_1, ac_class_qualifier_help_list _ac_class_qualifier_help_list_1) { + assertPhylum(_ac_direct_declarator_1, phylum_ac_direct_declarator); + assertPhylum(_ac_class_qualifier_help_list_1, phylum_ac_class_qualifier_help_list); + ac_class_qualifier_help_list kc_x = new impl_ac_class_qualifier_help_list(_ac_direct_declarator_1, _ac_class_qualifier_help_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_class_qualifier_help_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_class_qualifier_help_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_class_qualifier_list* + Nilac_class_qualifier_list() { + ac_class_qualifier_list kc_x = new impl_ac_class_qualifier_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_class_qualifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_class_qualifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_class_qualifier_list* + Consac_class_qualifier_list(ID _ID_1, ac_class_qualifier_list _ac_class_qualifier_list_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ac_class_qualifier_list_1, phylum_ac_class_qualifier_list); + ac_class_qualifier_list kc_x = new impl_ac_class_qualifier_list(_ID_1, _ac_class_qualifier_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_class_qualifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_class_qualifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_list* + Nilac_type_qualifier_list() { + ac_type_qualifier_list kc_x = new impl_ac_type_qualifier_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_type_qualifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_type_qualifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_type_qualifier_list* + Consac_type_qualifier_list(ac_type_qualifier _ac_type_qualifier_1, ac_type_qualifier_list _ac_type_qualifier_list_1) { + assertPhylum(_ac_type_qualifier_1, phylum_ac_type_qualifier); + assertPhylum(_ac_type_qualifier_list_1, phylum_ac_type_qualifier_list); + ac_type_qualifier_list kc_x = new impl_ac_type_qualifier_list(_ac_type_qualifier_1, _ac_type_qualifier_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_type_qualifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_type_qualifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_type_list_AcParList* + AcParList(ac_parameter_list _ac_parameter_list_1) { + assertPhylum(_ac_parameter_list_1, phylum_ac_parameter_list); + ac_parameter_type_list kc_x = new impl_ac_parameter_type_list_AcParList(_ac_parameter_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcParList)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcParList)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_type_list_AcParList3Dot* + AcParList3Dot(ac_parameter_list _ac_parameter_list_1) { + assertPhylum(_ac_parameter_list_1, phylum_ac_parameter_list); + ac_parameter_type_list kc_x = new impl_ac_parameter_type_list_AcParList3Dot(_ac_parameter_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcParList3Dot)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcParList3Dot)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_list* + Nilac_parameter_list() { + ac_parameter_list kc_x = new impl_ac_parameter_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_parameter_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_parameter_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_list* + Consac_parameter_list(ac_parameter_declaration _ac_parameter_declaration_1, ac_parameter_list _ac_parameter_list_1) { + assertPhylum(_ac_parameter_declaration_1, phylum_ac_parameter_declaration); + assertPhylum(_ac_parameter_list_1, phylum_ac_parameter_list); + ac_parameter_list kc_x = new impl_ac_parameter_list(_ac_parameter_declaration_1, _ac_parameter_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_parameter_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_parameter_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_declaration_AcParDeclDecl* + AcParDeclDecl(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_declarator _ac_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) { + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + assertPhylum(_ac_declarator_1, phylum_ac_declarator); + assertPhylum(_ac_constant_expression_option_1, phylum_ac_constant_expression_option); + ac_parameter_declaration kc_x = new impl_ac_parameter_declaration_AcParDeclDecl(_ac_declaration_specifiers_1, _ac_declarator_1, _ac_constant_expression_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcParDeclDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcParDeclDecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_parameter_declaration_AcParDeclAbsdecl* + AcParDeclAbsdecl(ac_declaration_specifiers _ac_declaration_specifiers_1, ac_abstract_declarator _ac_abstract_declarator_1, ac_constant_expression_option _ac_constant_expression_option_1) { + assertPhylum(_ac_declaration_specifiers_1, phylum_ac_declaration_specifiers); + assertPhylum(_ac_abstract_declarator_1, phylum_ac_abstract_declarator); + assertPhylum(_ac_constant_expression_option_1, phylum_ac_constant_expression_option); + ac_parameter_declaration kc_x = new impl_ac_parameter_declaration_AcParDeclAbsdecl(_ac_declaration_specifiers_1, _ac_abstract_declarator_1, _ac_constant_expression_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcParDeclAbsdecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcParDeclAbsdecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_identifier_list* + Nilac_identifier_list() { + ac_identifier_list kc_x = new impl_ac_identifier_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_identifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_identifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_identifier_list* + Consac_identifier_list(ID _ID_1, ac_identifier_list _ac_identifier_list_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ac_identifier_list_1, phylum_ac_identifier_list); + ac_identifier_list kc_x = new impl_ac_identifier_list(_ID_1, _ac_identifier_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_identifier_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_identifier_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_abstract_declarator_AcAbsdeclPointer* + AcAbsdeclPointer(ac_pointer _ac_pointer_1) { + assertPhylum(_ac_pointer_1, phylum_ac_pointer); + ac_abstract_declarator kc_x = new impl_ac_abstract_declarator_AcAbsdeclPointer(_ac_pointer_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcAbsdeclPointer)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcAbsdeclPointer)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_abstract_declarator_AcAbsdeclDirdecl* + AcAbsdeclDirdecl(ac_pointer_option _ac_pointer_option_1, ac_direct_abstract_declarator _ac_direct_abstract_declarator_1) { + assertPhylum(_ac_pointer_option_1, phylum_ac_pointer_option); + assertPhylum(_ac_direct_abstract_declarator_1, phylum_ac_direct_abstract_declarator); + ac_abstract_declarator kc_x = new impl_ac_abstract_declarator_AcAbsdeclDirdecl(_ac_pointer_option_1, _ac_direct_abstract_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcAbsdeclDirdecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcAbsdeclDirdecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_abstract_declarator_option_Noac_direct_abstract_declarator* + Noac_direct_abstract_declarator() { + ac_direct_abstract_declarator_option kc_x = new impl_ac_direct_abstract_declarator_option_Noac_direct_abstract_declarator(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Noac_direct_abstract_declarator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Noac_direct_abstract_declarator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator* + Yesac_direct_abstract_declarator(ac_direct_abstract_declarator _ac_direct_abstract_declarator_1) { + assertPhylum(_ac_direct_abstract_declarator_1, phylum_ac_direct_abstract_declarator); + ac_direct_abstract_declarator_option kc_x = new impl_ac_direct_abstract_declarator_option_Yesac_direct_abstract_declarator(_ac_direct_abstract_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Yesac_direct_abstract_declarator)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Yesac_direct_abstract_declarator)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_abstract_declarator_AcDirAbsdeclPack* + AcDirAbsdeclPack(ac_abstract_declarator _ac_abstract_declarator_1) { + assertPhylum(_ac_abstract_declarator_1, phylum_ac_abstract_declarator); + ac_direct_abstract_declarator kc_x = new impl_ac_direct_abstract_declarator_AcDirAbsdeclPack(_ac_abstract_declarator_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirAbsdeclPack)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirAbsdeclPack)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_abstract_declarator_AcDirAbsdeclArray* + AcDirAbsdeclArray(ac_direct_abstract_declarator_option _ac_direct_abstract_declarator_option_1, ac_constant_expression_option _ac_constant_expression_option_1) { + assertPhylum(_ac_direct_abstract_declarator_option_1, phylum_ac_direct_abstract_declarator_option); + assertPhylum(_ac_constant_expression_option_1, phylum_ac_constant_expression_option); + ac_direct_abstract_declarator kc_x = new impl_ac_direct_abstract_declarator_AcDirAbsdeclArray(_ac_direct_abstract_declarator_option_1, _ac_constant_expression_option_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirAbsdeclArray)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirAbsdeclArray)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_direct_abstract_declarator_AcDirAbsdeclFn* + AcDirAbsdeclFn(ac_direct_abstract_declarator_option _ac_direct_abstract_declarator_option_1, ac_parameter_type_list _ac_parameter_type_list_1) { + assertPhylum(_ac_direct_abstract_declarator_option_1, phylum_ac_direct_abstract_declarator_option); + assertPhylum(_ac_parameter_type_list_1, phylum_ac_parameter_type_list); + ac_direct_abstract_declarator kc_x = new impl_ac_direct_abstract_declarator_AcDirAbsdeclFn(_ac_direct_abstract_declarator_option_1, _ac_parameter_type_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcDirAbsdeclFn)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcDirAbsdeclFn)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_constant_expression_option_Yesac_constant_expression* + Yesac_constant_expression(ac_constant_expression _ac_constant_expression_1) { + assertPhylum(_ac_constant_expression_1, phylum_ac_constant_expression); + ac_constant_expression_option kc_x = new impl_ac_constant_expression_option_Yesac_constant_expression(_ac_constant_expression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Yesac_constant_expression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Yesac_constant_expression)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_constant_expression_option_Noac_constant_expression* + Noac_constant_expression() { + ac_constant_expression_option kc_x = new impl_ac_constant_expression_option_Noac_constant_expression(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Noac_constant_expression)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Noac_constant_expression)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_constant_expression_AcConstExpr* + AcConstExpr(Cexpression _Cexpression_1) { + assertPhylum(_Cexpression_1, phylum_Cexpression); + ac_constant_expression kc_x = new impl_ac_constant_expression_AcConstExpr(_Cexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcConstExpr)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcConstExpr)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_constant_expression_list* + Nilac_constant_expression_list() { + ac_constant_expression_list kc_x = new impl_ac_constant_expression_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_constant_expression_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_constant_expression_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_constant_expression_list* + Consac_constant_expression_list(ac_constant_expression _ac_constant_expression_1, ac_constant_expression_list _ac_constant_expression_list_1) { + assertPhylum(_ac_constant_expression_1, phylum_ac_constant_expression); + assertPhylum(_ac_constant_expression_list_1, phylum_ac_constant_expression_list); + ac_constant_expression_list kc_x = new impl_ac_constant_expression_list(_ac_constant_expression_1, _ac_constant_expression_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_constant_expression_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_constant_expression_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_opt_base_init_list_AcNoBaseInit* + AcNoBaseInit() { + ac_opt_base_init_list kc_x = new impl_ac_opt_base_init_list_AcNoBaseInit(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcNoBaseInit)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcNoBaseInit)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_opt_base_init_list_AcYesBaseInit* + AcYesBaseInit(ac_base_init_list _ac_base_init_list_1) { + assertPhylum(_ac_base_init_list_1, phylum_ac_base_init_list); + ac_opt_base_init_list kc_x = new impl_ac_opt_base_init_list_AcYesBaseInit(_ac_base_init_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcYesBaseInit)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcYesBaseInit)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_base_init_list* + Nilac_base_init_list() { + ac_base_init_list kc_x = new impl_ac_base_init_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilac_base_init_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilac_base_init_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_base_init_list* + Consac_base_init_list(ac_base_init _ac_base_init_1, ac_base_init_list _ac_base_init_list_1) { + assertPhylum(_ac_base_init_1, phylum_ac_base_init); + assertPhylum(_ac_base_init_list_1, phylum_ac_base_init_list); + ac_base_init_list kc_x = new impl_ac_base_init_list(_ac_base_init_1, _ac_base_init_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consac_base_init_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consac_base_init_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_ac_base_init_AcBaseInit* + AcBaseInit(ID _ID_1, ac_constant_expression _ac_constant_expression_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_ac_constant_expression_1, phylum_ac_constant_expression); + ac_base_init kc_x = new impl_ac_base_init_AcBaseInit(_ID_1, _ac_constant_expression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AcBaseInit)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AcBaseInit)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_baseclass_declarations* + Nilbaseclass_declarations() { + baseclass_declarations kc_x = new impl_baseclass_declarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilbaseclass_declarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilbaseclass_declarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_baseclass_declarations* + Consbaseclass_declarations(baseclass_decl _baseclass_decl_1, baseclass_declarations _baseclass_declarations_1) { + assertPhylum(_baseclass_decl_1, phylum_baseclass_decl); + assertPhylum(_baseclass_declarations_1, phylum_baseclass_declarations); + baseclass_declarations kc_x = new impl_baseclass_declarations(_baseclass_decl_1, _baseclass_declarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consbaseclass_declarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consbaseclass_declarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_baseclass_decl_BaseClassDecl* + BaseClassDecl(ID _ID_1, baseclass_list _baseclass_list_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_baseclass_list_1, phylum_baseclass_list); + baseclass_decl kc_x = new impl_baseclass_decl_BaseClassDecl(_ID_1, _baseclass_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_BaseClassDecl)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_BaseClassDecl)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_baseclass_list* + Nilbaseclass_list() { + baseclass_list kc_x = new impl_baseclass_list(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilbaseclass_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilbaseclass_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_baseclass_list* + Consbaseclass_list(ID _ID_1, baseclass_list _baseclass_list_1) { + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_baseclass_list_1, phylum_baseclass_list); + baseclass_list kc_x = new impl_baseclass_list(_ID_1, _baseclass_list_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consbaseclass_list)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consbaseclass_list)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_error_Fatal* + Fatal(fileline _fileline_1, problem _problem_1) { + assertPhylum(_fileline_1, phylum_fileline); + assertPhylum(_problem_1, phylum_problem); + error kc_x = new impl_error_Fatal(_fileline_1, _problem_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Fatal)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Fatal)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_error_NonFatal* + NonFatal(fileline _fileline_1, problem _problem_1) { + assertPhylum(_fileline_1, phylum_fileline); + assertPhylum(_problem_1, phylum_problem); + error kc_x = new impl_error_NonFatal(_fileline_1, _problem_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_NonFatal)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_NonFatal)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_error_Warning* + Warning(fileline _fileline_1, problem _problem_1) { + assertPhylum(_fileline_1, phylum_fileline); + assertPhylum(_problem_1, phylum_problem); + error kc_x = new impl_error_Warning(_fileline_1, _problem_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Warning)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Warning)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1* + Problem1(casestring _casestring_1) { + assertPhylum(_casestring_1, phylum_casestring); + problem kc_x = new impl_problem_Problem1(_casestring_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1ID* + Problem1ID(casestring _casestring_1, ID _ID_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + problem kc_x = new impl_problem_Problem1ID(_casestring_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1tID* + Problem1tID(casestring _casestring_1, ID _ID_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + problem kc_x = new impl_problem_Problem1tID(_casestring_1, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1tID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1tID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1we* + Problem1we(casestring _casestring_1, withexpression _withexpression_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_withexpression_1, phylum_withexpression); + problem kc_x = new impl_problem_Problem1we(_casestring_1, _withexpression_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1we)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1we)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1ID1ID* + Problem1ID1ID(casestring _casestring_1, ID _ID_1, casestring _casestring_2, ID _ID_2) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_2, phylum_ID); + problem kc_x = new impl_problem_Problem1ID1ID(_casestring_1, _ID_1, _casestring_2, _ID_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1ID1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1ID1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1t1ID* + Problem1t1ID(casestring _casestring_1, IDtype _IDtype_1, casestring _casestring_2, ID _ID_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_IDtype_1, phylum_IDtype); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + problem kc_x = new impl_problem_Problem1t1ID(_casestring_1, _IDtype_1, _casestring_2, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1t1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1t1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1INT* + Problem1INT(casestring _casestring_1, INT _INT_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_INT_1, phylum_INT); + problem kc_x = new impl_problem_Problem1INT(_casestring_1, _INT_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1INT)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1INT)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1int1* + Problem1int1(casestring _casestring_1, integer _integer_1, casestring _casestring_2) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_integer_1, phylum_integer); + assertPhylum(_casestring_2, phylum_casestring); + problem kc_x = new impl_problem_Problem1int1(_casestring_1, _integer_1, _casestring_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1int1)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1int1)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1INT1ID* + Problem1INT1ID(casestring _casestring_1, INT _INT_1, casestring _casestring_2, ID _ID_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_INT_1, phylum_INT); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + problem kc_x = new impl_problem_Problem1INT1ID(_casestring_1, _INT_1, _casestring_2, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1INT1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1INT1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1ID1ID1ID* + Problem1ID1ID1ID(casestring _casestring_1, ID _ID_1, casestring _casestring_2, ID _ID_2, casestring _casestring_3, ID _ID_3) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_2, phylum_ID); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_ID_3, phylum_ID); + problem kc_x = new impl_problem_Problem1ID1ID1ID(_casestring_1, _ID_1, _casestring_2, _ID_2, _casestring_3, _ID_3); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1ID1ID1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1ID1ID1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1INT1ID1ID* + Problem1INT1ID1ID(casestring _casestring_1, INT _INT_1, casestring _casestring_2, ID _ID_1, casestring _casestring_3, ID _ID_2) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_INT_1, phylum_INT); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_ID_2, phylum_ID); + problem kc_x = new impl_problem_Problem1INT1ID1ID(_casestring_1, _INT_1, _casestring_2, _ID_1, _casestring_3, _ID_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1INT1ID1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1INT1ID1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem1storageoption1ID* + Problem1storageoption1ID(casestring _casestring_1, storageoption _storageoption_1, casestring _casestring_2, ID _ID_1) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_storageoption_1, phylum_storageoption); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_ID_1, phylum_ID); + problem kc_x = new impl_problem_Problem1storageoption1ID(_casestring_1, _storageoption_1, _casestring_2, _ID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem1storageoption1ID)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem1storageoption1ID)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem2* + Problem2(casestring _casestring_1, casestring _casestring_2) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + problem kc_x = new impl_problem_Problem2(_casestring_1, _casestring_2); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem2)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem2)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem3* + Problem3(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_casestring_3, phylum_casestring); + problem kc_x = new impl_problem_Problem3(_casestring_1, _casestring_2, _casestring_3); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem3)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem3)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem3int1* + Problem3int1(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, integer _integer_1, casestring _casestring_4) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_integer_1, phylum_integer); + assertPhylum(_casestring_4, phylum_casestring); + problem kc_x = new impl_problem_Problem3int1(_casestring_1, _casestring_2, _casestring_3, _integer_1, _casestring_4); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem3int1)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem3int1)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem4* + Problem4(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_casestring_4, phylum_casestring); + problem kc_x = new impl_problem_Problem4(_casestring_1, _casestring_2, _casestring_3, _casestring_4); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem4)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem4)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem5* + Problem5(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4, casestring _casestring_5) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_casestring_4, phylum_casestring); + assertPhylum(_casestring_5, phylum_casestring); + problem kc_x = new impl_problem_Problem5(_casestring_1, _casestring_2, _casestring_3, _casestring_4, _casestring_5); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem5)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem5)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_problem_Problem6* + Problem6(casestring _casestring_1, casestring _casestring_2, casestring _casestring_3, casestring _casestring_4, casestring _casestring_5, casestring _casestring_6) { + assertPhylum(_casestring_1, phylum_casestring); + assertPhylum(_casestring_2, phylum_casestring); + assertPhylum(_casestring_3, phylum_casestring); + assertPhylum(_casestring_4, phylum_casestring); + assertPhylum(_casestring_5, phylum_casestring); + assertPhylum(_casestring_6, phylum_casestring); + problem kc_x = new impl_problem_Problem6(_casestring_1, _casestring_2, _casestring_3, _casestring_4, _casestring_5, _casestring_6); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Problem6)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Problem6)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_addedphylumdeclarations* + Niladdedphylumdeclarations() { + addedphylumdeclarations kc_x = new impl_addedphylumdeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Niladdedphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Niladdedphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_addedphylumdeclarations* + Consaddedphylumdeclarations(addedphylumdeclaration _addedphylumdeclaration_1, addedphylumdeclarations _addedphylumdeclarations_1) { + assertPhylum(_addedphylumdeclaration_1, phylum_addedphylumdeclaration); + assertPhylum(_addedphylumdeclarations_1, phylum_addedphylumdeclarations); + addedphylumdeclarations kc_x = new impl_addedphylumdeclarations(_addedphylumdeclaration_1, _addedphylumdeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consaddedphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consaddedphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_addedphylumdeclaration_AddedPhylumdeclaration* + AddedPhylumdeclaration(uniqID _uniqID_1) { + assertPhylum(_uniqID_1, phylum_uniqID); + addedphylumdeclaration kc_x = new impl_addedphylumdeclaration_AddedPhylumdeclaration(_uniqID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_AddedPhylumdeclaration)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_AddedPhylumdeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_addedphylumdeclaration(kc_x); + return static_cast(kc_x); + } + + impl_countedphylumdeclarations* + Nilcountedphylumdeclarations() { + countedphylumdeclarations kc_x = new impl_countedphylumdeclarations(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilcountedphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilcountedphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_countedphylumdeclarations* + Conscountedphylumdeclarations(countedphylumdeclaration _countedphylumdeclaration_1, countedphylumdeclarations _countedphylumdeclarations_1) { + assertPhylum(_countedphylumdeclaration_1, phylum_countedphylumdeclaration); + assertPhylum(_countedphylumdeclarations_1, phylum_countedphylumdeclarations); + countedphylumdeclarations kc_x = new impl_countedphylumdeclarations(_countedphylumdeclaration_1, _countedphylumdeclarations_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Conscountedphylumdeclarations)); + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Conscountedphylumdeclarations)); + kc_x->post_create(); + return static_cast(kc_x); + } + + impl_countedphylumdeclaration_CountedPhylumdeclaration* + CountedPhylumdeclaration(uniqID _uniqID_1) { + assertPhylum(_uniqID_1, phylum_uniqID); + countedphylumdeclaration kc_x=new impl_countedphylumdeclaration_CountedPhylumdeclaration(_uniqID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_CountedPhylumdeclaration)); + countedphylumdeclaration unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_CountedPhylumdeclaration)); + kc_x->post_create(); + kc_x = kc_initialize_countedphylumdeclaration(kc_x); + } + return static_cast(kc_x); + } + + impl_charruns_Newlines* + Newlines() { + charruns kc_x=new impl_charruns_Newlines(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Newlines)); + charruns unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Newlines)); + kc_x->post_create(); + } + return static_cast(kc_x); + } + + impl_charruns_QuotedNewlines* + QuotedNewlines() { + charruns kc_x=new impl_charruns_QuotedNewlines(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_QuotedNewlines)); + charruns unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_QuotedNewlines)); + kc_x->post_create(); + } + return static_cast(kc_x); + } + + impl_charruns_Stars* + Stars() { + charruns kc_x=new impl_charruns_Stars(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Stars)); + charruns unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Stars)); + kc_x->post_create(); + } + return static_cast(kc_x); + } + + impl_bindingidmarks* + Nilbindingidmarks() { + bindingidmarks kc_x=new impl_bindingidmarks(); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Nilbindingidmarks)); + bindingidmarks unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Nilbindingidmarks)); + kc_x->post_create(); + } + return static_cast(kc_x); + } + + impl_bindingidmarks* + Consbindingidmarks(bindingidmark _bindingidmark_1, bindingidmarks _bindingidmarks_1) { + assertPhylum(_bindingidmark_1, phylum_bindingidmark); + assertPhylum(_bindingidmarks_1, phylum_bindingidmarks); + bindingidmarks kc_x=new impl_bindingidmarks(_bindingidmark_1, _bindingidmarks_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_Consbindingidmarks)); + bindingidmarks unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_Consbindingidmarks)); + kc_x->post_create(); + } + return static_cast(kc_x); + } + + impl_bindingidmark_BindingIdMark* + BindingIdMark(uniqID _uniqID_1) { + assertPhylum(_uniqID_1, phylum_uniqID); + bindingidmark kc_x=new impl_bindingidmark_BindingIdMark(_uniqID_1); + KC_COLLECT_STATS0(KC_CREATE_STATS(sel_BindingIdMark)); + bindingidmark unique_kc_x= hashtables[uniq]->ht_check_insert(kc_x); + if(unique_kc_x!=kc_x) { + delete kc_x; + kc_x=unique_kc_x; + } else { + KC_COLLECT_STATS0(KC_EXISTINGNOTFOUND_STATS(sel_BindingIdMark)); + kc_x->post_create(); + kc_x = kc_initialize_bindingidmark(kc_x); + } + return static_cast(kc_x); + } + + + abstract_phylum + kc_create(enum_operators createOp, abstract_phylum kc_p1, abstract_phylum kc_p2, abstract_phylum kc_p3, abstract_phylum kc_p4, abstract_phylum kc_p5, abstract_phylum kc_p6, abstract_phylum kc_p7) + { + switch(createOp) { + case sel__VoidPtr: + case sel__Int: + case sel__Real: + case sel__Str: + case sel_NoCaseStr: + assertionFailed("Cannot create this kind of phylum - predefined phyla must be handled seperately");break; + case sel_BindingIdMark: + return BindingIdMark(phylum_cast(kc_p1)); + case sel_Consbindingidmarks: + return Consbindingidmarks(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilbindingidmarks: + return Nilbindingidmarks(); + case sel_Stars: + return Stars(); + case sel_QuotedNewlines: + return QuotedNewlines(); + case sel_Newlines: + return Newlines(); + case sel_CountedPhylumdeclaration: + return CountedPhylumdeclaration(phylum_cast(kc_p1)); + case sel_Conscountedphylumdeclarations: + return Conscountedphylumdeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilcountedphylumdeclarations: + return Nilcountedphylumdeclarations(); + case sel_AddedPhylumdeclaration: + return AddedPhylumdeclaration(phylum_cast(kc_p1)); + case sel_Consaddedphylumdeclarations: + return Consaddedphylumdeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Niladdedphylumdeclarations: + return Niladdedphylumdeclarations(); + case sel_Problem6: + return Problem6(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5), phylum_cast(kc_p6)); + case sel_Problem5: + return Problem5(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5)); + case sel_Problem4: + return Problem4(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Problem3int1: + return Problem3int1(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5)); + case sel_Problem3: + return Problem3(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Problem2: + return Problem2(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Problem1storageoption1ID: + return Problem1storageoption1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Problem1INT1ID1ID: + return Problem1INT1ID1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5), phylum_cast(kc_p6)); + case sel_Problem1ID1ID1ID: + return Problem1ID1ID1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5), phylum_cast(kc_p6)); + case sel_Problem1INT1ID: + return Problem1INT1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Problem1int1: + return Problem1int1(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Problem1INT: + return Problem1INT(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Problem1t1ID: + return Problem1t1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Problem1ID1ID: + return Problem1ID1ID(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Problem1we: + return Problem1we(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Problem1tID: + return Problem1tID(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Problem1ID: + return Problem1ID(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Problem1: + return Problem1(phylum_cast(kc_p1)); + case sel_Warning: + return Warning(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NonFatal: + return NonFatal(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Fatal: + return Fatal(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consbaseclass_list: + return Consbaseclass_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilbaseclass_list: + return Nilbaseclass_list(); + case sel_BaseClassDecl: + return BaseClassDecl(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consbaseclass_declarations: + return Consbaseclass_declarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilbaseclass_declarations: + return Nilbaseclass_declarations(); + case sel_AcBaseInit: + return AcBaseInit(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consac_base_init_list: + return Consac_base_init_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_base_init_list: + return Nilac_base_init_list(); + case sel_AcYesBaseInit: + return AcYesBaseInit(phylum_cast(kc_p1)); + case sel_AcNoBaseInit: + return AcNoBaseInit(); + case sel_Consac_constant_expression_list: + return Consac_constant_expression_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_constant_expression_list: + return Nilac_constant_expression_list(); + case sel_AcConstExpr: + return AcConstExpr(phylum_cast(kc_p1)); + case sel_Noac_constant_expression: + return Noac_constant_expression(); + case sel_Yesac_constant_expression: + return Yesac_constant_expression(phylum_cast(kc_p1)); + case sel_AcDirAbsdeclFn: + return AcDirAbsdeclFn(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcDirAbsdeclArray: + return AcDirAbsdeclArray(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcDirAbsdeclPack: + return AcDirAbsdeclPack(phylum_cast(kc_p1)); + case sel_Yesac_direct_abstract_declarator: + return Yesac_direct_abstract_declarator(phylum_cast(kc_p1)); + case sel_Noac_direct_abstract_declarator: + return Noac_direct_abstract_declarator(); + case sel_AcAbsdeclDirdecl: + return AcAbsdeclDirdecl(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcAbsdeclPointer: + return AcAbsdeclPointer(phylum_cast(kc_p1)); + case sel_Consac_identifier_list: + return Consac_identifier_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_identifier_list: + return Nilac_identifier_list(); + case sel_AcParDeclAbsdecl: + return AcParDeclAbsdecl(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_AcParDeclDecl: + return AcParDeclDecl(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Consac_parameter_list: + return Consac_parameter_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_parameter_list: + return Nilac_parameter_list(); + case sel_AcParList3Dot: + return AcParList3Dot(phylum_cast(kc_p1)); + case sel_AcParList: + return AcParList(phylum_cast(kc_p1)); + case sel_Consac_type_qualifier_list: + return Consac_type_qualifier_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_type_qualifier_list: + return Nilac_type_qualifier_list(); + case sel_Consac_class_qualifier_list: + return Consac_class_qualifier_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_class_qualifier_list: + return Nilac_class_qualifier_list(); + case sel_Consac_class_qualifier_help_list: + return Consac_class_qualifier_help_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_class_qualifier_help_list: + return Nilac_class_qualifier_help_list(); + case sel_AcOperatorName: + return AcOperatorName(phylum_cast(kc_p1)); + case sel_AcRef: + return AcRef(); + case sel_AcNoRef: + return AcNoRef(); + case sel_AcPointerCons: + return AcPointerCons(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcPointerNil: + return AcPointerNil(phylum_cast(kc_p1)); + case sel_Yespointer: + return Yespointer(phylum_cast(kc_p1)); + case sel_Nopointer: + return Nopointer(); + case sel_AcOperatorDeclId: + return AcOperatorDeclId(phylum_cast(kc_p1)); + case sel_AcConvOperatorDecl: + return AcConvOperatorDecl(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcMemberDecl: + return AcMemberDecl(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_AcQualifiedDeclProto: + return AcQualifiedDeclProto(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_AcDirectDeclProto: + return AcDirectDeclProto(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcDirectDeclArray: + return AcDirectDeclArray(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_AcDirectDeclPack: + return AcDirectDeclPack(phylum_cast(kc_p1)); + case sel_AcDirectDeclId: + return AcDirectDeclId(phylum_cast(kc_p1)); + case sel_AcDeclarator: + return AcDeclarator(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_AcInitDecl: + return AcInitDecl(phylum_cast(kc_p1)); + case sel_Consac_init_declarator_list: + return Consac_init_declarator_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_init_declarator_list: + return Nilac_init_declarator_list(); + case sel_AcNoQualifier: + return AcNoQualifier(); + case sel_AcUnsigned: + return AcUnsigned(); + case sel_AcVolatile: + return AcVolatile(); + case sel_AcConst: + return AcConst(); + case sel_AcTypeSpec: + return AcTypeSpec(phylum_cast(kc_p1)); + case sel_AcVirtual: + return AcVirtual(); + case sel_AcTypedef: + return AcTypedef(); + case sel_AcExtern: + return AcExtern(); + case sel_AcStatic: + return AcStatic(); + case sel_AcRegister: + return AcRegister(); + case sel_AcAuto: + return AcAuto(); + case sel_AcDeclSpecTypeQual: + return AcDeclSpecTypeQual(phylum_cast(kc_p1)); + case sel_AcDeclSpecTypeSpec: + return AcDeclSpecTypeSpec(phylum_cast(kc_p1)); + case sel_AcDeclSpecStorageSpec: + return AcDeclSpecStorageSpec(phylum_cast(kc_p1)); + case sel_Consac_declaration_specifiers: + return Consac_declaration_specifiers(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_declaration_specifiers: + return Nilac_declaration_specifiers(); + case sel_Consac_declaration_list: + return Consac_declaration_list(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilac_declaration_list: + return Nilac_declaration_list(); + case sel_AcDeclaration: + return AcDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Unparsedeclinfo: + return Unparsedeclinfo(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Consunparsedeclsinfo: + return Consunparsedeclsinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunparsedeclsinfo: + return Nilunparsedeclsinfo(); + case sel_Unparseviewinfo: + return Unparseviewinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consunparseviewsinfo: + return Consunparseviewsinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunparseviewsinfo: + return Nilunparseviewsinfo(); + case sel_Rewriteviewinfo: + return Rewriteviewinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consrewriteviewsinfo: + return Consrewriteviewsinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilrewriteviewsinfo: + return Nilrewriteviewsinfo(); + case sel_Withcaseinfo: + return Withcaseinfo(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Conswithcasesinfo: + return Conswithcasesinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilwithcasesinfo: + return Nilwithcasesinfo(); + case sel_Rewriteruleinfo: + return Rewriteruleinfo(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Consrewriterulesinfo: + return Consrewriterulesinfo(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilrewriterulesinfo: + return Nilrewriterulesinfo(); + case sel_Consargsnumbers: + return Consargsnumbers(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilargsnumbers: + return Nilargsnumbers(); + case sel_Conspaths: + return Conspaths(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpaths: + return Nilpaths(); + case sel_Conspath: + return Conspath(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpath: + return Nilpath(); + case sel_PRIntLiteral: + return PRIntLiteral(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_PRStringLiteral: + return PRStringLiteral(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_PRDefault: + return PRDefault(); + case sel_PRWildcard: + return PRWildcard(phylum_cast(kc_p1)); + case sel_PRNonLeafBinding: + return PRNonLeafBinding(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_PRUserPredicate: + return PRUserPredicate(phylum_cast(kc_p1)); + case sel_PROperPredicate: + return PROperPredicate(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_PRVarPredicate: + return PRVarPredicate(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_PRBinding: + return PRBinding(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Conspatternrepresentation: + return Conspatternrepresentation(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpatternrepresentation: + return Nilpatternrepresentation(); + case sel_Conspatternrepresentations: + return Conspatternrepresentations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpatternrepresentations: + return Nilpatternrepresentations(); + case sel_Bigger: + return Bigger(); + case sel_Smaller: + return Smaller(); + case sel_Equal: + return Equal(); + case sel_DVDisallowed: + return DVDisallowed(); + case sel_DVAllowed: + return DVAllowed(); + case sel_Consvariables: + return Consvariables(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilvariables: + return Nilvariables(); + case sel_Consphyla: + return Consphyla(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilphyla: + return Nilphyla(); + case sel_Consoperators: + return Consoperators(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Niloperators: + return Niloperators(); + case sel_ITLanguageName: + return ITLanguageName(phylum_cast(kc_p1)); + case sel_ITPatternVariable: + return ITPatternVariable(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_ITUserFunction: + return ITUserFunction(phylum_cast(kc_p1)); + case sel_ITUserRView: + return ITUserRView(); + case sel_ITPredefinedRView: + return ITPredefinedRView(); + case sel_ITUViewVar: + return ITUViewVar(); + case sel_ITUserUView: + return ITUserUView(); + case sel_ITPredefinedUView: + return ITPredefinedUView(); + case sel_ITStorageClass: + return ITStorageClass(); + case sel_ITPredefinedStorageClass: + return ITPredefinedStorageClass(); + case sel_ITUserOperator: + return ITUserOperator(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_ITPredefinedOperator: + return ITPredefinedOperator(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_ITUserPhylum: + return ITUserPhylum(phylum_cast(kc_p1)); + case sel_ITPredefinedPhylum: + return ITPredefinedPhylum(phylum_cast(kc_p1)); + case sel_ITUnknown: + return ITUnknown(); + case sel_ScopeTypeFileLine: + return ScopeTypeFileLine(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Consscopetypefilelinestack: + return Consscopetypefilelinestack(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilscopetypefilelinestack: + return Nilscopetypefilelinestack(); + case sel_PosNoFileLine: + return PosNoFileLine(); + case sel_NoFileLine: + return NoFileLine(); + case sel_FileLine: + return FileLine(); + case sel_Conslanguagenames: + return Conslanguagenames(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nillanguagenames: + return Nillanguagenames(); + case sel_LanguageList: + return LanguageList(phylum_cast(kc_p1)); + case sel_NoLanguagename: + return NoLanguagename(); + case sel_YesViewname: + return YesViewname(phylum_cast(kc_p1)); + case sel_NoViewname: + return NoViewname(); + case sel_Consunpattributes: + return Consunpattributes(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunpattributes: + return Nilunpattributes(); + case sel_UnpCastedVariable: + return UnpCastedVariable(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_UnpDollarvarAttr: + return UnpDollarvarAttr(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_UnpSubAttr: + return UnpSubAttr(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_UnpDollarvarTerm: + return UnpDollarvarTerm(phylum_cast(kc_p1)); + case sel_UnpSubTerm: + return UnpSubTerm(phylum_cast(kc_p1)); + case sel_UViewVarDecl: + return UViewVarDecl(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_UnpBody: + return UnpBody(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_UnpCtext: + return UnpCtext(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_UnpSubexpr: + return UnpSubexpr(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_UnpStr: + return UnpStr(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Consunparseitems: + return Consunparseitems(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunparseitems: + return Nilunparseitems(); + case sel_Consviewnames: + return Consviewnames(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilviewnames: + return Nilviewnames(); + case sel_UnparseClause: + return UnparseClause(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consunparseclauses: + return Consunparseclauses(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunparseclauses: + return Nilunparseclauses(); + case sel_UnparseDeclaration: + return UnparseDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consunparsedeclarations: + return Consunparsedeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilunparsedeclarations: + return Nilunparsedeclarations(); + case sel_Withcase: + return Withcase(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Conswithcases: + return Conswithcases(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilwithcases: + return Nilwithcases(); + case sel_WECexpression: + return WECexpression(phylum_cast(kc_p1)); + case sel_WEVariable: + return WEVariable(phylum_cast(kc_p1)); + case sel_Conswithexpressions: + return Conswithexpressions(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilwithexpressions: + return Nilwithexpressions(); + case sel_NotInForeachContext: + return NotInForeachContext(); + case sel_InForeachContext: + return InForeachContext(phylum_cast(kc_p1)); + case sel_ForeachAfter: + return ForeachAfter(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_NoForeachAfter: + return NoForeachAfter(); + case sel_CTextWithexpression: + return CTextWithexpression(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_CTextForeachexpression: + return CTextForeachexpression(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5)); + case sel_CTextCbody: + return CTextCbody(phylum_cast(kc_p1)); + case sel_CTextCexpressionSQ: + return CTextCexpressionSQ(phylum_cast(kc_p1)); + case sel_CTextCexpressionDQ: + return CTextCexpressionDQ(phylum_cast(kc_p1)); + case sel_CTextNl: + return CTextNl(phylum_cast(kc_p1)); + case sel_CTextDollarVar: + return CTextDollarVar(phylum_cast(kc_p1)); + case sel_CTextLine: + return CTextLine(phylum_cast(kc_p1)); + case sel_ConsCtext: + return ConsCtext(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilCtext: + return NilCtext(); + case sel_ConvOperatorFn: + return ConvOperatorFn(); + case sel_DestructorFn: + return DestructorFn(); + case sel_ConstructorFn: + return ConstructorFn(); + case sel_MemberFn: + return MemberFn(); + case sel_StaticFn: + return StaticFn(phylum_cast(kc_p1)); + case sel_GlobalFn: + return GlobalFn(); + case sel_AcMemberDeclaration: + return AcMemberDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_FnAcDeclaration: + return FnAcDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4), phylum_cast(kc_p5), phylum_cast(kc_p6), phylum_cast(kc_p7)); + case sel_Consfndeclarations: + return Consfndeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilfndeclarations: + return Nilfndeclarations(); + case sel_FnFile: + return FnFile(phylum_cast(kc_p1)); + case sel_Consfnfiles: + return Consfnfiles(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilfnfiles: + return Nilfnfiles(); + case sel_Consterms: + return Consterms(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilterms: + return Nilterms(); + case sel_TIntLiteral: + return TIntLiteral(phylum_cast(kc_p1)); + case sel_TStringLiteral: + return TStringLiteral(phylum_cast(kc_p1)); + case sel_TCTerm: + return TCTerm(phylum_cast(kc_p1)); + case sel_TMemberVarDot: + return TMemberVarDot(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_TMemberVar: + return TMemberVar(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_TMethodDot: + return TMethodDot(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_TMethod: + return TMethod(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_TOperator: + return TOperator(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_TVariable: + return TVariable(phylum_cast(kc_p1)); + case sel_Conspatterns: + return Conspatterns(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpatterns: + return Nilpatterns(); + case sel_PIntLiteral: + return PIntLiteral(phylum_cast(kc_p1)); + case sel_PStringLiteral: + return PStringLiteral(phylum_cast(kc_p1)); + case sel_PWildcard: + return PWildcard(); + case sel_PNonLeafVariable: + return PNonLeafVariable(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_POperator: + return POperator(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_PVariable: + return PVariable(phylum_cast(kc_p1)); + case sel_OPDefault: + return OPDefault(phylum_cast(kc_p1)); + case sel_OPWildcard: + return OPWildcard(phylum_cast(kc_p1)); + case sel_OPNonLeafVariable: + return OPNonLeafVariable(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_OPOperator: + return OPOperator(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_OPOperatorWildcard: + return OPOperatorWildcard(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_PatternchainitemDollarid: + return PatternchainitemDollarid(phylum_cast(kc_p1)); + case sel_PatternchainitemGroup: + return PatternchainitemGroup(phylum_cast(kc_p1)); + case sel_PatternchainitemOutmost: + return PatternchainitemOutmost(phylum_cast(kc_p1)); + case sel_Consoutmostpatterns: + return Consoutmostpatterns(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Niloutmostpatterns: + return Niloutmostpatterns(); + case sel_Conspatternchain: + return Conspatternchain(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpatternchain: + return Nilpatternchain(); + case sel_Conspatternchains: + return Conspatternchains(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilpatternchains: + return Nilpatternchains(); + case sel_RewriteClause: + return RewriteClause(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consrewriteclauses: + return Consrewriteclauses(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilrewriteclauses: + return Nilrewriteclauses(); + case sel_RwDeclaration: + return RwDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consrwdeclarations: + return Consrwdeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilrwdeclarations: + return Nilrwdeclarations(); + case sel_IncludeDeclaration: + return IncludeDeclaration(phylum_cast(kc_p1)); + case sel_Consincludedeclarations: + return Consincludedeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilincludedeclarations: + return Nilincludedeclarations(); + case sel_IncludeFile: + return IncludeFile(phylum_cast(kc_p1)); + case sel_Consincludefiles: + return Consincludefiles(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilincludefiles: + return Nilincludefiles(); + case sel_ConsCtexts: + return ConsCtexts(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilCtexts: + return NilCtexts(); + case sel_IdCexpression: + return IdCexpression(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_ConsidCexpressions: + return ConsidCexpressions(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilidCexpressions: + return NilidCexpressions(); + case sel_CExpressionSQNl: + return CExpressionSQNl(); + case sel_CExpressionSQPart: + return CExpressionSQPart(phylum_cast(kc_p1)); + case sel_ConsCexpressionSQ: + return ConsCexpressionSQ(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilCexpressionSQ: + return NilCexpressionSQ(); + case sel_CExpressionDQNl: + return CExpressionDQNl(); + case sel_CExpressionDQPart: + return CExpressionDQPart(phylum_cast(kc_p1)); + case sel_ConsCexpressionDQ: + return ConsCexpressionDQ(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilCexpressionDQ: + return NilCexpressionDQ(); + case sel_CExpressionArray: + return CExpressionArray(phylum_cast(kc_p1)); + case sel_CExpressionPack: + return CExpressionPack(phylum_cast(kc_p1)); + case sel_CExpressionSQ: + return CExpressionSQ(phylum_cast(kc_p1)); + case sel_CExpressionDQ: + return CExpressionDQ(phylum_cast(kc_p1)); + case sel_CExpressionNl: + return CExpressionNl(); + case sel_CExpressionDollarvar: + return CExpressionDollarvar(phylum_cast(kc_p1)); + case sel_CExpressionPart: + return CExpressionPart(phylum_cast(kc_p1)); + case sel_ConsCexpression: + return ConsCexpression(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_NilCexpression: + return NilCexpression(); + case sel_Yesattribute_initialisation: + return Yesattribute_initialisation(phylum_cast(kc_p1)); + case sel_Noattribute_initialisation: + return Noattribute_initialisation(); + case sel_Attribute: + return Attribute(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3)); + case sel_Consattributes: + return Consattributes(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilattributes: + return Nilattributes(); + case sel_CcodeOption: + return CcodeOption(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Argument: + return Argument(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consarguments: + return Consarguments(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilarguments: + return Nilarguments(); + case sel_Alternative: + return Alternative(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Consalternatives: + return Consalternatives(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilalternatives: + return Nilalternatives(); + case sel_PredefinedAlternatives: + return PredefinedAlternatives(phylum_cast(kc_p1)); + case sel_NonlistAlternatives: + return NonlistAlternatives(phylum_cast(kc_p1)); + case sel_ListAlternatives: + return ListAlternatives(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Emptyproductionblock: + return Emptyproductionblock(); + case sel_Consstorageclasses: + return Consstorageclasses(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilstorageclasses: + return Nilstorageclasses(); + case sel_PositiveStorageOption: + return PositiveStorageOption(phylum_cast(kc_p1)); + case sel_NegativeStorageOption: + return NegativeStorageOption(phylum_cast(kc_p1)); + case sel_NoStorageOption: + return NoStorageOption(); + case sel_PhylumDeclaration: + return PhylumDeclaration(phylum_cast(kc_p1), phylum_cast(kc_p2), phylum_cast(kc_p3), phylum_cast(kc_p4)); + case sel_Consphylumnames: + return Consphylumnames(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilphylumnames: + return Nilphylumnames(); + case sel_Consphylumdeclarations: + return Consphylumdeclarations(phylum_cast(kc_p1), phylum_cast(kc_p2)); + case sel_Nilphylumdeclarations: + return Nilphylumdeclarations(); + case sel_PhylumDeclarations: + return PhylumDeclarations(phylum_cast(kc_p1)); + case sel_String: + return String(phylum_cast(kc_p1)); + case sel_Int: + return Int(phylum_cast(kc_p1)); + case sel_Id: + return Id(phylum_cast(kc_p1)); + case sel_Str: + return Str(phylum_cast(kc_p1)); + default: + assertionFailed("Cannot create this kind of phylum - unkown operator id"); + } + NORETURN + } + + abstract_phylum& + attributeOf(abstract_phylum kc_p, int no) + { + assertionFailed("Cannot select attribute for this kind of phylum - has no attributes"); + NORETURN + } + + abstract_phylum + impl_abstract_phylum::subphylum(int) const + { + return 0; + } + + void + impl_abstract_phylum::set_subphylum(int,abstract_phylum) + { + } + + void + impl_abstract_phylum::free(bool kc_rec) + { + KC_COLLECT_STATS0(KC_FREE_CALLED_STATS(prod_sel(), kc_rec)); + if (!phylum_info[phylum()].uniq_stored) { + if (kc_rec) { + abstract_phylum son; + for (int kc_i=0; (son = subphylum(kc_i)); kc_i++) + { + if (son!=0) son->free(kc_rec); + son=0; + } + } + KC_COLLECT_STATS0(KC_FREED_STATS(prod_sel(), kc_rec)); + delete this; + } + } + + bool + impl_abstract_phylum::eq(c_abstract_phylum kc_p2) const + { + if (this == kc_p2) + return true; + if (prod_sel() != kc_p2->prod_sel()) + return false; + + int kc_st = phylum_info[phylum()].uniq_stored; + if (kc_st && kc_storageclass_still_uniq[kc_st]) + return false; + + c_abstract_phylum son1; + for (int kc_i=0; (son1 = subphylum(kc_i)); kc_i++) { + if (!son1->eq(kc_p2->subphylum(kc_i))) + return false; + } + + return true; + } + + static string kc_indentation = ""; + static const char *kc_printformat_not_nullary_open = "%s%s(\n"; + static const char *kc_printformat_list_open = "%s%s\n"; + + static const char *kc_printformat_not_nullary_close = "%s)\n"; + static const char *kc_printformat_nullary = "%s%s()\n"; + + void + impl_abstract_phylum::fprint(FILE*kc_f) + { + int kc_i; + + if (!kc_f) kc_f = stdout; + abstract_list al = dynamic_cast(this); + if (al != 0 && !al->is_nil()) { + fprintf(kc_f, kc_printformat_list_open, kc_indentation.c_str(), op_name()); + kc_indentation+="| "; + subphylum(0)->fprint(kc_f); + kc_indentation=kc_indentation.substr(0, kc_indentation.length()-2); + phylum_cast(subphylum(1))->fprint_list(kc_f); + kc_indentation=kc_indentation.substr(0, kc_indentation.length()-2); + } else // not list + switch(phylum()) { + case phylum_voidptr: + fprintf(kc_f, "%s%p\n", kc_indentation.c_str(), static_cast(this)->pointer); + break; + case phylum_casestring: + case phylum_nocasestring: + fprintf(kc_f, "%s%s\n", kc_indentation.c_str(), static_cast(this)->name); + break; + case phylum_integer: + fprintf(kc_f, "%s%i\n", kc_indentation.c_str(), static_cast(this)->value); + break; + case phylum_real: + fprintf(kc_f, "%s%f\n", kc_indentation.c_str(), static_cast(this)->value); + break; + default: + if (!subphylum(0)) { + fprintf(kc_f, kc_printformat_nullary, kc_indentation.c_str(), op_name()); + } else { + fprintf(kc_f, kc_printformat_not_nullary_open, kc_indentation.c_str(), op_name()); + kc_indentation+=" "; + abstract_phylum son; + for (kc_i=0; (son = subphylum(kc_i)); kc_i++) { + son->fprint(kc_f); + } + kc_indentation=kc_indentation.substr(0, kc_indentation.length()-2); + fprintf(kc_f, kc_printformat_not_nullary_close, kc_indentation.c_str()); + } + } + } + + void + impl_abstract_phylum::print() + { + fprint(stdout); + } + + void + impl_abstract_list::fprint_list(FILE*kc_f) + { + if (!kc_f) + kc_f = stdout; + if (this->is_nil()) { + kc_indentation+="`-"; + fprintf(kc_f, kc_printformat_nullary, kc_indentation.c_str(), op_name()); + } else { + kc_indentation+="|-"; + fprintf(kc_f, kc_printformat_list_open, kc_indentation.c_str(), op_name()); + kc_indentation=kc_indentation.substr(0, kc_indentation.length()-2); + kc_indentation+="| "; + subphylum(0)->fprint(kc_f); + kc_indentation=kc_indentation.substr(0, kc_indentation.length()-2); + phylum_cast(subphylum(1))->fprint_list(kc_f); + } + } + + int + impl_abstract_list::length() const + { + int kc_length = 0; + c_abstract_phylum kc_p = this; + while((kc_p = kc_p->subphylum(1))) + kc_length++; + return kc_length; + } + void impl_abstract_list::freelist() + { + abstract_phylum kc_p = this, kc_tmp_p; + do { + kc_tmp_p=kc_p->subphylum(1); + kc_p->free(false); + kc_p=kc_tmp_p; + } while(kc_p); + } + abstract_phylum + impl_abstract_list::do_concat(c_abstract_phylum kc_p2, enum_operators mk) const + { + abstract_phylum next = subphylum(1); + if(!next) + return const_cast(kc_p2); + return kc_create(mk, subphylum(0), static_cast(next)->do_concat(kc_p2, mk)); + } + + abstract_phylum + impl_abstract_list::do_reverse(c_abstract_phylum tail, enum_operators mk) const + { + for (impl_abstract_list const* iterator_ = this; iterator_->subphylum(1) != 0; + iterator_ = static_cast(iterator_->subphylum(1)) ) + tail = kc_create(mk, iterator_->subphylum(0), const_cast(tail)); + return const_cast(tail); + } + + abstract_phylum + impl_abstract_list::last() const + { + c_abstract_phylum kc_p = this, next = subphylum(1), nextnext; + #ifdef _AFX + ASSERT(next); + if(!next) + return NULL; + #else + if(!next){ + fflush(stdout); + fprintf(stderr, "Internal Error: list::last was called with argument Nil%s\n", phylum_name()); + exit(1); + } + #endif + while ((nextnext = next->subphylum(1))) { + kc_p = next; + next = nextnext; + } + return const_cast(kc_p->subphylum(0));/* XXX remove cast */ + } + + abstract_phylum + impl_abstract_list::do_map(abstract_phylum (*kc_fp)(abstract_phylum), enum_operators mk) + { + abstract_phylum el = subphylum(0); + if (!el) + return this; + abstract_list next = static_cast(subphylum(1)); + return kc_create(mk, kc_fp(el), next->do_map(kc_fp, mk)); + } + + abstract_phylum + impl_abstract_list::do_filter(bool (*kc_fp)(abstract_phylum), enum_operators mk) + { + abstract_phylum el = subphylum(0); + if (!el) + return this; + abstract_list next = static_cast(subphylum(1)); + if ((*kc_fp)(el)) { + return kc_create(mk, el, next->do_filter(kc_fp, mk)); + } else { + return next->do_filter(kc_fp, mk); + } + } + + abstract_list + impl_abstract_list::do_append(abstract_phylum new_last, abstract_list eol) + { + abstract_list next = this; + while (!next->is_nil()) + next = phylum_cast(next->subphylum(1)); + next->set_subphylum(0, new_last); + next->set_subphylum(1, eol); + return next; + } + + abstract_phylum + impl_abstract_list::do_merge(abstract_list second,abstract_phylum(*kc_fp)(abstract_phylum,abstract_phylum), enum_operators mk) + { + abstract_phylum el = subphylum(0); + if (!el) + return this; + abstract_phylum el2 = second->subphylum(0); + if (!el2) + return el2; + abstract_list next = static_cast(subphylum(1)); + abstract_list next2 = static_cast(second->subphylum(1)); + return kc_create(mk, kc_fp(el,el2), next->do_merge(next2, kc_fp, mk)); + } + + abstract_phylum + impl_abstract_list::do_reduce(abstract_phylum neutral, abstract_phylum(*kc_fp)(abstract_phylum,abstract_phylum)) { + abstract_phylum el = subphylum(0); + if (!el) + return neutral; + abstract_list next = static_cast(subphylum(1)); + return kc_fp(el,next->do_reduce(neutral,kc_fp)); + } + + + extern const char* kc_storageclassnames[]; + + #ifdef KC_STATISTICS + void do_print_operator_statistics(FILE * kc_f) + { + unsigned int kc_i; + assertNonNull( kc_f ); + fprintf(kc_f, "%-*s| %-*s| %-*s| %-*s| %-*s| %-*s| %-*s| %-*s| %-*s| %-*s\n", 38 , "Operator", 3, "Sz", 8, "#oper", 8, "#new", 8, "#exist", 8, "#frnrec", 8, "#frrec", 8, "#freed", 8, "#rem", 9, "total (bytes)"); + fprintf(kc_f, "%-*s|%*s |%*d |%*d |%*d |%*d |%*d |%*d |%*d |%*d\n", 38, "case sensitive strings", 3, "-", 8, operator_statistics[sel__Str].created, 8, operator_statistics[sel__Str].existing_not_found, 8, operator_statistics[sel__Str].created-operator_statistics[sel__Str].existing_not_found, 8, 0, 8, 0, 8, 0, 8, 0, 9, kc_casestring_strlen); + fprintf(kc_f, "%-*s|%*s |%*d |%*d |%*d |%*d |%*d |%*d |%*d |%*d\n", 38, "case insensitive strings", 3, "-", 8, operator_statistics[sel_NoCaseStr].created, 8, operator_statistics[sel_NoCaseStr].existing_not_found, 8, operator_statistics[sel_NoCaseStr].created-operator_statistics[sel_NoCaseStr].existing_not_found, 8, 0, 8, 0, 8, 0, 8, 0, 9, kc_nocasestring_strlen); + for (kc_i = one_before_first_operator+1; kc_i < last_operator; kc_i++) { + fprintf(kc_f, "%-*s|%*d |%*d |%*d |%*d |%*d |%*d |%*d |%*d |%*d\n", 38, operator_info[kc_i].name, 3, operator_info[kc_i].size, 8, operator_statistics[kc_i].created, 8, operator_statistics[kc_i].existing_not_found, 8, operator_statistics[kc_i].created-operator_statistics[kc_i].existing_not_found, 8, operator_statistics[kc_i].free_called[false], 8, operator_statistics[kc_i].free_called[true], 8, operator_statistics[kc_i].freed[false]+operator_statistics[kc_i].freed[true], 8, operator_statistics[kc_i].existing_not_found-(operator_statistics[kc_i].freed[false]+operator_statistics[kc_i].freed[true]), 9, operator_info[kc_i].size*(operator_statistics[kc_i].existing_not_found-(operator_statistics[kc_i].freed[false]+operator_statistics[kc_i].freed[true]))); + } + } + #endif // KC_STATISTICS + + const char* + phylumname_or_error(enum_phyla kc_phy) + { + if ((kc_phy <= one_before_first_phylum) || (kc_phy >= last_phylum)) { + char *kc_strof_error; + sprintf((kc_strof_error=new char[69]), "Internal Error: unknown phylum number: %d", kc_phy); + return kc_strof_error; + } else { + return phylum_info[kc_phy].name; + } } + + + const char* + kc_operatorname_or_error(enum_operators kc_operator) + { + if ((kc_operator <= one_before_first_operator) || (kc_operator >= last_operator)) { + char *kc_strof_error; + sprintf((kc_strof_error=new char[71]), "Internal Error: unknown operator number: %d", kc_operator); + return kc_strof_error; + } else { + return operator_info[kc_operator].name; + } } + + phylumdeclarations + concat(c_phylumdeclarations kc_p1, c_phylumdeclarations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consphylumdeclarations)); } + + phylumdeclarations + impl_phylumdeclarations::reverse() const + { return dynamic_cast(do_reverse(Nilphylumdeclarations(), sel_Consphylumdeclarations)); } + + phylumdeclaration + impl_phylumdeclarations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_phylumdeclarations::is_nil() const + { + return phylumdeclaration_1==0 && phylumdeclarations_1==0; + } + + phylumdeclarations + impl_phylumdeclarations::map(phylumdeclaration (*kc_fp)(phylumdeclaration)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consphylumdeclarations)); } + phylumdeclarations + impl_phylumdeclarations::filter(bool (*kc_fp)(phylumdeclaration)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consphylumdeclarations)); } + + phylumdeclarations + impl_phylumdeclarations::append(phylumdeclaration new_last) + { + return dynamic_cast(do_append(new_last, Nilphylumdeclarations())); + } + phylumdeclarations + impl_phylumdeclarations::merge( phylumdeclarations second, phylumdeclaration (*kc_fp)(phylumdeclaration, phylumdeclaration)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consphylumdeclarations)); + } + phylumdeclaration + impl_phylumdeclarations::reduce( phylumdeclaration neutral, phylumdeclaration (*kc_fp)(phylumdeclaration, phylumdeclaration)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + phylumnames + concat(c_phylumnames kc_p1, c_phylumnames kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consphylumnames)); } + + phylumnames + impl_phylumnames::reverse() const + { return dynamic_cast(do_reverse(Nilphylumnames(), sel_Consphylumnames)); } + + ID + impl_phylumnames::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_phylumnames::is_nil() const + { + return ID_1==0 && phylumnames_1==0; + } + + phylumnames + impl_phylumnames::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consphylumnames)); } + phylumnames + impl_phylumnames::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consphylumnames)); } + + phylumnames + impl_phylumnames::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilphylumnames())); + } + phylumnames + impl_phylumnames::merge( phylumnames second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consphylumnames)); + } + ID + impl_phylumnames::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + storageclasses + concat(c_storageclasses kc_p1, c_storageclasses kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consstorageclasses)); } + + storageclasses + impl_storageclasses::reverse() const + { return dynamic_cast(do_reverse(Nilstorageclasses(), sel_Consstorageclasses)); } + + ID + impl_storageclasses::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_storageclasses::is_nil() const + { + return ID_1==0 && storageclasses_1==0; + } + + storageclasses + impl_storageclasses::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consstorageclasses)); } + storageclasses + impl_storageclasses::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consstorageclasses)); } + + storageclasses + impl_storageclasses::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilstorageclasses())); + } + storageclasses + impl_storageclasses::merge( storageclasses second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consstorageclasses)); + } + ID + impl_storageclasses::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + alternatives + concat(c_alternatives kc_p1, c_alternatives kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consalternatives)); } + + alternatives + impl_alternatives::reverse() const + { return dynamic_cast(do_reverse(Nilalternatives(), sel_Consalternatives)); } + + alternative + impl_alternatives::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_alternatives::is_nil() const + { + return alternative_1==0 && alternatives_1==0; + } + + alternatives + impl_alternatives::map(alternative (*kc_fp)(alternative)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consalternatives)); } + alternatives + impl_alternatives::filter(bool (*kc_fp)(alternative)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consalternatives)); } + + alternatives + impl_alternatives::append(alternative new_last) + { + return dynamic_cast(do_append(new_last, Nilalternatives())); + } + alternatives + impl_alternatives::merge( alternatives second, alternative (*kc_fp)(alternative, alternative)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consalternatives)); + } + alternative + impl_alternatives::reduce( alternative neutral, alternative (*kc_fp)(alternative, alternative)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + arguments + concat(c_arguments kc_p1, c_arguments kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consarguments)); } + + arguments + impl_arguments::reverse() const + { return dynamic_cast(do_reverse(Nilarguments(), sel_Consarguments)); } + + ID + impl_arguments::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_arguments::is_nil() const + { + return ID_1==0 && arguments_1==0; + } + + arguments + impl_arguments::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consarguments)); } + arguments + impl_arguments::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consarguments)); } + + arguments + impl_arguments::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilarguments())); + } + arguments + impl_arguments::merge( arguments second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consarguments)); + } + ID + impl_arguments::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + attributes + concat(c_attributes kc_p1, c_attributes kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consattributes)); } + + attributes + impl_attributes::reverse() const + { return dynamic_cast(do_reverse(Nilattributes(), sel_Consattributes)); } + + attribute + impl_attributes::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_attributes::is_nil() const + { + return attribute_1==0 && attributes_1==0; + } + + attributes + impl_attributes::map(attribute (*kc_fp)(attribute)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consattributes)); } + attributes + impl_attributes::filter(bool (*kc_fp)(attribute)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consattributes)); } + + attributes + impl_attributes::append(attribute new_last) + { + return dynamic_cast(do_append(new_last, Nilattributes())); + } + attributes + impl_attributes::merge( attributes second, attribute (*kc_fp)(attribute, attribute)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consattributes)); + } + attribute + impl_attributes::reduce( attribute neutral, attribute (*kc_fp)(attribute, attribute)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + Cexpression + concat(c_Cexpression kc_p1, c_Cexpression kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsCexpression)); } + + Cexpression + impl_Cexpression::reverse() const + { return dynamic_cast(do_reverse(NilCexpression(), sel_ConsCexpression)); } + + Cexpression_elem + impl_Cexpression::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_Cexpression::is_nil() const + { + return Cexpression_elem_1==0 && Cexpression_1==0; + } + + Cexpression + impl_Cexpression::map(Cexpression_elem (*kc_fp)(Cexpression_elem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsCexpression)); } + Cexpression + impl_Cexpression::filter(bool (*kc_fp)(Cexpression_elem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsCexpression)); } + + Cexpression + impl_Cexpression::append(Cexpression_elem new_last) + { + return dynamic_cast(do_append(new_last, NilCexpression())); + } + Cexpression + impl_Cexpression::merge( Cexpression second, Cexpression_elem (*kc_fp)(Cexpression_elem, Cexpression_elem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsCexpression)); + } + Cexpression_elem + impl_Cexpression::reduce( Cexpression_elem neutral, Cexpression_elem (*kc_fp)(Cexpression_elem, Cexpression_elem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + CexpressionDQ + concat(c_CexpressionDQ kc_p1, c_CexpressionDQ kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsCexpressionDQ)); } + + CexpressionDQ + impl_CexpressionDQ::reverse() const + { return dynamic_cast(do_reverse(NilCexpressionDQ(), sel_ConsCexpressionDQ)); } + + CexpressionDQ_elem + impl_CexpressionDQ::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_CexpressionDQ::is_nil() const + { + return CexpressionDQ_elem_1==0 && CexpressionDQ_1==0; + } + + CexpressionDQ + impl_CexpressionDQ::map(CexpressionDQ_elem (*kc_fp)(CexpressionDQ_elem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsCexpressionDQ)); } + CexpressionDQ + impl_CexpressionDQ::filter(bool (*kc_fp)(CexpressionDQ_elem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsCexpressionDQ)); } + + CexpressionDQ + impl_CexpressionDQ::append(CexpressionDQ_elem new_last) + { + return dynamic_cast(do_append(new_last, NilCexpressionDQ())); + } + CexpressionDQ + impl_CexpressionDQ::merge( CexpressionDQ second, CexpressionDQ_elem (*kc_fp)(CexpressionDQ_elem, CexpressionDQ_elem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsCexpressionDQ)); + } + CexpressionDQ_elem + impl_CexpressionDQ::reduce( CexpressionDQ_elem neutral, CexpressionDQ_elem (*kc_fp)(CexpressionDQ_elem, CexpressionDQ_elem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + CexpressionSQ + concat(c_CexpressionSQ kc_p1, c_CexpressionSQ kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsCexpressionSQ)); } + + CexpressionSQ + impl_CexpressionSQ::reverse() const + { return dynamic_cast(do_reverse(NilCexpressionSQ(), sel_ConsCexpressionSQ)); } + + CexpressionSQ_elem + impl_CexpressionSQ::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_CexpressionSQ::is_nil() const + { + return CexpressionSQ_elem_1==0 && CexpressionSQ_1==0; + } + + CexpressionSQ + impl_CexpressionSQ::map(CexpressionSQ_elem (*kc_fp)(CexpressionSQ_elem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsCexpressionSQ)); } + CexpressionSQ + impl_CexpressionSQ::filter(bool (*kc_fp)(CexpressionSQ_elem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsCexpressionSQ)); } + + CexpressionSQ + impl_CexpressionSQ::append(CexpressionSQ_elem new_last) + { + return dynamic_cast(do_append(new_last, NilCexpressionSQ())); + } + CexpressionSQ + impl_CexpressionSQ::merge( CexpressionSQ second, CexpressionSQ_elem (*kc_fp)(CexpressionSQ_elem, CexpressionSQ_elem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsCexpressionSQ)); + } + CexpressionSQ_elem + impl_CexpressionSQ::reduce( CexpressionSQ_elem neutral, CexpressionSQ_elem (*kc_fp)(CexpressionSQ_elem, CexpressionSQ_elem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + idCexpressions + concat(c_idCexpressions kc_p1, c_idCexpressions kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsidCexpressions)); } + + idCexpressions + impl_idCexpressions::reverse() const + { return dynamic_cast(do_reverse(NilidCexpressions(), sel_ConsidCexpressions)); } + + idCexpression + impl_idCexpressions::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_idCexpressions::is_nil() const + { + return idCexpression_1==0 && idCexpressions_1==0; + } + + idCexpressions + impl_idCexpressions::map(idCexpression (*kc_fp)(idCexpression)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsidCexpressions)); } + idCexpressions + impl_idCexpressions::filter(bool (*kc_fp)(idCexpression)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsidCexpressions)); } + + idCexpressions + impl_idCexpressions::append(idCexpression new_last) + { + return dynamic_cast(do_append(new_last, NilidCexpressions())); + } + idCexpressions + impl_idCexpressions::merge( idCexpressions second, idCexpression (*kc_fp)(idCexpression, idCexpression)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsidCexpressions)); + } + idCexpression + impl_idCexpressions::reduce( idCexpression neutral, idCexpression (*kc_fp)(idCexpression, idCexpression)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + Ctexts + concat(c_Ctexts kc_p1, c_Ctexts kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsCtexts)); } + + Ctexts + impl_Ctexts::reverse() const + { return dynamic_cast(do_reverse(NilCtexts(), sel_ConsCtexts)); } + + Ctext + impl_Ctexts::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_Ctexts::is_nil() const + { + return Ctext_1==0 && Ctexts_1==0; + } + + Ctexts + impl_Ctexts::map(Ctext (*kc_fp)(Ctext)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsCtexts)); } + Ctexts + impl_Ctexts::filter(bool (*kc_fp)(Ctext)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsCtexts)); } + + Ctexts + impl_Ctexts::append(Ctext new_last) + { + return dynamic_cast(do_append(new_last, NilCtexts())); + } + Ctexts + impl_Ctexts::merge( Ctexts second, Ctext (*kc_fp)(Ctext, Ctext)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsCtexts)); + } + Ctext + impl_Ctexts::reduce( Ctext neutral, Ctext (*kc_fp)(Ctext, Ctext)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + includefiles + concat(c_includefiles kc_p1, c_includefiles kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consincludefiles)); } + + includefiles + impl_includefiles::reverse() const + { return dynamic_cast(do_reverse(Nilincludefiles(), sel_Consincludefiles)); } + + includefile + impl_includefiles::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_includefiles::is_nil() const + { + return includefile_1==0 && includefiles_1==0; + } + + includefiles + impl_includefiles::map(includefile (*kc_fp)(includefile)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consincludefiles)); } + includefiles + impl_includefiles::filter(bool (*kc_fp)(includefile)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consincludefiles)); } + + includefiles + impl_includefiles::append(includefile new_last) + { + return dynamic_cast(do_append(new_last, Nilincludefiles())); + } + includefiles + impl_includefiles::merge( includefiles second, includefile (*kc_fp)(includefile, includefile)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consincludefiles)); + } + includefile + impl_includefiles::reduce( includefile neutral, includefile (*kc_fp)(includefile, includefile)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + includedeclarations + concat(c_includedeclarations kc_p1, c_includedeclarations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consincludedeclarations)); } + + includedeclarations + impl_includedeclarations::reverse() const + { return dynamic_cast(do_reverse(Nilincludedeclarations(), sel_Consincludedeclarations)); } + + includedeclaration + impl_includedeclarations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_includedeclarations::is_nil() const + { + return includedeclaration_1==0 && includedeclarations_1==0; + } + + includedeclarations + impl_includedeclarations::map(includedeclaration (*kc_fp)(includedeclaration)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consincludedeclarations)); } + includedeclarations + impl_includedeclarations::filter(bool (*kc_fp)(includedeclaration)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consincludedeclarations)); } + + includedeclarations + impl_includedeclarations::append(includedeclaration new_last) + { + return dynamic_cast(do_append(new_last, Nilincludedeclarations())); + } + includedeclarations + impl_includedeclarations::merge( includedeclarations second, includedeclaration (*kc_fp)(includedeclaration, includedeclaration)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consincludedeclarations)); + } + includedeclaration + impl_includedeclarations::reduce( includedeclaration neutral, includedeclaration (*kc_fp)(includedeclaration, includedeclaration)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + rwdeclarations + concat(c_rwdeclarations kc_p1, c_rwdeclarations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consrwdeclarations)); } + + rwdeclarations + impl_rwdeclarations::reverse() const + { return dynamic_cast(do_reverse(Nilrwdeclarations(), sel_Consrwdeclarations)); } + + rwdeclaration + impl_rwdeclarations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_rwdeclarations::is_nil() const + { + return rwdeclaration_1==0 && rwdeclarations_1==0; + } + + rwdeclarations + impl_rwdeclarations::map(rwdeclaration (*kc_fp)(rwdeclaration)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consrwdeclarations)); } + rwdeclarations + impl_rwdeclarations::filter(bool (*kc_fp)(rwdeclaration)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consrwdeclarations)); } + + rwdeclarations + impl_rwdeclarations::append(rwdeclaration new_last) + { + return dynamic_cast(do_append(new_last, Nilrwdeclarations())); + } + rwdeclarations + impl_rwdeclarations::merge( rwdeclarations second, rwdeclaration (*kc_fp)(rwdeclaration, rwdeclaration)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consrwdeclarations)); + } + rwdeclaration + impl_rwdeclarations::reduce( rwdeclaration neutral, rwdeclaration (*kc_fp)(rwdeclaration, rwdeclaration)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + rewriteclauses + concat(c_rewriteclauses kc_p1, c_rewriteclauses kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consrewriteclauses)); } + + rewriteclauses + impl_rewriteclauses::reverse() const + { return dynamic_cast(do_reverse(Nilrewriteclauses(), sel_Consrewriteclauses)); } + + rewriteclause + impl_rewriteclauses::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_rewriteclauses::is_nil() const + { + return rewriteclause_1==0 && rewriteclauses_1==0; + } + + rewriteclauses + impl_rewriteclauses::map(rewriteclause (*kc_fp)(rewriteclause)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consrewriteclauses)); } + rewriteclauses + impl_rewriteclauses::filter(bool (*kc_fp)(rewriteclause)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consrewriteclauses)); } + + rewriteclauses + impl_rewriteclauses::append(rewriteclause new_last) + { + return dynamic_cast(do_append(new_last, Nilrewriteclauses())); + } + rewriteclauses + impl_rewriteclauses::merge( rewriteclauses second, rewriteclause (*kc_fp)(rewriteclause, rewriteclause)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consrewriteclauses)); + } + rewriteclause + impl_rewriteclauses::reduce( rewriteclause neutral, rewriteclause (*kc_fp)(rewriteclause, rewriteclause)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + patternchains + concat(c_patternchains kc_p1, c_patternchains kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspatternchains)); } + + patternchains + impl_patternchains::reverse() const + { return dynamic_cast(do_reverse(Nilpatternchains(), sel_Conspatternchains)); } + + patternchain + impl_patternchains::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_patternchains::is_nil() const + { + return patternchain_1==0 && patternchains_1==0; + } + + patternchains + impl_patternchains::map(patternchain (*kc_fp)(patternchain)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspatternchains)); } + patternchains + impl_patternchains::filter(bool (*kc_fp)(patternchain)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspatternchains)); } + + patternchains + impl_patternchains::append(patternchain new_last) + { + return dynamic_cast(do_append(new_last, Nilpatternchains())); + } + patternchains + impl_patternchains::merge( patternchains second, patternchain (*kc_fp)(patternchain, patternchain)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspatternchains)); + } + patternchain + impl_patternchains::reduce( patternchain neutral, patternchain (*kc_fp)(patternchain, patternchain)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + patternchain + concat(c_patternchain kc_p1, c_patternchain kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspatternchain)); } + + patternchain + impl_patternchain::reverse() const + { return dynamic_cast(do_reverse(Nilpatternchain(), sel_Conspatternchain)); } + + patternchainitem + impl_patternchain::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_patternchain::is_nil() const + { + return patternchainitem_1==0 && patternchain_1==0; + } + + patternchain + impl_patternchain::map(patternchainitem (*kc_fp)(patternchainitem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspatternchain)); } + patternchain + impl_patternchain::filter(bool (*kc_fp)(patternchainitem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspatternchain)); } + + patternchain + impl_patternchain::append(patternchainitem new_last) + { + return dynamic_cast(do_append(new_last, Nilpatternchain())); + } + patternchain + impl_patternchain::merge( patternchain second, patternchainitem (*kc_fp)(patternchainitem, patternchainitem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspatternchain)); + } + patternchainitem + impl_patternchain::reduce( patternchainitem neutral, patternchainitem (*kc_fp)(patternchainitem, patternchainitem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + outmostpatterns + concat(c_outmostpatterns kc_p1, c_outmostpatterns kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consoutmostpatterns)); } + + outmostpatterns + impl_outmostpatterns::reverse() const + { return dynamic_cast(do_reverse(Niloutmostpatterns(), sel_Consoutmostpatterns)); } + + outmostpattern + impl_outmostpatterns::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_outmostpatterns::is_nil() const + { + return outmostpattern_1==0 && outmostpatterns_1==0; + } + + outmostpatterns + impl_outmostpatterns::map(outmostpattern (*kc_fp)(outmostpattern)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consoutmostpatterns)); } + outmostpatterns + impl_outmostpatterns::filter(bool (*kc_fp)(outmostpattern)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consoutmostpatterns)); } + + outmostpatterns + impl_outmostpatterns::append(outmostpattern new_last) + { + return dynamic_cast(do_append(new_last, Niloutmostpatterns())); + } + outmostpatterns + impl_outmostpatterns::merge( outmostpatterns second, outmostpattern (*kc_fp)(outmostpattern, outmostpattern)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consoutmostpatterns)); + } + outmostpattern + impl_outmostpatterns::reduce( outmostpattern neutral, outmostpattern (*kc_fp)(outmostpattern, outmostpattern)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + patterns + concat(c_patterns kc_p1, c_patterns kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspatterns)); } + + patterns + impl_patterns::reverse() const + { return dynamic_cast(do_reverse(Nilpatterns(), sel_Conspatterns)); } + + pattern + impl_patterns::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_patterns::is_nil() const + { + return pattern_1==0 && patterns_1==0; + } + + patterns + impl_patterns::map(pattern (*kc_fp)(pattern)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspatterns)); } + patterns + impl_patterns::filter(bool (*kc_fp)(pattern)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspatterns)); } + + patterns + impl_patterns::append(pattern new_last) + { + return dynamic_cast(do_append(new_last, Nilpatterns())); + } + patterns + impl_patterns::merge( patterns second, pattern (*kc_fp)(pattern, pattern)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspatterns)); + } + pattern + impl_patterns::reduce( pattern neutral, pattern (*kc_fp)(pattern, pattern)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + terms + concat(c_terms kc_p1, c_terms kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consterms)); } + + terms + impl_terms::reverse() const + { return dynamic_cast(do_reverse(Nilterms(), sel_Consterms)); } + + term + impl_terms::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_terms::is_nil() const + { + return term_1==0 && terms_1==0; + } + + terms + impl_terms::map(term (*kc_fp)(term)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consterms)); } + terms + impl_terms::filter(bool (*kc_fp)(term)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consterms)); } + + terms + impl_terms::append(term new_last) + { + return dynamic_cast(do_append(new_last, Nilterms())); + } + terms + impl_terms::merge( terms second, term (*kc_fp)(term, term)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consterms)); + } + term + impl_terms::reduce( term neutral, term (*kc_fp)(term, term)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + fnfiles + concat(c_fnfiles kc_p1, c_fnfiles kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consfnfiles)); } + + fnfiles + impl_fnfiles::reverse() const + { return dynamic_cast(do_reverse(Nilfnfiles(), sel_Consfnfiles)); } + + fnfile + impl_fnfiles::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_fnfiles::is_nil() const + { + return fnfile_1==0 && fnfiles_1==0; + } + + fnfiles + impl_fnfiles::map(fnfile (*kc_fp)(fnfile)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consfnfiles)); } + fnfiles + impl_fnfiles::filter(bool (*kc_fp)(fnfile)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consfnfiles)); } + + fnfiles + impl_fnfiles::append(fnfile new_last) + { + return dynamic_cast(do_append(new_last, Nilfnfiles())); + } + fnfiles + impl_fnfiles::merge( fnfiles second, fnfile (*kc_fp)(fnfile, fnfile)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consfnfiles)); + } + fnfile + impl_fnfiles::reduce( fnfile neutral, fnfile (*kc_fp)(fnfile, fnfile)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + fndeclarations + concat(c_fndeclarations kc_p1, c_fndeclarations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consfndeclarations)); } + + fndeclarations + impl_fndeclarations::reverse() const + { return dynamic_cast(do_reverse(Nilfndeclarations(), sel_Consfndeclarations)); } + + fndeclaration + impl_fndeclarations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_fndeclarations::is_nil() const + { + return fndeclaration_1==0 && fndeclarations_1==0; + } + + fndeclarations + impl_fndeclarations::map(fndeclaration (*kc_fp)(fndeclaration)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consfndeclarations)); } + fndeclarations + impl_fndeclarations::filter(bool (*kc_fp)(fndeclaration)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consfndeclarations)); } + + fndeclarations + impl_fndeclarations::append(fndeclaration new_last) + { + return dynamic_cast(do_append(new_last, Nilfndeclarations())); + } + fndeclarations + impl_fndeclarations::merge( fndeclarations second, fndeclaration (*kc_fp)(fndeclaration, fndeclaration)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consfndeclarations)); + } + fndeclaration + impl_fndeclarations::reduce( fndeclaration neutral, fndeclaration (*kc_fp)(fndeclaration, fndeclaration)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + Ctext + concat(c_Ctext kc_p1, c_Ctext kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_ConsCtext)); } + + Ctext + impl_Ctext::reverse() const + { return dynamic_cast(do_reverse(NilCtext(), sel_ConsCtext)); } + + Ctext_elem + impl_Ctext::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_Ctext::is_nil() const + { + return Ctext_elem_1==0 && Ctext_1==0; + } + + Ctext + impl_Ctext::map(Ctext_elem (*kc_fp)(Ctext_elem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_ConsCtext)); } + Ctext + impl_Ctext::filter(bool (*kc_fp)(Ctext_elem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_ConsCtext)); } + + Ctext + impl_Ctext::append(Ctext_elem new_last) + { + return dynamic_cast(do_append(new_last, NilCtext())); + } + Ctext + impl_Ctext::merge( Ctext second, Ctext_elem (*kc_fp)(Ctext_elem, Ctext_elem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_ConsCtext)); + } + Ctext_elem + impl_Ctext::reduce( Ctext_elem neutral, Ctext_elem (*kc_fp)(Ctext_elem, Ctext_elem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + withexpressions + concat(c_withexpressions kc_p1, c_withexpressions kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conswithexpressions)); } + + withexpressions + impl_withexpressions::reverse() const + { return dynamic_cast(do_reverse(Nilwithexpressions(), sel_Conswithexpressions)); } + + withexpression + impl_withexpressions::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_withexpressions::is_nil() const + { + return withexpression_1==0 && withexpressions_1==0; + } + + withexpressions + impl_withexpressions::map(withexpression (*kc_fp)(withexpression)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conswithexpressions)); } + withexpressions + impl_withexpressions::filter(bool (*kc_fp)(withexpression)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conswithexpressions)); } + + withexpressions + impl_withexpressions::append(withexpression new_last) + { + return dynamic_cast(do_append(new_last, Nilwithexpressions())); + } + withexpressions + impl_withexpressions::merge( withexpressions second, withexpression (*kc_fp)(withexpression, withexpression)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conswithexpressions)); + } + withexpression + impl_withexpressions::reduce( withexpression neutral, withexpression (*kc_fp)(withexpression, withexpression)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + withcases + concat(c_withcases kc_p1, c_withcases kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conswithcases)); } + + withcases + impl_withcases::reverse() const + { return dynamic_cast(do_reverse(Nilwithcases(), sel_Conswithcases)); } + + withcase + impl_withcases::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_withcases::is_nil() const + { + return withcase_1==0 && withcases_1==0; + } + + withcases + impl_withcases::map(withcase (*kc_fp)(withcase)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conswithcases)); } + withcases + impl_withcases::filter(bool (*kc_fp)(withcase)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conswithcases)); } + + withcases + impl_withcases::append(withcase new_last) + { + return dynamic_cast(do_append(new_last, Nilwithcases())); + } + withcases + impl_withcases::merge( withcases second, withcase (*kc_fp)(withcase, withcase)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conswithcases)); + } + withcase + impl_withcases::reduce( withcase neutral, withcase (*kc_fp)(withcase, withcase)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + unparsedeclarations + concat(c_unparsedeclarations kc_p1, c_unparsedeclarations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consunparsedeclarations)); } + + unparsedeclarations + impl_unparsedeclarations::reverse() const + { return dynamic_cast(do_reverse(Nilunparsedeclarations(), sel_Consunparsedeclarations)); } + + unparsedeclaration + impl_unparsedeclarations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_unparsedeclarations::is_nil() const + { + return unparsedeclaration_1==0 && unparsedeclarations_1==0; + } + + unparsedeclarations + impl_unparsedeclarations::map(unparsedeclaration (*kc_fp)(unparsedeclaration)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consunparsedeclarations)); } + unparsedeclarations + impl_unparsedeclarations::filter(bool (*kc_fp)(unparsedeclaration)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consunparsedeclarations)); } + + unparsedeclarations + impl_unparsedeclarations::append(unparsedeclaration new_last) + { + return dynamic_cast(do_append(new_last, Nilunparsedeclarations())); + } + unparsedeclarations + impl_unparsedeclarations::merge( unparsedeclarations second, unparsedeclaration (*kc_fp)(unparsedeclaration, unparsedeclaration)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consunparsedeclarations)); + } + unparsedeclaration + impl_unparsedeclarations::reduce( unparsedeclaration neutral, unparsedeclaration (*kc_fp)(unparsedeclaration, unparsedeclaration)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + unparseclauses + concat(c_unparseclauses kc_p1, c_unparseclauses kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consunparseclauses)); } + + unparseclauses + impl_unparseclauses::reverse() const + { return dynamic_cast(do_reverse(Nilunparseclauses(), sel_Consunparseclauses)); } + + unparseclause + impl_unparseclauses::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_unparseclauses::is_nil() const + { + return unparseclause_1==0 && unparseclauses_1==0; + } + + unparseclauses + impl_unparseclauses::map(unparseclause (*kc_fp)(unparseclause)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consunparseclauses)); } + unparseclauses + impl_unparseclauses::filter(bool (*kc_fp)(unparseclause)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consunparseclauses)); } + + unparseclauses + impl_unparseclauses::append(unparseclause new_last) + { + return dynamic_cast(do_append(new_last, Nilunparseclauses())); + } + unparseclauses + impl_unparseclauses::merge( unparseclauses second, unparseclause (*kc_fp)(unparseclause, unparseclause)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consunparseclauses)); + } + unparseclause + impl_unparseclauses::reduce( unparseclause neutral, unparseclause (*kc_fp)(unparseclause, unparseclause)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + viewnames + concat(c_viewnames kc_p1, c_viewnames kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consviewnames)); } + + viewnames + impl_viewnames::reverse() const + { return dynamic_cast(do_reverse(Nilviewnames(), sel_Consviewnames)); } + + ID + impl_viewnames::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_viewnames::is_nil() const + { + return ID_1==0 && viewnames_1==0; + } + + viewnames + impl_viewnames::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consviewnames)); } + viewnames + impl_viewnames::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consviewnames)); } + + viewnames + impl_viewnames::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilviewnames())); + } + viewnames + impl_viewnames::merge( viewnames second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consviewnames)); + } + ID + impl_viewnames::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + unparseitems + concat(c_unparseitems kc_p1, c_unparseitems kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consunparseitems)); } + + unparseitems + impl_unparseitems::reverse() const + { return dynamic_cast(do_reverse(Nilunparseitems(), sel_Consunparseitems)); } + + unparseitem + impl_unparseitems::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_unparseitems::is_nil() const + { + return unparseitem_1==0 && unparseitems_1==0; + } + + unparseitems + impl_unparseitems::map(unparseitem (*kc_fp)(unparseitem)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consunparseitems)); } + unparseitems + impl_unparseitems::filter(bool (*kc_fp)(unparseitem)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consunparseitems)); } + + unparseitems + impl_unparseitems::append(unparseitem new_last) + { + return dynamic_cast(do_append(new_last, Nilunparseitems())); + } + unparseitems + impl_unparseitems::merge( unparseitems second, unparseitem (*kc_fp)(unparseitem, unparseitem)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consunparseitems)); + } + unparseitem + impl_unparseitems::reduce( unparseitem neutral, unparseitem (*kc_fp)(unparseitem, unparseitem)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + unpattributes + concat(c_unpattributes kc_p1, c_unpattributes kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consunpattributes)); } + + unpattributes + impl_unpattributes::reverse() const + { return dynamic_cast(do_reverse(Nilunpattributes(), sel_Consunpattributes)); } + + ID + impl_unpattributes::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_unpattributes::is_nil() const + { + return ID_1==0 && unpattributes_1==0; + } + + unpattributes + impl_unpattributes::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consunpattributes)); } + unpattributes + impl_unpattributes::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consunpattributes)); } + + unpattributes + impl_unpattributes::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilunpattributes())); + } + unpattributes + impl_unpattributes::merge( unpattributes second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consunpattributes)); + } + ID + impl_unpattributes::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + languagenames + concat(c_languagenames kc_p1, c_languagenames kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conslanguagenames)); } + + languagenames + impl_languagenames::reverse() const + { return dynamic_cast(do_reverse(Nillanguagenames(), sel_Conslanguagenames)); } + + ID + impl_languagenames::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_languagenames::is_nil() const + { + return ID_1==0 && languagenames_1==0; + } + + languagenames + impl_languagenames::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conslanguagenames)); } + languagenames + impl_languagenames::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conslanguagenames)); } + + languagenames + impl_languagenames::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nillanguagenames())); + } + languagenames + impl_languagenames::merge( languagenames second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conslanguagenames)); + } + ID + impl_languagenames::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + scopetypefilelinestack + concat(c_scopetypefilelinestack kc_p1, c_scopetypefilelinestack kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consscopetypefilelinestack)); } + + scopetypefilelinestack + impl_scopetypefilelinestack::reverse() const + { return dynamic_cast(do_reverse(Nilscopetypefilelinestack(), sel_Consscopetypefilelinestack)); } + + scopetypefileline + impl_scopetypefilelinestack::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_scopetypefilelinestack::is_nil() const + { + return scopetypefileline_1==0 && scopetypefilelinestack_1==0; + } + + scopetypefilelinestack + impl_scopetypefilelinestack::map(scopetypefileline (*kc_fp)(scopetypefileline)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consscopetypefilelinestack)); } + scopetypefilelinestack + impl_scopetypefilelinestack::filter(bool (*kc_fp)(scopetypefileline)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consscopetypefilelinestack)); } + + scopetypefilelinestack + impl_scopetypefilelinestack::append(scopetypefileline new_last) + { + return dynamic_cast(do_append(new_last, Nilscopetypefilelinestack())); + } + scopetypefilelinestack + impl_scopetypefilelinestack::merge( scopetypefilelinestack second, scopetypefileline (*kc_fp)(scopetypefileline, scopetypefileline)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consscopetypefilelinestack)); + } + scopetypefileline + impl_scopetypefilelinestack::reduce( scopetypefileline neutral, scopetypefileline (*kc_fp)(scopetypefileline, scopetypefileline)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + operators + concat(c_operators kc_p1, c_operators kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consoperators)); } + + operators + impl_operators::reverse() const + { return dynamic_cast(do_reverse(Niloperators(), sel_Consoperators)); } + + ID + impl_operators::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_operators::is_nil() const + { + return ID_1==0 && operators_1==0; + } + + operators + impl_operators::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consoperators)); } + operators + impl_operators::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consoperators)); } + + operators + impl_operators::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Niloperators())); + } + operators + impl_operators::merge( operators second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consoperators)); + } + ID + impl_operators::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + phyla + concat(c_phyla kc_p1, c_phyla kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consphyla)); } + + phyla + impl_phyla::reverse() const + { return dynamic_cast(do_reverse(Nilphyla(), sel_Consphyla)); } + + ID + impl_phyla::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_phyla::is_nil() const + { + return ID_1==0 && phyla_1==0; + } + + phyla + impl_phyla::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consphyla)); } + phyla + impl_phyla::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consphyla)); } + + phyla + impl_phyla::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilphyla())); + } + phyla + impl_phyla::merge( phyla second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consphyla)); + } + ID + impl_phyla::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + variables + concat(c_variables kc_p1, c_variables kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consvariables)); } + + variables + impl_variables::reverse() const + { return dynamic_cast(do_reverse(Nilvariables(), sel_Consvariables)); } + + ID + impl_variables::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_variables::is_nil() const + { + return ID_1==0 && variables_1==0; + } + + variables + impl_variables::map(ID (*kc_fp)(ID)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consvariables)); } + variables + impl_variables::filter(bool (*kc_fp)(ID)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consvariables)); } + + variables + impl_variables::append(ID new_last) + { + return dynamic_cast(do_append(new_last, Nilvariables())); + } + variables + impl_variables::merge( variables second, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consvariables)); + } + ID + impl_variables::reduce( ID neutral, ID (*kc_fp)(ID, ID)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + patternrepresentations + concat(c_patternrepresentations kc_p1, c_patternrepresentations kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspatternrepresentations)); } + + patternrepresentations + impl_patternrepresentations::reverse() const + { return dynamic_cast(do_reverse(Nilpatternrepresentations(), sel_Conspatternrepresentations)); } + + patternrepresentation + impl_patternrepresentations::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_patternrepresentations::is_nil() const + { + return patternrepresentation_1==0 && patternrepresentations_1==0; + } + + patternrepresentations + impl_patternrepresentations::map(patternrepresentation (*kc_fp)(patternrepresentation)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspatternrepresentations)); } + patternrepresentations + impl_patternrepresentations::filter(bool (*kc_fp)(patternrepresentation)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspatternrepresentations)); } + + patternrepresentations + impl_patternrepresentations::append(patternrepresentation new_last) + { + return dynamic_cast(do_append(new_last, Nilpatternrepresentations())); + } + patternrepresentations + impl_patternrepresentations::merge( patternrepresentations second, patternrepresentation (*kc_fp)(patternrepresentation, patternrepresentation)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspatternrepresentations)); + } + patternrepresentation + impl_patternrepresentations::reduce( patternrepresentation neutral, patternrepresentation (*kc_fp)(patternrepresentation, patternrepresentation)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + patternrepresentation + concat(c_patternrepresentation kc_p1, c_patternrepresentation kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspatternrepresentation)); } + + patternrepresentation + impl_patternrepresentation::reverse() const + { return dynamic_cast(do_reverse(Nilpatternrepresentation(), sel_Conspatternrepresentation)); } + + elem_patternrepresentation + impl_patternrepresentation::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_patternrepresentation::is_nil() const + { + return elem_patternrepresentation_1==0 && patternrepresentation_1==0; + } + + patternrepresentation + impl_patternrepresentation::map(elem_patternrepresentation (*kc_fp)(elem_patternrepresentation)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspatternrepresentation)); } + patternrepresentation + impl_patternrepresentation::filter(bool (*kc_fp)(elem_patternrepresentation)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspatternrepresentation)); } + + patternrepresentation + impl_patternrepresentation::append(elem_patternrepresentation new_last) + { + return dynamic_cast(do_append(new_last, Nilpatternrepresentation())); + } + patternrepresentation + impl_patternrepresentation::merge( patternrepresentation second, elem_patternrepresentation (*kc_fp)(elem_patternrepresentation, elem_patternrepresentation)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspatternrepresentation)); + } + elem_patternrepresentation + impl_patternrepresentation::reduce( elem_patternrepresentation neutral, elem_patternrepresentation (*kc_fp)(elem_patternrepresentation, elem_patternrepresentation)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + path + concat(c_path kc_p1, c_path kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspath)); } + + path + impl_path::reverse() const + { return dynamic_cast(do_reverse(Nilpath(), sel_Conspath)); } + + integer + impl_path::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_path::is_nil() const + { + return integer_1==0 && path_1==0; + } + + path + impl_path::map(integer (*kc_fp)(integer)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspath)); } + path + impl_path::filter(bool (*kc_fp)(integer)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspath)); } + + path + impl_path::append(integer new_last) + { + return dynamic_cast(do_append(new_last, Nilpath())); + } + path + impl_path::merge( path second, integer (*kc_fp)(integer, integer)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspath)); + } + integer + impl_path::reduce( integer neutral, integer (*kc_fp)(integer, integer)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + paths + concat(c_paths kc_p1, c_paths kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conspaths)); } + + paths + impl_paths::reverse() const + { return dynamic_cast(do_reverse(Nilpaths(), sel_Conspaths)); } + + path + impl_paths::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_paths::is_nil() const + { + return path_1==0 && paths_1==0; + } + + paths + impl_paths::map(path (*kc_fp)(path)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conspaths)); } + paths + impl_paths::filter(bool (*kc_fp)(path)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conspaths)); } + + paths + impl_paths::append(path new_last) + { + return dynamic_cast(do_append(new_last, Nilpaths())); + } + paths + impl_paths::merge( paths second, path (*kc_fp)(path, path)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conspaths)); + } + path + impl_paths::reduce( path neutral, path (*kc_fp)(path, path)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + argsnumbers + concat(c_argsnumbers kc_p1, c_argsnumbers kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consargsnumbers)); } + + argsnumbers + impl_argsnumbers::reverse() const + { return dynamic_cast(do_reverse(Nilargsnumbers(), sel_Consargsnumbers)); } + + integer + impl_argsnumbers::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_argsnumbers::is_nil() const + { + return integer_1==0 && argsnumbers_1==0; + } + + argsnumbers + impl_argsnumbers::map(integer (*kc_fp)(integer)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consargsnumbers)); } + argsnumbers + impl_argsnumbers::filter(bool (*kc_fp)(integer)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consargsnumbers)); } + + argsnumbers + impl_argsnumbers::append(integer new_last) + { + return dynamic_cast(do_append(new_last, Nilargsnumbers())); + } + argsnumbers + impl_argsnumbers::merge( argsnumbers second, integer (*kc_fp)(integer, integer)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consargsnumbers)); + } + integer + impl_argsnumbers::reduce( integer neutral, integer (*kc_fp)(integer, integer)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + rewriterulesinfo + concat(c_rewriterulesinfo kc_p1, c_rewriterulesinfo kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consrewriterulesinfo)); } + + rewriterulesinfo + impl_rewriterulesinfo::reverse() const + { return dynamic_cast(do_reverse(Nilrewriterulesinfo(), sel_Consrewriterulesinfo)); } + + rewriteruleinfo + impl_rewriterulesinfo::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_rewriterulesinfo::is_nil() const + { + return rewriteruleinfo_1==0 && rewriterulesinfo_1==0; + } + + rewriterulesinfo + impl_rewriterulesinfo::map(rewriteruleinfo (*kc_fp)(rewriteruleinfo)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consrewriterulesinfo)); } + rewriterulesinfo + impl_rewriterulesinfo::filter(bool (*kc_fp)(rewriteruleinfo)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consrewriterulesinfo)); } + + rewriterulesinfo + impl_rewriterulesinfo::append(rewriteruleinfo new_last) + { + return dynamic_cast(do_append(new_last, Nilrewriterulesinfo())); + } + rewriterulesinfo + impl_rewriterulesinfo::merge( rewriterulesinfo second, rewriteruleinfo (*kc_fp)(rewriteruleinfo, rewriteruleinfo)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consrewriterulesinfo)); + } + rewriteruleinfo + impl_rewriterulesinfo::reduce( rewriteruleinfo neutral, rewriteruleinfo (*kc_fp)(rewriteruleinfo, rewriteruleinfo)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + withcasesinfo + concat(c_withcasesinfo kc_p1, c_withcasesinfo kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Conswithcasesinfo)); } + + withcasesinfo + impl_withcasesinfo::reverse() const + { return dynamic_cast(do_reverse(Nilwithcasesinfo(), sel_Conswithcasesinfo)); } + + withcaseinfo + impl_withcasesinfo::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_withcasesinfo::is_nil() const + { + return withcaseinfo_1==0 && withcasesinfo_1==0; + } + + withcasesinfo + impl_withcasesinfo::map(withcaseinfo (*kc_fp)(withcaseinfo)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Conswithcasesinfo)); } + withcasesinfo + impl_withcasesinfo::filter(bool (*kc_fp)(withcaseinfo)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Conswithcasesinfo)); } + + withcasesinfo + impl_withcasesinfo::append(withcaseinfo new_last) + { + return dynamic_cast(do_append(new_last, Nilwithcasesinfo())); + } + withcasesinfo + impl_withcasesinfo::merge( withcasesinfo second, withcaseinfo (*kc_fp)(withcaseinfo, withcaseinfo)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Conswithcasesinfo)); + } + withcaseinfo + impl_withcasesinfo::reduce( withcaseinfo neutral, withcaseinfo (*kc_fp)(withcaseinfo, withcaseinfo)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + rewriteviewsinfo + concat(c_rewriteviewsinfo kc_p1, c_rewriteviewsinfo kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consrewriteviewsinfo)); } + + rewriteviewsinfo + impl_rewriteviewsinfo::reverse() const + { return dynamic_cast(do_reverse(Nilrewriteviewsinfo(), sel_Consrewriteviewsinfo)); } + + rewriteviewinfo + impl_rewriteviewsinfo::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_rewriteviewsinfo::is_nil() const + { + return rewriteviewinfo_1==0 && rewriteviewsinfo_1==0; + } + + rewriteviewsinfo + impl_rewriteviewsinfo::map(rewriteviewinfo (*kc_fp)(rewriteviewinfo)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consrewriteviewsinfo)); } + rewriteviewsinfo + impl_rewriteviewsinfo::filter(bool (*kc_fp)(rewriteviewinfo)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consrewriteviewsinfo)); } + + rewriteviewsinfo + impl_rewriteviewsinfo::append(rewriteviewinfo new_last) + { + return dynamic_cast(do_append(new_last, Nilrewriteviewsinfo())); + } + rewriteviewsinfo + impl_rewriteviewsinfo::merge( rewriteviewsinfo second, rewriteviewinfo (*kc_fp)(rewriteviewinfo, rewriteviewinfo)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp, sel_Consrewriteviewsinfo)); + } + rewriteviewinfo + impl_rewriteviewsinfo::reduce( rewriteviewinfo neutral, rewriteviewinfo (*kc_fp)(rewriteviewinfo, rewriteviewinfo)) + { + return dynamic_cast(do_reduce(neutral,(abstract_phylum(*)(abstract_phylum,abstract_phylum))kc_fp)); + } + + unparseviewsinfo + concat(c_unparseviewsinfo kc_p1, c_unparseviewsinfo kc_p2) + { return dynamic_cast(kc_p1->do_concat(kc_p2, sel_Consunparseviewsinfo)); } + + unparseviewsinfo + impl_unparseviewsinfo::reverse() const + { return dynamic_cast(do_reverse(Nilunparseviewsinfo(), sel_Consunparseviewsinfo)); } + + unparseviewinfo + impl_unparseviewsinfo::last() const + { return dynamic_cast(impl_abstract_list::last()); } + + bool + impl_unparseviewsinfo::is_nil() const + { + return unparseviewinfo_1==0 && unparseviewsinfo_1==0; + } + + unparseviewsinfo + impl_unparseviewsinfo::map(unparseviewinfo (*kc_fp)(unparseviewinfo)) + { return dynamic_cast(do_map((abstract_phylum (*)(abstract_phylum))kc_fp, sel_Consunparseviewsinfo)); } + unparseviewsinfo + impl_unparseviewsinfo::filter(bool (*kc_fp)(unparseviewinfo)) + { return dynamic_cast(do_filter((bool (*)(abstract_phylum))kc_fp, sel_Consunparseviewsinfo)); } + + unparseviewsinfo + impl_unparseviewsinfo::append(unparseviewinfo new_last) + { + return dynamic_cast(do_append(new_last, Nilunparseviewsinfo())); + } + unparseviewsinfo + impl_unparseviewsinfo::merge( unparseviewsinfo second, unparseviewinfo (*kc_fp)(unparseviewinfo, unparseviewinfo)) + { + return dynamic_cast(do_merge(second,(abstract_phylum(*)(abstract_phyl