diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | Makefile.in | 144 | ||||
-rw-r--r-- | README | 43 | ||||
-rw-r--r-- | aapl/COPYING | 502 | ||||
-rw-r--r-- | aapl/README | 6 | ||||
-rw-r--r-- | aapl/astring.h | 809 | ||||
-rw-r--r-- | aapl/avlbasic.h | 65 | ||||
-rw-r--r-- | aapl/avlcommon.h | 1630 | ||||
-rw-r--r-- | aapl/avlibasic.h | 67 | ||||
-rw-r--r-- | aapl/avlikeyless.h | 64 | ||||
-rw-r--r-- | aapl/avlimap.h | 77 | ||||
-rw-r--r-- | aapl/avlimel.h | 79 | ||||
-rw-r--r-- | aapl/avlimelkey.h | 76 | ||||
-rw-r--r-- | aapl/avliset.h | 75 | ||||
-rw-r--r-- | aapl/avlitree.h | 78 | ||||
-rw-r--r-- | aapl/avlkeyless.h | 58 | ||||
-rw-r--r-- | aapl/avlmap.h | 74 | ||||
-rw-r--r-- | aapl/avlmel.h | 74 | ||||
-rw-r--r-- | aapl/avlmelkey.h | 71 | ||||
-rw-r--r-- | aapl/avlset.h | 70 | ||||
-rw-r--r-- | aapl/avltree.h | 73 | ||||
-rw-r--r-- | aapl/bstcommon.h | 814 | ||||
-rw-r--r-- | aapl/bstmap.h | 113 | ||||
-rw-r--r-- | aapl/bstset.h | 86 | ||||
-rw-r--r-- | aapl/bsttable.h | 84 | ||||
-rw-r--r-- | aapl/bubblesort.h | 94 | ||||
-rw-r--r-- | aapl/compare.h | 273 | ||||
-rw-r--r-- | aapl/dlcommon.h | 790 | ||||
-rw-r--r-- | aapl/dlist.h | 64 | ||||
-rw-r--r-- | aapl/dlistmel.h | 71 | ||||
-rw-r--r-- | aapl/dlistval.h | 71 | ||||
-rw-r--r-- | aapl/insertsort.h | 94 | ||||
-rw-r--r-- | aapl/mergesort.h | 140 | ||||
-rw-r--r-- | aapl/quicksort.h | 185 | ||||
-rw-r--r-- | aapl/resize.h | 344 | ||||
-rw-r--r-- | aapl/sbstmap.h | 121 | ||||
-rw-r--r-- | aapl/sbstset.h | 94 | ||||
-rw-r--r-- | aapl/sbsttable.h | 93 | ||||
-rw-r--r-- | aapl/svector.h | 1350 | ||||
-rw-r--r-- | aapl/table.h | 252 | ||||
-rw-r--r-- | aapl/vector.h | 1189 | ||||
-rw-r--r-- | colm.vim | 91 | ||||
-rw-r--r-- | colm/Makefile.in | 161 | ||||
-rw-r--r-- | colm/buffer.h (renamed from buffer.h) | 0 | ||||
-rw-r--r-- | colm/bytecode.cpp (renamed from bytecode.cpp) | 0 | ||||
-rw-r--r-- | colm/bytecode.h (renamed from bytecode.h) | 0 | ||||
-rw-r--r-- | colm/closure.cpp (renamed from closure.cpp) | 0 | ||||
-rw-r--r-- | colm/colm.h (renamed from colm.h) | 0 | ||||
-rw-r--r-- | colm/compile.cpp (renamed from compile.cpp) | 0 | ||||
-rw-r--r-- | colm/config.h.in (renamed from config.h.in) | 0 | ||||
-rw-r--r-- | colm/dotgen.cpp (renamed from dotgen.cpp) | 0 | ||||
-rw-r--r-- | colm/dotgen.h (renamed from dotgen.h) | 0 | ||||
-rw-r--r-- | colm/fsmap.cpp (renamed from fsmap.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmattach.cpp (renamed from fsmattach.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmbase.cpp (renamed from fsmbase.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmcodegen.cpp (renamed from fsmcodegen.cpp) | 8 | ||||
-rw-r--r-- | colm/fsmcodegen.h (renamed from fsmcodegen.h) | 0 | ||||
-rw-r--r-- | colm/fsmexec.cpp (renamed from fsmexec.cpp) | 22 | ||||
-rw-r--r-- | colm/fsmgraph.cpp (renamed from fsmgraph.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmgraph.h (renamed from fsmgraph.h) | 0 | ||||
-rw-r--r-- | colm/fsmmin.cpp (renamed from fsmmin.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmrun.cpp (renamed from fsmrun.cpp) | 0 | ||||
-rw-r--r-- | colm/fsmrun.h (renamed from fsmrun.h) | 2 | ||||
-rw-r--r-- | colm/fsmstate.cpp (renamed from fsmstate.cpp) | 0 | ||||
-rw-r--r-- | colm/input.cpp (renamed from input.cpp) | 0 | ||||
-rw-r--r-- | colm/input.h (renamed from input.h) | 0 | ||||
-rw-r--r-- | colm/keyops.h (renamed from keyops.h) | 0 | ||||
-rw-r--r-- | colm/list.cpp (renamed from list.cpp) | 0 | ||||
-rw-r--r-- | colm/lmparse.kh (renamed from lmparse.kh) | 0 | ||||
-rw-r--r-- | colm/lmparse.kl (renamed from lmparse.kl) | 0 | ||||
-rw-r--r-- | colm/lmscan.h (renamed from lmscan.h) | 0 | ||||
-rw-r--r-- | colm/lmscan.rl (renamed from lmscan.rl) | 0 | ||||
-rw-r--r-- | colm/main.cpp (renamed from main.cpp) | 0 | ||||
-rw-r--r-- | colm/map.cpp (renamed from map.cpp) | 0 | ||||
-rw-r--r-- | colm/parsedata.cpp (renamed from parsedata.cpp) | 0 | ||||
-rw-r--r-- | colm/parsedata.h (renamed from parsedata.h) | 0 | ||||
-rw-r--r-- | colm/parsetree.cpp (renamed from parsetree.cpp) | 0 | ||||
-rw-r--r-- | colm/parsetree.h (renamed from parsetree.h) | 0 | ||||
-rw-r--r-- | colm/pcheck.cpp (renamed from pcheck.cpp) | 0 | ||||
-rw-r--r-- | colm/pcheck.h (renamed from pcheck.h) | 0 | ||||
-rw-r--r-- | colm/pdabuild.cpp (renamed from pdabuild.cpp) | 0 | ||||
-rw-r--r-- | colm/pdacodegen.cpp (renamed from pdacodegen.cpp) | 0 | ||||
-rw-r--r-- | colm/pdacodegen.h (renamed from pdacodegen.h) | 0 | ||||
-rw-r--r-- | colm/pdagraph.cpp (renamed from pdagraph.cpp) | 0 | ||||
-rw-r--r-- | colm/pdagraph.h (renamed from pdagraph.h) | 0 | ||||
-rw-r--r-- | colm/pdarun.cpp (renamed from pdarun.cpp) | 0 | ||||
-rw-r--r-- | colm/pdarun.h (renamed from pdarun.h) | 0 | ||||
-rw-r--r-- | colm/redbuild.cpp (renamed from redbuild.cpp) | 0 | ||||
-rw-r--r-- | colm/redbuild.h (renamed from redbuild.h) | 0 | ||||
-rw-r--r-- | colm/redfsm.cpp (renamed from redfsm.cpp) | 0 | ||||
-rw-r--r-- | colm/redfsm.h (renamed from redfsm.h) | 0 | ||||
-rw-r--r-- | colm/string.cpp (renamed from string.cpp) | 0 | ||||
-rw-r--r-- | colm/tree.cpp (renamed from tree.cpp) | 0 | ||||
-rwxr-xr-x | configure | 4177 | ||||
-rw-r--r-- | configure.in | 75 | ||||
-rw-r--r-- | test/Makefile | 46 | ||||
-rw-r--r-- | test/backtrack1.lm | 24 | ||||
-rw-r--r-- | test/backtrack2.lm | 24 | ||||
-rw-r--r-- | test/backtrack3.lm | 27 | ||||
-rw-r--r-- | test/btscan.in | 2 | ||||
-rw-r--r-- | test/btscan.lm | 34 | ||||
-rw-r--r-- | test/commitbt.in | 1 | ||||
-rw-r--r-- | test/commitbt.lm | 110 | ||||
-rw-r--r-- | test/constructex.in | 3 | ||||
-rw-r--r-- | test/constructex.lm | 37 | ||||
-rw-r--r-- | test/counting1.in | 1 | ||||
-rw-r--r-- | test/counting1.lm | 91 | ||||
-rw-r--r-- | test/counting2.lm | 82 | ||||
-rw-r--r-- | test/counting3.lm | 92 | ||||
-rw-r--r-- | test/counting4.lm | 89 | ||||
-rw-r--r-- | test/cxx/Makefile | 34 | ||||
-rw-r--r-- | test/cxx/cxx.lm | 2168 | ||||
-rw-r--r-- | test/cxx/input01.cpp | 17 | ||||
-rw-r--r-- | test/cxx/input02.cpp | 16 | ||||
-rw-r--r-- | test/cxx/input03.cpp | 19 | ||||
-rw-r--r-- | test/cxx/input04.cpp | 17 | ||||
-rw-r--r-- | test/cxx/input05.cpp | 8 | ||||
-rw-r--r-- | test/cxx/input06.cpp | 7 | ||||
-rw-r--r-- | test/cxx/input07.cpp | 18 | ||||
-rw-r--r-- | test/cxx/input08.cpp | 13 | ||||
-rw-r--r-- | test/cxx/input09.cpp | 7 | ||||
-rw-r--r-- | test/cxx/input10.cpp | 11 | ||||
-rw-r--r-- | test/cxx/input11.cpp | 2 | ||||
-rw-r--r-- | test/cxx/input12.cpp | 8 | ||||
-rw-r--r-- | test/cxx/input13.cpp | 14 | ||||
-rwxr-xr-x | test/cxx/preproc | 5 | ||||
-rw-r--r-- | test/diff/Makefile | 34 | ||||
-rw-r--r-- | test/diff/diff.lm | 84 | ||||
-rw-r--r-- | test/diff/input1.diff | 86 | ||||
-rw-r--r-- | test/dns/Makefile | 20 | ||||
-rw-r--r-- | test/dns/dns.lm | 488 | ||||
-rw-r--r-- | test/dns/dumpdns | 11 | ||||
-rw-r--r-- | test/dns/extract.c | 48 | ||||
-rw-r--r-- | test/heredoc.in | 3 | ||||
-rw-r--r-- | test/heredoc.lm | 45 | ||||
-rw-r--r-- | test/html/Makefile | 34 | ||||
-rw-r--r-- | test/html/html-lextag.lm | 324 | ||||
-rw-r--r-- | test/html/html.lm | 307 | ||||
-rw-r--r-- | test/html/input01.html | 8 | ||||
-rw-r--r-- | test/http/Makefile | 34 | ||||
-rw-r--r-- | test/http/http.lm | 68 | ||||
-rw-r--r-- | test/http/input1 | 2 | ||||
-rw-r--r-- | test/http/input2 | 13 | ||||
-rw-r--r-- | test/http/input3 | 8 | ||||
-rw-r--r-- | test/http/xinetd.conf | 10 | ||||
-rw-r--r-- | test/island.in | 19 | ||||
-rw-r--r-- | test/island.lm | 57 | ||||
-rw-r--r-- | test/liftattrs.in | 3 | ||||
-rw-r--r-- | test/liftattrs.lm | 74 | ||||
-rw-r--r-- | test/mailbox.in | 29 | ||||
-rw-r--r-- | test/mailbox.lm | 44 | ||||
-rw-r--r-- | test/matchex.in | 3 | ||||
-rw-r--r-- | test/matchex.lm | 34 | ||||
-rw-r--r-- | test/maxlen.lm | 44 | ||||
-rw-r--r-- | test/mediawiki/Makefile | 43 | ||||
-rw-r--r-- | test/mediawiki/garticle.rl | 135 | ||||
-rw-r--r-- | test/mediawiki/mediawiki.lm | 196 | ||||
-rw-r--r-- | test/mediawiki/pdump.rl | 115 | ||||
-rw-r--r-- | test/nestedcomm.in | 1 | ||||
-rw-r--r-- | test/nestedcomm.lm | 41 | ||||
-rw-r--r-- | test/python/Makefile | 33 | ||||
-rw-r--r-- | test/python/input1.py | 18 | ||||
-rw-r--r-- | test/python/input2.py | 20 | ||||
-rw-r--r-- | test/python/input3.py | 1 | ||||
-rw-r--r-- | test/python/input4.py | 10 | ||||
-rw-r--r-- | test/python/python.lm | 727 | ||||
-rw-r--r-- | test/ragelambig.in | 1 | ||||
-rw-r--r-- | test/ragelambig1.lm | 65 | ||||
-rw-r--r-- | test/ragelambig2.lm | 65 | ||||
-rw-r--r-- | test/ragelambig3.lm | 64 | ||||
-rw-r--r-- | test/ragelambig4.lm | 69 | ||||
-rw-r--r-- | test/rediv.in | 1 | ||||
-rw-r--r-- | test/rediv.lm | 92 | ||||
-rw-r--r-- | test/ruby/Makefile | 34 | ||||
-rw-r--r-- | test/ruby/ruby.lm | 606 | ||||
-rw-r--r-- | test/rubyhere.in | 8 | ||||
-rw-r--r-- | test/rubyhere.lm | 89 | ||||
-rw-r--r-- | test/string.in | 2 | ||||
-rw-r--r-- | test/string.lm | 54 | ||||
-rw-r--r-- | test/superid.in | 1 | ||||
-rw-r--r-- | test/superid.lm | 59 | ||||
-rw-r--r-- | test/tags.in | 1 | ||||
-rw-r--r-- | test/tags.lm | 82 | ||||
-rw-r--r-- | test/til.in | 14 | ||||
-rw-r--r-- | test/til.lm | 168 | ||||
-rw-r--r-- | test/travs1.in | 1 | ||||
-rw-r--r-- | test/travs1.lm | 144 | ||||
-rw-r--r-- | test/travs2.in | 1 | ||||
-rw-r--r-- | test/travs2.lm | 93 | ||||
-rw-r--r-- | test/xml/Makefile | 34 | ||||
-rw-r--r-- | test/xml/xml.in | 3962 | ||||
-rw-r--r-- | test/xml/xml.lm | 168 | ||||
-rw-r--r-- | version.mk | 2 |
193 files changed, 27383 insertions, 131 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..ec0507be --- /dev/null +++ b/COPYING @@ -0,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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 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. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile.in b/Makefile.in index 9b247eae..c16f4e8d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -19,143 +19,57 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# Logging: -# colm: rt on/off -# rt_prd: off -# rt_db: on -# rt_clm: rt on/off - -INCS += -I../aapl - -DEFS_COLM += -DCOLM_LOG -DPREFIX='"$(prefix)"' -DEFS_RT_P += -DEFS_RT_D += -DCOLM_LOG - -CFLAGS += -g -Wall -Wwrite-strings -LDFLAGS += - -# Frequently changed ones first. -COLM_SRC = \ - compile.cpp \ - lmparse.cpp \ - lmscan.cpp \ - parsetree.cpp \ - parsedata.cpp \ - fsmstate.cpp \ - fsmbase.cpp \ - fsmattach.cpp \ - fsmmin.cpp \ - fsmgraph.cpp \ - pdagraph.cpp \ - pdabuild.cpp \ - pdacodegen.cpp \ - fsmcodegen.cpp \ - redfsm.cpp \ - fsmexec.cpp \ - main.cpp \ - redbuild.cpp \ - closure.cpp \ - fsmap.cpp \ - dotgen.cpp \ - pcheck.cpp - -RUNTIME_SRC = fsmrun.cpp pdarun.cpp bytecode.cpp list.cpp \ - map.cpp string.cpp input.cpp tree.cpp - -ALL_SRC = $(COLM_SRC) $(RUNTIME_SRC) - -# Files in ALL_SRC that are generated. -GEN_SRC = version.h lmscan.cpp lmparse.h lmparse.cpp - -RUNTIME_P = libcolmp.a -RUNTIME_D = libcolmd.a - -LIBS = +BUILD_SUBDIRS = colm +ALL_SUBDIRS = $(BUILD_SUBDIRS) test #************************************* -# Get the version info. -include ../version.mk - -prefix = @prefix@ - -BUILD_PARSERS = @BUILD_PARSERS@ - # Programs CXX = @CXX@ -# Get objects and dependencies from sources. -COLM_OBJ = $(COLM_SRC:%.cpp=%.o) -RUNTIME_OBJ_P = $(RUNTIME_SRC:%.cpp=%_p.o) -RUNTIME_OBJ_D = $(RUNTIME_SRC:%.cpp=%_d.o) - -DEPS = $(COLM_SRC:%.cpp=.%.d) $(RUNTIME_SRC:%.cpp=.%_p.d) $(RUNTIME_SRC:%.cpp=.%_d.d) - -# Rules. -all: colm $(RUNTIME_P) $(RUNTIME_D) +# Get the version info. +include version.mk -colm: $(GEN_SRC) $(COLM_OBJ) $(RUNTIME_OBJ_D) $(LIBS) - $(CXX) $(LDFLAGS) -o $@ $(COLM_OBJ) $(RUNTIME_OBJ_D) $(LIBS) +# build targets +all: $(BUILD_SUBDIRS) -$(RUNTIME_P): $(RUNTIME_OBJ_P) - ar -cr $@ $^ +.PHONY: $(BUILD_SUBDIRS) -$(RUNTIME_D): $(RUNTIME_OBJ_D) - ar -cr $@ $^ +$(BUILD_SUBDIRS): + @cd $@ && $(MAKE) -version.h: ../version.mk - echo '#define VERSION "$(VERSION)"' > version.h - echo '#define PUBDATE "$(PUBDATE)"' >> version.h +# clean targets. -ifeq ($(BUILD_PARSERS),true) +CLEAN_SUBDIRS = $(ALL_SUBDIRS:%=%-clean) -lmparse.h: lmparse.kh - kelbt -o $@ $< +.PHONY: $(CLEAN_SUBDIRS) -lmparse.cpp: lmparse.kl lmparse.kh - kelbt -o $@ $< +$(CLEAN_SUBDIRS): + @cd $(@:%-clean=%) && $(MAKE) clean -lmscan.cpp: lmparse.h +clean: $(CLEAN_SUBDIRS) + rm -f tags -lmscan.cpp: lmscan.rl - ragel -G2 -o $@ $< +# distcleaan targets -endif +DISTCLEAN_SUBDIRS = $(ALL_SUBDIRS:%=%-distclean) -$(COLM_OBJ): %.o: %.cpp - @$(CXX) -M $(DEFS_COLM) $(INCS) $< > .$*.d - $(CXX) -c $(CFLAGS) $(DEFS_COLM) $(INCS) -o $@ $< +.PHONY: $(DISTCLEAN_SUBDIRS) -$(RUNTIME_OBJ_P): %_p.o: %.cpp - @$(CXX) -M -MT $@ $(DEFS_RT_P) $(INCS) $< > .$*_p.d - $(CXX) -c $(CFLAGS) $(DEFS_RT_P) $(INCS) -o $@ $< +$(DISTCLEAN_SUBDIRS): + @cd $(@:%-distclean=%) && $(MAKE) clean -$(RUNTIME_OBJ_D): %_d.o: %.cpp - @$(CXX) -M -MT $@ $(DEFS_RT_D) $(INCS) $< > .$*_d.d - $(CXX) -c $(CFLAGS) $(DEFS_RT_D) $(INCS) -o $@ $< +distclean: $(DISTCLEAN_SUBDIRS) + rm -f Makefile config.cache config.status config.log +#install targets -distclean: clean - rm -f Makefile config.h +INSTALL_SUBDIRS = $(BUILD_SUBDIRS:%=%-install) -ifeq ($(BUILD_PARSERS),true) -EXTRA_CLEAN = $(GEN_SRC) -endif +.PHONY: $(INSTALL_SUBDIRS) -clean: - rm -f tags .*.d *.o colm $(EXTRA_CLEAN) $(RUNTIME_P) $(RUNTIME_D) +$(INSTALL_SUBDIRS): + @cd $(@:%-install=%) && $(MAKE) install -install: all - install -d $(prefix)/bin - install -d $(prefix)/include - install -d $(prefix)/include/colm - install -d $(prefix)/lib - install -s colm $(prefix)/bin/colm - install libcolmp.a libcolmd.a $(prefix)/lib - install ../aapl/astring.h ../aapl/avlcommon.h ../aapl/avlmap.h \ - ../aapl/compare.h ../aapl/dlcommon.h ../aapl/dlist.h \ - ../aapl/dlistval.h ../aapl/resize.h ../aapl/table.h \ - ../aapl/vector.h bytecode.h config.h fsmrun.h input.h \ - pdarun.h $(prefix)/include/colm +install: $(INSTALL_SUBDIRS) --include $(DEPS) @@ -0,0 +1,43 @@ +BUILDING +======== + +Colm is currently supported only on Unix-like systems. It depends on the mmap +function and it must be able to find g++ on the path. + +Building Colm from the source repository requires that you have ragel and kelbt +installed. Building these two packages is straightforward. The usual +./configure && make should be all that's needed. Alternatively, you may find +packages for your system. + +http://www.complang.org/ragel/ +http://www.complang.org/kelbt/ + +SYNTAX HIGHLIGHTING +=================== + +There is a vim syntax definition file colm.vim + +RUNNING +======= + +The colm executable takes a Colm program and generates a .cpp file from it. It +then compiles this program using g++. The g++ compile phase depends on include +directories in the colm distribution, as well as a runtime library. Colm finds +these using argv[0]: + + -I dirname(argv[0])"../aapl" + -I dirname(argv[0])"../colm" + dirname(argv[0])"../colm/runtime.a" + +Therefore it is easiest to just run colm from the place it was built. This is +temporary. In the future a proper install scheme will be provided. + +$ ./colm prog.lm + +Will produce: + prog.cpp + prog.bin + +The prog.bin program can then be run on some input: + +$ ./prog.bin < inputfile diff --git a/aapl/COPYING b/aapl/COPYING new file mode 100644 index 00000000..c6ed510b --- /dev/null +++ b/aapl/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/aapl/README b/aapl/README new file mode 100644 index 00000000..a2fa5e65 --- /dev/null +++ b/aapl/README @@ -0,0 +1,6 @@ +This directory contains the Aapl source distribution. For the +documentation, build scripts, test programs, ChangeLog, etc. get the +aapldev package. + +AaplDev and other information about Aapl is available from +http://www.elude.ca/aapl/ diff --git a/aapl/astring.h b/aapl/astring.h new file mode 100644 index 00000000..59343726 --- /dev/null +++ b/aapl/astring.h @@ -0,0 +1,809 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_ASTRING_H +#define _AAPL_ASTRING_H + +#include <new> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <assert.h> + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +#ifdef AAPL_DOCUMENTATION + +/** + * \defgroup astring String + * \brief Implicitly shared copy-on-write string. + * + * @{ + */ + +/** + * \class String + * \brief Implicitly shared copy-on-write string. + */ + +/*@}*/ + +class String +{ +public: + /** + * \brief Create a null string. Data points to NULL. + */ + String(); + + /** + * \brief Construct a string from a c-style string. + * + * A new buffer is allocated for the c string. Initially, this string will + * be the only String class referencing the data. + */ + String( const char *s ); + + /** + * \brief Construct a string from a c-style string of specific length. + * + * A new buffer is allocated for the c string. Initially, this string will + * be the only String class referencing the data. + */ + String( const char *s, long len ); + + /** + * \brief Construct a string from another String. + * + * A refernce to the buffer allocated for s is taken. A new buffer is + * not allocated. + */ + String( const String &s ); + + /** + * \brief Construct a string using snprintf. + * + * Requires a maximum length for the resulting string. If the formatting + * (not including trailing null) requires more space than maxLen, the + * result will be truncated to maxLen long. Only the length actually + * written will be used by the new string. This string will be the only + * String class referencing the data. + */ + String( long maxLen, const char *format, ... ) + + /** + * \brief Clean up the string. + * + * If the string is not null, the referenced data is detached. If no other + * string refernces the detached data, it is deleted. + */ + ~String(); + + /** + * \brief Set the string from a c-style string. + * + * If this string is not null, the current buffer is dereferenced and + * possibly deleted. A new buffer is allocated (or possibly the old buffer + * reused) for the string. Initially, this string will be the only String + * class referencing the data. + * + * If s is null, then this string becomes a null ptr. + * + * \returns A reference to this. + */ + String &operator=( const char *s ); + + /** + * \brief Set the string from a c-style of specific length. + * + * If this string is not null, the current buffer is dereferenced and + * possibly deleted. A new buffer is allocated (or possibly the old buffer + * reused) for the string. Initially, this string will be the only String + * class referencing the data. + * + * If s is null, then this string becomes a null ptr. + * + * \returns A reference to this. + */ + void setAs( const char *s, long len ); + + /** + * \brief Set the string from a single char. + * + * The current buffer is dereferenced and possibly deleted. A new buffer + * is allocated (or possibly the old buffer reused) for the string. + * Initially, this string will be the only String class referencing the + * data. + * + * If s is null, then this string becomes a null ptr. + * + * \returns A reference to this. + */ + String &operator=( const char c ); + + + /** + * \brief Set the string from another String. + * + * If this string is not null, the current buffer is dereferenced and + * possibly deleted. A reference to the buffer allocated for s is taken. + * A new buffer is not allocated. + * + * If s is null, then this string becomes a null ptr. + * + * \returns a reference to this. + */ + String &operator=( const String &s ); + + /** + * \brief Append a c string to the end of this string. + * + * If this string shares its allocation with another, a copy is first + * taken. The buffer for this string is grown and s is appended to the + * end. + * + * If s is null nothing happens. + * + * \returns a reference to this. + */ + String &operator+=( const char *s ); + + /** + * \brief Append a c string of specific length to the end of this string. + * + * If this string shares its allocation with another, a copy is first + * taken. The buffer for this string is grown and s is appended to the + * end. + * + * If s is null nothing happens. + * + * \returns a reference to this. + */ + void append( const char *s, long len ); + + /** + * \brief Append a single char to the end of this string. + * + * If this string shares its allocation with another, a copy is first + * taken. The buffer for this string is grown and s is appended to the + * end. + * + * \returns a reference to this. + */ + String &operator+=( const char c ); + + /** + * \brief Append a String to the end of this string. + * + * If this string shares its allocation with another, a copy is first + * taken. The buffer for this string is grown and the data of s is + * appeneded to the end. + * + * If s is null nothing happens. + * + * returns a reference to this. + */ + String &operator+=( const String &s ); + + /** + * \brief Cast to a char star. + * + * \returns the string data. A null string returns 0. + */ + operator char*() const; + + /** + * \brief Get a pointer to the data. + * + * \returns the string Data + */ + char *get() const; + + /** + * \brief Get the length of the string + * + * If the string is null, then undefined behaviour results. + * + * \returns the length of the string. + */ + long length() const; + + /** + * \brief Pointer to the data. + * + * Publically accessible pointer to the data. Immediately in front of the + * string data block is the string header which stores the refcount and + * length. Consequently, care should be taken if modifying this pointer. + */ + char *data; +}; + +/** + * \relates String + * \brief Concatenate a c-style string and a String. + * + * \returns The concatenation of the two strings in a String. + */ +String operator+( const String &s1, const char *s2 ); + +/** + * \relates String + * \brief Concatenate a String and a c-style string. + * + * \returns The concatenation of the two strings in a String. + */ +String operator+( const char *s1, const String &s2 ); + +/** + * \relates String + * \brief Concatenate two String classes. + * + * \returns The concatenation of the two strings in a String. + */ +String operator+( const String &s1, const String &s2 ); + +#endif + +template<class T> class StrTmpl +{ +public: + class Fresh {}; + + /* Header located just before string data. Keeps the length and a refcount on + * the data. */ + struct Head + { + long refCount; + long length; + }; + + /** + * \brief Create a null string. + */ + StrTmpl() : data(0) { } + + /* Clean up the string. */ + ~StrTmpl(); + + /* Construct a string from a c-style string. */ + StrTmpl( const char *s ); + + /* Construct a string from a c-style string of specific len. */ + StrTmpl( const char *s, long len ); + + /* Allocate len spaces. */ + StrTmpl( const Fresh &, long len ); + + /* Construct a string from another StrTmpl. */ + StrTmpl( const StrTmpl &s ); + + /* Construct a string from with, sprintf. */ + StrTmpl( long lenGuess, const char *format, ... ); + + /* Set the string from a c-style string. */ + StrTmpl &operator=( const char *s ); + + /* Set the string from a c-style string of specific len. */ + void setAs( const char *s, long len ); + + /* Allocate len spaces. */ + void setAs( const Fresh &, long len ); + + void chop( long len ); + + /* Construct a string from with, sprintf. */ + void setAs( long lenGuess, const char *format, ... ); + + /* Set the string from a single char. */ + StrTmpl &operator=( const char c ); + + /* Set the string from another StrTmpl. */ + StrTmpl &operator=( const StrTmpl &s ); + + /* Append a c string to the end of this string. */ + StrTmpl &operator+=( const char *s ); + + /* Append a c string to the end of this string of specifi len. */ + void append( const char *s, long len ); + + /* Append a single char to the end of this string. */ + StrTmpl &operator+=( const char c ); + + /* Append an StrTmpl to the end of this string. */ + StrTmpl &operator+=( const StrTmpl &s ); + + /* Cast to a char star. */ + operator char*() const { return data; } + + /* Get a pointer to the data. */ + char *get() const { return data; } + + /* Return the length of the string. Must check for null data pointer. */ + long length() const { return data ? (((Head*)data)-1)->length : 0; } + + /** + * \brief Pointer to the data. + */ + char *data; + +protected: + /* Make space for a string of length len to be appended. */ + char *appendSpace( long len ); + void initSpace( long length ); + void setSpace( long length ); + + template <class FT> friend StrTmpl<FT> operator+( + const StrTmpl<FT> &s1, const char *s2 ); + template <class FT> friend StrTmpl<FT> operator+( + const char *s1, const StrTmpl<FT> &s2 ); + template <class FT> friend StrTmpl<FT> operator+( + const StrTmpl<FT> &s1, const StrTmpl<FT> &s2 ); + +private: + /* A dummy struct solely to make a constructor that will never be + * ambiguous with the public constructors. */ + struct DisAmbig { }; + StrTmpl( char *data, const DisAmbig & ) : data(data) { } +}; + +/* Free all mem used by the string. */ +template<class T> StrTmpl<T>::~StrTmpl() +{ + if ( data != 0 ) { + /* If we are the only ones referencing the string, then delete it. */ + Head *head = ((Head*) data) - 1; + head->refCount -= 1; + if ( head->refCount == 0 ) + free( head ); + } +} + +/* Create from a c-style string. */ +template<class T> StrTmpl<T>::StrTmpl( const char *s ) +{ + if ( s == 0 ) + data = 0; + else { + /* Find the length and allocate the space for the shared string. */ + long length = strlen( s ); + + /* Init space for the data. */ + initSpace( length ); + + /* Copy in the data. */ + memcpy( data, s, length+1 ); + } +} + +/* Create from a c-style string. */ +template<class T> StrTmpl<T>::StrTmpl( const char *s, long length ) +{ + if ( s == 0 ) + data = 0; + else { + /* Init space for the data. */ + initSpace( length ); + + /* Copy in the data. */ + memcpy( data, s, length ); + data[length] = 0; + } +} + +/* Create from a c-style string. */ +template<class T> StrTmpl<T>::StrTmpl( const Fresh &, long length ) +{ + /* Init space for the data. */ + initSpace( length ); + data[length] = 0; +} + +/* Create from another string class. */ +template<class T> StrTmpl<T>::StrTmpl( const StrTmpl &s ) +{ + if ( s.data == 0 ) + data = 0; + else { + /* Take a reference to the string. */ + Head *strHead = ((Head*)s.data) - 1; + strHead->refCount += 1; + data = (char*) (strHead+1); + } +} + +/* Construct a string from with, sprintf. */ +template<class T> StrTmpl<T>::StrTmpl( long lenGuess, const char *format, ... ) +{ + /* Set the string for len. */ + initSpace( lenGuess ); + + va_list args; + + /* Write to the temporary buffer. */ + va_start( args, format ); + + long written = vsnprintf( data, lenGuess+1, format, args ); + if ( written > lenGuess ) { + setSpace( written ); + written = vsnprintf( data, written+1, format, args ); + } + chop( written ); + + va_end( args ); +} + +/* Construct a string from with, sprintf. */ +template<class T> void StrTmpl<T>::setAs( long lenGuess, const char *format, ... ) +{ + /* Set the string for len. */ + setSpace( lenGuess ); + + va_list args; + + /* Write to the temporary buffer. */ + va_start( args, format ); + + long written = vsnprintf( data, lenGuess+1, format, args ); + if ( written > lenGuess ) { + setSpace( written ); + written = vsnprintf( data, written+1, format, args ); + } + chop( written ); + + va_end( args ); +} + +template<class T> void StrTmpl<T>::initSpace( long length ) +{ + /* Find the length and allocate the space for the shared string. */ + Head *head = (Head*) malloc( sizeof(Head) + length+1 ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Init the header. */ + head->refCount = 1; + head->length = length; + + /* Save the pointer to the data. */ + data = (char*) (head+1); +} + + +/* Set this string to be the c string exactly. The old string is discarded. + * Returns a reference to this. */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator=( const char *s ) +{ + if ( s == 0 ) { + /* Just free the data, we are being set to null. */ + if ( data != 0 ) { + Head *head = ((Head*)data) - 1; + head->refCount -= 1; + if ( head->refCount == 0 ) + free(head); + data = 0; + } + } + else { + /* Find the length of the string we are setting. */ + long length = strlen( s ); + + /* Set the string for len. */ + setSpace( length ); + + /* Copy in the data. */ + memcpy( data, s, length+1 ); + } + return *this; +} + +/* Set this string to be the c string exactly. The old string is discarded. + * Returns a reference to this. */ +template<class T> void StrTmpl<T>::setAs( const char *s, long length ) +{ + if ( s == 0 ) { + /* Just free the data, we are being set to null. */ + if ( data != 0 ) { + Head *head = ((Head*)data) - 1; + head->refCount -= 1; + if ( head->refCount == 0 ) + free(head); + data = 0; + } + } + else { + /* Set the string for len. */ + setSpace( length ); + + /* Copy in the data. */ + memcpy( data, s, length ); + data[length] = 0; + } +} + +template<class T> void StrTmpl<T>::chop( long length ) +{ + /* Detach from the existing string. */ + Head *head = ((Head*)data) - 1; + assert( head->refCount == 1 ); + assert( length <= head->length ); + head->length = length; + data[length] = 0; +} + +/* Set this string to be the c string exactly. The old string is discarded. + * Returns a reference to this. */ +template<class T> void StrTmpl<T>::setAs( const Fresh &, long length ) +{ + setSpace( length ); + data[length] = 0; +} + +/* Set this string to be the single char exactly. The old string is discarded. + * Returns a reference to this. */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator=( const char c ) +{ + /* Set to length 1. */ + setSpace( 1 ); + + /* Copy in the data. */ + data[0] = c; + data[1] = 0; + + /* Return ourselves. */ + return *this; +} + +/* Set this string to be the StrTmpl s exactly. The old string is + * discarded. */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator=( const StrTmpl &s ) +{ + /* Detach from the existing string. */ + if ( data != 0 ) { + Head *head = ((Head*)data) - 1; + head->refCount -= 1; + if ( head->refCount == 0 ) + free( head ); + } + + if ( s.data != 0 ) { + /* Take a reference to the string. */ + Head *strHead = ((Head*)s.data) - 1; + strHead->refCount += 1; + data = (char*)(strHead+1); + } + else { + /* Setting from a null string, just null our pointer. */ + data = 0; + } + return *this; +} + +/* Prepare the string to be set to something else of the given length. */ +template<class T> void StrTmpl<T>::setSpace( long length ) +{ + /* Detach from the existing string. */ + Head *head = ((Head*)data) - 1; + if ( data != 0 && --head->refCount == 0 ) { + /* Resuse the space. */ + head = (Head*) realloc( head, sizeof(Head) + length+1 ); + } + else { + /* Need to make new space, there is no usable old space. */ + head = (Head*) malloc( sizeof(Head) + length+1 ); + } + if ( head == 0 ) + throw std::bad_alloc(); + + /* Init the header. */ + head->refCount = 1; + head->length = length; + + /* Copy in the data and save the pointer to it. */ + data = (char*) (head+1); +} + + +/* Append a c-style string to the end of this string. Returns a reference to + * this */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator+=( const char *s ) +{ + /* Find the length of the string appended. */ + if ( s != 0 ) { + /* Get the string length and make space on the end. */ + long addedLen = strlen( s ); + char *dest = appendSpace( addedLen ); + + /* Copy the data in. Plus one for the null. */ + memcpy( dest, s, addedLen+1 ); + } + return *this; +} + +/* Append a c-style string of specific length to the end of this string. + * Returns a reference to this */ +template<class T> void StrTmpl<T>::append( const char *s, long length ) +{ + /* Find the length of the string appended. */ + if ( s != 0 ) { + /* Make space on the end. */ + char *dest = appendSpace( length ); + + /* Copy the data in. Plus one for the null. */ + memcpy( dest, s, length ); + dest[length] = 0; + } +} + +/* Append a single char to the end of this string. Returns a reference to + * this */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator+=( const char c ) +{ + /* Grow on the end. */ + char *dst = appendSpace( 1 ); + + /* Append a single charachter. */ + dst[0] = c; + dst[1] = 0; + return *this; +} + + +/* Append an StrTmpl string to the end of this string. Returns a reference + * to this */ +template<class T> StrTmpl<T> &StrTmpl<T>::operator+=( const StrTmpl &s ) +{ + /* Find the length of the string appended. */ + if ( s.data != 0 ) { + /* Find the length to append. */ + long addedLen = (((Head*)s.data) - 1)->length; + + /* Make space on the end to put the string. */ + char *dest = appendSpace( addedLen ); + + /* Append the data, add one for the null. */ + memcpy( dest, s.data, addedLen+1 ); + } + return *this; +} + +/* Make space for a string of length len to be appended. */ +template<class T> char *StrTmpl<T>::appendSpace( long len ) +{ + /* Find the length of this and the string appended. */ + Head *head = (((Head*)data) - 1); + long thisLen = head->length; + + if ( head->refCount == 1 ) { + /* No other string is using the space, grow this space. */ + head = (Head*) realloc( head, + sizeof(Head) + thisLen + len + 1 ); + if ( head == 0 ) + throw std::bad_alloc(); + data = (char*) (head+1); + + /* Adjust the length. */ + head->length += len; + } + else { + /* Another string is using this space, make new space. */ + head->refCount -= 1; + Head *newHead = (Head*) malloc( + sizeof(Head) + thisLen + len + 1 ); + if ( newHead == 0 ) + throw std::bad_alloc(); + data = (char*) (newHead+1); + + /* Set the new header and data from this. */ + newHead->refCount = 1; + newHead->length = thisLen + len; + memcpy( data, head+1, thisLen ); + } + + /* Return writing position. */ + return data + thisLen; +} + +/* Concatenate a String and a c-style string. */ +template<class T> StrTmpl<T> operator+( const StrTmpl<T> &s1, const char *s2 ) +{ + /* Find s2 length and alloc the space for the result. */ + long str1Len = (((typename StrTmpl<T>::Head*)(s1.data)) - 1)->length; + long str2Len = strlen( s2 ); + + typename StrTmpl<T>::Head *head = (typename StrTmpl<T>::Head*) + malloc( sizeof(typename StrTmpl<T>::Head) + str1Len + str2Len + 1 ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Set up the header. */ + head->refCount = 1; + head->length = str1Len + str2Len; + + /* Save the pointer to data and copy the data in. */ + char *data = (char*) (head+1); + memcpy( data, s1.data, str1Len ); + memcpy( data + str1Len, s2, str2Len + 1 ); + return StrTmpl<T>( data, typename StrTmpl<T>::DisAmbig() ); +} + +/* Concatenate a c-style string and a String. */ +template<class T> StrTmpl<T> operator+( const char *s1, const StrTmpl<T> &s2 ) +{ + /* Find s2 length and alloc the space for the result. */ + long str1Len = strlen( s1 ); + long str2Len = (((typename StrTmpl<T>::Head*)(s2.data)) - 1)->length; + + typename StrTmpl<T>::Head *head = (typename StrTmpl<T>::Head*) + malloc( sizeof(typename StrTmpl<T>::Head) + str1Len + str2Len + 1 ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Set up the header. */ + head->refCount = 1; + head->length = str1Len + str2Len; + + /* Save the pointer to data and copy the data in. */ + char *data = (char*) (head+1); + memcpy( data, s1, str1Len ); + memcpy( data + str1Len, s2.data, str2Len + 1 ); + return StrTmpl<T>( data, typename StrTmpl<T>::DisAmbig() ); +} + +/* Add two StrTmpl strings. */ +template<class T> StrTmpl<T> operator+( const StrTmpl<T> &s1, const StrTmpl<T> &s2 ) +{ + /* Find s2 length and alloc the space for the result. */ + long str1Len = (((typename StrTmpl<T>::Head*)(s1.data)) - 1)->length; + long str2Len = (((typename StrTmpl<T>::Head*)(s2.data)) - 1)->length; + typename StrTmpl<T>::Head *head = (typename StrTmpl<T>::Head*) + malloc( sizeof(typename StrTmpl<T>::Head) + str1Len + str2Len + 1 ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Set up the header. */ + head->refCount = 1; + head->length = str1Len + str2Len; + + /* Save the pointer to data and copy the data in. */ + char *data = (char*) (head+1); + memcpy( data, s1.data, str1Len ); + memcpy( data + str1Len, s2.data, str2Len + 1 ); + return StrTmpl<T>( data, typename StrTmpl<T>::DisAmbig() ); +} + +/* Operator used in case the compiler does not support the conversion. */ +template <class T> inline std::ostream &operator<<( std::ostream &o, const StrTmpl<T> &s ) +{ + return o.write( s.data, s.length() ); +} + +typedef StrTmpl<char> String; + + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_ASTRING_H */ diff --git a/aapl/avlbasic.h b/aapl/avlbasic.h new file mode 100644 index 00000000..ed826f38 --- /dev/null +++ b/aapl/avlbasic.h @@ -0,0 +1,65 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLBASIC_H +#define _AAPL_AVLBASIC_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlBasic + * \brief AVL Tree in which the entire element structure is the key. + * + * AvlBasic is an AVL tree that does not distinguish between the element that + * it contains and the key. The entire element structure is the key that is + * used to compare the relative ordering of elements. This is similar to the + * BstSet structure. + * + * AvlBasic does not assume ownership of elements in the tree. Items must be + * explicitly de-allocated. + */ + +/*@}*/ + +#define BASE_EL(name) name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Element, class Compare +#define AVLMEL_TEMPDEF class Element, class Compare +#define AVLMEL_TEMPUSE Element, Compare +#define AvlTree AvlBasic +#define AVL_BASIC + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef AVL_BASIC + +#endif /* _AAPL_AVLBASIC_H */ diff --git a/aapl/avlcommon.h b/aapl/avlcommon.h new file mode 100644 index 00000000..6cb0b89a --- /dev/null +++ b/aapl/avlcommon.h @@ -0,0 +1,1630 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This header is not wrapped in ifndef becuase it is not intended to + * be included by the user. */ + +#include <assert.h> + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +#ifdef WALKABLE +/* This is used by AvlTree, AvlMel and AvlMelKey so it + * must be protected by global ifdefs. */ +#ifndef __AAPL_AVLI_EL__ +#define __AAPL_AVLI_EL__ + +/** + * \brief Tree element properties for linked AVL trees. + * + * AvliTreeEl needs to be inherited by classes that intend to be element in an + * AvliTree. + */ +template<class SubClassEl> struct AvliTreeEl +{ + /** + * \brief Tree pointers connecting element in a tree. + */ + SubClassEl *left, *right, *parent; + + /** + * \brief Linked list pointers. + */ + SubClassEl *prev, *next; + + /** + * \brief Height of the tree rooted at this element. + * + * Height is required by the AVL balancing algorithm. + */ + long height; +}; +#endif /* __AAPL_AVLI_EL__ */ + +#else /* not WALKABLE */ + +/* This is used by All the non walkable trees so it must be + * protected by a global ifdef. */ +#ifndef __AAPL_AVL_EL__ +#define __AAPL_AVL_EL__ +/** + * \brief Tree element properties for linked AVL trees. + * + * AvlTreeEl needs to be inherited by classes that intend to be element in an + * AvlTree. + */ +template<class SubClassEl> struct AvlTreeEl +{ + /** + * \brief Tree pointers connecting element in a tree. + */ + SubClassEl *left, *right, *parent; + + /** + * \brief Height of the tree rooted at this element. + * + * Height is required by the AVL balancing algorithm. + */ + long height; +}; +#endif /* __AAPL_AVL_EL__ */ +#endif /* def WALKABLE */ + + +#if defined( AVLTREE_MAP ) + +#ifdef WALKABLE + +/** + * \brief Tree element for AvliMap + * + * Stores the key and value pair. + */ +template <class Key, class Value> struct AvliMapEl : + public AvliTreeEl< AvliMapEl<Key, Value> > +{ + AvliMapEl(const Key &key) + : key(key) { } + AvliMapEl(const Key &key, const Value &value) + : key(key), value(value) { } + + const Key &getKey() const { return key; } + + /** \brief The key. */ + Key key; + + /** \brief The value. */ + Value value; +}; +#else /* not WALKABLE */ + +/** + * \brief Tree element for AvlMap + * + * Stores the key and value pair. + */ +template <class Key, class Value> struct AvlMapEl : + public AvlTreeEl< AvlMapEl<Key, Value> > +{ + AvlMapEl(const Key &key) + : key(key) { } + AvlMapEl(const Key &key, const Value &value) + : key(key), value(value) { } + + const Key &getKey() const { return key; } + + /** \brief The key. */ + Key key; + + /** \brief The value. */ + Value value; +}; +#endif /* def WALKABLE */ + +#elif defined( AVLTREE_SET ) + +#ifdef WALKABLE +/** + * \brief Tree element for AvliSet + * + * Stores the key. + */ +template <class Key> struct AvliSetEl : + public AvliTreeEl< AvliSetEl<Key> > +{ + AvliSetEl(const Key &key) : key(key) { } + + const Key &getKey() const { return key; } + + /** \brief The key. */ + Key key; +}; +#else /* not WALKABLE */ +/** + * \brief Tree element for AvlSet + * + * Stores the key. + */ +template <class Key> struct AvlSetEl : + public AvlTreeEl< AvlSetEl<Key> > +{ + AvlSetEl(const Key &key) : key(key) { } + + const Key &getKey() const { return key; } + + /** \brief The key. */ + Key key; +}; +#endif /* def WALKABLE */ + +#endif /* AVLTREE_SET */ + +/* Common AvlTree Class */ +template < AVLMEL_CLASSDEF > class AvlTree +#if !defined( AVL_KEYLESS ) && defined ( WALKABLE ) + : public Compare, public BASELIST +#elif !defined( AVL_KEYLESS ) + : public Compare +#elif defined( WALKABLE ) + : public BASELIST +#endif +{ +public: + /** + * \brief Create an empty tree. + */ +#ifdef WALKABLE + AvlTree() : root(0), treeSize(0) { } +#else + AvlTree() : root(0), head(0), tail(0), treeSize(0) { } +#endif + + /** + * \brief Perform a deep copy of the tree. + * + * Each element is duplicated for the new tree. Copy constructors are used + * to create the new elements. + */ + AvlTree(const AvlTree &other); + +#if defined( AVLTREE_MAP ) || defined( AVLTREE_SET ) + /** + * \brief Clear the contents of the tree. + * + * All element are deleted. + */ + ~AvlTree() { empty(); } + + /** + * \brief Perform a deep copy of the tree. + * + * Each element is duplicated for the new tree. Copy constructors are used + * to create the new element. If this tree contains items, they are first + * deleted. + * + * \returns A reference to this. + */ + AvlTree &operator=( const AvlTree &tree ); + + /** + * \brief Transfer the elements of another tree into this. + * + * First deletes all elements in this tree. + */ + void transfer( AvlTree &tree ); +#else + /** + * \brief Abandon all elements in the tree. + * + * Tree elements are not deleted. + */ + ~AvlTree() {} + + /** + * \brief Perform a deep copy of the tree. + * + * Each element is duplicated for the new tree. Copy constructors are used + * to create the new element. If this tree contains items, they are + * abandoned. + * + * \returns A reference to this. + */ + AvlTree &operator=( const AvlTree &tree ); + + /** + * \brief Transfer the elements of another tree into this. + * + * All elements in this tree are abandoned first. + */ + void transfer( AvlTree &tree ); +#endif + +#ifndef AVL_KEYLESS + /* Insert a element into the tree. */ + Element *insert( Element *element, Element **lastFound = 0 ); + +#ifdef AVL_BASIC + /* Find a element in the tree. Returns the element if + * element exists, false otherwise. */ + Element *find( const Element *element ) const; + +#else + Element *insert( const Key &key, Element **lastFound = 0 ); + +#ifdef AVLTREE_MAP + Element *insert( const Key &key, const Value &val, + Element **lastFound = 0 ); +#endif + + /* Find a element in the tree. Returns the element if + * key exists, false otherwise. */ + Element *find( const Key &key ) const; + + /* Detach a element from the tree. */ + Element *detach( const Key &key ); + + /* Detach and delete a element from the tree. */ + bool remove( const Key &key ); +#endif /* AVL_BASIC */ +#endif /* AVL_KEYLESS */ + + /* Detach a element from the tree. */ + Element *detach( Element *element ); + + /* Detach and delete a element from the tree. */ + void remove( Element *element ); + + /* Free all memory used by tree. */ + void empty(); + + /* Abandon all element in the tree. Does not delete element. */ + void abandon(); + + /** Root element of the tree. */ + Element *root; + +#ifndef WALKABLE + Element *head, *tail; +#endif + + /** The number of element in the tree. */ + long treeSize; + + /** \brief Return the number of elements in the tree. */ + long length() const { return treeSize; } + + /** \brief Return the number of elements in the tree. */ + long size() const { return treeSize; } + + /* Various classes for setting the iterator */ + struct Iter; + struct IterFirst { IterFirst( const AvlTree &t ) : t(t) { } const AvlTree &t; }; + struct IterLast { IterLast( const AvlTree &t ) : t(t) { } const AvlTree &t; }; + struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; + struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; + +#ifdef WALKABLE + /** + * \brief Avl Tree Iterator. + * \ingroup iterators + */ + struct Iter + { + /* Default construct. */ + Iter() : ptr(0) { } + + /* Construct from an avl tree and iterator-setting classes. */ + Iter( const AvlTree &t ) : ptr(t.head) { } + Iter( const IterFirst &af ) : ptr(af.t.head) { } + Iter( const IterLast &al ) : ptr(al.t.tail) { } + Iter( const IterNext &an ) : ptr(findNext(an.i.ptr)) { } + Iter( const IterPrev &ap ) : ptr(findPrev(ap.i.ptr)) { } + + /* Assign from a tree and iterator-setting classes. */ + Iter &operator=( const AvlTree &tree ) { ptr = tree.head; return *this; } + Iter &operator=( const IterFirst &af ) { ptr = af.t.head; return *this; } + Iter &operator=( const IterLast &al ) { ptr = al.t.tail; return *this; } + Iter &operator=( const IterNext &an ) { ptr = findNext(an.i.ptr); return *this; } + Iter &operator=( const IterPrev &ap ) { ptr = findPrev(ap.i.ptr); return *this; } + + /** \brief Less than end? */ + bool lte() const { return ptr != 0; } + + /** \brief At end? */ + bool end() const { return ptr == 0; } + + /** \brief Greater than beginning? */ + bool gtb() const { return ptr != 0; } + + /** \brief At beginning? */ + bool beg() const { return ptr == 0; } + + /** \brief At first element? */ + bool first() const { return ptr && ptr->BASE_EL(prev) == 0; } + + /** \brief At last element? */ + bool last() const { return ptr && ptr->BASE_EL(next) == 0; } + + /** \brief Implicit cast to Element*. */ + operator Element*() const { return ptr; } + + /** \brief Dereference operator returns Element&. */ + Element &operator *() const { return *ptr; } + + /** \brief Arrow operator returns Element*. */ + Element *operator->() const { return ptr; } + + /** \brief Move to next item. */ + inline Element *operator++(); + + /** \brief Move to next item. */ + inline Element *operator++(int); + + /** \brief Move to next item. */ + inline Element *increment(); + + /** \brief Move to previous item. */ + inline Element *operator--(); + + /** \brief Move to previous item. */ + inline Element *operator--(int); + + /** \brief Move to previous item. */ + inline Element *decrement(); + + /** \brief Return the next item. Does not modify this. */ + IterNext next() const { return IterNext( *this ); } + + /** \brief Return the previous item. Does not modify this. */ + IterPrev prev() const { return IterPrev( *this ); } + + private: + static Element *findPrev( Element *element ) { return element->BASE_EL(prev); } + static Element *findNext( Element *element ) { return element->BASE_EL(next); } + + public: + + /** \brief The iterator is simply a pointer. */ + Element *ptr; + }; + +#else + + /** + * \brief Avl Tree Iterator. + * \ingroup iterators + */ + struct Iter + { + /* Default construct. */ + Iter() : ptr(0), tree(0) { } + + /* Construct from a tree and iterator-setting classes. */ + Iter( const AvlTree &t ) : ptr(t.head), tree(&t) { } + Iter( const IterFirst &af ) : ptr(af.t.head), tree(&af.t) { } + Iter( const IterLast &al ) : ptr(al.t.tail), tree(&al.t) { } + Iter( const IterNext &an ) : ptr(findNext(an.i.ptr)), tree(an.i.tree) { } + Iter( const IterPrev &ap ) : ptr(findPrev(ap.i.ptr)), tree(ap.i.tree) { } + + /* Assign from a tree and iterator-setting classes. */ + Iter &operator=( const AvlTree &t ) + { ptr = t.head; tree = &t; return *this; } + Iter &operator=( const IterFirst &af ) + { ptr = af.t.head; tree = &af.t; return *this; } + Iter &operator=( const IterLast &al ) + { ptr = al.t.tail; tree = &al.t; return *this; } + Iter &operator=( const IterNext &an ) + { ptr = findNext(an.i.ptr); tree = an.i.tree; return *this; } + Iter &operator=( const IterPrev &ap ) + { ptr = findPrev(ap.i.ptr); tree = ap.i.tree; return *this; } + + /** \brief Less than end? */ + bool lte() const { return ptr != 0; } + + /** \brief At end? */ + bool end() const { return ptr == 0; } + + /** \brief Greater than beginning? */ + bool gtb() const { return ptr != 0; } + + /** \brief At beginning? */ + bool beg() const { return ptr == 0; } + + /** \brief At first element? */ + bool first() const { return ptr && ptr == tree->head; } + + /** \brief At last element? */ + bool last() const { return ptr && ptr == tree->tail; } + + /** \brief Implicit cast to Element*. */ + operator Element*() const { return ptr; } + + /** \brief Dereference operator returns Element&. */ + Element &operator *() const { return *ptr; } + + /** \brief Arrow operator returns Element*. */ + Element *operator->() const { return ptr; } + + /** \brief Move to next item. */ + inline Element *operator++(); + + /** \brief Move to next item. */ + inline Element *operator++(int); + + /** \brief Move to next item. */ + inline Element *increment(); + + /** \brief Move to previous item. */ + inline Element *operator--(); + + /** \brief Move to previous item. */ + inline Element *operator--(int); + + /** \brief Move to previous item. */ + inline Element *decrement(); + + /** \brief Return the next item. Does not modify this. */ + IterNext next() const { return IterNext( *this ); } + + /** \brief Return the previous item. Does not modify this. */ + IterPrev prev() const { return IterPrev( *this ); } + + private: + static Element *findPrev( Element *element ); + static Element *findNext( Element *element ); + + public: + /** \brief The iterator is simply a pointer. */ + Element *ptr; + + /* The list is not walkable so we need to keep a pointerto the tree + * so we can test against head and tail in O(1) time. */ + const AvlTree *tree; + }; +#endif + + /** \brief Return first element. */ + IterFirst first() { return IterFirst( *this ); } + + /** \brief Return last element. */ + IterLast last() { return IterLast( *this ); } + +protected: + /* Recursive worker for the copy constructor. */ + Element *copyBranch( Element *element ); + + /* Recursively delete element in the tree. */ + void deleteChildrenOf(Element *n); + + /* rebalance the tree beginning at the leaf whose + * grandparent is unbalanced. */ + Element *rebalance(Element *start); + + /* Move up the tree from a given element, recalculating the heights. */ + void recalcHeights(Element *start); + + /* Move up the tree and find the first element whose + * grand-parent is unbalanced. */ + Element *findFirstUnbalGP(Element *start); + + /* Move up the tree and find the first element which is unbalanced. */ + Element *findFirstUnbalEl(Element *start); + + /* Replace a element in the tree with another element not in the tree. */ + void replaceEl(Element *element, Element *replacement); + + /* Remove a element from the tree and put another (normally a child of element) + * in its place. */ + void removeEl(Element *element, Element *filler); + + /* Once an insertion point is found at a leaf then do the insert. */ + void attachRebal( Element *element, Element *parentEl, Element *lastLess ); +}; + +/* Copy constructor. New up each item. */ +template <AVLMEL_TEMPDEF> AvlTree<AVLMEL_TEMPUSE>:: + AvlTree(const AvlTree<AVLMEL_TEMPUSE> &other) +#if !defined( AVL_KEYLESS ) && defined ( WALKABLE ) + /* BASELIST should be made empty. The copyBranch function + * will fill in the details for us. */ + : Compare( other ), BASELIST() +#elif !defined( AVL_KEYLESS ) + : Compare( other ) +#elif defined( WALKABLE ) + : BASELIST( ) +#endif +{ + treeSize = other.treeSize; + root = other.root; + +#ifndef WALKABLE + head = 0; + tail = 0; +#endif + + /* If there is a root, copy the tree. */ + if ( other.root != 0 ) + root = copyBranch( other.root ); +} + +#if defined( AVLTREE_MAP ) || defined( AVLTREE_SET ) + +/* Assignment does deep copy. */ +template <AVLMEL_TEMPDEF> AvlTree<AVLMEL_TEMPUSE> &AvlTree<AVLMEL_TEMPUSE>:: + operator=( const AvlTree &other ) +{ + /* Clear the tree first. */ + empty(); + + /* Reset the list pointers, the tree copy will fill in the list for us. */ +#ifdef WALKABLE + BASELIST::abandon(); +#else + head = 0; + tail = 0; +#endif + + /* Copy the entire tree. */ + treeSize = other.treeSize; + root = other.root; + if ( other.root != 0 ) + root = copyBranch( other.root ); + return *this; +} + +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + transfer(AvlTree<AVLMEL_TEMPUSE> &other) +{ + /* Clear the tree first. */ + empty(); + + treeSize = other.treeSize; + root = other.root; + +#ifdef WALKABLE + BASELIST::head = other.BASELIST::head; + BASELIST::tail = other.BASELIST::tail; + BASELIST::listLen = other.BASELIST::listLen; +#else + head = other.head; + tail = other.tail; +#endif + + other.abandon(); +} + +#else /* ! AVLTREE_MAP && ! AVLTREE_SET */ + +/* Assignment does deep copy. This version does not clear the tree first. */ +template <AVLMEL_TEMPDEF> AvlTree<AVLMEL_TEMPUSE> &AvlTree<AVLMEL_TEMPUSE>:: + operator=( const AvlTree &other ) +{ + /* Reset the list pointers, the tree copy will fill in the list for us. */ +#ifdef WALKABLE + BASELIST::abandon(); +#else + head = 0; + tail = 0; +#endif + + /* Copy the entire tree. */ + treeSize = other.treeSize; + root = other.root; + if ( other.root != 0 ) + root = copyBranch( other.root ); + return *this; +} + +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + transfer(AvlTree<AVLMEL_TEMPUSE> &other) +{ + treeSize = other.treeSize; + root = other.root; + +#ifdef WALKABLE + BASELIST::head = other.BASELIST::head; + BASELIST::tail = other.BASELIST::tail; + BASELIST::listLen = other.BASELIST::listLen; +#else + head = other.head; + tail = other.tail; +#endif + + other.abandon(); +} + +#endif + +/* + * Iterator operators. + */ + +/* Prefix ++ */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + operator++() +{ + return ptr = findNext( ptr ); +} + +/* Postfix ++ */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + operator++(int) +{ + Element *rtn = ptr; + ptr = findNext( ptr ); + return rtn; +} + +/* increment */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + increment() +{ + return ptr = findNext( ptr ); +} + +/* Prefix -- */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + operator--() +{ + return ptr = findPrev( ptr ); +} + +/* Postfix -- */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + operator--(int) +{ + Element *rtn = ptr; + ptr = findPrev( ptr ); + return rtn; +} + +/* decrement */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + decrement() +{ + return ptr = findPrev( ptr ); +} + +#ifndef WALKABLE + +/* Move ahead one. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + findNext( Element *element ) +{ + /* Try to go right once then infinite left. */ + if ( element->BASE_EL(right) != 0 ) { + element = element->BASE_EL(right); + while ( element->BASE_EL(left) != 0 ) + element = element->BASE_EL(left); + } + else { + /* Go up to parent until we were just a left child. */ + while ( true ) { + Element *last = element; + element = element->BASE_EL(parent); + if ( element == 0 || element->BASE_EL(left) == last ) + break; + } + } + return element; +} + +/* Move back one. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>::Iter:: + findPrev( Element *element ) +{ + /* Try to go left once then infinite right. */ + if ( element->BASE_EL(left) != 0 ) { + element = element->BASE_EL(left); + while ( element->BASE_EL(right) != 0 ) + element = element->BASE_EL(right); + } + else { + /* Go up to parent until we were just a left child. */ + while ( true ) { + Element *last = element; + element = element->BASE_EL(parent); + if ( element == 0 || element->BASE_EL(right) == last ) + break; + } + } + return element; +} + +#endif + + +/* Recursive worker for tree copying. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + copyBranch( Element *element ) +{ + /* Duplicate element. Either the base element's copy constructor or defaul + * constructor will get called. Both will suffice for initting the + * pointers to null when they need to be. */ + Element *retVal = new Element(*element); + + /* If the left tree is there, copy it. */ + if ( retVal->BASE_EL(left) ) { + retVal->BASE_EL(left) = copyBranch(retVal->BASE_EL(left)); + retVal->BASE_EL(left)->BASE_EL(parent) = retVal; + } + +#ifdef WALKABLE + BASELIST::addAfter( BASELIST::tail, retVal ); +#else + if ( head == 0 ) + head = retVal; + tail = retVal; +#endif + + /* If the right tree is there, copy it. */ + if ( retVal->BASE_EL(right) ) { + retVal->BASE_EL(right) = copyBranch(retVal->BASE_EL(right)); + retVal->BASE_EL(right)->BASE_EL(parent) = retVal; + } + return retVal; +} + +/* Once an insertion position is found, attach a element to the tree. */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + attachRebal( Element *element, Element *parentEl, Element *lastLess ) +{ + /* Increment the number of element in the tree. */ + treeSize += 1; + + /* Set element's parent. */ + element->BASE_EL(parent) = parentEl; + + /* New element always starts as a leaf with height 1. */ + element->BASE_EL(left) = 0; + element->BASE_EL(right) = 0; + element->BASE_EL(height) = 1; + + /* Are we inserting in the tree somewhere? */ + if ( parentEl != 0 ) { + /* We have a parent so we are somewhere in the tree. If the parent + * equals lastLess, then the last traversal in the insertion went + * left, otherwise it went right. */ + if ( lastLess == parentEl ) { + parentEl->BASE_EL(left) = element; +#ifdef WALKABLE + BASELIST::addBefore( parentEl, element ); +#endif + } + else { + parentEl->BASE_EL(right) = element; +#ifdef WALKABLE + BASELIST::addAfter( parentEl, element ); +#endif + } + +#ifndef WALKABLE + /* Maintain the first and last pointers. */ + if ( head->BASE_EL(left) == element ) + head = element; + + /* Maintain the first and last pointers. */ + if ( tail->BASE_EL(right) == element ) + tail = element; +#endif + } + else { + /* No parent element so we are inserting the root. */ + root = element; +#ifdef WALKABLE + BASELIST::addAfter( BASELIST::tail, element ); +#else + head = tail = element; +#endif + } + + + /* Recalculate the heights. */ + recalcHeights(parentEl); + + /* Find the first unbalance. */ + Element *ub = findFirstUnbalGP(element); + + /* rebalance. */ + if ( ub != 0 ) + { + /* We assert that after this single rotation the + * tree is now properly balanced. */ + rebalance(ub); + } +} + +#ifndef AVL_KEYLESS + +/** + * \brief Insert an existing element into the tree. + * + * If the insert succeeds and lastFound is given then it is set to the element + * inserted. If the insert fails then lastFound is set to the existing element in + * the tree that has the same key as element. If the element's avl pointers are + * already in use then undefined behaviour results. + * + * \returns The element inserted upon success, null upon failure. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + insert( Element *element, Element **lastFound ) +{ + long keyRelation; + Element *curEl = root, *parentEl = 0; + Element *lastLess = 0; + + while (true) { + if ( curEl == 0 ) { + /* We are at an external element and did not find the key we were + * looking for. Attach underneath the leaf and rebalance. */ + attachRebal( element, parentEl, lastLess ); + + if ( lastFound != 0 ) + *lastFound = element; + return element; + } + +#ifdef AVL_BASIC + keyRelation = compare( *element, *curEl ); +#else + keyRelation = compare( element->BASEKEY(getKey()), + curEl->BASEKEY(getKey()) ); +#endif + + /* Do we go left? */ + if ( keyRelation < 0 ) { + parentEl = lastLess = curEl; + curEl = curEl->BASE_EL(left); + } + /* Do we go right? */ + else if ( keyRelation > 0 ) { + parentEl = curEl; + curEl = curEl->BASE_EL(right); + } + /* We have hit the target. */ + else { + if ( lastFound != 0 ) + *lastFound = curEl; + return 0; + } + } +} + +#ifdef AVL_BASIC + +/** + * \brief Find a element in the tree with the given key. + * + * \returns The element if key exists, null if the key does not exist. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + find( const Element *element ) const +{ + Element *curEl = root; + long keyRelation; + + while (curEl) { + keyRelation = compare( *element, *curEl ); + + /* Do we go left? */ + if ( keyRelation < 0 ) + curEl = curEl->BASE_EL(left); + /* Do we go right? */ + else if ( keyRelation > 0 ) + curEl = curEl->BASE_EL(right); + /* We have hit the target. */ + else { + return curEl; + } + } + return 0; +} + +#else + +/** + * \brief Insert a new element into the tree with given key. + * + * If the key is not already in the tree then a new element is made using the + * Element(const Key &key) constructor and the insert succeeds. If lastFound is + * given then it is set to the element inserted. If the insert fails then + * lastFound is set to the existing element in the tree that has the same key as + * element. + * + * \returns The new element upon success, null upon failure. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + insert( const Key &key, Element **lastFound ) +{ + long keyRelation; + Element *curEl = root, *parentEl = 0; + Element *lastLess = 0; + + while (true) { + if ( curEl == 0 ) { + /* We are at an external element and did not find the key we were + * looking for. Create the new element, attach it underneath the leaf + * and rebalance. */ + Element *element = new Element( key ); + attachRebal( element, parentEl, lastLess ); + + if ( lastFound != 0 ) + *lastFound = element; + return element; + } + + keyRelation = compare( key, curEl->BASEKEY(getKey()) ); + + /* Do we go left? */ + if ( keyRelation < 0 ) { + parentEl = lastLess = curEl; + curEl = curEl->BASE_EL(left); + } + /* Do we go right? */ + else if ( keyRelation > 0 ) { + parentEl = curEl; + curEl = curEl->BASE_EL(right); + } + /* We have hit the target. */ + else { + if ( lastFound != 0 ) + *lastFound = curEl; + return 0; + } + } +} + +#ifdef AVLTREE_MAP +/** + * \brief Insert a new element into the tree with key and value. + * + * If the key is not already in the tree then a new element is constructed and + * the insert succeeds. If lastFound is given then it is set to the element + * inserted. If the insert fails then lastFound is set to the existing element in + * the tree that has the same key as element. This insert routine is only + * available in AvlMap because it is the only class that knows about a Value + * type. + * + * \returns The new element upon success, null upon failure. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + insert( const Key &key, const Value &val, Element **lastFound ) +{ + long keyRelation; + Element *curEl = root, *parentEl = 0; + Element *lastLess = 0; + + while (true) { + if ( curEl == 0 ) { + /* We are at an external element and did not find the key we were + * looking for. Create the new element, attach it underneath the leaf + * and rebalance. */ + Element *element = new Element( key, val ); + attachRebal( element, parentEl, lastLess ); + + if ( lastFound != 0 ) + *lastFound = element; + return element; + } + + keyRelation = compare(key, curEl->getKey()); + + /* Do we go left? */ + if ( keyRelation < 0 ) { + parentEl = lastLess = curEl; + curEl = curEl->BASE_EL(left); + } + /* Do we go right? */ + else if ( keyRelation > 0 ) { + parentEl = curEl; + curEl = curEl->BASE_EL(right); + } + /* We have hit the target. */ + else { + if ( lastFound != 0 ) + *lastFound = curEl; + return 0; + } + } +} +#endif /* AVLTREE_MAP */ + + +/** + * \brief Find a element in the tree with the given key. + * + * \returns The element if key exists, null if the key does not exist. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + find( const Key &key ) const +{ + Element *curEl = root; + long keyRelation; + + while (curEl) { + keyRelation = compare( key, curEl->BASEKEY(getKey()) ); + + /* Do we go left? */ + if ( keyRelation < 0 ) + curEl = curEl->BASE_EL(left); + /* Do we go right? */ + else if ( keyRelation > 0 ) + curEl = curEl->BASE_EL(right); + /* We have hit the target. */ + else { + return curEl; + } + } + return 0; +} + + +/** + * \brief Find a element, then detach it from the tree. + * + * The element is not deleted. + * + * \returns The element detached if the key is found, othewise returns null. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + detach(const Key &key) +{ + Element *element = find( key ); + if ( element ) { + detach(element); + } + + return element; +} + +/** + * \brief Find, detach and delete a element from the tree. + * + * \returns True if the element was found and deleted, false otherwise. + */ +template <AVLMEL_TEMPDEF> bool AvlTree<AVLMEL_TEMPUSE>:: + remove(const Key &key) +{ + /* Assume not found. */ + bool retVal = false; + + /* Look for the key. */ + Element *element = find( key ); + if ( element != 0 ) { + /* If found, detach the element and delete. */ + detach( element ); + delete element; + retVal = true; + } + + return retVal; +} + +#endif /* AVL_BASIC */ +#endif /* AVL_KEYLESS */ + + +/** + * \brief Detach and delete a element from the tree. + * + * If the element is not in the tree then undefined behaviour results. + */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + remove(Element *element) +{ + /* Detach and delete. */ + detach(element); + delete element; +} + +/** + * \brief Detach a element from the tree. + * + * If the element is not in the tree then undefined behaviour results. + * + * \returns The element given. + */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + detach(Element *element) +{ + Element *replacement, *fixfrom; + long lheight, rheight; + +#ifdef WALKABLE + /* Remove the element from the ordered list. */ + BASELIST::detach( element ); +#endif + + /* Update treeSize. */ + treeSize--; + + /* Find a replacement element. */ + if (element->BASE_EL(right)) + { + /* Find the leftmost element of the right subtree. */ + replacement = element->BASE_EL(right); + while (replacement->BASE_EL(left)) + replacement = replacement->BASE_EL(left); + + /* If replacing the element the with its child then we need to start + * fixing at the replacement, otherwise we start fixing at the + * parent of the replacement. */ + if (replacement->BASE_EL(parent) == element) + fixfrom = replacement; + else + fixfrom = replacement->BASE_EL(parent); + +#ifndef WALKABLE + if ( element == head ) + head = replacement; +#endif + + removeEl(replacement, replacement->BASE_EL(right)); + replaceEl(element, replacement); + } + else if (element->BASE_EL(left)) + { + /* Find the rightmost element of the left subtree. */ + replacement = element->BASE_EL(left); + while (replacement->BASE_EL(right)) + replacement = replacement->BASE_EL(right); + + /* If replacing the element the with its child then we need to start + * fixing at the replacement, otherwise we start fixing at the + * parent of the replacement. */ + if (replacement->BASE_EL(parent) == element) + fixfrom = replacement; + else + fixfrom = replacement->BASE_EL(parent); + +#ifndef WALKABLE + if ( element == tail ) + tail = replacement; +#endif + + removeEl(replacement, replacement->BASE_EL(left)); + replaceEl(element, replacement); + } + else + { + /* We need to start fixing at the parent of the element. */ + fixfrom = element->BASE_EL(parent); + +#ifndef WALKABLE + if ( element == head ) + head = element->BASE_EL(parent); + if ( element == tail ) + tail = element->BASE_EL(parent); +#endif + + /* The element we are deleting is a leaf element. */ + removeEl(element, 0); + } + + /* If fixfrom is null it means we just deleted + * the root of the tree. */ + if ( fixfrom == 0 ) + return element; + + /* Fix the heights after the deletion. */ + recalcHeights(fixfrom); + + /* Fix every unbalanced element going up in the tree. */ + Element *ub = findFirstUnbalEl(fixfrom); + while ( ub ) + { + /* Find the element to rebalance by moving down from the first unbalanced + * element 2 levels in the direction of the greatest heights. On the + * second move down, the heights may be equal ( but not on the first ). + * In which case go in the direction of the first move. */ + lheight = ub->BASE_EL(left) ? ub->BASE_EL(left)->BASE_EL(height) : 0; + rheight = ub->BASE_EL(right) ? ub->BASE_EL(right)->BASE_EL(height) : 0; + assert( lheight != rheight ); + if (rheight > lheight) + { + ub = ub->BASE_EL(right); + lheight = ub->BASE_EL(left) ? + ub->BASE_EL(left)->BASE_EL(height) : 0; + rheight = ub->BASE_EL(right) ? + ub->BASE_EL(right)->BASE_EL(height) : 0; + if (rheight > lheight) + ub = ub->BASE_EL(right); + else if (rheight < lheight) + ub = ub->BASE_EL(left); + else + ub = ub->BASE_EL(right); + } + else + { + ub = ub->BASE_EL(left); + lheight = ub->BASE_EL(left) ? + ub->BASE_EL(left)->BASE_EL(height) : 0; + rheight = ub->BASE_EL(right) ? + ub->BASE_EL(right)->BASE_EL(height) : 0; + if (rheight > lheight) + ub = ub->BASE_EL(right); + else if (rheight < lheight) + ub = ub->BASE_EL(left); + else + ub = ub->BASE_EL(left); + } + + + /* rebalance returns the grandparant of the subtree formed + * by the element that were rebalanced. + * We must continue upward from there rebalancing. */ + fixfrom = rebalance(ub); + + /* Find the next unbalaced element. */ + ub = findFirstUnbalEl(fixfrom); + } + + return element; +} + + +/** + * \brief Empty the tree and delete all the element. + * + * Resets the tree to its initial state. + */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>::empty() +{ + if ( root ) { + /* Recursively delete from the tree structure. */ + deleteChildrenOf(root); + delete root; + root = 0; + treeSize = 0; + +#ifdef WALKABLE + BASELIST::abandon(); +#endif + } +} + +/** + * \brief Forget all element in the tree. + * + * Does not delete element. Resets the the tree to it's initial state. + */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>::abandon() +{ + root = 0; + treeSize = 0; + +#ifdef WALKABLE + BASELIST::abandon(); +#endif +} + +/* Recursively delete all the children of a element. */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + deleteChildrenOf( Element *element ) +{ + /* Recurse left. */ + if (element->BASE_EL(left)) { + deleteChildrenOf(element->BASE_EL(left)); + + /* Delete left element. */ + delete element->BASE_EL(left); + element->BASE_EL(left) = 0; + } + + /* Recurse right. */ + if (element->BASE_EL(right)) { + deleteChildrenOf(element->BASE_EL(right)); + + /* Delete right element. */ + delete element->BASE_EL(right); + element->BASE_EL(left) = 0; + } +} + +/* rebalance from a element whose gradparent is unbalanced. Only + * call on a element that has a grandparent. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + rebalance(Element *n) +{ + long lheight, rheight; + Element *a, *b, *c; + Element *t1, *t2, *t3, *t4; + + Element *p = n->BASE_EL(parent); /* parent (Non-NUL). L*/ + Element *gp = p->BASE_EL(parent); /* Grand-parent (Non-NULL). */ + Element *ggp = gp->BASE_EL(parent); /* Great grand-parent (may be NULL). */ + + if (gp->BASE_EL(right) == p) + { + /* gp + * \ + * p + */ + if (p->BASE_EL(right) == n) + { + /* gp + * \ + * p + * \ + * n + */ + a = gp; + b = p; + c = n; + t1 = gp->BASE_EL(left); + t2 = p->BASE_EL(left); + t3 = n->BASE_EL(left); + t4 = n->BASE_EL(right); + } + else + { + /* gp + * \ + * p + * / + * n + */ + a = gp; + b = n; + c = p; + t1 = gp->BASE_EL(left); + t2 = n->BASE_EL(left); + t3 = n->BASE_EL(right); + t4 = p->BASE_EL(right); + } + } + else + { + /* gp + * / + * p + */ + if (p->BASE_EL(right) == n) + { + /* gp + * / + * p + * \ + * n + */ + a = p; + b = n; + c = gp; + t1 = p->BASE_EL(left); + t2 = n->BASE_EL(left); + t3 = n->BASE_EL(right); + t4 = gp->BASE_EL(right); + } + else + { + /* gp + * / + * p + * / + * n + */ + a = n; + b = p; + c = gp; + t1 = n->BASE_EL(left); + t2 = n->BASE_EL(right); + t3 = p->BASE_EL(right); + t4 = gp->BASE_EL(right); + } + } + + /* Perform rotation. + */ + + /* Tie b to the great grandparent. */ + if ( ggp == 0 ) + root = b; + else if ( ggp->BASE_EL(left) == gp ) + ggp->BASE_EL(left) = b; + else + ggp->BASE_EL(right) = b; + b->BASE_EL(parent) = ggp; + + /* Tie a as a leftchild of b. */ + b->BASE_EL(left) = a; + a->BASE_EL(parent) = b; + + /* Tie c as a rightchild of b. */ + b->BASE_EL(right) = c; + c->BASE_EL(parent) = b; + + /* Tie t1 as a leftchild of a. */ + a->BASE_EL(left) = t1; + if ( t1 != 0 ) t1->BASE_EL(parent) = a; + + /* Tie t2 as a rightchild of a. */ + a->BASE_EL(right) = t2; + if ( t2 != 0 ) t2->BASE_EL(parent) = a; + + /* Tie t3 as a leftchild of c. */ + c->BASE_EL(left) = t3; + if ( t3 != 0 ) t3->BASE_EL(parent) = c; + + /* Tie t4 as a rightchild of c. */ + c->BASE_EL(right) = t4; + if ( t4 != 0 ) t4->BASE_EL(parent) = c; + + /* The heights are all recalculated manualy and the great + * grand-parent is passed to recalcHeights() to ensure + * the heights are correct up the tree. + * + * Note that recalcHeights() cuts out when it comes across + * a height that hasn't changed. + */ + + /* Fix height of a. */ + lheight = a->BASE_EL(left) ? a->BASE_EL(left)->BASE_EL(height) : 0; + rheight = a->BASE_EL(right) ? a->BASE_EL(right)->BASE_EL(height) : 0; + a->BASE_EL(height) = (lheight > rheight ? lheight : rheight) + 1; + + /* Fix height of c. */ + lheight = c->BASE_EL(left) ? c->BASE_EL(left)->BASE_EL(height) : 0; + rheight = c->BASE_EL(right) ? c->BASE_EL(right)->BASE_EL(height) : 0; + c->BASE_EL(height) = (lheight > rheight ? lheight : rheight) + 1; + + /* Fix height of b. */ + lheight = a->BASE_EL(height); + rheight = c->BASE_EL(height); + b->BASE_EL(height) = (lheight > rheight ? lheight : rheight) + 1; + + /* Fix height of b's parents. */ + recalcHeights(ggp); + return ggp; +} + +/* Recalculates the heights of all the ancestors of element. */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + recalcHeights(Element *element) +{ + long lheight, rheight, new_height; + while ( element != 0 ) + { + lheight = element->BASE_EL(left) ? element->BASE_EL(left)->BASE_EL(height) : 0; + rheight = element->BASE_EL(right) ? element->BASE_EL(right)->BASE_EL(height) : 0; + + new_height = (lheight > rheight ? lheight : rheight) + 1; + + /* If there is no chage in the height, then there will be no + * change in any of the ancestor's height. We can stop going up. + * If there was a change, continue upward. */ + if (new_height == element->BASE_EL(height)) + return; + else + element->BASE_EL(height) = new_height; + + element = element->BASE_EL(parent); + } +} + +/* Finds the first element whose grandparent is unbalanced. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + findFirstUnbalGP(Element *element) +{ + long lheight, rheight, balanceProp; + Element *gp; + + if ( element == 0 || element->BASE_EL(parent) == 0 || + element->BASE_EL(parent)->BASE_EL(parent) == 0 ) + return 0; + + /* Don't do anything if we we have no grandparent. */ + gp = element->BASE_EL(parent)->BASE_EL(parent); + while ( gp != 0 ) + { + lheight = gp->BASE_EL(left) ? gp->BASE_EL(left)->BASE_EL(height) : 0; + rheight = gp->BASE_EL(right) ? gp->BASE_EL(right)->BASE_EL(height) : 0; + balanceProp = lheight - rheight; + + if ( balanceProp < -1 || balanceProp > 1 ) + return element; + + element = element->BASE_EL(parent); + gp = gp->BASE_EL(parent); + } + return 0; +} + + +/* Finds the first element that is unbalanced. */ +template <AVLMEL_TEMPDEF> Element *AvlTree<AVLMEL_TEMPUSE>:: + findFirstUnbalEl(Element *element) +{ + if ( element == 0 ) + return 0; + + while ( element != 0 ) + { + long lheight = element->BASE_EL(left) ? + element->BASE_EL(left)->BASE_EL(height) : 0; + long rheight = element->BASE_EL(right) ? + element->BASE_EL(right)->BASE_EL(height) : 0; + long balanceProp = lheight - rheight; + + if ( balanceProp < -1 || balanceProp > 1 ) + return element; + + element = element->BASE_EL(parent); + } + return 0; +} + +/* Replace a element in the tree with another element not in the tree. */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + replaceEl(Element *element, Element *replacement) +{ + Element *parent = element->BASE_EL(parent), + *left = element->BASE_EL(left), + *right = element->BASE_EL(right); + + replacement->BASE_EL(left) = left; + if (left) + left->BASE_EL(parent) = replacement; + replacement->BASE_EL(right) = right; + if (right) + right->BASE_EL(parent) = replacement; + + replacement->BASE_EL(parent) = parent; + if (parent) + { + if (parent->BASE_EL(left) == element) + parent->BASE_EL(left) = replacement; + else + parent->BASE_EL(right) = replacement; + } + else + root = replacement; + + replacement->BASE_EL(height) = element->BASE_EL(height); +} + +/* Removes a element from a tree and puts filler in it's place. + * Filler should be null or a child of element. */ +template <AVLMEL_TEMPDEF> void AvlTree<AVLMEL_TEMPUSE>:: + removeEl(Element *element, Element *filler) +{ + Element *parent = element->BASE_EL(parent); + + if (parent) + { + if (parent->BASE_EL(left) == element) + parent->BASE_EL(left) = filler; + else + parent->BASE_EL(right) = filler; + } + else + root = filler; + + if (filler) + filler->BASE_EL(parent) = parent; + + return; +} + +#ifdef AAPL_NAMESPACE +} +#endif diff --git a/aapl/avlibasic.h b/aapl/avlibasic.h new file mode 100644 index 00000000..b916f742 --- /dev/null +++ b/aapl/avlibasic.h @@ -0,0 +1,67 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLIBASIC_H +#define _AAPL_AVLIBASIC_H + +#include "compare.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliBasic + * \brief Linked AVL Tree in which the entire element structure is the key. + * + * AvliBasic is a linked AVL tree that does not distinguish between the + * element that it contains and the key. The entire element structure is the + * key that is used to compare the relative ordering of elements. This is + * similar to the BstSet structure. + * + * AvliBasic does not assume ownership of elements in the tree. Items must be + * explicitly de-allocated. + */ + +/*@}*/ + +#define BASE_EL(name) name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Element, class Compare +#define AVLMEL_TEMPDEF class Element, class Compare +#define AVLMEL_TEMPUSE Element, Compare +#define AvlTree AvliBasic +#define AVL_BASIC +#define WALKABLE + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef AVL_BASIC +#undef WALKABLE + +#endif /* _AAPL_AVLIBASIC_H */ diff --git a/aapl/avlikeyless.h b/aapl/avlikeyless.h new file mode 100644 index 00000000..0c606089 --- /dev/null +++ b/aapl/avlikeyless.h @@ -0,0 +1,64 @@ +/* + * Copyright 2002, 2003 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLIKEYLESS_H +#define _AAPL_AVLIKEYLESS_H + +#include "compare.h" +#include "dlistmel.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliKeyless + * \brief Linked AVL tree that has no insert/find/remove functions that take a + * key. + * + * AvliKeyless is an implementation of the AVL tree rebalancing functionality + * only. It provides the common code for the tiny AVL tree implementations. + */ + +/*@}*/ + +#define BASE_EL(name) name +#define BASELIST DListMel< Element, AvliTreeEl<Element> > +#define AVLMEL_CLASSDEF class Element +#define AVLMEL_TEMPDEF class Element +#define AVLMEL_TEMPUSE Element +#define AvlTree AvliKeyless +#define WALKABLE +#define AVL_KEYLESS + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef WALKABLE +#undef AVL_KEYLESS + +#endif /* _AAPL_AVLIKEYLESS_H */ diff --git a/aapl/avlimap.h b/aapl/avlimap.h new file mode 100644 index 00000000..c207dc52 --- /dev/null +++ b/aapl/avlimap.h @@ -0,0 +1,77 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLIMAP_H +#define _AAPL_AVLIMAP_H + +#include "compare.h" +#include "dlist.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliMap + * \brief Linked key and value oriented AVL tree. + * + * AvliMap stores key and value pairs in elements that managed by the tree. It + * is intendend to be similar to map template found in the STL. AvliMap + * requires that a Key type, a Value type, and a class containing a compare() + * routine for Key be given. Items can be inserted with just a key or with a + * key and value pair. + * + * AvliMap assumes all elements in the tree are allocated on the heap and are + * to be managed by the tree. This means that the class destructor will delete + * the contents of the tree. A deep copy will cause existing elements to be + * deleted first. + * + * \include ex_avlimap.cpp + */ + +/*@}*/ + +#define AVLTREE_MAP +#define BASE_EL(name) name +#define BASEKEY(name) name +#define BASELIST DList< AvliMapEl<Key,Value> > +#define AVLMEL_CLASSDEF class Key, class Value, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Key, class Value, class Compare +#define AVLMEL_TEMPUSE Key, Value, Compare +#define AvlTree AvliMap +#define Element AvliMapEl<Key,Value> +#define WALKABLE + +#include "avlcommon.h" + +#undef AVLTREE_MAP +#undef BASE_EL +#undef BASEKEY +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef Element +#undef WALKABLE + +#endif /* _AAPL_AVLIMAP_H */ diff --git a/aapl/avlimel.h b/aapl/avlimel.h new file mode 100644 index 00000000..bceddcd4 --- /dev/null +++ b/aapl/avlimel.h @@ -0,0 +1,79 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLIMEL_H +#define _AAPL_AVLIMEL_H + +#include "compare.h" +#include "dlistmel.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliMel + * \brief Linked AVL tree for element appearing in multiple trees. + * + * AvliMel allows for an element to simultaneously be in multiple trees without + * the trees interferring with one another. For each tree that the element is + * to appear in, there must be a distinct set of AVL Tree management data that + * can be unambiguously referenced with some base class name. This name + * is passed to the tree as a template parameter and is used in the tree + * algorithms. + * + * The element must use the same key type and value in each tree that it + * appears in. If distinct keys are required, the AvliMelKey structure is + * available. + * + * AvliMel does not assume ownership of elements in the tree. The destructor + * will not delete the elements. If the user wishes to explicitly deallocate + * all the items in the tree the empty() routine is available. + * + * \include ex_avlimel.cpp + */ + +/*@}*/ + +#define BASE_EL(name) BaseEl::name +#define BASEKEY(name) name +#define BASELIST DListMel< Element, BaseEl > +#define AVLMEL_CLASSDEF class Element, class Key, \ + class BaseEl, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, \ + class BaseEl, class Compare +#define AVLMEL_TEMPUSE Element, Key, BaseEl, Compare +#define AvlTree AvliMel +#define WALKABLE + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef WALKABLE + +#endif /* _AAPL_AVLIMEL_H */ diff --git a/aapl/avlimelkey.h b/aapl/avlimelkey.h new file mode 100644 index 00000000..52d3a409 --- /dev/null +++ b/aapl/avlimelkey.h @@ -0,0 +1,76 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLIMELKEY_H +#define _AAPL_AVLIMELKEY_H + +#include "compare.h" +#include "dlistmel.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliMelKey + * \brief Linked AVL tree for element appearing in multiple trees with different keys. + * + * AvliMelKey is similar to AvliMel, except that an additional template + * parameter, BaseKey, is provided for resolving ambiguous references to + * getKey(). This means that if an element is stored in multiple trees, each + * tree can use a different key for ordering the elements in it. Using + * AvliMelKey an array of data structures can be indexed with an O(log(n)) + * search on two or more of the values contained within it and without + * allocating any additional data. + * + * AvliMelKey does not assume ownership of elements in the tree. The destructor + * will not delete the elements. If the user wishes to explicitly deallocate + * all the items in the tree the empty() routine is available. + * + * \include ex_avlimelkey.cpp + */ + +/*@}*/ + +#define BASE_EL(name) BaseEl::name +#define BASEKEY(name) BaseKey::name +#define BASELIST DListMel< Element, BaseEl > +#define AVLMEL_CLASSDEF class Element, class Key, class BaseEl, \ + class BaseKey, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, class BaseEl, \ + class BaseKey, class Compare +#define AVLMEL_TEMPUSE Element, Key, BaseEl, BaseKey, Compare +#define AvlTree AvliMelKey +#define WALKABLE + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef WALKABLE + +#endif /* _AAPL_AVLIMELKEY_H */ diff --git a/aapl/avliset.h b/aapl/avliset.h new file mode 100644 index 00000000..9594e7d7 --- /dev/null +++ b/aapl/avliset.h @@ -0,0 +1,75 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLISET_H +#define _AAPL_AVLISET_H + +#include "compare.h" +#include "dlist.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliSet + * \brief Linked Key-only oriented tree. + * + * AvliSet stores only keys in elements that are managed by the tree. AvliSet + * requires that a Key type and a class containing a compare() routine + * for Key be given. Items are inserted with just a key value. + * + * AvliSet assumes all elements in the tree are allocated on the heap and are + * to be managed by the tree. This means that the class destructor will delete + * the contents of the tree. A deep copy will cause existing elements to be + * deleted first. + * + * \include ex_avliset.cpp + */ + +/*@}*/ + +#define AVLTREE_SET +#define BASE_EL(name) name +#define BASEKEY(name) name +#define BASELIST DList< AvliSetEl<Key> > +#define AVLMEL_CLASSDEF class Key, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Key, class Compare +#define AVLMEL_TEMPUSE Key, Compare +#define AvlTree AvliSet +#define Element AvliSetEl<Key> +#define WALKABLE + +#include "avlcommon.h" + +#undef AVLTREE_SET +#undef BASE_EL +#undef BASEKEY +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef Element +#undef WALKABLE + +#endif /* _AAPL_AVLISET_H */ diff --git a/aapl/avlitree.h b/aapl/avlitree.h new file mode 100644 index 00000000..28394bb1 --- /dev/null +++ b/aapl/avlitree.h @@ -0,0 +1,78 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLITREE_H +#define _AAPL_AVLITREE_H + +#include "compare.h" +#include "dlistmel.h" + +/** + * \addtogroup avlitree + * @{ + */ + +/** + * \class AvliTree + * \brief Linked AVL tree. + * + * AvliTree is the standard linked by-structure AVL tree. To use this + * structure the user must define an element type and give it the necessary + * properties. At the very least it must have a getKey() function that will be + * used to compare the relative ordering of elements and tree management data + * necessary for the AVL algorithm. An element type can acquire the management + * data by inheriting the AvliTreeEl class. + * + * AvliTree does not presume to manage the allocation of elements in the tree. + * The destructor will not delete the items in the tree, instead the elements + * must be explicitly de-allocated by the user if necessary and when it is + * safe to do so. The empty() routine will traverse the tree and delete all + * items. + * + * Since the tree does not manage the elements, it can contain elements that + * are allocated statically or that are part of another data structure. + * + * \include ex_avlitree.cpp + */ + +/*@}*/ + +#define BASE_EL(name) name +#define BASEKEY(name) name +#define BASELIST DListMel< Element, AvliTreeEl<Element> > +#define AVLMEL_CLASSDEF class Element, class Key, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, class Compare +#define AVLMEL_TEMPUSE Element, Key, Compare +#define AvlTree AvliTree +#define WALKABLE + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef BASELIST +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef WALKABLE + +#endif /* _AAPL_AVLITREE_H */ diff --git a/aapl/avlkeyless.h b/aapl/avlkeyless.h new file mode 100644 index 00000000..fecf8bda --- /dev/null +++ b/aapl/avlkeyless.h @@ -0,0 +1,58 @@ +/* + * Copyright 2002, 2003 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLKEYLESS_H +#define _AAPL_AVLKEYLESS_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlKeyless + * \brief AVL tree that has no insert/find/remove functions that take a key. + * + * AvlKeyless is an implementation of the AVL tree rebalancing functionality + * only. It provides the common code for the tiny AVL tree implementations. + */ + +/*@}*/ + +#define BASE_EL(name) name +#define AVLMEL_CLASSDEF class Element +#define AVLMEL_TEMPDEF class Element +#define AVLMEL_TEMPUSE Element +#define AvlTree AvlKeyless +#define AVL_KEYLESS + +#include "avlcommon.h" + +#undef BASE_EL +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef AVL_KEYLESS + +#endif /* _AAPL_AVLKEYLESS_H */ diff --git a/aapl/avlmap.h b/aapl/avlmap.h new file mode 100644 index 00000000..378613cd --- /dev/null +++ b/aapl/avlmap.h @@ -0,0 +1,74 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLMAP_H +#define _AAPL_AVLMAP_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlMap + * \brief Key and value oriented AVL tree. + * + * AvlMap stores key and value pairs in elements that managed by the tree. It + * is intendend to be similar to map template found in the STL. AvlMap + * requires that a Key type, a Value type, and a class containing a compare() + * routine for Key be given. Items can be inserted with just a key or with a + * key and value pair. + * + * AvlMap assumes all elements in the tree are allocated on the heap and are + * to be managed by the tree. This means that the class destructor will delete + * the contents of the tree. A deep copy will cause existing elements to be + * deleted first. + * + * \include ex_avlmap.cpp + */ + +/*@}*/ + +#define AVLTREE_MAP +#define BASE_EL(name) name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Key, class Value, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Key, class Value, class Compare +#define AVLMEL_TEMPUSE Key, Value, Compare +#define AvlTree AvlMap +#define Element AvlMapEl<Key,Value> + +#include "avlcommon.h" + +#undef AVLTREE_MAP +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef Element + + + +#endif /* _AAPL_AVLMAP_H */ diff --git a/aapl/avlmel.h b/aapl/avlmel.h new file mode 100644 index 00000000..6d0deb7d --- /dev/null +++ b/aapl/avlmel.h @@ -0,0 +1,74 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLMEL_H +#define _AAPL_AVLMEL_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlMel + * \brief AVL tree for elements appearing in multiple trees. + * + * AvlMel allows for an element to simultaneously be in multiple trees without + * the trees interferring with one another. For each tree that the element is + * to appear in, there must be a distinct set of AVL Tree management data that + * can be unambiguously referenced with some base class name. This name + * is passed to the tree as a template parameter and is used in the tree + * algorithms. + * + * The element must use the same key type and value in each tree that it + * appears in. If distinct keys are required, the AvlMelKey structure is + * available. + * + * AvlMel does not assume ownership of elements in the tree. The destructor + * will not delete the elements. If the user wishes to explicitly deallocate + * all the items in the tree the empty() routine is available. + * + * \include ex_avlmel.cpp + */ + +/*@}*/ + +#define BASE_EL(name) BaseEl::name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Element, class Key, \ + class BaseEl, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, \ + class BaseEl, class Compare +#define AVLMEL_TEMPUSE Element, Key, BaseEl, Compare +#define AvlTree AvlMel + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree + +#endif /* _AAPL_AVLMEL_H */ diff --git a/aapl/avlmelkey.h b/aapl/avlmelkey.h new file mode 100644 index 00000000..5a66c9c2 --- /dev/null +++ b/aapl/avlmelkey.h @@ -0,0 +1,71 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLMELKEY_H +#define _AAPL_AVLMELKEY_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlMelKey + * \brief AVL tree for elements appearing in multiple trees with different keys. + * + * AvlMelKey is similar to AvlMel, except that an additional template + * parameter, BaseKey, is provided for resolving ambiguous references to + * getKey(). This means that if an element is stored in multiple trees, each + * tree can use a different key for ordering the elements in it. Using + * AvlMelKey an array of data structures can be indexed with an O(log(n)) + * search on two or more of the values contained within it and without + * allocating any additional data. + * + * AvlMelKey does not assume ownership of elements in the tree. The destructor + * will not delete the elements. If the user wishes to explicitly deallocate + * all the items in the tree the empty() routine is available. + * + * \include ex_avlmelkey.cpp + */ + +/*@}*/ + +#define BASE_EL(name) BaseEl::name +#define BASEKEY(name) BaseKey::name +#define AVLMEL_CLASSDEF class Element, class Key, class BaseEl, \ + class BaseKey, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, class BaseEl, \ + class BaseKey, class Compare +#define AVLMEL_TEMPUSE Element, Key, BaseEl, BaseKey, Compare +#define AvlTree AvlMelKey + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree + +#endif /* _AAPL_AVLMELKEY_H */ diff --git a/aapl/avlset.h b/aapl/avlset.h new file mode 100644 index 00000000..579378a3 --- /dev/null +++ b/aapl/avlset.h @@ -0,0 +1,70 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLSET_H +#define _AAPL_AVLSET_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlSet + * \brief Key-only oriented tree. + * + * AvlSet stores only keys in elements that are managed by the tree. AvlSet + * requires that a Key type and a class containing a compare() routine + * for Key be given. Items are inserted with just a key value. + * + * AvlSet assumes all elements in the tree are allocated on the heap and are + * to be managed by the tree. This means that the class destructor will delete + * the contents of the tree. A deep copy will cause existing elements to be + * deleted first. + * + * \include ex_avlset.cpp + */ + +/*@}*/ + +#define AVLTREE_SET +#define BASE_EL(name) name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Key, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Key, class Compare +#define AVLMEL_TEMPUSE Key, Compare +#define AvlTree AvlSet +#define Element AvlSetEl<Key> + +#include "avlcommon.h" + +#undef AVLTREE_SET +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree +#undef Element + +#endif /* _AAPL_AVLSET_H */ diff --git a/aapl/avltree.h b/aapl/avltree.h new file mode 100644 index 00000000..2aa8e15f --- /dev/null +++ b/aapl/avltree.h @@ -0,0 +1,73 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_AVLTREE_H +#define _AAPL_AVLTREE_H + +#include "compare.h" + +/** + * \addtogroup avltree + * @{ + */ + +/** + * \class AvlTree + * \brief Basic AVL tree. + * + * AvlTree is the standard by-structure AVL tree. To use this structure the + * user must define an element type and give it the necessary properties. At + * the very least it must have a getKey() function that will be used to + * compare the relative ordering of elements and tree management data + * necessary for the AVL algorithm. An element type can acquire the management + * data by inheriting the AvlTreeEl class. + * + * AvlTree does not presume to manage the allocation of elements in the tree. + * The destructor will not delete the items in the tree, instead the elements + * must be explicitly de-allocated by the user if necessary and when it is + * safe to do so. The empty() routine will traverse the tree and delete all + * items. + * + * Since the tree does not manage the elements, it can contain elements that + * are allocated statically or that are part of another data structure. + * + * \include ex_avltree.cpp + */ + +/*@}*/ + +#define BASE_EL(name) name +#define BASEKEY(name) name +#define AVLMEL_CLASSDEF class Element, class Key, class Compare = CmpOrd<Key> +#define AVLMEL_TEMPDEF class Element, class Key, class Compare +#define AVLMEL_TEMPUSE Element, Key, Compare +#define AvlTree AvlTree + +#include "avlcommon.h" + +#undef BASE_EL +#undef BASEKEY +#undef AVLMEL_CLASSDEF +#undef AVLMEL_TEMPDEF +#undef AVLMEL_TEMPUSE +#undef AvlTree + +#endif /* _AAPL_AVLTREE_H */ diff --git a/aapl/bstcommon.h b/aapl/bstcommon.h new file mode 100644 index 00000000..888717f3 --- /dev/null +++ b/aapl/bstcommon.h @@ -0,0 +1,814 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This header is not wrapped in ifndefs because it is + * not intended to be included by users directly. */ + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/* Binary Search Table */ +template < BST_TEMPL_DECLARE > class BstTable : + public Compare, + public Vector< Element, Resize > +{ + typedef Vector<Element, Resize> BaseVector; + typedef Table<Element> BaseTable; + +public: + /** + * \brief Default constructor. + * + * Create an empty binary search table. + */ + BstTable() { } + + /** + * \brief Construct with initial value. + * + * Constructs a binary search table with an initial item. Uses the default + * constructor for initializing Value. + */ + BstTable(const Key &key) + { insert(key); } + +#if defined( BSTMAP ) + /** + * \brief Construct with initial value. + * + * Constructs a binary search table with an initial key/value pair. + */ + BstTable(const Key &key, const Value &val) + { insert(key, val); } +#endif + +#if ! defined( BSTSET ) + /** + * \brief Construct with initial value. + * + * Constructs a binary search table with an initial Element. + */ + BstTable(const Element &el) + { insert(el); } +#endif + + Element *insert(const Key &key, Element **lastFound = 0); + Element *insertMulti(const Key &key); + + bool insert(const BstTable &other); + void insertMulti(const BstTable &other); + +#if defined( BSTMAP ) + Element *insert(const Key &key, const Value &val, + Element **lastFound = 0); + Element *insertMulti(const Key &key, const Value &val ); +#endif + +#if ! defined( BSTSET ) + Element *insert(const Element &el, Element **lastFound = 0); + Element *insertMulti(const Element &el); +#endif + + Element *find(const Key &key, Element **lastFound = 0) const; + bool findMulti( const Key &key, Element *&lower, + Element *&upper ) const; + + bool remove(const Key &key); + bool remove(Element *item); + long removeMulti(const Key &key); + long removeMulti(Element *lower, Element *upper); + + /* The following provide access to the underlying insert and remove + * functions that my be hidden by the BST insert and remove. The insertDup + * and insertNew functions will never be hidden. They are provided for + * consistency. The difference between the non-shared and the shared + * tables is the documentation reference to the invoked function. */ + +#if !defined( SHARED_BST ) + /*@{*/ + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes Vector::insert( long pos, const T &val ). + */ + void vinsert(long pos, const Element &val) + { Vector< Element, Resize >::insert( pos, &val, 1 ); } + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes Vector::insert( long pos, const T *val, long len ). + */ + void vinsert(long pos, const Element *val, long len) + { Vector< Element, Resize >::insert( pos, val, len ); } + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes Vector::insert( long pos, const Vector &v ). + */ + void vinsert(long pos, const BstTable &v) + { Vector< Element, Resize >::insert( pos, v.data, v.tabLen ); } + + /*@}*/ + + /*@{*/ + + /** \brief Call the remove of the underlying vector. + * + * Provides access to the vector remove, which may become hidden. + * Invokes Vector::remove( long pos ). + */ + void vremove(long pos) + { Vector< Element, Resize >::remove( pos, 1 ); } + + /** \brief Call the remove of the underlying vector. + * + * Proves access to the vector remove, which may become hidden. + * Invokes Vector::remove( long pos, long len ). + */ + void vremove(long pos, long len) + { Vector< Element, Resize >::remove( pos, len ); } + + /*@}*/ +#else /* SHARED_BST */ + /*@{*/ + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes SVector::insert( long pos, const T &val ). + */ + void vinsert(long pos, const Element &val) + { Vector< Element, Resize >::insert( pos, &val, 1 ); } + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes SVector::insert( long pos, const T *val, long len ). + */ + void vinsert(long pos, const Element *val, long len) + { Vector< Element, Resize >::insert( pos, val, len ); } + + /** \brief Call the insert of the underlying vector. + * + * Provides to access to the vector insert, which may become hidden. Care + * should be taken to ensure that after the insert the ordering of + * elements is preserved. + * Invokes SVector::insert( long pos, const SVector &v ). + */ + void vinsert(long pos, const BstTable &v) + { Vector< Element, Resize >::insert( pos, v.data, v.length() ); } + + /*@}*/ + + /*@{*/ + + /** \brief Call the remove of the underlying vector. + * + * Provides access to the vector remove, which may become hidden. + * Invokes SVector::remove( long pos ). + */ + void vremove(long pos) + { Vector< Element, Resize >::remove( pos, 1 ); } + + /** \brief Call the remove of the underlying vector. + * + * Proves access to the vector remove, which may become hidden. + * Invokes SVector::remove( long pos, long len ). + */ + void vremove(long pos, long len) + { Vector< Element, Resize >::remove( pos, len ); } + + /*@}*/ + +#endif /* SHARED_BST */ +}; + + +#if 0 +#if defined( SHARED_BST ) +/** + * \brief Construct a binary search table with an initial amount of + * allocation. + * + * The table is initialized to have room for allocLength elements. The + * table starts empty. + */ +template <BST_TEMPL_DEF> BstTable<BST_TEMPL_USE>:: + BstTable( long allocLen ) +{ + /* Allocate the space if we are given a positive allocLen. */ + if ( allocLen > 0 ) { + /* Allocate the data needed. */ + STabHead *head = (STabHead*) + malloc( sizeof(STabHead) + sizeof(Element) * allocLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Set up the header and save the data pointer. */ + head->refCount = 1; + head->allocLen = allocLen; + head->tabLen = 0; + BaseTable::data = (Element*) (head + 1); + } +} +#else +/** + * \brief Construct a binary search table with an initial amount of + * allocation. + * + * The table is initialized to have room for allocLength elements. The + * table starts empty. + */ +template <BST_TEMPL_DEF> BstTable<BST_TEMPL_USE>:: + BstTable( long allocLen ) +{ + /* Allocate the space if we are given a positive allocLen. */ + BaseTable::allocLen = allocLen; + if ( BaseTable::allocLen > 0 ) { + BaseTable::data = (Element*) malloc(sizeof(Element) * BaseTable::allocLen); + if ( BaseTable::data == NULL ) + throw std::bad_alloc(); + } +} + +#endif +#endif + +/** + * \brief Find the element with the given key and remove it. + * + * If multiple elements with the given key exist, then it is unspecified which + * element will be removed. + * + * \returns True if an element is found and consequently removed, false + * otherwise. + */ +template <BST_TEMPL_DEF> bool BstTable<BST_TEMPL_USE>:: + remove(const Key &key) +{ + Element *el = find(key); + if ( el != 0 ) { + Vector< Element >::remove(el - BaseTable::data); + return true; + } + return false; +} + +/** + * \brief Remove the element pointed to by item. + * + * If item does not point to an element in the tree, then undefined behaviour + * results. If item is null, then remove has no effect. + * + * \returns True if item is not null, false otherwise. + */ +template <BST_TEMPL_DEF> bool BstTable<BST_TEMPL_USE>:: + remove( Element *item ) +{ + if ( item != 0 ) { + Vector< Element >::remove(item - BaseTable::data); + return true; + } + return false; +} + +/** + * \brief Find and remove the entire range of elements with the given key. + * + * \returns The number of elements removed. + */ +template <BST_TEMPL_DEF> long BstTable<BST_TEMPL_USE>:: + removeMulti(const Key &key) +{ + Element *low, *high; + if ( findMulti(key, low, high) ) { + /* Get the length of the range. */ + long num = high - low + 1; + Vector< Element >::remove(low - BaseTable::data, num); + return num; + } + + return 0; +} + +template <BST_TEMPL_DEF> long BstTable<BST_TEMPL_USE>:: + removeMulti(Element *lower, Element *upper) +{ + /* Get the length of the range. */ + long num = upper - lower + 1; + Vector< Element >::remove(lower - BaseTable::data, num); + return num; +} + + +/** + * \brief Find a range of elements with the given key. + * + * If any elements with the given key exist then lower and upper are set to + * the low and high ends of the continous range of elements with the key. + * Lower and upper will point to the first and last elements with the key. + * + * \returns True if any elements are found, false otherwise. + */ +template <BST_TEMPL_DEF> bool BstTable<BST_TEMPL_USE>:: + findMulti(const Key &key, Element *&low, Element *&high ) const +{ + const Element *lower, *mid, *upper; + long keyRelation; + const long tblLen = BaseTable::length(); + + if ( BaseTable::data == 0 ) + return false; + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the fd in the array. */ + return false; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(key, GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + Element *lowEnd = BaseTable::data - 1; + Element *highEnd = BaseTable::data + tblLen; + + lower = mid - 1; + while ( lower != lowEnd && + compare(key, GET_KEY(*lower)) == 0 ) + lower--; + + upper = mid + 1; + while ( upper != highEnd && + compare(key, GET_KEY(*upper)) == 0 ) + upper++; + + low = (Element*)lower + 1; + high = (Element*)upper - 1; + return true; + } + } +} + +/** + * \brief Find an element with the given key. + * + * If the find succeeds then lastFound is set to the element found. If the + * find fails then lastFound is set the location where the key would be + * inserted. If there is more than one element in the tree with the given key, + * then it is unspecified which element is returned as the match. + * + * \returns The element found on success, null on failure. + */ +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + find( const Key &key, Element **lastFound ) const +{ + const Element *lower, *mid, *upper; + long keyRelation; + const long tblLen = BaseTable::length(); + + if ( BaseTable::data == 0 ) + return 0; + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the key. Last found gets the insert location. */ + if ( lastFound != 0 ) + *lastFound = (Element*)lower; + return 0; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(key, GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + /* Key is found. Last found gets the found record. */ + if ( lastFound != 0 ) + *lastFound = (Element*)mid; + return (Element*)mid; + } + } +} + +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insert(const Key &key, Element **lastFound) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the key in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(key, GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + if ( lastFound != 0 ) + *lastFound = (Element*)mid; + return 0; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. After makeRawSpaceFor, lower pointer is no good. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(key); + + /* Set lastFound */ + if ( lastFound != 0 ) + *lastFound = BaseTable::data + insertPos; + return BaseTable::data + insertPos; +} + + +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insertMulti(const Key &key) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the key in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(key, GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + lower = mid; + goto insert; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(key); + + /* Return the element inserted. */ + return BaseTable::data + insertPos; +} + +/** + * \brief Insert each element from other. + * + * Always attempts to insert all elements even if the insert of some item from + * other fails. + * + * \returns True if all items inserted successfully, false if any insert + * failed. + */ +template <BST_TEMPL_DEF> bool BstTable<BST_TEMPL_USE>:: + insert(const BstTable &other) +{ + bool allSuccess = true; + long otherLen = other.length(); + for ( long i = 0; i < otherLen; i++ ) { + Element *el = insert( other.data[i] ); + if ( el == 0 ) + allSuccess = false; + } + return allSuccess; +} + +/** + * \brief Insert each element from other even if the elements exist already. + * + * No individual insertMulti can fail. + */ +template <BST_TEMPL_DEF> void BstTable<BST_TEMPL_USE>:: + insertMulti(const BstTable &other) +{ + long otherLen = other.length(); + for ( long i = 0; i < otherLen; i++ ) + insertMulti( other.data[i] ); +} + +#if ! defined( BSTSET ) + +/** + * \brief Insert the given element. + * + * If the key in the given element does not already exist in the table then a + * new element is inserted. They element copy constructor is used to place the + * element into the table. If lastFound is given, it is set to the new element + * created. If the insert fails then lastFound is set to the existing element + * of the same key. + * + * \returns The new element created upon success, null upon failure. + */ +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insert(const Element &el, Element **lastFound ) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the key in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(GET_KEY(el), GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + if ( lastFound != 0 ) + *lastFound = (Element*)mid; + return 0; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. After makeRawSpaceFor, lower pointer is no good. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(el); + + /* Set lastFound */ + if ( lastFound != 0 ) + *lastFound = BaseTable::data + insertPos; + return BaseTable::data + insertPos; +} + +/** + * \brief Insert the given element even if it exists already. + * + * If the key in the given element exists already then the new element is + * placed next to some other element of the same key. InsertMulti cannot fail. + * The element copy constructor is used to place the element in the table. + * + * \returns The new element created. + */ +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insertMulti(const Element &el) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the fd in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = compare(GET_KEY(el), GET_KEY(*mid)); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + lower = mid; + goto insert; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(el); + + /* Return the element inserted. */ + return BaseTable::data + insertPos; +} +#endif + + +#if defined( BSTMAP ) + +/** + * \brief Insert the given key-value pair. + * + * If the given key does not already exist in the table then the key-value + * pair is inserted. Copy constructors are used to place the pair in the + * table. If lastFound is given, it is set to the new entry created. If the + * insert fails then lastFound is set to the existing pair of the same key. + * + * \returns The new element created upon success, null upon failure. + */ +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insert(const Key &key, const Value &val, Element **lastFound) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the fd in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = Compare::compare(key, mid->key); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + if ( lastFound != NULL ) + *lastFound = (Element*)mid; + return 0; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(key, val); + + /* Set lastFound */ + if ( lastFound != NULL ) + *lastFound = BaseTable::data + insertPos; + return BaseTable::data + insertPos; +} + + +/** + * \brief Insert the given key-value pair even if the key exists already. + * + * If the key exists already then the key-value pair is placed next to some + * other pair of the same key. InsertMulti cannot fail. Copy constructors are + * used to place the pair in the table. + * + * \returns The new element created. + */ +template <BST_TEMPL_DEF> Element *BstTable<BST_TEMPL_USE>:: + insertMulti(const Key &key, const Value &val) +{ + const Element *lower, *mid, *upper; + long keyRelation, insertPos; + const long tblLen = BaseTable::length(); + + if ( tblLen == 0 ) { + /* If the table is empty then go straight to insert. */ + lower = BaseTable::data; + goto insert; + } + + lower = BaseTable::data; + upper = BaseTable::data + tblLen - 1; + while ( true ) { + if ( upper < lower ) { + /* Did not find the key in the array. + * Place to insert at is lower. */ + goto insert; + } + + mid = lower + ((upper-lower)>>1); + keyRelation = Compare::compare(key, mid->key); + + if ( keyRelation < 0 ) + upper = mid - 1; + else if ( keyRelation > 0 ) + lower = mid + 1; + else { + lower = mid; + goto insert; + } + } + +insert: + /* Get the insert pos. */ + insertPos = lower - BaseTable::data; + + /* Do the insert. */ + BaseVector::makeRawSpaceFor(insertPos, 1); + new(BaseTable::data + insertPos) Element(key, val); + + /* Return the element inserted. */ + return BaseTable::data + insertPos; +} + +#endif + +#ifdef AAPL_NAMESPACE +} +#endif diff --git a/aapl/bstmap.h b/aapl/bstmap.h new file mode 100644 index 00000000..30c8e3c5 --- /dev/null +++ b/aapl/bstmap.h @@ -0,0 +1,113 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_BSTMAP_H +#define _AAPL_BSTMAP_H + +#include "compare.h" +#include "vector.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \brief Element for BstMap. + * + * Stores the key and value pair. + */ +template <class Key, class Value> struct BstMapEl +{ + BstMapEl() {} + BstMapEl(const Key &key) : key(key) {} + BstMapEl(const Key &key, const Value &val) : key(key), value(val) {} + + /** \brief The key */ + Key key; + + /** \brief The value. */ + Value value; +}; + +#ifdef AAPL_NAMESPACE +} +#endif + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class BstMap + * \brief Binary search table for key and value pairs. + * + * BstMap stores key and value pairs in each element. The key and value can be + * any type. A compare class for the key must be supplied. + */ + +/*@}*/ + +#define BST_TEMPL_DECLARE class Key, class Value, \ + class Compare = CmpOrd<Key>, class Resize = ResizeExpn +#define BST_TEMPL_DEF class Key, class Value, class Compare, class Resize +#define BST_TEMPL_USE Key, Value, Compare, Resize +#define GET_KEY(el) ((el).key) +#define BstTable BstMap +#define Element BstMapEl<Key, Value> +#define BSTMAP + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BstTable +#undef Element +#undef BSTMAP + +/** + * \fn BstMap::insert(const Key &key, BstMapEl<Key, Value> **lastFound) + * \brief Insert the given key. + * + * If the given key does not already exist in the table then a new element + * having key is inserted. They key copy constructor and value default + * constructor are used to place the pair in the table. If lastFound is given, + * it is set to the new entry created. If the insert fails then lastFound is + * set to the existing pair of the same key. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn BstMap::insertMulti(const Key &key) + * \brief Insert the given key even if it exists already. + * + * If the key exists already then the new element having key is placed next + * to some other pair of the same key. InsertMulti cannot fail. The key copy + * constructor and the value default constructor are used to place the pair in + * the table. + * + * \returns The new element created. + */ + +#endif /* _AAPL_BSTMAP_H */ diff --git a/aapl/bstset.h b/aapl/bstset.h new file mode 100644 index 00000000..4a0f88ee --- /dev/null +++ b/aapl/bstset.h @@ -0,0 +1,86 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_BSTSET_H +#define _AAPL_BSTSET_H + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class BstSet + * \brief Binary search table for types that are the key. + * + * BstSet is suitable for types that comprise the entire key. Rather than look + * into the element to retrieve the key, the element is the key. A class that + * contains a comparison routine for the key must be given. + */ + +/*@}*/ + +#include "compare.h" +#include "vector.h" + +#define BST_TEMPL_DECLARE class Key, class Compare = CmpOrd<Key>, \ + class Resize = ResizeExpn +#define BST_TEMPL_DEF class Key, class Compare, class Resize +#define BST_TEMPL_USE Key, Compare, Resize +#define GET_KEY(el) (el) +#define BstTable BstSet +#define Element Key +#define BSTSET + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BstTable +#undef Element +#undef BSTSET + +/** + * \fn BstSet::insert(const Key &key, Key **lastFound) + * \brief Insert the given key. + * + * If the given key does not already exist in the table then it is inserted. + * The key's copy constructor is used to place the item in the table. If + * lastFound is given, it is set to the new entry created. If the insert fails + * then lastFound is set to the existing key of the same value. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn BstSet::insertMulti(const Key &key) + * \brief Insert the given key even if it exists already. + * + * If the key exists already then it is placed next to some other key of the + * same value. InsertMulti cannot fail. The key's copy constructor is used to + * place the item in the table. + * + * \returns The new element created. + */ + +#endif /* _AAPL_BSTSET_H */ diff --git a/aapl/bsttable.h b/aapl/bsttable.h new file mode 100644 index 00000000..4e4babc3 --- /dev/null +++ b/aapl/bsttable.h @@ -0,0 +1,84 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_BSTTABLE_H +#define _AAPL_BSTTABLE_H + +#include "compare.h" +#include "vector.h" + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class BstTable + * \brief Binary search table for structures that contain a key. + * + * This is the basic binary search table. It can be used to contain a + * structure that has a key and possibly some data. The key should be a member + * of the element class and accessible with getKey(). A class containing the + * compare routine must be supplied. + */ + +/*@}*/ + +#define BST_TEMPL_DECLARE class Element, class Key, \ + class Compare = CmpOrd<Key>, class Resize = ResizeExpn +#define BST_TEMPL_DEF class Element, class Key, class Compare, class Resize +#define BST_TEMPL_USE Element, Key, Compare, Resize +#define GET_KEY(el) ((el).getKey()) +#define BSTTABLE + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BSTTABLE + +/** + * \fn BstTable::insert(const Key &key, Element **lastFound) + * \brief Insert a new element with the given key. + * + * If the given key does not already exist in the table a new element is + * inserted with the given key. A constructor taking only const Key& is used + * to initialize the new element. If lastFound is given, it is set to the new + * element created. If the insert fails then lastFound is set to the existing + * element with the same key. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn BstTable::insertMulti(const Key &key) + * \brief Insert a new element even if the key exists already. + * + * If the key exists already then the new element is placed next to some + * element with the same key. InsertMulti cannot fail. A constructor taking + * only const Key& is used to initialize the new element. + * + * \returns The new element created. + */ + +#endif /* _AAPL_BSTTABLE_H */ diff --git a/aapl/bubblesort.h b/aapl/bubblesort.h new file mode 100644 index 00000000..bcc2fb6a --- /dev/null +++ b/aapl/bubblesort.h @@ -0,0 +1,94 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_BUBBLESORT_H +#define _AAPL_BUBBLESORT_H + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup sort + * @{ + */ + +/** + * \class BubbleSort + * \brief Bubble sort an array of data. + * + * BubbleSort can be used to sort any array of objects of type T provided a + * compare class is given. BubbleSort is in-place. It does not require any + * temporary storage. + * + * Objects are not made aware that they are being moved around in memory. + * Assignment operators, constructors and destructors are never invoked by the + * sort. + * + * BubbleSort runs in O(n^2) time. It is most useful when sorting arrays that + * are nearly sorted. It is best when neighbouring pairs are out of place. + * BubbleSort is a stable sort, meaning that objects with the same key have + * their relative ordering preserved. + */ + +/*@}*/ + +/* BubbleSort. */ +template <class T, class Compare> class BubbleSort + : public Compare +{ +public: + /* Sorting interface routine. */ + void sort(T *data, long len); +}; + + +/** + * \brief Bubble sort an array of data. + */ +template <class T, class Compare> void BubbleSort<T,Compare>:: + sort(T *data, long len) +{ + bool changed = true; + for ( long pass = 1; changed && pass < len; pass ++ ) { + changed = false; + for ( long i = 0; i < len-pass; i++ ) { + /* Do we swap pos with the next one? */ + if ( compare( data[i], data[i+1] ) > 0 ) { + char tmp[sizeof(T)]; + + /* Swap the two items. */ + memcpy( tmp, data+i, sizeof(T) ); + memcpy( data+i, data+i+1, sizeof(T) ); + memcpy( data+i+1, tmp, sizeof(T) ); + + /* Note that we made a change. */ + changed = true; + } + } + } +} + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_BUBBLESORT_H */ diff --git a/aapl/compare.h b/aapl/compare.h new file mode 100644 index 00000000..22937e9b --- /dev/null +++ b/aapl/compare.h @@ -0,0 +1,273 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_COMPARE_H +#define _AAPL_COMPARE_H + +#include <string.h> +#include "astring.h" +#include "table.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \defgroup compare Compare + * \brief Basic compare clases. + * + * Compare classes are used by data structures that need to know the relative + * ordering of elemets. To become a compare class, a class must imlement a + * routine long compare(const T &key1, const T &key2) that behaves just like + * strcmp. + * + * Compare classes are passed to the template data structure as a template + * parameter and are inherited. In most cases the compare routine will base + * the key comparision only on the two keys and the compare routine can + * therefore be static. Though sometimes it is useful to include data in the + * compare class and use this data in the comparison. For example the compare + * class may contain a pointer to some other data structure to which the + * comparison is delegated. + * + * @{ + */ + +/** + * \brief Compare two null terminated character sequences. + * + * This comparision class is a wrapper for strcmp. + */ +template<class T> struct CmpStrTmpl +{ + /** + * \brief Compare two null terminated string types. + */ + static inline long compare( const char *k1, const char *k2 ) + { return strcmp(k1, k2); } + + static int compare( const StrTmpl<T> &s1, const StrTmpl<T> &s2 ) + { + if ( s1.length() < s2.length() ) + return -1; + else if ( s1.length() > s2.length() ) + return 1; + else + return memcmp( s1.data, s2.data, s1.length() ); + } +}; + +typedef CmpStrTmpl<char> CmpStr; + +/** + * \brief Compare a type for which < and > are implemented. + * + * CmpOrd is suitable for simple types such as integers and pointers that by + * default have the less-than and greater-than operators defined. + */ +template <class T> struct CmpOrd +{ + /** + * \brief Compare two ordinal types. + * + * This compare routine copies its arguements in by value. + */ + static inline long compare(const T k1, const T k2) + { + if (k1 < k2) + return -1; + else if (k1 > k2) + return 1; + else + return 0; + } +}; + +/** + * \brief Compare two tables of type T + * + * Table comparison is useful for keying a data structure on a vector or + * binary search table. T is the element type stored in the table. + * CompareT is the comparison structure used to compare the individual values + * in the table. + */ +template < class T, class CompareT = CmpOrd<T> > struct CmpTable + : public CompareT +{ + /** + * \brief Compare two tables storing type T. + */ + static inline long compare(const Table<T> &t1, const Table<T> &t2) + { + if ( t1.tabLen < t2.tabLen ) + return -1; + else if ( t1.tabLen > t2.tabLen ) + return 1; + else + { + T *i1 = t1.data, *i2 = t2.data; + long len = t1.tabLen, cmpResult; + for ( long pos = 0; pos < len; + pos += 1, i1 += 1, i2 += 1 ) + { + cmpResult = CompareT::compare(*i1, *i2); + if ( cmpResult != 0 ) + return cmpResult; + } + return 0; + } + } +}; + +/** + * \brief Compare two tables of type T -- non-static version. + * + * CmpTableNs is identical to CmpTable, however the compare routine is + * non-static. If the CompareT class contains a non-static compare, then this + * version must be used because a static member cannot invoke a non-static + * member. + * + * Table comparison is useful for keying a data structure on a vector or binary + * search table. T is the element type stored in the table. CompareT + * is the comparison structure used to compare the individual values in the + * table. + */ +template < class T, class CompareT = CmpOrd<T> > struct CmpTableNs + : public CompareT +{ + /** + * \brief Compare two tables storing type T. + */ + inline long compare(const Table<T> &t1, const Table<T> &t2) + { + if ( t1.tabLen < t2.tabLen ) + return -1; + else if ( t1.tabLen > t2.tabLen ) + return 1; + else + { + T *i1 = t1.data, *i2 = t2.data; + long len = t1.tabLen, cmpResult; + for ( long pos = 0; pos < len; + pos += 1, i1 += 1, i2 += 1 ) + { + cmpResult = CompareT::compare(*i1, *i2); + if ( cmpResult != 0 ) + return cmpResult; + } + return 0; + } + } +}; + +/** + * \brief Compare two implicitly shared tables of type T + * + * This table comparison is for data structures based on implicitly + * shared tables. + * + * Table comparison is useful for keying a data structure on a vector or + * binary search table. T is the element type stored in the table. + * CompareT is the comparison structure used to compare the individual values + * in the table. + */ +template < class T, class CompareT = CmpOrd<T> > struct CmpSTable : public CompareT +{ + /** + * \brief Compare two tables storing type T. + */ + static inline long compare(const STable<T> &t1, const STable<T> &t2) + { + long t1Length = t1.length(); + long t2Length = t2.length(); + + /* Compare lengths. */ + if ( t1Length < t2Length ) + return -1; + else if ( t1Length > t2Length ) + return 1; + else { + /* Compare the table data. */ + T *i1 = t1.data, *i2 = t2.data; + for ( long pos = 0; pos < t1Length; + pos += 1, i1 += 1, i2 += 1 ) + { + long cmpResult = CompareT::compare(*i1, *i2); + if ( cmpResult != 0 ) + return cmpResult; + } + return 0; + } + } +}; + +/** + * \brief Compare two implicitly shared tables of type T -- non-static + * version. + * + * This is a non-static table comparison for data structures based on + * implicitly shared tables. If the CompareT class contains a non-static + * compare, then this version must be used because a static member cannot + * invoke a non-static member. + * + * Table comparison is useful for keying a data structure on a vector or + * binary search table. T is the element type stored in the table. + * CompareT is the comparison structure used to compare the individual values + * in the table. + */ +template < class T, class CompareT = CmpOrd<T> > struct CmpSTableNs + : public CompareT +{ + /** + * \brief Compare two tables storing type T. + */ + inline long compare(const STable<T> &t1, const STable<T> &t2) + { + long t1Length = t1.length(); + long t2Length = t2.length(); + + /* Compare lengths. */ + if ( t1Length < t2Length ) + return -1; + else if ( t1Length > t2Length ) + return 1; + else { + /* Compare the table data. */ + T *i1 = t1.data, *i2 = t2.data; + for ( long pos = 0; pos < t1Length; + pos += 1, i1 += 1, i2 += 1 ) + { + long cmpResult = CompareT::compare(*i1, *i2); + if ( cmpResult != 0 ) + return cmpResult; + } + return 0; + } + } +}; + + +/*@}*/ + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_COMPARE_H */ diff --git a/aapl/dlcommon.h b/aapl/dlcommon.h new file mode 100644 index 00000000..91dff25f --- /dev/null +++ b/aapl/dlcommon.h @@ -0,0 +1,790 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This header is not wrapped in ifndef becuase it is not intended to + * be included by the user. */ + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +#if defined( DOUBLELIST_VALUE ) +/** + * \brief Double list element for DListVal. + * + * DListValEl stores the type T of DListVal by value. + */ +template <class T> struct DListValEl +{ + /** + * \brief Construct a DListValEl with a given value. + * + * The only constructor available initializes the value element. This + * enforces that DListVal elements are never created without having their + * value intialzed by the user. T's copy constructor is used to copy the + * value in. + */ + DListValEl( const T &val ) : value(val) { } + + /** + * \brief Value stored by the list element. + * + * Value is always copied into new list elements using the copy + * constructor. + */ + T value; + + /** + * \brief List previous pointer. + * + * Points to the previous item in the list. If this is the first item in + * the list, then prev is NULL. If this element is not in a list then + * prev is undefined. + */ + DListValEl<T> *prev; + + /** + * \brief List next pointer. + * + * Points to the next item in the list. If this is the list item in the + * list, then next is NULL. If this element is not in a list then next is + * undefined. + */ + DListValEl<T> *next; +}; +#else + +#ifndef __AAPL_DOUBLE_LIST_EL +#define __AAPL_DOUBLE_LIST_EL +/** + * \brief Double list element properties. + * + * This class can be inherited to make a class suitable to be a double list + * element. It simply provides the next and previous pointers. An alternative + * is to put the next and previous pointers in the class directly. + */ +template <class Element> struct DListEl +{ + /** + * \brief List previous pointer. + * + * Points to the previous item in the list. If this is the first item in + * the list, then prev is NULL. If this element is not in a list then + * prev is undefined. + */ + Element *prev; + + /** + * \brief List next pointer. + * + * Points to the next item in the list. If this is the list item in the + * list, then next is NULL. If this element is not in a list then next is + * undefined. + */ + Element *next; +}; +#endif /* __AAPL_DOUBLE_LIST_EL */ + +#endif + +/* Doubly Linked List */ +template <DLMEL_TEMPDEF> class DList +{ +public: + /** \brief Initialize an empty list. */ + DList() : head(0), tail(0), listLen(0) {} + + /** + * \brief Perform a deep copy of the list. + * + * The elements of the other list are duplicated and put into this list. + * Elements are copied using the copy constructor. + */ + DList(const DList &other); + +#ifdef DOUBLELIST_VALUE + /** + * \brief Clear the double list contents. + * + * All elements are deleted. + */ + ~DList() { empty(); } + + /** + * \brief Assign another list into this list using a deep copy. + * + * The elements of the other list are duplicated and put into this list. + * Each list item is created using the copy constructor. If this list + * contains any elements before the copy, they are deleted first. + * + * \returns A reference to this. + */ + DList &operator=(const DList &other); + + /** + * \brief Transfer the contents of another list into this list. + * + * The elements of the other list moved in. The other list will be empty + * afterwards. If this list contains any elements before the copy, then + * they are deleted. + */ + void transfer(DList &other); +#else + /** + * \brief Abandon all elements in the list. + * + * List elements are not deleted. + */ + ~DList() {} + + /** + * \brief Perform a deep copy of the list. + * + * The elements of the other list are duplicated and put into this list. + * Each list item is created using the copy constructor. If this list + * contains any elements before the copy, they are abandoned. + * + * \returns A reference to this. + */ + DList &operator=(const DList &other); + + /** + * \brief Transfer the contents of another list into this list. + * + * The elements of the other list moved in. The other list will be empty + * afterwards. If this list contains any elements before the copy, they + * are abandoned. + */ + void transfer(DList &other); +#endif + + +#ifdef DOUBLELIST_VALUE + /** + * \brief Make a new element and prepend it to the front of the list. + * + * The item is copied into the new element using the copy constructor. + * Equivalent to list.addBefore(list.head, item). + */ + void prepend(const T &item); + + /** + * \brief Make a new element and append it to the end of the list. + * + * The item is copied into the new element using the copy constructor. + * Equivalent to list.addAfter(list.tail, item). + */ + void append(const T &item); + + /** + * \brief Make a new element and insert it immediately after an element in + * the list. + * + * The item is copied into the new element using the copy constructor. If + * prev_el is NULL then the new element is prepended to the front of the + * list. If prev_el is not already in the list then undefined behaviour + * results. Equivalent to list.addAfter(prev_el, new DListValEl(item)). + */ + void addAfter(Element *prev_el, const T &item); + + /** + * \brief Make a new element and insert it immediately before an element + * in the list. + * + * The item is copied into the new element using the copy construcotor. If + * next_el is NULL then the new element is appended to the end of the + * list. If next_el is not already in the list then undefined behaviour + * results. Equivalent to list.addBefore(next_el, new DListValEl(item)). + */ + void addBefore(Element *next_el, const T &item); +#endif + + /** + * \brief Prepend a single element to the front of the list. + * + * If new_el is already an element of some list, then undefined behaviour + * results. Equivalent to list.addBefore(list.head, new_el). + */ + void prepend(Element *new_el) { addBefore(head, new_el); } + + /** + * \brief Append a single element to the end of the list. + * + * If new_el is alreay an element of some list, then undefined behaviour + * results. Equivalent to list.addAfter(list.tail, new_el). + */ + void append(Element *new_el) { addAfter(tail, new_el); } + + /** + * \brief Prepend an entire list to the beginning of this list. + * + * All items are moved, not copied. Afterwards, the other list is emtpy. + * All items are prepended at once, so this is an O(1) operation. + * Equivalent to list.addBefore(list.head, dl). + */ + void prepend(DList &dl) { addBefore(head, dl); } + + /** + * \brief Append an entire list to the end of the list. + * + * All items are moved, not copied. Afterwards, the other list is empty. + * All items are appened at once, so this is an O(1) operation. + * Equivalent to list.addAfter(list.tail, dl). + */ + void append(DList &dl) { addAfter(tail, dl); } + + void addAfter(Element *prev_el, Element *new_el); + void addBefore(Element *next_el, Element *new_el); + + void addAfter(Element *prev_el, DList &dl); + void addBefore(Element *next_el, DList &dl); + + /** + * \brief Detach the head of the list + * + * The element detached is not deleted. If there is no head of the list + * (the list is empty) then undefined behaviour results. Equivalent to + * list.detach(list.head). + * + * \returns The element detached. + */ + Element *detachFirst() { return detach(head); } + + /** + * \brief Detach the tail of the list + * + * The element detached is not deleted. If there is no tail of the list + * (the list is empty) then undefined behaviour results. Equivalent to + * list.detach(list.tail). + * + * \returns The element detached. + */ + Element *detachLast() { return detach(tail); } + + /* Detaches an element from the list. Does not free any memory. */ + Element *detach(Element *el); + + /** + * \brief Detach and delete the first element in the list. + * + * If there is no first element (the list is empty) then undefined + * behaviour results. Equivalent to delete list.detach(list.head); + */ + void removeFirst() { delete detach( head ); } + + /** + * \brief Detach and delete the last element in the list. + * + * If there is no last element (the list is emtpy) then undefined + * behaviour results. Equivalent to delete list.detach(list.tail); + */ + void removeLast() { delete detach( tail ); } + + /** + * \brief Detach and delete an element from the list. + * + * If the element is not in the list, then undefined behaviour results. + * Equivalent to delete list.detach(el); + */ + void remove(Element *el) { delete detach( el ); } + + void empty(); + void abandon(); + + /** \brief The number of elements in the list. */ + long length() const { return listLen; } + + /** \brief Head and tail of the linked list. */ + Element *head, *tail; + + /** \brief The number of element in the list. */ + long listLen; + + /* Convenience access. */ + long size() const { return listLen; } + + /* Forward this so a ref can be used. */ + struct Iter; + + /* Class for setting the iterator. */ + struct IterFirst { IterFirst( const DList &l ) : l(l) { } const DList &l; }; + struct IterLast { IterLast( const DList &l ) : l(l) { } const DList &l; }; + struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; + struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; + + /** + * \brief Double List Iterator. + * \ingroup iterators + */ + struct Iter + { + /* Default construct. */ + Iter() : ptr(0) { } + + /* Construct from a double list. */ + Iter( const DList &dl ) : ptr(dl.head) { } + Iter( Element *el ) : ptr(el) { } + Iter( const IterFirst &dlf ) : ptr(dlf.l.head) { } + Iter( const IterLast &dll ) : ptr(dll.l.tail) { } + Iter( const IterNext &dln ) : ptr(dln.i.ptr->BASE_EL(next)) { } + Iter( const IterPrev &dlp ) : ptr(dlp.i.ptr->BASE_EL(prev)) { } + + /* Assign from a double list. */ + Iter &operator=( const DList &dl ) { ptr = dl.head; return *this; } + Iter &operator=( Element *el ) { ptr = el; return *this; } + Iter &operator=( const IterFirst &af ) { ptr = af.l.head; return *this; } + Iter &operator=( const IterLast &al ) { ptr = al.l.tail; return *this; } + Iter &operator=( const IterNext &an ) { ptr = an.i.ptr->BASE_EL(next); return *this; } + Iter &operator=( const IterPrev &ap ) { ptr = ap.i.ptr->BASE_EL(prev); return *this; } + + /** \brief Less than end? */ + bool lte() const { return ptr != 0; } + + /** \brief At end? */ + bool end() const { return ptr == 0; } + + /** \brief Greater than beginning? */ + bool gtb() const { return ptr != 0; } + + /** \brief At beginning? */ + bool beg() const { return ptr == 0; } + + /** \brief At first element? */ + bool first() const { return ptr && ptr->BASE_EL(prev) == 0; } + + /** \brief At last element? */ + bool last() const { return ptr && ptr->BASE_EL(next) == 0; } + + /** \brief Implicit cast to Element*. */ + operator Element*() const { return ptr; } + + /** \brief Dereference operator returns Element&. */ + Element &operator *() const { return *ptr; } + + /** \brief Arrow operator returns Element*. */ + Element *operator->() const { return ptr; } + + /** \brief Move to next item. */ + inline Element *operator++() { return ptr = ptr->BASE_EL(next); } + + /** \brief Move to next item. */ + inline Element *increment() { return ptr = ptr->BASE_EL(next); } + + /** \brief Move to next item. */ + inline Element *operator++(int); + + /** \brief Move to previous item. */ + inline Element *operator--() { return ptr = ptr->BASE_EL(prev); } + + /** \brief Move to previous item. */ + inline Element *decrement() { return ptr = ptr->BASE_EL(prev); } + + /** \brief Move to previous item. */ + inline Element *operator--(int); + + /** \brief Return the next item. Does not modify this. */ + inline IterNext next() const { return IterNext(*this); } + + /** \brief Return the prev item. Does not modify this. */ + inline IterPrev prev() const { return IterPrev(*this); } + + /** \brief The iterator is simply a pointer. */ + Element *ptr; + }; + + /** \brief Return first element. */ + IterFirst first() { return IterFirst(*this); } + + /** \brief Return last element. */ + IterLast last() { return IterLast(*this); } +}; + +/* Copy constructor, does a deep copy of other. */ +template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE>:: + DList(const DList<DLMEL_TEMPUSE> &other) : + head(0), tail(0), listLen(0) +{ + Element *el = other.head; + while( el != 0 ) { + append( new Element(*el) ); + el = el->BASE_EL(next); + } +} + +#ifdef DOUBLELIST_VALUE + +/* Assignement operator does deep copy. */ +template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE> &DList<DLMEL_TEMPUSE>:: + operator=(const DList &other) +{ + /* Free the old list. The value list assumes items were allocated on the + * heap by itself. */ + empty(); + + Element *el = other.head; + while( el != 0 ) { + append( new Element(*el) ); + el = el->BASE_EL(next); + } + return *this; +} + +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + transfer(DList &other) +{ + /* Free the old list. The value list assumes items were allocated on the + * heap by itself. */ + empty(); + + head = other.head; + tail = other.tail; + listLen = other.listLen; + + other.abandon(); +} + +#else + +/* Assignement operator does deep copy. */ +template <DLMEL_TEMPDEF> DList<DLMEL_TEMPUSE> &DList<DLMEL_TEMPUSE>:: + operator=(const DList &other) +{ + Element *el = other.head; + while( el != 0 ) { + append( new Element(*el) ); + el = el->BASE_EL(next); + } + return *this; +} + +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + transfer(DList &other) +{ + head = other.head; + tail = other.tail; + listLen = other.listLen; + + other.abandon(); +} + +#endif + +#ifdef DOUBLELIST_VALUE + +/* Prepend a new item. Inlining this bloats the caller with new overhead. */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + prepend(const T &item) +{ + addBefore(head, new Element(item)); +} + +/* Append a new item. Inlining this bloats the caller with the new overhead. */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + append(const T &item) +{ + addAfter(tail, new Element(item)); +} + +/* Add a new item after a prev element. Inlining this bloats the caller with + * the new overhead. */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addAfter(Element *prev_el, const T &item) +{ + addAfter(prev_el, new Element(item)); +} + +/* Add a new item before a next element. Inlining this bloats the caller with + * the new overhead. */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addBefore(Element *next_el, const T &item) +{ + addBefore(next_el, new Element(item)); +} + +#endif + +/* + * The larger iterator operators. + */ + +/* Postfix ++ */ +template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>::Iter:: + operator++(int) +{ + Element *rtn = ptr; + ptr = ptr->BASE_EL(next); + return rtn; +} + +/* Postfix -- */ +template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>::Iter:: + operator--(int) +{ + Element *rtn = ptr; + ptr = ptr->BASE_EL(prev); + return rtn; +} + +/** + * \brief Insert an element immediately after an element in the list. + * + * If prev_el is NULL then new_el is prepended to the front of the list. If + * prev_el is not in the list or if new_el is already in a list, then + * undefined behaviour results. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addAfter(Element *prev_el, Element *new_el) +{ + /* Set the previous pointer of new_el to prev_el. We do + * this regardless of the state of the list. */ + new_el->BASE_EL(prev) = prev_el; + + /* Set forward pointers. */ + if (prev_el == 0) { + /* There was no prev_el, we are inserting at the head. */ + new_el->BASE_EL(next) = head; + head = new_el; + } + else { + /* There was a prev_el, we can access previous next. */ + new_el->BASE_EL(next) = prev_el->BASE_EL(next); + prev_el->BASE_EL(next) = new_el; + } + + /* Set reverse pointers. */ + if (new_el->BASE_EL(next) == 0) { + /* There is no next element. Set the tail pointer. */ + tail = new_el; + } + else { + /* There is a next element. Set it's prev pointer. */ + new_el->BASE_EL(next)->BASE_EL(prev) = new_el; + } + + /* Update list length. */ + listLen++; +} + +/** + * \brief Insert an element immediatly before an element in the list. + * + * If next_el is NULL then new_el is appended to the end of the list. If + * next_el is not in the list or if new_el is already in a list, then + * undefined behaviour results. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addBefore(Element *next_el, Element *new_el) +{ + /* Set the next pointer of the new element to next_el. We do + * this regardless of the state of the list. */ + new_el->BASE_EL(next) = next_el; + + /* Set reverse pointers. */ + if (next_el == 0) { + /* There is no next elememnt. We are inserting at the tail. */ + new_el->BASE_EL(prev) = tail; + tail = new_el; + } + else { + /* There is a next element and we can access next's previous. */ + new_el->BASE_EL(prev) = next_el->BASE_EL(prev); + next_el->BASE_EL(prev) = new_el; + } + + /* Set forward pointers. */ + if (new_el->BASE_EL(prev) == 0) { + /* There is no previous element. Set the head pointer.*/ + head = new_el; + } + else { + /* There is a previous element, set it's next pointer to new_el. */ + new_el->BASE_EL(prev)->BASE_EL(next) = new_el; + } + + /* Update list length. */ + listLen++; +} + +/** + * \brief Insert an entire list immediatly after an element in this list. + * + * Elements are moved, not copied. Afterwards, the other list is empty. If + * prev_el is NULL then the elements are prepended to the front of the list. + * If prev_el is not in the list then undefined behaviour results. All + * elements are inserted into the list at once, so this is an O(1) operation. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addAfter( Element *prev_el, DList<DLMEL_TEMPUSE> &dl ) +{ + /* Do not bother if dl has no elements. */ + if ( dl.listLen == 0 ) + return; + + /* Set the previous pointer of dl.head to prev_el. We do + * this regardless of the state of the list. */ + dl.head->BASE_EL(prev) = prev_el; + + /* Set forward pointers. */ + if (prev_el == 0) { + /* There was no prev_el, we are inserting at the head. */ + dl.tail->BASE_EL(next) = head; + head = dl.head; + } + else { + /* There was a prev_el, we can access previous next. */ + dl.tail->BASE_EL(next) = prev_el->BASE_EL(next); + prev_el->BASE_EL(next) = dl.head; + } + + /* Set reverse pointers. */ + if (dl.tail->BASE_EL(next) == 0) { + /* There is no next element. Set the tail pointer. */ + tail = dl.tail; + } + else { + /* There is a next element. Set it's prev pointer. */ + dl.tail->BASE_EL(next)->BASE_EL(prev) = dl.tail; + } + + /* Update the list length. */ + listLen += dl.listLen; + + /* Empty out dl. */ + dl.head = dl.tail = 0; + dl.listLen = 0; +} + +/** + * \brief Insert an entire list immediately before an element in this list. + * + * Elements are moved, not copied. Afterwards, the other list is empty. If + * next_el is NULL then the elements are appended to the end of the list. If + * next_el is not in the list then undefined behaviour results. All elements + * are inserted at once, so this is an O(1) operation. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>:: + addBefore( Element *next_el, DList<DLMEL_TEMPUSE> &dl ) +{ + /* Do not bother if dl has no elements. */ + if ( dl.listLen == 0 ) + return; + + /* Set the next pointer of dl.tail to next_el. We do + * this regardless of the state of the list. */ + dl.tail->BASE_EL(next) = next_el; + + /* Set reverse pointers. */ + if (next_el == 0) { + /* There is no next elememnt. We are inserting at the tail. */ + dl.head->BASE_EL(prev) = tail; + tail = dl.tail; + } + else { + /* There is a next element and we can access next's previous. */ + dl.head->BASE_EL(prev) = next_el->BASE_EL(prev); + next_el->BASE_EL(prev) = dl.tail; + } + + /* Set forward pointers. */ + if (dl.head->BASE_EL(prev) == 0) { + /* There is no previous element. Set the head pointer.*/ + head = dl.head; + } + else { + /* There is a previous element, set it's next pointer to new_el. */ + dl.head->BASE_EL(prev)->BASE_EL(next) = dl.head; + } + + /* Update list length. */ + listLen += dl.listLen; + + /* Empty out dl. */ + dl.head = dl.tail = 0; + dl.listLen = 0; +} + + +/** + * \brief Detach an element from the list. + * + * The element is not deleted. If the element is not in the list, then + * undefined behaviour results. + * + * \returns The element detached. + */ +template <DLMEL_TEMPDEF> Element *DList<DLMEL_TEMPUSE>:: + detach(Element *el) +{ + /* Set forward pointers to skip over el. */ + if (el->BASE_EL(prev) == 0) + head = el->BASE_EL(next); + else { + el->BASE_EL(prev)->BASE_EL(next) = + el->BASE_EL(next); + } + + /* Set reverse pointers to skip over el. */ + if (el->BASE_EL(next) == 0) + tail = el->BASE_EL(prev); + else { + el->BASE_EL(next)->BASE_EL(prev) = + el->BASE_EL(prev); + } + + /* Update List length and return element we detached. */ + listLen--; + return el; +} + +/** + * \brief Clear the list by deleting all elements. + * + * Each item in the list is deleted. The list is reset to its initial state. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::empty() +{ + Element *nextToGo = 0, *cur = head; + + while (cur != 0) + { + nextToGo = cur->BASE_EL(next); + delete cur; + cur = nextToGo; + } + head = tail = 0; + listLen = 0; +} + +/** + * \brief Clear the list by forgetting all elements. + * + * All elements are abandoned, not deleted. The list is reset to it's initial + * state. + */ +template <DLMEL_TEMPDEF> void DList<DLMEL_TEMPUSE>::abandon() +{ + head = tail = 0; + listLen = 0; +} + +#ifdef AAPL_NAMESPACE +} +#endif diff --git a/aapl/dlist.h b/aapl/dlist.h new file mode 100644 index 00000000..e34c8da4 --- /dev/null +++ b/aapl/dlist.h @@ -0,0 +1,64 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_DLIST_H +#define _AAPL_DLIST_H + +#define BASE_EL(name) name +#define DLMEL_TEMPDEF class Element +#define DLMEL_TEMPUSE Element +#define DList DList + +/** + * \addtogroup dlist + * @{ + */ + +/** + * \class DList + * \brief Basic doubly linked list. + * + * DList is the standard by-structure list type. This class requires the + * programmer to declare a list element type that has the necessary next and + * previous pointers in it. This can be achieved by inheriting from the + * DListEl class or by simply adding next and previous pointers directly into + * the list element class. + * + * DList does not assume ownership of elements in the list. If the elements + * are known to reside on the heap, the provided empty() routine can be used to + * delete all elements, however the destructor will not call this routine, it + * will simply abandon all the elements. It is up to the programmer to + * explicitly de-allocate items when necessary. + * + * \include ex_dlist.cpp + */ + +/*@}*/ + +#include "dlcommon.h" + +#undef BASE_EL +#undef DLMEL_TEMPDEF +#undef DLMEL_TEMPUSE +#undef DList + +#endif /* _AAPL_DLIST_H */ + diff --git a/aapl/dlistmel.h b/aapl/dlistmel.h new file mode 100644 index 00000000..17de5432 --- /dev/null +++ b/aapl/dlistmel.h @@ -0,0 +1,71 @@ +/* + * Copyright 2001 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_DLISTMEL_H +#define _AAPL_DLISTMEL_H + +/** + * \addtogroup dlist + * @{ + */ + +/** + * \class DListMel + * \brief Doubly linked list for elements that may appear in multiple lists. + * + * This class is similar to DList, except that the user defined list element + * can inherit from multple DListEl classes and consequently be an element in + * multiple lists. In other words, DListMel allows a single instance of a data + * structure to be an element in multiple lists without the lists interfereing + * with one another. + * + * For each list that an element class is to appear in, the element must have + * unique next and previous pointers that can be unambiguously refered to with + * some base class name. This name is given to DListMel as a template argument + * so it can use the correct next and previous pointers in its list + * operations. + * + * DListMel does not assume ownership of elements in the list. If the elements + * are known to reside on the heap and are not contained in any other list or + * data structure, the provided empty() routine can be used to delete all + * elements, however the destructor will not call this routine, it will simply + * abandon all the elements. It is up to the programmer to explicitly + * de-allocate items when it is safe to do so. + * + * \include ex_dlistmel.cpp + */ + +/*@}*/ + +#define BASE_EL(name) BaseEl::name +#define DLMEL_TEMPDEF class Element, class BaseEl +#define DLMEL_TEMPUSE Element, BaseEl +#define DList DListMel + +#include "dlcommon.h" + +#undef BASE_EL +#undef DLMEL_TEMPDEF +#undef DLMEL_TEMPUSE +#undef DList + +#endif /* _AAPL_DLISTMEL_H */ + diff --git a/aapl/dlistval.h b/aapl/dlistval.h new file mode 100644 index 00000000..4fcf33fa --- /dev/null +++ b/aapl/dlistval.h @@ -0,0 +1,71 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_DLISTVAL_H +#define _AAPL_DLISTVAL_H + +/** + * \addtogroup dlist + * @{ + */ + +/** + * \class DListVal + * \brief By-value doubly linked list. + * + * This class is a doubly linked list that does not require a list element + * type to be declared. The user instead gives a type that is to be stored in + * the list element. When inserting a new data item, the value is copied into + * a newly allocated element. This list is inteded to behave and be utilized + * like the list template found in the STL. + * + * DListVal is different from the other lists in that it allocates elements + * itself. The raw element insert interface is still exposed for convenience, + * however, the list assumes all elements in the list are allocated on the + * heap and are to be managed by the list. The destructor WILL delete the + * contents of the list. If the list is ever copied in from another list, the + * existing contents are deleted first. This is in contrast to DList and + * DListMel, which will never delete their contents to allow for statically + * allocated elements. + * + * \include ex_dlistval.cpp + */ + +/*@}*/ + +#define BASE_EL(name) name +#define DLMEL_TEMPDEF class T +#define DLMEL_TEMPUSE T +#define DList DListVal +#define Element DListValEl<T> +#define DOUBLELIST_VALUE + +#include "dlcommon.h" + +#undef BASE_EL +#undef DLMEL_TEMPDEF +#undef DLMEL_TEMPUSE +#undef DList +#undef Element +#undef DOUBLELIST_VALUE + +#endif /* _AAPL_DLISTVAL_H */ + diff --git a/aapl/insertsort.h b/aapl/insertsort.h new file mode 100644 index 00000000..94aef7b2 --- /dev/null +++ b/aapl/insertsort.h @@ -0,0 +1,94 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_INSERTSORT_H +#define _AAPL_INSERTSORT_H + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup sort + * @{ + */ + +/** + * \class InsertSort + * \brief Insertion sort an array of data. + * + * InsertSort can be used to sort any array of objects of type T provided a + * compare class is given. InsertSort is in-place. It does not require any + * temporary storage. + * + * Objects are not made aware that they are being moved around in memory. + * Assignment operators, constructors and destructors are never invoked by the + * sort. + * + * InsertSort runs in O(n^2) time. It is most useful when sorting small arrays. + * where it can outperform the O(n*log(n)) sorters due to its simplicity. + * InsertSort is a not a stable sort. Elements with the same key will not have + * their relative ordering preserved. + */ + +/*@}*/ + +/* InsertSort. */ +template <class T, class Compare> class InsertSort + : public Compare +{ +public: + /* Sorting interface routine. */ + void sort(T *data, long len); +}; + + +/** + * \brief Insertion sort an array of data. + */ +template <class T, class Compare> + void InsertSort<T,Compare>::sort(T *data, long len) +{ + /* For each next largest spot in the sorted array... */ + for ( T *dest = data; dest < data+len-1; dest++ ) { + /* Find the next smallest element in the unsorted array. */ + T *smallest = dest; + for ( T *src = dest+1; src < data+len; src++ ) { + /* If src is smaller than the current src, then use it. */ + if ( compare( *src, *smallest ) < 0 ) + smallest = src; + } + + if ( smallest != dest ) { + /* Swap dest, smallest. */ + char tmp[sizeof(T)]; + memcpy( tmp, dest, sizeof(T) ); + memcpy( dest, smallest, sizeof(T) ); + memcpy( smallest, tmp, sizeof(T) ); + } + } +} + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_INSERTSORT_H */ diff --git a/aapl/mergesort.h b/aapl/mergesort.h new file mode 100644 index 00000000..68b84260 --- /dev/null +++ b/aapl/mergesort.h @@ -0,0 +1,140 @@ +/* + * Copyright 2001, 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_MERGESORT_H +#define _AAPL_MERGESORT_H + +#include "bubblesort.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup sort + * @{ + */ + +/** + * \class MergeSort + * \brief Merge sort an array of data. + * + * MergeSort can be used to sort any array of objects of type T provided a + * compare class is given. MergeSort is not in-place, it requires temporary + * storage equal to the size of the array. The temporary storage is allocated + * on the heap. + * + * Objects are not made aware that they are being moved around in memory. + * Assignment operators, constructors and destructors are never invoked by the + * sort. + * + * MergeSort runs in worst case O(n*log(n)) time. In most cases it is slower + * than QuickSort because more copying is neccessary. But on the other hand, + * it is a stable sort, meaning that objects with the same key have their + * relative ordering preserved. Also, its worst case is better. MergeSort + * switches to a BubbleSort when the size of the array being sorted is small. + * This happens when directly sorting a small array or when MergeSort calls + * itself recursively on a small portion of a larger array. + */ + +/*@}*/ + + +/* MergeSort. */ +template <class T, class Compare> class MergeSort + : public BubbleSort<T, Compare> +{ +public: + /* Sorting interface routine. */ + void sort(T *data, long len); + +private: + /* Recursive worker. */ + void doSort(T *tmpStor, T *data, long len); +}; + +#define _MS_BUBBLE_THRESH 16 + +/* Recursive mergesort worker. Split data, make recursive calls, merge + * results. */ +template< class T, class Compare> void MergeSort<T,Compare>:: + doSort(T *tmpStor, T *data, long len) +{ + if ( len <= 1 ) + return; + + if ( len <= _MS_BUBBLE_THRESH ) { + BubbleSort<T, Compare>::sort( data, len ); + return; + } + + long mid = len / 2; + + doSort( tmpStor, data, mid ); + doSort( tmpStor + mid, data + mid, len - mid ); + + /* Merge the data. */ + T *endLower = data + mid, *lower = data; + T *endUpper = data + len, *upper = data + mid; + T *dest = tmpStor; + while ( true ) { + if ( lower == endLower ) { + /* Possibly upper left. */ + if ( upper != endUpper ) + memcpy( dest, upper, (endUpper - upper) * sizeof(T) ); + break; + } + else if ( upper == endUpper ) { + /* Only lower left. */ + if ( lower != endLower ) + memcpy( dest, lower, (endLower - lower) * sizeof(T) ); + break; + } + else { + /* Both upper and lower left. */ + if ( compare(*lower, *upper) <= 0 ) + memcpy( dest++, lower++, sizeof(T) ); + else + memcpy( dest++, upper++, sizeof(T) ); + } + } + + /* Copy back from the tmpStor array. */ + memcpy( data, tmpStor, sizeof( T ) * len ); +} + +/** + * \brief Merge sort an array of data. + */ +template< class T, class Compare> + void MergeSort<T,Compare>::sort(T *data, long len) +{ + /* Allocate the tmp space needed by merge sort, sort and free. */ + T *tmpStor = (T*) new char[sizeof(T) * len]; + doSort( tmpStor, data, len ); + delete[] (char*) tmpStor; +} + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_MERGESORT_H */ diff --git a/aapl/quicksort.h b/aapl/quicksort.h new file mode 100644 index 00000000..bb6941ef --- /dev/null +++ b/aapl/quicksort.h @@ -0,0 +1,185 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_QUICKSORT_H +#define _AAPL_QUICKSORT_H + +#include "insertsort.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup sort + * @{ + */ + +/** + * \class QuickSort + * \brief Quick sort an array of data. + * + * QuickSort can be used to sort any array of objects of type T provided a + * compare class is given. QuickSort is in-place. It does not require any + * temporary storage. + * + * Objects are not made aware that they are being moved around in memory. + * Assignment operators, constructors and destructors are never invoked by the + * sort. + * + * QuickSort runs in O(n*log(n)) time in the average case. It is faster than + * mergsort in the average case because it does less moving of data. The + * performance of quicksort depends mostly on the choice of pivot. This + * implementation picks the pivot as the median of first, middle, last. This + * choice of pivot avoids the O(n^2) worst case for input already sorted, but + * it is still possible to encounter the O(n^2) worst case. For example an + * array of identical elements will run in O(n^2) + * + * QuickSort is not a stable sort. Elements with the same key will not have + * their relative ordering preserved. QuickSort switches to an InsertSort + * when the size of the array being sorted is small. This happens when + * directly sorting a small array or when QuickSort calls iteself recursively + * on a small portion of a larger array. + */ + +/*@}*/ + +/* QuickSort. */ +template <class T, class Compare> class QuickSort : + public InsertSort<T, Compare> +{ +public: + /* Sorting interface routine. */ + void sort(T *data, long len); + +private: + /* Recursive worker. */ + void doSort(T *start, T *end); + T *partition(T *start, T *end); + inline T *median(T *start, T *end); +}; + +#define _QS_INSERTION_THRESH 16 + +/* Finds the median of start, middle, end. */ +template <class T, class Compare> T *QuickSort<T,Compare>:: + median(T *start, T *end) +{ + T *pivot, *mid = start + (end-start)/2; + + /* CChoose the pivot. */ + if ( compare(*start, *mid) < 0 ) { + if ( compare(*mid, *end) < 0 ) + pivot = mid; + else if ( compare(*start, *end) < 0 ) + pivot = end; + else + pivot = start; + } + else if ( compare(*start, *end) < 0 ) + pivot = start; + else if ( compare(*mid, *end) < 0 ) + pivot = end; + else + pivot = mid; + + return pivot; +} + +template <class T, class Compare> T *QuickSort<T,Compare>:: + partition(T *start, T *end) +{ + /* Use the median of start, middle, end as the pivot. First save + * it off then move the last element to the free spot. */ + char pcPivot[sizeof(T)]; + T *pivot = median(start, end); + + memcpy( pcPivot, pivot, sizeof(T) ); + if ( pivot != end ) + memcpy( pivot, end, sizeof(T) ); + + T *first = start-1; + T *last = end; + pivot = (T*) pcPivot; + + /* Shuffle element to the correct side of the pivot, ending + * up with the free spot where the pivot will go. */ + while ( true ) { + /* Throw one element ahead to the free spot at last. */ + while ( true ) { + first += 1; + if ( first == last ) + goto done; + if ( compare( *first, *pivot ) > 0 ) { + memcpy(last, first, sizeof(T)); + break; + } + } + + /* Throw one element back to the free spot at first. */ + while ( true ) { + last -= 1; + if ( last == first ) + goto done; + if ( compare( *last, *pivot ) < 0 ) { + memcpy(first, last, sizeof(T)); + break; + } + } + } +done: + /* Put the pivot into the middle spot for it. */ + memcpy( first, pivot, sizeof(T) ); + return first; +} + + +template< class T, class Compare> void QuickSort<T,Compare>:: + doSort(T *start, T *end) +{ + long len = end - start + 1; + if ( len > _QS_INSERTION_THRESH ) { + /* Use quicksort. */ + T *pivot = partition( start, end ); + doSort(start, pivot-1); + doSort(pivot+1, end); + } + else if ( len > 1 ) { + /* Array is small, use insertion sort. */ + InsertSort<T, Compare>::sort( start, len ); + } +} + +/** + * \brief Quick sort an array of data. + */ +template< class T, class Compare> + void QuickSort<T,Compare>::sort(T *data, long len) +{ + /* Call recursive worker. */ + doSort(data, data+len-1); +} + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_QUICKSORT_H */ diff --git a/aapl/resize.h b/aapl/resize.h new file mode 100644 index 00000000..9e8491aa --- /dev/null +++ b/aapl/resize.h @@ -0,0 +1,344 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_RESIZE_H +#define _AAPL_RESIZE_H + +#include <assert.h> + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/* This step is expressed in units of T. Changing this requires changes to + * docs in ResizeLin constructor. */ +#define LIN_DEFAULT_STEP 256 + +/* + * Resizing macros giving different resize methods. + */ + +/* If needed is greater than existing, give twice needed. */ +#define EXPN_UP( existing, needed ) \ + needed > existing ? (needed<<1) : existing + +/* If needed is less than 1 quarter existing, give twice needed. */ +#define EXPN_DOWN( existing, needed ) \ + needed < (existing>>2) ? (needed<<1) : existing + +/* If needed is greater than existing, give needed plus step. */ +#define LIN_UP( existing, needed ) \ + needed > existing ? (needed+step) : existing + +/* If needed is less than existing - 2 * step then give needed plus step. */ +#define LIN_DOWN( existing, needed ) \ + needed < (existing-(step<<1)) ? (needed+step) : existing + +/* Return existing. */ +#define CONST_UP( existing, needed ) existing + +/* Return existing. */ +#define CONST_DOWN( existing, needed ) existing + +/** + * \addtogroup vector + * @{ + */ + +/** \class ResizeLin + * \brief Linear table resizer. + * + * When an up resize or a down resize is needed, ResizeLin allocates the space + * needed plus some user defined step. The result is that when growing the + * vector in a linear fashion, the number of resizes is also linear. + * + * If only up resizing is done, then there will never be more than step unused + * spaces in the vector. If down resizing is done as well, there will never be + * more than 2*step unused spaces in the vector. The up resizing and down + * resizing policies are offset to improve performance when repeatedly + * inserting and removing a small number of elements relative to the step. + * This scheme guarantees that repetitive inserting and removing of a small + * number of elements will never result in repetative reallocation. + * + * The vectors pass sizes to the resizer in units of T, so the step gets + * interpreted as units of T. + */ + +/*@}*/ + +/* Linear resizing. */ +class ResizeLin +{ +protected: + /** + * \brief Default constructor. + * + * Intializes resize step to 256 units of the table type T. + */ + ResizeLin() : step(LIN_DEFAULT_STEP) { } + + /** + * \brief Determine the new table size when up resizing. + * + * If the existing size is insufficient for the space needed, then allocate + * the space needed plus the step. The step is in units of T. + */ + inline long upResize( long existing, long needed ) + { return LIN_UP(existing, needed); } + + /** + * \brief Determine the new table size when down resizing. + * + * If space needed is less than the existing - 2*step, then allocate the + * space needed space plus the step. The step is in units of T. + */ + inline long downResize( long existing, long needed ) + { return LIN_DOWN(existing, needed); } + +public: + /** + * \brief Step for linear resize. + * + * Amount of extra space in units of T added each time a resize must take + * place. This may be changed at any time. The step should be >= 0. + */ + long step; +}; + +/** + * \addtogroup vector + * @{ + */ + +/** \class ResizeCtLin + * \brief Linear table resizer with compile time step. + * + * When an up resize or a down resize is needed, ResizeCtLin allocates the + * space needed plus some compile time defined step. The result is that when + * growing the vector in a linear fashion, the number of resizes is also + * linear. + * + * If only up resizing is done, then there will never be more than step unused + * spaces in the vector. If down resizing is done as well, there will never be + * more than 2*step unused spaces in the vector. The up resizing and down + * resizing policies are offset to improve performance when repeatedly + * inserting and removing a small number of elements relative to the step. + * This scheme guarantees that repetitive inserting and removing of a small + * number of elements will never result in repetative reallocation. + * + * The vectors pass sizes to the resizer in units of T, so the step gets + * interpreted as units of T. + */ + +/*@}*/ + +/* Linear resizing. */ +template <long step> class ResizeCtLin +{ +protected: + /** + * \brief Determine the new table size when up resizing. + * + * If the existing size is insufficient for the space needed, then allocate + * the space needed plus the step. The step is in units of T. + */ + inline long upResize( long existing, long needed ) + { return LIN_UP(existing, needed); } + + /** + * \brief Determine the new table size when down resizing. + * + * If space needed is less than the existing - 2*step, then allocate the + * space needed space plus the step. The step is in units of T. + */ + inline long downResize( long existing, long needed ) + { return LIN_DOWN(existing, needed); } +}; + +/** + * \addtogroup vector + * @{ + */ + +/** \class ResizeConst + * \brief Constant table resizer. + * + * When an up resize is needed the existing size is always used. ResizeConst + * does not allow dynamic resizing. To use ResizeConst, the vector needs to be + * constructed with and initial allocation amount otherwise it will be + * unusable. + */ + +/*@}*/ + +/* Constant table resizing. */ +class ResizeConst +{ +protected: + /* Assert don't need more than exists. Return existing. */ + static inline long upResize( long existing, long needed ); + + /** + * \brief Determine the new table size when down resizing. + * + * Always returns the existing table size. + */ + static inline long downResize( long existing, long needed ) + { return CONST_DOWN(existing, needed); } +}; + +/** + * \brief Determine the new table size when up resizing. + * + * If the existing size is insufficient for the space needed, then an assertion + * will fail. Otherwise returns the existing size. + */ +inline long ResizeConst::upResize( long existing, long needed ) +{ + assert( needed <= existing ); + return CONST_UP(existing, needed); +} + +/** + * \addtogroup vector + * @{ + */ + +/** \class ResizeRunTime + * \brief Run time settable table resizer. + * + * ResizeRunTime can have it's up and down resizing policies set at run time. + * Both up and down policies can be set independently to one of Exponential, + * Linear, or Constant. See the documentation for ResizeExpn, ResizeLin, and + * ResizeConst for the details of the resizing policies. + * + * The policies may be changed at any time. The default policies are + * both Exponential. + */ + +/*@}*/ + +/* Run time resizing. */ +class ResizeRunTime +{ +protected: + /** + * \brief Default constuctor. + * + * The up and down resizing it initialized to Exponetial. The step + * defaults to 256 units of T. + */ + inline ResizeRunTime(); + + /** + * \brief Resizing policies. + */ + enum ResizeType { + Exponential, /*!< Exponential resizing. */ + Linear, /*!< Linear resizing. */ + Constant /*!< Constant table size. */ + }; + + inline long upResize( long existing, long needed ); + inline long downResize( long existing, long needed ); + +public: + /** + * \brief Step for linear resize. + * + * Amount of extra space in units of T added each time a resize must take + * place. This may be changed at any time. The step should be >= 0. + */ + long step; + + /** + * \brief Up resizing policy. + */ + ResizeType upResizeType; + + /** + * \brief Down resizing policy. + */ + ResizeType downResizeType; +}; + +inline ResizeRunTime::ResizeRunTime() +: + step( LIN_DEFAULT_STEP ), + upResizeType( Exponential ), + downResizeType( Exponential ) +{ +} + +/** + * \brief Determine the new table size when up resizing. + * + * Type of up resizing is determined by upResizeType. Exponential, Linear and + * Constant resizing is the same as that of ResizeExpn, ResizeLin and + * ResizeConst. + */ +inline long ResizeRunTime::upResize( long existing, long needed ) +{ + switch ( upResizeType ) { + case Exponential: + return EXPN_UP(existing, needed); + case Linear: + return LIN_UP(existing, needed); + case Constant: + assert( needed <= existing ); + return CONST_UP(existing, needed); + } + return 0; +}; + +/** + * \brief Determine the new table size when down resizing. + * + * Type of down resizing is determined by downResiizeType. Exponential, Linear + * and Constant resizing is the same as that of ResizeExpn, ResizeLin and + * ResizeConst. + */ +inline long ResizeRunTime::downResize( long existing, long needed ) +{ + switch ( downResizeType ) { + case Exponential: + return EXPN_DOWN(existing, needed); + case Linear: + return LIN_DOWN(existing, needed); + case Constant: + return CONST_DOWN(existing, needed); + } + return 0; +} + +/* Don't need these anymore. */ +#undef EXPN_UP +#undef EXPN_DOWN +#undef LIN_UP +#undef LIN_DOWN +#undef CONST_UP +#undef CONST_DOWN + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_RESIZE_H */ diff --git a/aapl/sbstmap.h b/aapl/sbstmap.h new file mode 100644 index 00000000..e3975a1c --- /dev/null +++ b/aapl/sbstmap.h @@ -0,0 +1,121 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_SBSTMAP_H +#define _AAPL_SBSTMAP_H + +#include "compare.h" +#include "svector.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \brief Element for BstMap. + * + * Stores the key and value pair. + */ +template <class Key, class Value> struct SBstMapEl +{ + SBstMapEl() {} + SBstMapEl(const Key &key) : key(key) {} + SBstMapEl(const Key &key, const Value &val) : key(key), value(val) {} + + /** \brief The key */ + Key key; + + /** \brief The value. */ + Value value; +}; + +#ifdef AAPL_NAMESPACE +} +#endif + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class SBstMap + * \brief Copy-on-write binary search table for key and value pairs. + * + * This is a map style binary search table that employs the copy-on-write + * mechanism for table data. BstMap stores key and value pairs in each + * element. The key and value can be any type. A compare class for the key + * must be supplied. + */ + +/*@}*/ + +#define BST_TEMPL_DECLARE class Key, class Value, \ + class Compare = CmpOrd<Key>, class Resize = ResizeExpn +#define BST_TEMPL_DEF class Key, class Value, class Compare, class Resize +#define BST_TEMPL_USE Key, Value, Compare, Resize +#define GET_KEY(el) ((el).key) +#define BstTable SBstMap +#define Vector SVector +#define Table STable +#define Element SBstMapEl<Key, Value> +#define BSTMAP +#define SHARED_BST + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BstTable +#undef Vector +#undef Table +#undef Element +#undef BSTMAP +#undef SHARED_BST + +/** + * \fn SBstMap::insert(const Key &key, BstMapEl<Key, Value> **lastFound) + * \brief Insert the given key. + * + * If the given key does not already exist in the table then a new element + * having key is inserted. They key copy constructor and value default + * constructor are used to place the pair in the table. If lastFound is given, + * it is set to the new entry created. If the insert fails then lastFound is + * set to the existing pair of the same key. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn SBstMap::insertMulti(const Key &key) + * \brief Insert the given key even if it exists already. + * + * If the key exists already then the new element having key is placed next + * to some other pair of the same key. InsertMulti cannot fail. The key copy + * constructor and the value default constructor are used to place the pair in + * the table. + * + * \returns The new element created. + */ + +#endif /* _AAPL_SBSTMAP_H */ diff --git a/aapl/sbstset.h b/aapl/sbstset.h new file mode 100644 index 00000000..3487ee75 --- /dev/null +++ b/aapl/sbstset.h @@ -0,0 +1,94 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_SBSTSET_H +#define _AAPL_SBSTSET_H + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class SBstSet + * \brief Copy-on-write binary search table for types that are the key. + * + * This is a set style binary search table that employs the copy-on-write + * mechanism for storing table data. BstSet is suitable for types that + * comprise the entire key. Rather than look into the element to retrieve the + * key, the element is the key. A class that contains a comparison routine + * for the key must be given. + */ + +/*@}*/ + +#include "compare.h" +#include "svector.h" + +#define BST_TEMPL_DECLARE class Key, class Compare = CmpOrd<Key>, \ + class Resize = ResizeExpn +#define BST_TEMPL_DEF class Key, class Compare, class Resize +#define BST_TEMPL_USE Key, Compare, Resize +#define GET_KEY(el) (el) +#define BstTable SBstSet +#define Vector SVector +#define Table STable +#define Element Key +#define BSTSET +#define SHARED_BST + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BstTable +#undef Vector +#undef Table +#undef Element +#undef BSTSET +#undef SHARED_BST + +/** + * \fn SBstSet::insert(const Key &key, Key **lastFound) + * \brief Insert the given key. + * + * If the given key does not already exist in the table then it is inserted. + * The key's copy constructor is used to place the item in the table. If + * lastFound is given, it is set to the new entry created. If the insert fails + * then lastFound is set to the existing key of the same value. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn SBstSet::insertMulti(const Key &key) + * \brief Insert the given key even if it exists already. + * + * If the key exists already then it is placed next to some other key of the + * same value. InsertMulti cannot fail. The key's copy constructor is used to + * place the item in the table. + * + * \returns The new element created. + */ + +#endif /* _AAPL_SBSTSET_H */ diff --git a/aapl/sbsttable.h b/aapl/sbsttable.h new file mode 100644 index 00000000..348f1fd0 --- /dev/null +++ b/aapl/sbsttable.h @@ -0,0 +1,93 @@ +/* + * Copyright 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_SBSTTABLE_H +#define _AAPL_SBSTTABLE_H + +#include "compare.h" +#include "svector.h" + +/** + * \addtogroup bst + * @{ + */ + +/** + * \class SBstTable + * \brief Copy-on-write binary search table for structures that contain a key. + * + * This is a basic binary search table that employs a copy-on-write data + * storage mechanism. It can be used to contain a structure that has a key and + * possibly some data. The key should be a member of the element class and + * accessible with getKey(). A class containing the compare routine must be + * supplied. + */ + +/*@}*/ + +#define BST_TEMPL_DECLARE class Element, class Key, \ + class Compare = CmpOrd<Key>, class Resize = ResizeExpn +#define BST_TEMPL_DEF class Element, class Key, class Compare, class Resize +#define BST_TEMPL_USE Element, Key, Compare, Resize +#define GET_KEY(el) ((el).getKey()) +#define BstTable SBstTable +#define Vector SVector +#define Table STable +#define BSTTABLE +#define SHARED_BST + +#include "bstcommon.h" + +#undef BST_TEMPL_DECLARE +#undef BST_TEMPL_DEF +#undef BST_TEMPL_USE +#undef GET_KEY +#undef BstTable +#undef Vector +#undef Table +#undef BSTTABLE +#undef SHARED_BST + +/** + * \fn SBstTable::insert(const Key &key, Element **lastFound) + * \brief Insert a new element with the given key. + * + * If the given key does not already exist in the table a new element is + * inserted with the given key. A constructor taking only const Key& is used + * to initialize the new element. If lastFound is given, it is set to the new + * element created. If the insert fails then lastFound is set to the existing + * element with the same key. + * + * \returns The new element created upon success, null upon failure. + */ + +/** + * \fn SBstTable::insertMulti(const Key &key) + * \brief Insert a new element even if the key exists already. + * + * If the key exists already then the new element is placed next to some + * element with the same key. InsertMulti cannot fail. A constructor taking + * only const Key& is used to initialize the new element. + * + * \returns The new element created. + */ + +#endif /* _AAPL_SBSTTABLE_H */ diff --git a/aapl/svector.h b/aapl/svector.h new file mode 100644 index 00000000..7dcae62c --- /dev/null +++ b/aapl/svector.h @@ -0,0 +1,1350 @@ +/* + * Copyright 2002, 2006 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_SVECTOR_H +#define _AAPL_SVECTOR_H + +#include <new> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include "table.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup vector + * @{ + */ + +/** \class SVector + * \brief Copy-on-write dynamic array. + * + * SVector is a variant of Vector that employs copy-on-write behaviour. The + * SVector copy constructor and = operator make shallow copies. If a vector + * that references shared data is modified with insert, replace, append, + * prepend, setAs or remove, a new copy is made so as not to interfere with + * the shared data. However, shared individual elements may be modified by + * bypassing the SVector interface. + * + * SVector is a dynamic array that can be used to contain complex data + * structures that have constructors and destructors as well as simple types + * such as integers and pointers. + * + * SVector supports inserting, overwriting, and removing single or multiple + * elements at once. Constructors and destructors are called wherever + * appropriate. For example, before an element is overwritten, it's + * destructor is called. + * + * SVector provides automatic resizing of allocated memory as needed and + * offers different allocation schemes for controlling how the automatic + * allocation is done. Two senses of the the length of the data is + * maintained: the amount of raw memory allocated to the vector and the number + * of actual elements in the vector. The various allocation schemes control + * how the allocated space is changed in relation to the number of elements in + * the vector. + */ + +/*@}*/ + +/* SVector */ +template < class T, class Resize = ResizeExpn > class SVector : + public STable<T>, public Resize +{ +private: + typedef STable<T> BaseTable; + +public: + /** + * \brief Initialize an empty vector with no space allocated. + * + * If a linear resizer is used, the step defaults to 256 units of T. For a + * runtime vector both up and down allocation schemes default to + * Exponential. + */ + SVector() { } + + /** + * \brief Create a vector that contains an initial element. + * + * The vector becomes one element in length. The element's copy + * constructor is used to place the value in the vector. + */ + SVector(const T &val) { setAs(&val, 1); } + + /** + * \brief Create a vector that contains an array of elements. + * + * The vector becomes len elements in length. Copy constructors are used + * to place the new elements in the vector. + */ + SVector(const T *val, long len) { setAs(val, len); } + + /* Shallow copy. */ + SVector( const SVector &v ); + + /** + * \brief Free all memory used by the vector. + * + * The vector is reset to zero elements. Destructors are called on all + * elements in the vector. The space allocated for the vector is freed. + */ + ~SVector() { empty(); } + + /* Delete all items. */ + void empty(); + + /** + * \brief Deep copy another vector into this vector. + * + * Copies the entire contents of the other vector into this vector. Any + * existing contents are first deleted. Equivalent to setAs. + */ + void deepCopy( const SVector &v ) { setAs(v.data, v.length()); } + + /* Perform a shallow copy of another vector. */ + SVector &operator=( const SVector &v ); + + + /*@{*/ + /** + * \brief Insert one element at position pos. + * + * Elements in the vector from pos onward are shifted one space to the + * right. The copy constructor is used to place the element into this + * vector. If pos is greater than the length of the vector then undefined + * behaviour results. If pos is negative then it is treated as an offset + * relative to the length of the vector. + */ + void insert(long pos, const T &val) { insert(pos, &val, 1); } + + /* Insert an array of values. */ + void insert(long pos, const T *val, long len); + + /** + * \brief Insert all the elements from another vector at position pos. + * + * Elements in this vector from pos onward are shifted v.length() spaces + * to the right. The element's copy constructor is used to copy the items + * into this vector. The other vector is left unchanged. If pos is off the + * end of the vector, then undefined behaviour results. If pos is negative + * then it is treated as an offset relative to the length of the vector. + * Equivalent to vector.insert(pos, other.data, other.length()). + */ + void insert(long pos, const SVector &v) { insert(pos, v.data, v.length()); } + + /* Insert len copies of val into the vector. */ + void insertDup(long pos, const T &val, long len); + + /** + * \brief Insert one new element using the default constrcutor. + * + * Elements in the vector from pos onward are shifted one space to the right. + * The default constructor is used to init the new element. If pos is greater + * than the length of the vector then undefined behaviour results. If pos is + * negative then it is treated as an offset relative to the length of the + * vector. + */ + void insertNew(long pos) { insertNew(pos, 1); } + + /* Insert len new items using default constructor. */ + void insertNew(long pos, long len); + /*@}*/ + + /*@{*/ + /** + * \brief Remove one element at position pos. + * + * The element's destructor is called. Elements to the right of pos are + * shifted one space to the left to take up the free space. If pos is greater + * than or equal to the length of the vector then undefined behavior results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ + void remove(long pos) { remove(pos, 1); } + + /* Delete a number of elements. */ + void remove(long pos, long len); + /*@}*/ + + /*@{*/ + /** + * \brief Replace one element at position pos. + * + * If there is an existing element at position pos (if pos is less than the + * length of the vector) then its destructor is called before the space is + * used. The copy constructor is used to place the element into the vector. + * If pos is greater than the length of the vector then undefined behaviour + * results. If pos is negative then it is treated as an offset relative to + * the length of the vector. + */ + void replace(long pos, const T &val) { replace(pos, &val, 1); } + + /* Replace with an array of values. */ + void replace(long pos, const T *val, long len); + + /** + * \brief Replace at position pos with all the elements of another vector. + * + * Replace at position pos with all the elements of another vector. The other + * vector is left unchanged. If there are existing elements at the positions + * to be replaced, then destructors are called before the space is used. Copy + * constructors are used to place the elements into this vector. It is + * allowable for the pos and length of the other vector to specify a + * replacement that overwrites existing elements and creates new ones. If pos + * is greater than the length of the vector then undefined behaviour results. + * If pos is negative, then it is treated as an offset relative to the length + * of the vector. + */ + void replace(long pos, const SVector &v) { replace(pos, v.data, v.length()); } + + /* Replace len items with len copies of val. */ + void replaceDup(long pos, const T &val, long len); + + /** + * \brief Replace at position pos with one new element. + * + * If there is an existing element at the position to be replaced (pos is + * less than the length of the vector) then the element's destructor is + * called before the space is used. The default constructor is used to + * initialize the new element. If pos is greater than the length of the + * vector then undefined behaviour results. If pos is negative, then it is + * treated as an offset relative to the length of the vector. + */ + void replaceNew(long pos) { replaceNew(pos, 1); } + + /* Replace len items at pos with newly constructed objects. */ + void replaceNew(long pos, long len); + /*@}*/ + + /*@{*/ + + /** + * \brief Set the contents of the vector to be val exactly. + * + * The vector becomes one element in length. Destructors are called on any + * existing elements in the vector. The element's copy constructor is used to + * place the val in the vector. + */ + void setAs(const T &val) { setAs(&val, 1); } + + /* Set to the contents of an array. */ + void setAs(const T *val, long len); + + /** + * \brief Set the vector to exactly the contents of another vector. + * + * The vector becomes v.length() elements in length. Destructors are called + * on any existing elements. Copy constructors are used to place the new + * elements in the vector. + */ + void setAs(const SVector &v) { setAs(v.data, v.length()); } + + /* Set as len copies of item. */ + void setAsDup(const T &item, long len); + + /** + * \brief Set the vector to exactly one new item. + * + * The vector becomes one element in length. Destructors are called on any + * existing elements in the vector. The default constructor is used to + * init the new item. + */ + void setAsNew() { setAsNew(1); } + + /* Set as newly constructed objects using the default constructor. */ + void setAsNew(long len); + /*@}*/ + + /*@{*/ + /** + * \brief Append one elment to the end of the vector. + * + * Copy constructor is used to place the element in the vector. + */ + void append(const T &val) { replace(BaseTable::length(), &val, 1); } + + /** + * \brief Append len elements to the end of the vector. + * + * Copy constructors are used to place the elements in the vector. + */ + void append(const T *val, long len) { replace(BaseTable::length(), val, len); } + + /** + * \brief Append the contents of another vector. + * + * The other vector is left unchanged. Copy constructors are used to place + * the elements in the vector. + */ + void append(const SVector &v) + { replace(BaseTable::length(), v.data, v.length()); } + + /** + * \brief Append len copies of item. + * + * The copy constructor is used to place the item in the vector. + */ + void appendDup(const T &item, long len) { replaceDup(BaseTable::length(), item, len); } + + /** + * \brief Append a single newly created item. + * + * The new element is initialized with the default constructor. + */ + void appendNew() { replaceNew(BaseTable::length(), 1); } + + /** + * \brief Append len newly created items. + * + * The new elements are initialized with the default constructor. + */ + void appendNew(long len) { replaceNew(BaseTable::length(), len); } + /*@}*/ + + + /*@{*/ + /** + * \brief Prepend one elment to the front of the vector. + * + * Copy constructor is used to place the element in the vector. + */ + void prepend(const T &val) { insert(0, &val, 1); } + + /** + * \brief Prepend len elements to the front of the vector. + * + * Copy constructors are used to place the elements in the vector. + */ + void prepend(const T *val, long len) { insert(0, val, len); } + + /** + * \brief Prepend the contents of another vector. + * + * The other vector is left unchanged. Copy constructors are used to place + * the elements in the vector. + */ + void prepend(const SVector &v) { insert(0, v.data, v.length()); } + + /** + * \brief Prepend len copies of item. + * + * The copy constructor is used to place the item in the vector. + */ + void prependDup(const T &item, long len) { insertDup(0, item, len); } + + /** + * \brief Prepend a single newly created item. + * + * The new element is initialized with the default constructor. + */ + void prependNew() { insertNew(0, 1); } + + /** + * \brief Prepend len newly created items. + * + * The new elements are initialized with the default constructor. + */ + void prependNew(long len) { insertNew(0, len); } + /*@}*/ + + /* Convenience access. */ + T &operator[](int i) const { return BaseTable::data[i]; } + long size() const { return BaseTable::length(); } + + /* Various classes for setting the iterator */ + struct Iter; + struct IterFirst { IterFirst( const SVector &v ) : v(v) { } const SVector &v; }; + struct IterLast { IterLast( const SVector &v ) : v(v) { } const SVector &v; }; + struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; + struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; + + /** + * \brief Shared Vector Iterator. + * \ingroup iterators + */ + struct Iter + { + /* Construct, assign. */ + Iter() : ptr(0), ptrBeg(0), ptrEnd(0) { } + + /* Construct. */ + Iter( const SVector &v ); + Iter( const IterFirst &vf ); + Iter( const IterLast &vl ); + inline Iter( const IterNext &vn ); + inline Iter( const IterPrev &vp ); + + /* Assign. */ + Iter &operator=( const SVector &v ); + Iter &operator=( const IterFirst &vf ); + Iter &operator=( const IterLast &vl ); + inline Iter &operator=( const IterNext &vf ); + inline Iter &operator=( const IterPrev &vl ); + + /** \brief Less than end? */ + bool lte() const { return ptr != ptrEnd; } + + /** \brief At end? */ + bool end() const { return ptr == ptrEnd; } + + /** \brief Greater than beginning? */ + bool gtb() const { return ptr != ptrBeg; } + + /** \brief At beginning? */ + bool beg() const { return ptr == ptrBeg; } + + /** \brief At first element? */ + bool first() const { return ptr == ptrBeg+1; } + + /** \brief At last element? */ + bool last() const { return ptr == ptrEnd-1; } + + /* Return the position. */ + long pos() const { return ptr - ptrBeg - 1; } + T &operator[](int i) const { return ptr[i]; } + + /** \brief Implicit cast to T*. */ + operator T*() const { return ptr; } + + /** \brief Dereference operator returns T&. */ + T &operator *() const { return *ptr; } + + /** \brief Arrow operator returns T*. */ + T *operator->() const { return ptr; } + + /** \brief Move to next item. */ + T *operator++() { return ++ptr; } + + /** \brief Move to next item. */ + T *operator++(int) { return ptr++; } + + /** \brief Move to next item. */ + T *increment() { return ++ptr; } + + /** \brief Move to previous item. */ + T *operator--() { return --ptr; } + + /** \brief Move to previous item. */ + T *operator--(int) { return ptr--; } + + /** \brief Move to previous item. */ + T *decrement() { return --ptr; } + + /** \brief Return the next item. Does not modify this. */ + inline IterNext next() const { return IterNext(*this); } + + /** \brief Return the previous item. Does not modify this. */ + inline IterPrev prev() const { return IterPrev(*this); } + + /** \brief The iterator is simply a pointer. */ + T *ptr; + + /* For testing endpoints. */ + T *ptrBeg, *ptrEnd; + }; + + /** \brief Return first element. */ + IterFirst first() { return IterFirst( *this ); } + + /** \brief Return last element. */ + IterLast last() { return IterLast( *this ); } + +protected: + void makeRawSpaceFor(long pos, long len); + + void setAsCommon(long len); + long replaceCommon(long pos, long len); + long insertCommon(long pos, long len); + + void upResize(long len); + void upResizeDup(long len); + void upResizeFromEmpty(long len); + void downResize(long len); + void downResizeDup(long len); +}; + +/** + * \brief Perform a shallow copy of the vector. + * + * Takes a reference to the contents of the other vector. + */ +template <class T, class Resize> SVector<T, Resize>:: + SVector(const SVector<T, Resize> &v) +{ + /* Take a reference to other, if any data is allocated. */ + if ( v.data == 0 ) + BaseTable::data = 0; + else { + /* Get the source header, up the refcount and ref it. */ + STabHead *srcHead = ((STabHead*) v.data) - 1; + srcHead->refCount += 1; + BaseTable::data = (T*) (srcHead + 1); + } +} + +/** + * \brief Shallow copy another vector into this vector. + * + * Takes a reference to the other vector. The contents of this vector are + * first emptied. + * + * \returns A reference to this. + */ +template <class T, class Resize> SVector<T, Resize> & + SVector<T, Resize>:: operator=( const SVector &v ) +{ + /* First clean out the current contents. */ + empty(); + + /* Take a reference to other, if any data is allocated. */ + if ( v.data == 0 ) + BaseTable::data = 0; + else { + /* Get the source header, up the refcount and ref it. */ + STabHead *srcHead = ((STabHead*) v.data) - 1; + srcHead->refCount += 1; + BaseTable::data = (T*) (srcHead + 1); + } + return *this; +} + +/* Init a vector iterator with just a vector. */ +template <class T, class Resize> SVector<T, Resize>:: + Iter::Iter( const SVector &v ) +{ + long length; + if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = v.data; + ptrBeg = v.data-1; + ptrEnd = v.data+length; + } +} + +/* Init a vector iterator with the first of a vector. */ +template <class T, class Resize> SVector<T, Resize>:: + Iter::Iter( const IterFirst &vf ) +{ + long length; + if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vf.v.data; + ptrBeg = vf.v.data-1; + ptrEnd = vf.v.data+length; + } +} + +/* Init a vector iterator with the last of a vector. */ +template <class T, class Resize> SVector<T, Resize>:: + Iter::Iter( const IterLast &vl ) +{ + long length; + if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vl.v.data+length-1; + ptrBeg = vl.v.data-1; + ptrEnd = vl.v.data+length; + } +} + +/* Init a vector iterator with the next of some other iterator. */ +template <class T, class Resize> SVector<T, Resize>:: + Iter::Iter( const IterNext &vn ) +: + ptr(vn.i.ptr+1), + ptrBeg(vn.i.ptrBeg), + ptrEnd(vn.i.ptrEnd) +{ +} + +/* Init a vector iterator with the prev of some other iterator. */ +template <class T, class Resize> SVector<T, Resize>:: + Iter::Iter( const IterPrev &vp ) +: + ptr(vp.i.ptr-1), + ptrBeg(vp.i.ptrBeg), + ptrEnd(vp.i.ptrEnd) +{ +} + +/* Set a vector iterator with some vector. */ +template <class T, class Resize> typename SVector<T, Resize>::Iter & + SVector<T, Resize>::Iter::operator=( const SVector &v ) +{ + long length; + if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = v.data; + ptrBeg = v.data-1; + ptrEnd = v.data+length; + } + return *this; +} + +/* Set a vector iterator with the first element in a vector. */ +template <class T, class Resize> typename SVector<T, Resize>::Iter & + SVector<T, Resize>::Iter::operator=( const IterFirst &vf ) +{ + long length; + if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vf.v.data; + ptrBeg = vf.v.data-1; + ptrEnd = vf.v.data+length; + } + return *this; +} + +/* Set a vector iterator with the last element in a vector. */ +template <class T, class Resize> typename SVector<T, Resize>::Iter & + SVector<T, Resize>::Iter::operator=( const IterLast &vl ) +{ + long length; + if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vl.v.data+length-1; + ptrBeg = vl.v.data-1; + ptrEnd = vl.v.data+length; + } + return *this; +} + +/* Set a vector iterator with the next of some other iterator. */ +template <class T, class Resize> typename SVector<T, Resize>::Iter & + SVector<T, Resize>::Iter::operator=( const IterNext &vn ) +{ + ptr = vn.i.ptr+1; + ptrBeg = vn.i.ptrBeg; + ptrEnd = vn.i.ptrEnd; + return *this; +} + +/* Set a vector iterator with the prev of some other iterator. */ +template <class T, class Resize> typename SVector<T, Resize>::Iter & + SVector<T, Resize>::Iter::operator=( const IterPrev &vp ) +{ + ptr = vp.i.ptr-1; + ptrBeg = vp.i.ptrBeg; + ptrEnd = vp.i.ptrEnd; + return *this; +} + +/* Up resize the data for len elements using Resize::upResize to tell us the + * new length. Reads and writes allocLen. Does not read or write length. + * Assumes that there is some data allocated already. */ +template <class T, class Resize> void SVector<T, Resize>:: + upResize(long len) +{ + /* Get the current header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* Ask the resizer what the new length will be. */ + long newLen = Resize::upResize(head->allocLen, len); + + /* Did the data grow? */ + if ( newLen > head->allocLen ) { + head->allocLen = newLen; + + /* Table exists already, resize it up. */ + head = (STabHead*) realloc( head, sizeof(STabHead) + + sizeof(T) * newLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Save the data pointer. */ + BaseTable::data = (T*) (head + 1); + } +} + +/* Allocates a new buffer for an up resize that requires a duplication of the + * data. Uses Resize::upResize to get the allocation length. Reads and writes + * allocLen. This upResize does write the new length. Assumes that there is + * some data allocated already. */ +template <class T, class Resize> void SVector<T, Resize>:: + upResizeDup(long len) +{ + /* Get the current header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* Ask the resizer what the new length will be. */ + long newLen = Resize::upResize(head->allocLen, len); + + /* Dereferencing the existing data, decrement the refcount. */ + head->refCount -= 1; + + /* Table exists already, resize it up. */ + head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + head->refCount = 1; + head->allocLen = newLen; + head->tabLen = len; + + /* Save the data pointer. */ + BaseTable::data = (T*) (head + 1); +} + +/* Up resize the data for len elements using Resize::upResize to tell us the + * new length. Reads and writes allocLen. This upresize DOES write length. + * Assumes that no data is allocated. */ +template <class T, class Resize> void SVector<T, Resize>:: + upResizeFromEmpty(long len) +{ + /* There is no table yet. If the len is zero, then there is no need to + * create a table. */ + if ( len > 0 ) { + /* Ask the resizer what the new length will be. */ + long newLen = Resize::upResize(0, len); + + /* If len is greater than zero then we are always allocating the table. */ + STabHead *head = (STabHead*) malloc( sizeof(STabHead) + + sizeof(T) * newLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Set up the header and save the data pointer. Note that we set the + * length here. This differs from the other upResizes. */ + head->refCount = 1; + head->allocLen = newLen; + head->tabLen = len; + BaseTable::data = (T*) (head + 1); + } +} + +/* Down resize the data for len elements using Resize::downResize to determine + * the new length. Reads and writes allocLen. Does not read or write length. */ +template <class T, class Resize> void SVector<T, Resize>:: + downResize(long len) +{ + /* If there is already no length, then there is nothing we can do. */ + if ( BaseTable::data != 0 ) { + /* Get the current header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* Ask the resizer what the new length will be. */ + long newLen = Resize::downResize( head->allocLen, len ); + + /* Did the data shrink? */ + if ( newLen < head->allocLen ) { + if ( newLen == 0 ) { + /* Simply free the data. */ + free( head ); + BaseTable::data = 0; + } + else { + /* Save the new allocated length. */ + head->allocLen = newLen; + + /* Not shrinking to size zero, realloc it to the smaller size. */ + head = (STabHead*) realloc( head, sizeof(STabHead) + + sizeof(T) * newLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Save the new data ptr. */ + BaseTable::data = (T*) (head + 1); + } + } + } +} + +/* Allocate a new buffer for a down resize and duplication of the array. The + * new array will be len long and allocation size will be determined using + * Resize::downResize with the old array's allocLen. Does not actually copy + * any data. Reads and writes allocLen and writes the new len. */ +template <class T, class Resize> void SVector<T, Resize>:: + downResizeDup(long len) +{ + /* If there is already no length, then there is nothing we can do. */ + if ( BaseTable::data != 0 ) { + /* Get the current header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* Ask the resizer what the new length will be. */ + long newLen = Resize::downResize( head->allocLen, len ); + + /* Detaching from the existing head, decrement the refcount. */ + head->refCount -= 1; + + /* Not shrinking to size zero, malloc it to the smaller size. */ + head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen ); + if ( head == 0 ) + throw std::bad_alloc(); + + /* Save the new allocated length. */ + head->refCount = 1; + head->allocLen = newLen; + head->tabLen = len; + + /* Save the data pointer. */ + BaseTable::data = (T*) (head + 1); + } +} + +/** + * \brief Free all memory used by the vector. + * + * The vector is reset to zero elements. Destructors are called on all + * elements in the vector. The space allocated for the vector is freed. + */ +template <class T, class Resize> void SVector<T, Resize>:: + empty() +{ + if ( BaseTable::data != 0 ) { + /* Get the header and drop the refcount on the data. */ + STabHead *head = ((STabHead*) BaseTable::data) - 1; + head->refCount -= 1; + + /* If the refcount just went down to zero nobody else is referencing + * the data. */ + if ( head->refCount == 0 ) { + /* Call All destructors. */ + T *pos = BaseTable::data; + for ( long i = 0; i < head->tabLen; pos++, i++ ) + pos->~T(); + + /* Free the data space. */ + free( head ); + } + + /* Clear the pointer. */ + BaseTable::data = 0; + } +} + +/* Prepare for setting the contents of the vector to some array len long. + * Handles reusing the existing space, detaching from a common space or + * growing from zero length automatically. */ +template <class T, class Resize> void SVector<T, Resize>:: + setAsCommon(long len) +{ + if ( BaseTable::data != 0 ) { + /* Get the header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* If the refCount is one, then we can reuse the space. Otherwise we + * must detach from the referenced data create new space. */ + if ( head->refCount == 1 ) { + /* Call All destructors. */ + T *pos = BaseTable::data; + for ( long i = 0; i < head->tabLen; pos++, i++ ) + pos->~T(); + + /* Adjust the allocated length. */ + if ( len < head->tabLen ) + downResize( len ); + else if ( len > head->tabLen ) + upResize( len ); + + if ( BaseTable::data != 0 ) { + /* Get the header again and set the length. */ + head = ((STabHead*)BaseTable::data) - 1; + head->tabLen = len; + } + } + else { + /* Just detach from the data. */ + head->refCount -= 1; + BaseTable::data = 0; + + /* Make enough space. This will set the length. */ + upResizeFromEmpty( len ); + } + } + else { + /* The table is currently empty. Make enough space. This will set the + * length. */ + upResizeFromEmpty( len ); + } +} + +/** + * \brief Set the contents of the vector to be len elements exactly. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. Copy constructors are used to place the + * new elements in the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + setAs(const T *val, long len) +{ + /* Common stuff for setting the array to len long. */ + setAsCommon( len ); + + /* Copy data in. */ + T *dst = BaseTable::data; + const T *src = val; + for ( long i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); +} + + +/** + * \brief Set the vector to len copies of item. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. The element's copy constructor is used to + * copy the item into the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + setAsDup(const T &item, long len) +{ + /* Do the common stuff for setting the array to len long. */ + setAsCommon( len ); + + /* Copy item in one spot at a time. */ + T *dst = BaseTable::data; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(item); +} + +/** + * \brief Set the vector to exactly len new items. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. Default constructors are used to init the + * new items. + */ +template <class T, class Resize> void SVector<T, Resize>:: + setAsNew(long len) +{ + /* Do the common stuff for setting the array to len long. */ + setAsCommon( len ); + + /* Create items using default constructor. */ + T *dst = BaseTable::data; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); +} + +/* Make space in vector for a replacement at pos of len items. Handles reusing + * existing space, detaching or growing from zero space. */ +template <class T, class Resize> long SVector<T, Resize>:: + replaceCommon(long pos, long len) +{ + if ( BaseTable::data != 0 ) { + /* Get the header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* If we are given a negative position to replace at then treat it as + * a position relative to the length. This doesn't have any meaning + * unless the length is at least one. */ + if ( pos < 0 ) + pos = head->tabLen + pos; + + /* The end is the one past the last item that we want to write to. */ + long i, endPos = pos + len; + + if ( head->refCount == 1 ) { + /* We can reuse the space. Make sure we have enough space. */ + if ( endPos > head->tabLen ) { + upResize( endPos ); + + /* Get the header again, whose addr may have changed after + * resizing. */ + head = ((STabHead*)BaseTable::data) - 1; + + /* Delete any objects we need to delete. */ + T *item = BaseTable::data + pos; + for ( i = pos; i < head->tabLen; i++, item++ ) + item->~T(); + + /* We are extending the vector, set the new data length. */ + head->tabLen = endPos; + } + else { + /* Delete any objects we need to delete. */ + T *item = BaseTable::data + pos; + for ( i = pos; i < endPos; i++, item++ ) + item->~T(); + } + } + else { + /* Use endPos to calc the end of the vector. */ + long newLen = endPos; + if ( newLen < head->tabLen ) + newLen = head->tabLen; + + /* Duplicate and grow up to endPos. This will set the length. */ + upResizeDup( newLen ); + + /* Copy from src up to pos. */ + const T *src = (T*) (head + 1); + T *dst = BaseTable::data; + for ( i = 0; i < pos; i++, dst++, src++) + new(dst) T(*src); + + /* Copy any items after the replace range. */ + for ( i += len, src += len, dst += len; + i < head->tabLen; i++, dst++, src++ ) + new(dst) T(*src); + } + } + else { + /* There is no data initially, must grow from zero. This will set the + * new length. */ + upResizeFromEmpty( len ); + } + + return pos; +} + + +/** + * \brief Replace len elements at position pos. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. Copy constructors are used + * to place the elements into the vector. It is allowable for the pos and + * length to specify a replacement that overwrites existing elements and + * creates new ones. If pos is greater than the length of the vector then + * undefined behaviour results. If pos is negative, then it is treated as an + * offset relative to the length of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + replace(long pos, const T *val, long len) +{ + /* Common work for replacing in the vector. */ + pos = replaceCommon( pos, len ); + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + const T *src = val; + for ( long i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); +} + +/** + * \brief Replace at position pos with len copies of an item. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. The copy constructor is + * used to place the element into this vector. It is allowable for the pos and + * length to specify a replacement that overwrites existing elements and + * creates new ones. If pos is greater than the length of the vector then + * undefined behaviour results. If pos is negative, then it is treated as an + * offset relative to the length of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + replaceDup(long pos, const T &val, long len) +{ + /* Common replacement stuff. */ + pos = replaceCommon( pos, len ); + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(val); +} + +/** + * \brief Replace at position pos with len new elements. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. The default constructor is + * used to initialize the new elements. It is allowable for the pos and length + * to specify a replacement that overwrites existing elements and creates new + * ones. If pos is greater than the length of the vector then undefined + * behaviour results. If pos is negative, then it is treated as an offset + * relative to the length of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + replaceNew(long pos, long len) +{ + /* Do the common replacement stuff. */ + pos = replaceCommon( pos, len ); + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); +} + +/** + * \brief Remove len elements at position pos. + * + * Destructor is called on all elements removed. Elements to the right of pos + * are shifted len spaces to the left to take up the free space. If pos is + * greater than or equal to the length of the vector then undefined behavior + * results. If pos is negative then it is treated as an offset relative to the + * length of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + remove(long pos, long len) +{ + /* If there is no data, we can't delete anything anyways. */ + if ( BaseTable::data != 0 ) { + /* Get the header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* If we are given a negative position to remove at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = head->tabLen + pos; + + /* The first position after the last item deleted. */ + long endPos = pos + len; + + /* The New data length. */ + long i, newLen = head->tabLen - len; + + if ( head->refCount == 1 ) { + /* We are the only ones using the data. We can reuse + * the existing space. */ + + /* The place in the data we are deleting at. */ + T *dst = BaseTable::data + pos; + + /* Call Destructors. */ + T *item = BaseTable::data + pos; + for ( i = 0; i < len; i += 1, item += 1 ) + item->~T(); + + /* Shift data over if necessary. */ + long lenToSlideOver = head->tabLen - endPos; + if ( len > 0 && lenToSlideOver > 0 ) + memmove(BaseTable::data + pos, dst + len, sizeof(T)*lenToSlideOver); + + /* Shrink the data if necessary. */ + downResize( newLen ); + + if ( BaseTable::data != 0 ) { + /* Get the header again (because of the resize) and set the + * new data length. */ + head = ((STabHead*)BaseTable::data) - 1; + head->tabLen = newLen; + } + } + else { + /* Must detach from the common data. Just copy the non-deleted + * items from the common data. */ + + /* Duplicate and grow down to newLen. This will set the length. */ + downResizeDup( newLen ); + + /* Copy over just the non-deleted parts. */ + const T *src = (T*) (head + 1); + T *dst = BaseTable::data; + for ( i = 0; i < pos; i++, dst++, src++ ) + new(dst) T(*src); + + /* ... and the second half. */ + for ( i += len, src += len; i < head->tabLen; i++, src++, dst++ ) + new(dst) T(*src); + } + } +} + +/* Shift over existing data. Handles reusing existing space, detaching or + * growing from zero space. */ +template <class T, class Resize> long SVector<T, Resize>:: + insertCommon(long pos, long len) +{ + if ( BaseTable::data != 0 ) { + /* Get the header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* If we are given a negative position to insert at then treat it as a + * position relative to the length. This only has meaning if there is + * existing data. */ + if ( pos < 0 ) + pos = head->tabLen + pos; + + /* Calculate the new length. */ + long i, newLen = head->tabLen + len; + + if ( head->refCount == 1 ) { + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Get the header again, (the addr may have changed after + * resizing). */ + head = ((STabHead*)BaseTable::data) - 1; + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < head->tabLen ) { + memmove( BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(head->tabLen - pos) ); + } + + /* Grow the length by the len inserted. */ + head->tabLen += len; + } + else { + /* Need to detach from the existing array. Copy over the other + * parts. This will set the length. */ + upResizeDup( newLen ); + + /* Copy over the parts around the insert. */ + const T *src = (T*) (head + 1); + T *dst = BaseTable::data; + for ( i = 0; i < pos; i++, dst++, src++ ) + new(dst) T(*src); + + /* ... and the second half. */ + for ( dst += len; i < head->tabLen; i++, src++, dst++ ) + new(dst) T(*src); + } + } + else { + /* There is no existing data. Start from zero. This will set the + * length. */ + upResizeFromEmpty( len ); + } + + return pos; +} + + +/** + * \brief Insert len elements at position pos. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * The copy constructor is used to place the elements into this vector. If pos + * is greater than the length of the vector then undefined behaviour results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + insert(long pos, const T *val, long len) +{ + /* Do the common insertion stuff. */ + pos = insertCommon( pos, len ); + + /* Copy data in element by element. */ + T *dst = BaseTable::data + pos; + const T *src = val; + for ( long i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); +} + +/** + * \brief Insert len copies of item at position pos. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * The copy constructor is used to place the element into this vector. If pos + * is greater than the length of the vector then undefined behaviour results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + insertDup(long pos, const T &item, long len) +{ + /* Do the common insertion stuff. */ + pos = insertCommon( pos, len ); + + /* Copy the data item in one at a time. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(item); +} + + +/** + * \brief Insert len new elements using the default constructor. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * Default constructors are used to init the new elements. If pos is off the + * end of the vector then undefined behaviour results. If pos is negative then + * it is treated as an offset relative to the length of the vector. + */ +template <class T, class Resize> void SVector<T, Resize>:: + insertNew(long pos, long len) +{ + /* Do the common insertion stuff. */ + pos = insertCommon( pos, len ); + + /* Init new data with default constructors. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); +} + +/* Makes space for len items, Does not init the items in any way. If pos is + * greater than the length of the vector then undefined behaviour results. + * Updates the length of the vector. */ +template <class T, class Resize> void SVector<T, Resize>:: + makeRawSpaceFor(long pos, long len) +{ + if ( BaseTable::data != 0 ) { + /* Get the header. */ + STabHead *head = ((STabHead*)BaseTable::data) - 1; + + /* Calculate the new length. */ + long i, newLen = head->tabLen + len; + + if ( head->refCount == 1 ) { + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Get the header again, (the addr may have changed after + * resizing). */ + head = ((STabHead*)BaseTable::data) - 1; + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < head->tabLen ) { + memmove( BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(head->tabLen - pos) ); + } + + /* Grow the length by the len inserted. */ + head->tabLen += len; + } + else { + /* Need to detach from the existing array. Copy over the other + * parts. This will set the length. */ + upResizeDup( newLen ); + + /* Copy over the parts around the insert. */ + const T *src = (T*) (head + 1); + T *dst = BaseTable::data; + for ( i = 0; i < pos; i++, dst++, src++ ) + new(dst) T(*src); + + /* ... and the second half. */ + for ( dst += len; i < head->tabLen; i++, src++, dst++ ) + new(dst) T(*src); + } + } + else { + /* There is no existing data. Start from zero. This will set the + * length. */ + upResizeFromEmpty( len ); + } +} + + +#ifdef AAPL_NAMESPACE +} +#endif + + +#endif /* _AAPL_SVECTOR_H */ diff --git a/aapl/table.h b/aapl/table.h new file mode 100644 index 00000000..c218281b --- /dev/null +++ b/aapl/table.h @@ -0,0 +1,252 @@ +/* + * Copyright 2001, 2002 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_TABLE_H +#define _AAPL_TABLE_H + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup vector + * @{ + */ + +/** \class Table + * \brief Base class for dynamic arrays. + * + * Table is used as the common data storage class for vectors. It does not + * provide any methods to operate on the data and as such it is not intended + * to be used directly. It exists so that algorithms that operatate on dynamic + * arrays can be written without knowing about the various vector classes that + * my exist. + */ + +/*@}*/ + +/* Table class. */ +template <class T> class Table +{ +public: + /* Default Constructor. */ + inline Table(); + + /** + * \brief Get the length of the vector. + * + * \returns the length of the vector. + */ + long length() const + { return tabLen; } + + /** + * \brief Table data. + * + * The pointer to the elements in the vector. Modifying the vector may + * cause this pointer to change. + */ + T *data; + + /** + * \brief Table length. + * + * The number of items of type T in the table. + */ + long tabLen; + + /** + * \brief Allocated length. + * + * The number of items for which there is room in the current allocation. + */ + long allocLen; +}; + +/** + * \brief Default constructor + * + * Initialize table data to empty. + */ +template <class T> inline Table<T>::Table() +: + data(0), + tabLen(0), + allocLen(0) +{ +} + +/* Default shared table header class. */ +struct STabHead +{ + /** + * \brief Table length. + * + * The number of items of type T in the table. + */ + long tabLen; + + /** + * \brief Allocated length. + * + * The number of items for which there is room in the current allocation. + */ + long allocLen; + + /** + * \brief Ref Count. + * + * The number of shared vectors referencing this data. + */ + long refCount; +}; + +/** + * \addtogroup vector + * @{ + */ + +/** \class STable + * \brief Base class for implicitly shared dynamic arrays. + * + * STable is used as the common data storage class for shared vectors. It does + * not provide any methods to operate on the data and as such it is not + * intended to be used directly. It exists so that algorithms that operatate + * on dynamic arrays can be written without knowing about the various shared + * vector classes that my exist. + */ + +/*@}*/ + +/* STable class. */ +template <class T> class STable +{ +public: + /* Default Constructor. */ + inline STable(); + + /** + * \brief Get the length of the shared vector. + * + * \returns the length of the shared vector. + */ + long length() const + { return data == 0 ? 0 : (((STabHead*)data) - 1)->tabLen; } + + /** + * \brief Get header of the shared vector. + * + * \returns the header of the shared vector. + */ + STabHead *header() const + { return data == 0 ? 0 : (((STabHead*)data) - 1); } + + /** + * \brief Table data. + * + * The pointer to the elements in the vector. The shared table header is + * located just behind the data. Modifying the vector may cause this + * pointer to change. + */ + T *data; +}; + +/** + * \brief Default constructor + * + * Initialize shared table data to empty. + */ +template <class T> inline STable<T>::STable() +: + data(0) +{ +} + +/* If needed is greater than existing, give twice needed. */ +#define EXPN_UP( existing, needed ) \ + needed > existing ? (needed<<1) : existing + +/* If needed is less than 1 quarter existing, give twice needed. */ +#define EXPN_DOWN( existing, needed ) \ + needed < (existing>>2) ? (needed<<1) : existing + +/** + * \addtogroup vector + * @{ + */ + +/** \class ResizeExpn + * \brief Exponential table resizer. + * + * ResizeExpn is the default table resizer. When an up resize is needed, space + * is doubled. When a down resize is needed, space is halved. The result is + * that when growing the vector in a linear fashion, the number of resizes of + * the allocated space behaves logarithmically. + * + * If only up resizes are done, there will never be more than 2 times the + * needed space allocated. If down resizes are done as well, there will never + * be more than 4 times the needed space allocated. ResizeExpn uses this 50% + * usage policy on up resizing and 25% usage policy on down resizing to + * improve performance when repeatedly inserting and removing a small number + * of elements relative to the size of the array. This scheme guarantees that + * repetitive inserting and removing of a small number of elements will never + * result in repetative reallocation. + * + * The sizes passed to the resizer from the vectors are in units of T. + */ + +/*@}*/ + +/* Exponential resizer. */ +class ResizeExpn +{ +protected: + /** + * \brief Determine the new table size when up resizing. + * + * If the existing size is insufficient for the space needed then allocate + * twice the space needed. Otherwise use the existing size. + * + * \returns The new table size. + */ + static inline long upResize( long existing, long needed ) + { return EXPN_UP( existing, needed ); } + + /** + * \brief Determine the new table size when down resizing. + * + * If the space needed is less than one quarter of the existing size then + * allocate twice the space needed. Otherwise use the exitsing size. + * + * \returns The new table size. + */ + static inline long downResize( long existing, long needed ) + { return EXPN_DOWN( existing, needed ); } +}; + +#undef EXPN_UP +#undef EXPN_DOWN + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_TABLE_H */ diff --git a/aapl/vector.h b/aapl/vector.h new file mode 100644 index 00000000..5e7f9e57 --- /dev/null +++ b/aapl/vector.h @@ -0,0 +1,1189 @@ +/* + * Copyright 2002, 2006 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Aapl. + * + * Aapl 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. + * + * Aapl 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 Aapl; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AAPL_VECTOR_H +#define _AAPL_VECTOR_H + +#include <new> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include "table.h" + +#ifdef AAPL_NAMESPACE +namespace Aapl { +#endif + +/** + * \addtogroup vector + * @{ + */ + +/** \class Vector + * \brief Dynamic array. + * + * This is typical vector implementation. It is a dynamic array that can be + * used to contain complex data structures that have constructors and + * destructors as well as simple types such as integers and pointers. + * + * Vector supports inserting, overwriting, and removing single or multiple + * elements at once. Constructors and destructors are called wherever + * appropriate. For example, before an element is overwritten, it's + * destructor is called. + * + * Vector provides automatic resizing of allocated memory as needed and offers + * different allocation schemes for controlling how the automatic allocation + * is done. Two senses of the the length of the data is maintained: the + * amount of raw memory allocated to the vector and the number of actual + * elements in the vector. The various allocation schemes control how the + * allocated space is changed in relation to the number of elements in the + * vector. + * + * \include ex_vector.cpp + */ + +/*@}*/ + +template < class T, class Resize = ResizeExpn > class Vector + : public Table<T>, public Resize +{ +private: + typedef Table<T> BaseTable; + +public: + /** + * \brief Initialize an empty vector with no space allocated. + * + * If a linear resizer is used, the step defaults to 256 units of T. For a + * runtime vector both up and down allocation schemes default to + * Exponential. + */ + Vector() { } + + /** + * \brief Create a vector that contains an initial element. + * + * The vector becomes one element in length. The element's copy + * constructor is used to place the value in the vector. + */ + Vector(const T &val) { setAs(&val, 1); } + + /** + * \brief Create a vector that contains an array of elements. + * + * The vector becomes len elements in length. Copy constructors are used + * to place the new elements in the vector. + */ + Vector(const T *val, long len) { setAs(val, len); } + + /* Deep copy. */ + Vector( const Vector &v ); + + /* Free all mem used by the vector. */ + ~Vector() { empty(); } + + /* Delete all items. */ + void empty(); + + /* Abandon the contents of the vector without deleteing. */ + void abandon(); + + /* Transfers the elements of another vector into this vector. First emptys + * the current vector. */ + void transfer( Vector &v ); + + /* Perform a deep copy of another vector into this vector. */ + Vector &operator=( const Vector &v ); + + /* Stack operations. */ + void push( const T &t ) { append( t ); } + void pop() { remove( BaseTable::tabLen - 1 ); } + T &top() { return BaseTable::data[BaseTable::tabLen - 1]; } + + /*@{*/ + /** + * \brief Insert one element at position pos. + * + * Elements in the vector from pos onward are shifted one space to the + * right. The copy constructor is used to place the element into this + * vector. If pos is greater than the length of the vector then undefined + * behaviour results. If pos is negative then it is treated as an offset + * relative to the length of the vector. + */ + void insert(long pos, const T &val) { insert(pos, &val, 1); } + + /* Insert an array of values. */ + void insert(long pos, const T *val, long len); + + /** + * \brief Insert all the elements from another vector at position pos. + * + * Elements in this vector from pos onward are shifted v.tabLen spaces to + * the right. The element's copy constructor is used to copy the items + * into this vector. The other vector is left unchanged. If pos is off the + * end of the vector, then undefined behaviour results. If pos is negative + * then it is treated as an offset relative to the length of the vector. + * Equivalent to vector.insert(pos, other.data, other.tabLen). + */ + void insert(long pos, const Vector &v) { insert(pos, v.data, v.tabLen); } + + /* Insert len copies of val into the vector. */ + void insertDup(long pos, const T &val, long len); + + /** + * \brief Insert one new element using the default constrcutor. + * + * Elements in the vector from pos onward are shifted one space to the + * right. The default constructor is used to init the new element. If pos + * is greater than the length of the vector then undefined behaviour + * results. If pos is negative then it is treated as an offset relative to + * the length of the vector. + */ + void insertNew(long pos) { insertNew(pos, 1); } + + /* Insert len new items using default constructor. */ + void insertNew(long pos, long len); + /*@}*/ + + /*@{*/ + /** + * \brief Remove one element at position pos. + * + * The element's destructor is called. Elements to the right of pos are + * shifted one space to the left to take up the free space. If pos is greater + * than or equal to the length of the vector then undefined behavior results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ + void remove(long pos) { remove(pos, 1); } + + /* Delete a number of elements. */ + void remove(long pos, long len); + /*@}*/ + + /*@{*/ + /** + * \brief Replace one element at position pos. + * + * If there is an existing element at position pos (if pos is less than + * the length of the vector) then its destructor is called before the + * space is used. The copy constructor is used to place the element into + * the vector. If pos is greater than the length of the vector then + * undefined behaviour results. If pos is negative then it is treated as + * an offset relative to the length of the vector. + */ + void replace(long pos, const T &val) { replace(pos, &val, 1); } + + /* Replace with an array of values. */ + void replace(long pos, const T *val, long len); + + /** + * \brief Replace at position pos with all the elements of another vector. + * + * Replace at position pos with all the elements of another vector. The + * other vector is left unchanged. If there are existing elements at the + * positions to be replaced, then destructors are called before the space + * is used. Copy constructors are used to place the elements into this + * vector. It is allowable for the pos and length of the other vector to + * specify a replacement that overwrites existing elements and creates new + * ones. If pos is greater than the length of the vector then undefined + * behaviour results. If pos is negative, then it is treated as an offset + * relative to the length of the vector. + */ + void replace(long pos, const Vector &v) { replace(pos, v.data, v.tabLen); } + + /* Replace len items with len copies of val. */ + void replaceDup(long pos, const T &val, long len); + + /** + * \brief Replace at position pos with one new element. + * + * If there is an existing element at the position to be replaced (pos is + * less than the length of the vector) then the element's destructor is + * called before the space is used. The default constructor is used to + * initialize the new element. If pos is greater than the length of the + * vector then undefined behaviour results. If pos is negative, then it is + * treated as an offset relative to the length of the vector. + */ + void replaceNew(long pos) { replaceNew(pos, 1); } + + /* Replace len items at pos with newly constructed objects. */ + void replaceNew(long pos, long len); + /*@}*/ + + /*@{*/ + /** + * \brief Set the contents of the vector to be val exactly. + * + * The vector becomes one element in length. Destructors are called on any + * existing elements in the vector. The element's copy constructor is used + * to place the val in the vector. + */ + void setAs(const T &val) { setAs(&val, 1); } + + /* Set to the contents of an array. */ + void setAs(const T *val, long len); + + /** + * \brief Set the vector to exactly the contents of another vector. + * + * The vector becomes v.tabLen elements in length. Destructors are called + * on any existing elements. Copy constructors are used to place the new + * elements in the vector. + */ + void setAs(const Vector &v) { setAs(v.data, v.tabLen); } + + /* Set as len copies of item. */ + void setAsDup(const T &item, long len); + + /** + * \brief Set the vector to exactly one new item. + * + * The vector becomes one element in length. Destructors are called on any + * existing elements in the vector. The default constructor is used to + * init the new item. + */ + void setAsNew() { setAsNew(1); } + + /* Set as newly constructed objects using the default constructor. */ + void setAsNew(long len); + /*@}*/ + + /*@{*/ + /** + * \brief Append one elment to the end of the vector. + * + * Copy constructor is used to place the element in the vector. + */ + void append(const T &val) { replace(BaseTable::tabLen, &val, 1); } + + /** + * \brief Append len elements to the end of the vector. + * + * Copy constructors are used to place the elements in the vector. + */ + void append(const T *val, long len) { replace(BaseTable::tabLen, val, len); } + + /** + * \brief Append the contents of another vector. + * + * The other vector is left unchanged. Copy constructors are used to place the + * elements in the vector. + */ + void append(const Vector &v) { replace(BaseTable::tabLen, v.data, v.tabLen); } + + /** + * \brief Append len copies of item. + * + * The copy constructor is used to place the item in the vector. + */ + void appendDup(const T &item, long len) { replaceDup(BaseTable::tabLen, item, len); } + + /** + * \brief Append a single newly created item. + * + * The new element is initialized with the default constructor. + */ + void appendNew() { replaceNew(BaseTable::tabLen, 1); } + + /** + * \brief Append len newly created items. + * + * The new elements are initialized with the default constructor. + */ + void appendNew(long len) { replaceNew(BaseTable::tabLen, len); } + /*@}*/ + + /*@{*/ + /** \fn Vector::prepend(const T &val) + * \brief Prepend one elment to the front of the vector. + * + * Copy constructor is used to place the element in the vector. + */ + void prepend(const T &val) { insert(0, &val, 1); } + + /** + * \brief Prepend len elements to the front of the vector. + * + * Copy constructors are used to place the elements in the vector. + */ + void prepend(const T *val, long len) { insert(0, val, len); } + + /** + * \brief Prepend the contents of another vector. + * + * The other vector is left unchanged. Copy constructors are used to place the + * elements in the vector. + */ + void prepend(const Vector &v) { insert(0, v.data, v.tabLen); } + + /** + * \brief Prepend len copies of item. + * + * The copy constructor is used to place the item in the vector. + */ + void prependDup(const T &item, long len) { insertDup(0, item, len); } + + /** + * \brief Prepend a single newly created item. + * + * The new element is initialized with the default constructor. + */ + void prependNew() { insertNew(0, 1); } + + /** + * \brief Prepend len newly created items. + * + * The new elements are initialized with the default constructor. + */ + void prependNew(long len) { insertNew(0, len); } + /*@}*/ + + /* Convenience access. */ + T &operator[](int i) const { return BaseTable::data[i]; } + long size() const { return BaseTable::tabLen; } + + /* Forward this so a ref can be used. */ + struct Iter; + + /* Various classes for setting the iterator */ + struct IterFirst { IterFirst( const Vector &v ) : v(v) { } const Vector &v; }; + struct IterLast { IterLast( const Vector &v ) : v(v) { } const Vector &v; }; + struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; + struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; + + /** + * \brief Vector Iterator. + * \ingroup iterators + */ + struct Iter + { + /* Construct, assign. */ + Iter() : ptr(0), ptrBeg(0), ptrEnd(0) { } + + /* Construct. */ + Iter( const Vector &v ); + Iter( const IterFirst &vf ); + Iter( const IterLast &vl ); + inline Iter( const IterNext &vn ); + inline Iter( const IterPrev &vp ); + + /* Assign. */ + Iter &operator=( const Vector &v ); + Iter &operator=( const IterFirst &vf ); + Iter &operator=( const IterLast &vl ); + inline Iter &operator=( const IterNext &vf ); + inline Iter &operator=( const IterPrev &vl ); + + /** \brief Less than end? */ + bool lte() const { return ptr != ptrEnd; } + + /** \brief At end? */ + bool end() const { return ptr == ptrEnd; } + + /** \brief Greater than beginning? */ + bool gtb() const { return ptr != ptrBeg; } + + /** \brief At beginning? */ + bool beg() const { return ptr == ptrBeg; } + + /** \brief At first element? */ + bool first() const { return ptr == ptrBeg+1; } + + /** \brief At last element? */ + bool last() const { return ptr == ptrEnd-1; } + + /* Return the position. */ + long pos() const { return ptr - ptrBeg - 1; } + T &operator[](int i) const { return ptr[i]; } + + /** \brief Implicit cast to T*. */ + operator T*() const { return ptr; } + + /** \brief Dereference operator returns T&. */ + T &operator *() const { return *ptr; } + + /** \brief Arrow operator returns T*. */ + T *operator->() const { return ptr; } + + /** \brief Move to next item. */ + T *operator++() { return ++ptr; } + + /** \brief Move to next item. */ + T *operator++(int) { return ptr++; } + + /** \brief Move to next item. */ + T *increment() { return ++ptr; } + + /** \brief Move n items forward. */ + T *operator+=(long n) { return ptr+=n; } + + /** \brief Move to previous item. */ + T *operator--() { return --ptr; } + + /** \brief Move to previous item. */ + T *operator--(int) { return ptr--; } + + /** \brief Move to previous item. */ + T *decrement() { return --ptr; } + + /** \brief Move n items back. */ + T *operator-=(long n) { return ptr-=n; } + + /** \brief Return the next item. Does not modify this. */ + inline IterNext next() const { return IterNext(*this); } + + /** \brief Return the previous item. Does not modify this. */ + inline IterPrev prev() const { return IterPrev(*this); } + + /** \brief The iterator is simply a pointer. */ + T *ptr; + + /* For testing endpoints. */ + T *ptrBeg, *ptrEnd; + }; + + /** \brief Return first element. */ + IterFirst first() { return IterFirst( *this ); } + + /** \brief Return last element. */ + IterLast last() { return IterLast( *this ); } + +protected: + void makeRawSpaceFor(long pos, long len); + + void upResize(long len); + void downResize(long len); +}; + +/* Init a vector iterator with just a vector. */ +template <class T, class Resize> Vector<T, Resize>::Iter::Iter( const Vector &v ) +{ + if ( v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = v.data; + ptrBeg = v.data-1; + ptrEnd = v.data+v.tabLen; + } +} + +/* Init a vector iterator with the first of a vector. */ +template <class T, class Resize> Vector<T, Resize>::Iter::Iter( + const IterFirst &vf ) +{ + if ( vf.v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vf.v.data; + ptrBeg = vf.v.data-1; + ptrEnd = vf.v.data+vf.v.tabLen; + } +} + +/* Init a vector iterator with the last of a vector. */ +template <class T, class Resize> Vector<T, Resize>::Iter::Iter( + const IterLast &vl ) +{ + if ( vl.v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vl.v.data+vl.v.tabLen-1; + ptrBeg = vl.v.data-1; + ptrEnd = vl.v.data+vl.v.tabLen; + } +} + +/* Init a vector iterator with the next of some other iterator. */ +template <class T, class Resize> Vector<T, Resize>::Iter::Iter( + const IterNext &vn ) +: + ptr(vn.i.ptr+1), + ptrBeg(vn.i.ptrBeg), + ptrEnd(vn.i.ptrEnd) +{ +} + +/* Init a vector iterator with the prev of some other iterator. */ +template <class T, class Resize> Vector<T, Resize>::Iter::Iter( + const IterPrev &vp ) +: + ptr(vp.i.ptr-1), + ptrBeg(vp.i.ptrBeg), + ptrEnd(vp.i.ptrEnd) +{ +} + +/* Set a vector iterator with some vector. */ +template <class T, class Resize> typename Vector<T, Resize>::Iter & + Vector<T, Resize>::Iter::operator=( const Vector &v ) +{ + if ( v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = v.data; + ptrBeg = v.data-1; + ptrEnd = v.data+v.tabLen; + } + return *this; +} + +/* Set a vector iterator with the first element in a vector. */ +template <class T, class Resize> typename Vector<T, Resize>::Iter & + Vector<T, Resize>::Iter::operator=( const IterFirst &vf ) +{ + if ( vf.v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vf.v.data; + ptrBeg = vf.v.data-1; + ptrEnd = vf.v.data+vf.v.tabLen; + } + return *this; +} + +/* Set a vector iterator with the last element in a vector. */ +template <class T, class Resize> typename Vector<T, Resize>::Iter & + Vector<T, Resize>::Iter::operator=( const IterLast &vl ) +{ + if ( vl.v.tabLen == 0 ) + ptr = ptrBeg = ptrEnd = 0; + else { + ptr = vl.v.data+vl.v.tabLen-1; + ptrBeg = vl.v.data-1; + ptrEnd = vl.v.data+vl.v.tabLen; + } + return *this; +} + +/* Set a vector iterator with the next of some other iterator. */ +template <class T, class Resize> typename Vector<T, Resize>::Iter & + Vector<T, Resize>::Iter::operator=( const IterNext &vn ) +{ + ptr = vn.i.ptr+1; + ptrBeg = vn.i.ptrBeg; + ptrEnd = vn.i.ptrEnd; + return *this; +} + +/* Set a vector iterator with the prev of some other iterator. */ +template <class T, class Resize> typename Vector<T, Resize>::Iter & + Vector<T, Resize>::Iter::operator=( const IterPrev &vp ) +{ + ptr = vp.i.ptr-1; + ptrBeg = vp.i.ptrBeg; + ptrEnd = vp.i.ptrEnd; + return *this; +} + +/** + * \brief Forget all elements in the vector. + * + * The contents of the vector are reset to null without without the space + * being freed. + */ +template<class T, class Resize> void Vector<T, Resize>:: + abandon() +{ + BaseTable::data = 0; + BaseTable::tabLen = 0; + BaseTable::allocLen = 0; +} + +/** + * \brief Transfer the contents of another vector into this vector. + * + * The dynamic array of the other vector is moved into this vector by + * reference. If this vector is non-empty then its contents are first deleted. + * Afterward the other vector will be empty. + */ +template<class T, class Resize> void Vector<T, Resize>:: + transfer( Vector &v ) +{ + empty(); + + BaseTable::data = v.data; + BaseTable::tabLen = v.tabLen; + BaseTable::allocLen = v.allocLen; + + v.abandon(); +} + +/** + * \brief Deep copy another vector into this vector. + * + * Copies the entire contents of the other vector into this vector. Any + * existing contents are first deleted. Equivalent to setAs. + * + * \returns A reference to this. + */ +template<class T, class Resize> Vector<T, Resize> &Vector<T, Resize>:: + operator=( const Vector &v ) +{ + setAs(v.data, v.tabLen); + return *this; +} + +/* Up resize the data for len elements using Resize::upResize to tell us the + * new tabLen. Reads and writes allocLen. Does not read or write tabLen. */ +template<class T, class Resize> void Vector<T, Resize>:: + upResize(long len) +{ + /* Ask the resizer what the new tabLen will be. */ + long newLen = Resize::upResize(BaseTable::allocLen, len); + + /* Did the data grow? */ + if ( newLen > BaseTable::allocLen ) { + BaseTable::allocLen = newLen; + if ( BaseTable::data != 0 ) { + /* Table exists already, resize it up. */ + BaseTable::data = (T*) realloc( BaseTable::data, sizeof(T) * newLen ); + if ( BaseTable::data == 0 ) + throw std::bad_alloc(); + } + else { + /* Create the data. */ + BaseTable::data = (T*) malloc( sizeof(T) * newLen ); + if ( BaseTable::data == 0 ) + throw std::bad_alloc(); + } + } +} + +/* Down resize the data for len elements using Resize::downResize to determine + * the new tabLen. Reads and writes allocLen. Does not read or write tabLen. */ +template<class T, class Resize> void Vector<T, Resize>:: + downResize(long len) +{ + /* Ask the resizer what the new tabLen will be. */ + long newLen = Resize::downResize( BaseTable::allocLen, len ); + + /* Did the data shrink? */ + if ( newLen < BaseTable::allocLen ) { + BaseTable::allocLen = newLen; + if ( newLen == 0 ) { + /* Simply free the data. */ + free( BaseTable::data ); + BaseTable::data = 0; + } + else { + /* Not shrinking to size zero, realloc it to the smaller size. */ + BaseTable::data = (T*) realloc( BaseTable::data, sizeof(T) * newLen ); + if ( BaseTable::data == 0 ) + throw std::bad_alloc(); + } + } +} + +/** + * \brief Perform a deep copy of the vector. + * + * The contents of the other vector are copied into this vector. This vector + * gets the same allocation size as the other vector. All items are copied + * using the element's copy constructor. + */ +template<class T, class Resize> Vector<T, Resize>:: + Vector(const Vector<T, Resize> &v) +{ + BaseTable::tabLen = v.tabLen; + BaseTable::allocLen = v.allocLen; + + if ( BaseTable::allocLen > 0 ) { + /* Allocate needed space. */ + BaseTable::data = (T*) malloc(sizeof(T) * BaseTable::allocLen); + if ( BaseTable::data == 0 ) + throw std::bad_alloc(); + + /* If there are any items in the src data, copy them in. */ + T *dst = BaseTable::data, *src = v.data; + for (long pos = 0; pos < BaseTable::tabLen; pos++, dst++, src++ ) + new(dst) T(*src); + } + else { + /* Nothing allocated. */ + BaseTable::data = 0; + } +} + +/** \fn Vector::~Vector() + * \brief Free all memory used by the vector. + * + * The vector is reset to zero elements. Destructors are called on all + * elements in the vector. The space allocated for the vector is freed. + */ + + +/** + * \brief Free all memory used by the vector. + * + * The vector is reset to zero elements. Destructors are called on all + * elements in the vector. The space allocated for the vector is freed. + */ +template<class T, class Resize> void Vector<T, Resize>:: + empty() +{ + if ( BaseTable::data != 0 ) { + /* Call All destructors. */ + T *pos = BaseTable::data; + for ( long i = 0; i < BaseTable::tabLen; pos++, i++ ) + pos->~T(); + + /* Free the data space. */ + free( BaseTable::data ); + BaseTable::data = 0; + BaseTable::tabLen = BaseTable::allocLen = 0; + } +} + +/** + * \brief Set the contents of the vector to be len elements exactly. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. Copy constructors are used to place the + * new elements in the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + setAs(const T *val, long len) +{ + /* Call All destructors. */ + long i; + T *pos = BaseTable::data; + for ( i = 0; i < BaseTable::tabLen; pos++, i++ ) + pos->~T(); + + /* Adjust the allocated length. */ + if ( len < BaseTable::tabLen ) + downResize( len ); + else if ( len > BaseTable::tabLen ) + upResize( len ); + + /* Set the new data length to exactly len. */ + BaseTable::tabLen = len; + + /* Copy data in. */ + T *dst = BaseTable::data; + const T *src = val; + for ( i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); +} + +/** + * \brief Set the vector to len copies of item. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. The element's copy constructor is used to + * copy the item into the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + setAsDup(const T &item, long len) +{ + /* Call All destructors. */ + T *pos = BaseTable::data; + for ( long i = 0; i < BaseTable::tabLen; pos++, i++ ) + pos->~T(); + + /* Adjust the allocated length. */ + if ( len < BaseTable::tabLen ) + downResize( len ); + else if ( len > BaseTable::tabLen ) + upResize( len ); + + /* Set the new data length to exactly len. */ + BaseTable::tabLen = len; + + /* Copy item in one spot at a time. */ + T *dst = BaseTable::data; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(item); +} + +/** + * \brief Set the vector to exactly len new items. + * + * The vector becomes len elements in length. Destructors are called on any + * existing elements in the vector. Default constructors are used to init the + * new items. + */ +template<class T, class Resize> void Vector<T, Resize>:: + setAsNew(long len) +{ + /* Call All destructors. */ + T *pos = BaseTable::data; + for ( long i = 0; i < BaseTable::tabLen; pos++, i++ ) + pos->~T(); + + /* Adjust the allocated length. */ + if ( len < BaseTable::tabLen ) + downResize( len ); + else if ( len > BaseTable::tabLen ) + upResize( len ); + + /* Set the new data length to exactly len. */ + BaseTable::tabLen = len; + + /* Create items using default constructor. */ + T *dst = BaseTable::data; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); +} + + +/** + * \brief Replace len elements at position pos. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. Copy constructors are used + * to place the elements into the vector. It is allowable for the pos and + * length to specify a replacement that overwrites existing elements and + * creates new ones. If pos is greater than the length of the vector then + * undefined behaviour results. If pos is negative, then it is treated as an + * offset relative to the length of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + replace(long pos, const T *val, long len) +{ + long endPos, i; + T *item; + + /* If we are given a negative position to replace at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* The end is the one past the last item that we want + * to write to. */ + endPos = pos + len; + + /* Make sure we have enough space. */ + if ( endPos > BaseTable::tabLen ) { + upResize( endPos ); + + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < BaseTable::tabLen; i++, item++ ) + item->~T(); + + /* We are extending the vector, set the new data length. */ + BaseTable::tabLen = endPos; + } + else { + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < endPos; i++, item++ ) + item->~T(); + } + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + const T *src = val; + for ( i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); +} + +/** + * \brief Replace at position pos with len copies of an item. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. The copy constructor is + * used to place the element into this vector. It is allowable for the pos and + * length to specify a replacement that overwrites existing elements and + * creates new ones. If pos is greater than the length of the vector then + * undefined behaviour results. If pos is negative, then it is treated as an + * offset relative to the length of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + replaceDup(long pos, const T &val, long len) +{ + long endPos, i; + T *item; + + /* If we are given a negative position to replace at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* The end is the one past the last item that we want + * to write to. */ + endPos = pos + len; + + /* Make sure we have enough space. */ + if ( endPos > BaseTable::tabLen ) { + upResize( endPos ); + + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < BaseTable::tabLen; i++, item++ ) + item->~T(); + + /* We are extending the vector, set the new data length. */ + BaseTable::tabLen = endPos; + } + else { + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < endPos; i++, item++ ) + item->~T(); + } + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(val); +} + +/** + * \brief Replace at position pos with len new elements. + * + * If there are existing elements at the positions to be replaced, then + * destructors are called before the space is used. The default constructor is + * used to initialize the new elements. It is allowable for the pos and length + * to specify a replacement that overwrites existing elements and creates new + * ones. If pos is greater than the length of the vector then undefined + * behaviour results. If pos is negative, then it is treated as an offset + * relative to the length of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + replaceNew(long pos, long len) +{ + long endPos, i; + T *item; + + /* If we are given a negative position to replace at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* The end is the one past the last item that we want + * to write to. */ + endPos = pos + len; + + /* Make sure we have enough space. */ + if ( endPos > BaseTable::tabLen ) { + upResize( endPos ); + + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < BaseTable::tabLen; i++, item++ ) + item->~T(); + + /* We are extending the vector, set the new data length. */ + BaseTable::tabLen = endPos; + } + else { + /* Delete any objects we need to delete. */ + item = BaseTable::data + pos; + for ( i = pos; i < endPos; i++, item++ ) + item->~T(); + } + + /* Copy data in using copy constructor. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); +} + +/** + * \brief Remove len elements at position pos. + * + * Destructor is called on all elements removed. Elements to the right of pos + * are shifted len spaces to the left to take up the free space. If pos is + * greater than or equal to the length of the vector then undefined behavior + * results. If pos is negative then it is treated as an offset relative to the + * length of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + remove(long pos, long len) +{ + long newLen, lenToSlideOver, endPos; + T *dst, *item; + + /* If we are given a negative position to remove at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* The first position after the last item deleted. */ + endPos = pos + len; + + /* The new data length. */ + newLen = BaseTable::tabLen - len; + + /* The place in the data we are deleting at. */ + dst = BaseTable::data + pos; + + /* Call Destructors. */ + item = dst; + for ( long i = 0; i < len; i += 1, item += 1 ) + item->~T(); + + /* Shift data over if necessary. */ + lenToSlideOver = BaseTable::tabLen - endPos; + if ( len > 0 && lenToSlideOver > 0 ) + memmove(dst, dst + len, sizeof(T)*lenToSlideOver); + + /* Shrink the data if necessary. */ + downResize( newLen ); + + /* Set the new data length. */ + BaseTable::tabLen = newLen; +} + +/** + * \brief Insert len elements at position pos. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * The copy constructor is used to place the elements into this vector. If pos + * is greater than the length of the vector then undefined behaviour results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + insert(long pos, const T *val, long len) +{ + /* If we are given a negative position to insert at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* Calculate the new length. */ + long newLen = BaseTable::tabLen + len; + + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < BaseTable::tabLen ) { + memmove(BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(BaseTable::tabLen-pos)); + } + + /* Copy data in element by element. */ + T *dst = BaseTable::data + pos; + const T *src = val; + for ( long i = 0; i < len; i++, dst++, src++ ) + new(dst) T(*src); + + /* Set the new length. */ + BaseTable::tabLen = newLen; +} + +/** + * \brief Insert len copies of item at position pos. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * The copy constructor is used to place the element into this vector. If pos + * is greater than the length of the vector then undefined behaviour results. + * If pos is negative then it is treated as an offset relative to the length + * of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + insertDup(long pos, const T &item, long len) +{ + /* If we are given a negative position to insert at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* Calculate the new length. */ + long newLen = BaseTable::tabLen + len; + + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < BaseTable::tabLen ) { + memmove(BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(BaseTable::tabLen-pos)); + } + + /* Copy the data item in one at a time. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(item); + + /* Set the new length. */ + BaseTable::tabLen = newLen; +} + +/** + * \brief Insert len new elements using the default constructor. + * + * Elements in the vector from pos onward are shifted len spaces to the right. + * Default constructors are used to init the new elements. If pos is off the + * end of the vector then undefined behaviour results. If pos is negative then + * it is treated as an offset relative to the length of the vector. + */ +template<class T, class Resize> void Vector<T, Resize>:: + insertNew(long pos, long len) +{ + /* If we are given a negative position to insert at then + * treat it as a position relative to the length. */ + if ( pos < 0 ) + pos = BaseTable::tabLen + pos; + + /* Calculate the new length. */ + long newLen = BaseTable::tabLen + len; + + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < BaseTable::tabLen ) { + memmove(BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(BaseTable::tabLen-pos)); + } + + /* Init new data with default constructors. */ + T *dst = BaseTable::data + pos; + for ( long i = 0; i < len; i++, dst++ ) + new(dst) T(); + + /* Set the new length. */ + BaseTable::tabLen = newLen; +} + +/* Makes space for len items, Does not init the items in any way. If pos is + * greater than the length of the vector then undefined behaviour results. + * Updates the length of the vector. */ +template<class T, class Resize> void Vector<T, Resize>:: + makeRawSpaceFor(long pos, long len) +{ + /* Calculate the new length. */ + long newLen = BaseTable::tabLen + len; + + /* Up resize, we are growing. */ + upResize( newLen ); + + /* Shift over data at insert spot if needed. */ + if ( len > 0 && pos < BaseTable::tabLen ) { + memmove(BaseTable::data + pos + len, BaseTable::data + pos, + sizeof(T)*(BaseTable::tabLen-pos)); + } + + /* Save the new length. */ + BaseTable::tabLen = newLen; +} + +#ifdef AAPL_NAMESPACE +} +#endif + +#endif /* _AAPL_VECTOR_H */ diff --git a/colm.vim b/colm.vim new file mode 100644 index 00000000..8b7b5799 --- /dev/null +++ b/colm.vim @@ -0,0 +1,91 @@ +" Vim syntax file +" +" Language: Colm +" Author: Adrian Thurston + +syntax clear + +" +" Regular Language Types +" + +" Identifiers +syntax match rlId "[a-zA-Z_][a-zA-Z_0-9]*" contained + +" Literals +syntax match rlLiteral "'\(\\.\|[^'\\]\)*'[i]*" contained +syntax match rlLiteral "\"\(\\.\|[^\"\\]\)*\"[i]*" contained +syntax match rlLiteral "\[\(\\.\|[^\]\\]\)*\]" contained + +" Numbers +syntax match rlNumber "[0-9][0-9]*" contained +syntax match rlNumber "0x[0-9a-fA-F][0-9a-fA-F]*" contained + +" Operators +syntax match rlOtherOps ":>" contained +syntax match rlOtherOps ":>>" contained +syntax match rlOtherOps "<:" contained + +syntax cluster rlTypes contains=rlId,rlLiteral,rlNumber,rlOtherOps +syntax region rlTypeRegion matchgroup=regionDelimiter start="/" end="/" + \ contains=@rlTypes + +syntax region cflTypeRegion matchgroup=regionDelimiter start="\[" end="\]" + \ contains=cflTypeRegion,patRegion,otLit,typeKeywords +syntax region patRegion matchgroup=String start="\"" end="\"" end="\n" + \ contains=char,cflTypeRegion + +syntax match char "[^\"\[]" contained +syntax match char "\\." contained + +syntax match otLit "\~.*$" +syntax match otLit "'\(\\.\|[^'\\]\)*'[i]*" + +" +" Other stuff +" + +syntax match tlComment "#.*$" +syntax match tlIdentifier "[a-zA-Z_][a-zA-Z_0-9]*" +syntax match tlNumber "[0-9][0-9]*" +syntax match tlNumber "nil" +syntax match tlNumber "true" +syntax match tlNumber "false" + +syntax keyword Type + \ commit include literal iter + \ namespace lex reducefirst global include + \ construct parse parse_stop match require + \ preeof left right nonassoc prec + +syntax keyword typeKeywords + \ int str bool any ref vector map list ptr + +syntax keyword Keyword + \ reject else elsif return yield for while if + \ typeid in break + \ new deref + +syntax match tokenName "[a-zA-Z_][a-zA-Z_0-9]*" contained + +syntax region defTypes matchgroup=defKeywords + \ start="\<rl\>" start="\<def\>" start="\<token\>" start="\<ignore\>" + \ matchgroup=Function end="[a-zA-Z_][a-zA-Z0-9_]*" end="/"me=e-1 + +syntax sync match colmSyncPat grouphere NONE "([{}]|\<token\>|\<ignore\>|\<def\>)" + +" +" Specifying Groups +" +hi link tlComment Comment +hi link tlNumber Number +hi link otLit String +hi link rlNumber Number +hi link rlLiteral String +hi link defKeywords Type +hi link typeKeywords Type +hi link regionDelimiter Type +hi link char String +hi link tokenName Function + +let b:current_syntax = "colm" diff --git a/colm/Makefile.in b/colm/Makefile.in new file mode 100644 index 00000000..9b247eae --- /dev/null +++ b/colm/Makefile.in @@ -0,0 +1,161 @@ +# +# Copyright 2001-2007 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +# Logging: +# colm: rt on/off +# rt_prd: off +# rt_db: on +# rt_clm: rt on/off + +INCS += -I../aapl + +DEFS_COLM += -DCOLM_LOG -DPREFIX='"$(prefix)"' +DEFS_RT_P += +DEFS_RT_D += -DCOLM_LOG + +CFLAGS += -g -Wall -Wwrite-strings +LDFLAGS += + +# Frequently changed ones first. +COLM_SRC = \ + compile.cpp \ + lmparse.cpp \ + lmscan.cpp \ + parsetree.cpp \ + parsedata.cpp \ + fsmstate.cpp \ + fsmbase.cpp \ + fsmattach.cpp \ + fsmmin.cpp \ + fsmgraph.cpp \ + pdagraph.cpp \ + pdabuild.cpp \ + pdacodegen.cpp \ + fsmcodegen.cpp \ + redfsm.cpp \ + fsmexec.cpp \ + main.cpp \ + redbuild.cpp \ + closure.cpp \ + fsmap.cpp \ + dotgen.cpp \ + pcheck.cpp + +RUNTIME_SRC = fsmrun.cpp pdarun.cpp bytecode.cpp list.cpp \ + map.cpp string.cpp input.cpp tree.cpp + +ALL_SRC = $(COLM_SRC) $(RUNTIME_SRC) + +# Files in ALL_SRC that are generated. +GEN_SRC = version.h lmscan.cpp lmparse.h lmparse.cpp + +RUNTIME_P = libcolmp.a +RUNTIME_D = libcolmd.a + +LIBS = + +#************************************* + +# Get the version info. +include ../version.mk + +prefix = @prefix@ + +BUILD_PARSERS = @BUILD_PARSERS@ + +# Programs +CXX = @CXX@ + +# Get objects and dependencies from sources. +COLM_OBJ = $(COLM_SRC:%.cpp=%.o) +RUNTIME_OBJ_P = $(RUNTIME_SRC:%.cpp=%_p.o) +RUNTIME_OBJ_D = $(RUNTIME_SRC:%.cpp=%_d.o) + +DEPS = $(COLM_SRC:%.cpp=.%.d) $(RUNTIME_SRC:%.cpp=.%_p.d) $(RUNTIME_SRC:%.cpp=.%_d.d) + +# Rules. +all: colm $(RUNTIME_P) $(RUNTIME_D) + +colm: $(GEN_SRC) $(COLM_OBJ) $(RUNTIME_OBJ_D) $(LIBS) + $(CXX) $(LDFLAGS) -o $@ $(COLM_OBJ) $(RUNTIME_OBJ_D) $(LIBS) + +$(RUNTIME_P): $(RUNTIME_OBJ_P) + ar -cr $@ $^ + +$(RUNTIME_D): $(RUNTIME_OBJ_D) + ar -cr $@ $^ + +version.h: ../version.mk + echo '#define VERSION "$(VERSION)"' > version.h + echo '#define PUBDATE "$(PUBDATE)"' >> version.h + +ifeq ($(BUILD_PARSERS),true) + +lmparse.h: lmparse.kh + kelbt -o $@ $< + +lmparse.cpp: lmparse.kl lmparse.kh + kelbt -o $@ $< + +lmscan.cpp: lmparse.h + +lmscan.cpp: lmscan.rl + ragel -G2 -o $@ $< + +endif + +$(COLM_OBJ): %.o: %.cpp + @$(CXX) -M $(DEFS_COLM) $(INCS) $< > .$*.d + $(CXX) -c $(CFLAGS) $(DEFS_COLM) $(INCS) -o $@ $< + +$(RUNTIME_OBJ_P): %_p.o: %.cpp + @$(CXX) -M -MT $@ $(DEFS_RT_P) $(INCS) $< > .$*_p.d + $(CXX) -c $(CFLAGS) $(DEFS_RT_P) $(INCS) -o $@ $< + +$(RUNTIME_OBJ_D): %_d.o: %.cpp + @$(CXX) -M -MT $@ $(DEFS_RT_D) $(INCS) $< > .$*_d.d + $(CXX) -c $(CFLAGS) $(DEFS_RT_D) $(INCS) -o $@ $< + + +distclean: clean + rm -f Makefile config.h + +ifeq ($(BUILD_PARSERS),true) +EXTRA_CLEAN = $(GEN_SRC) +endif + +clean: + rm -f tags .*.d *.o colm $(EXTRA_CLEAN) $(RUNTIME_P) $(RUNTIME_D) + +install: all + install -d $(prefix)/bin + install -d $(prefix)/include + install -d $(prefix)/include/colm + install -d $(prefix)/lib + install -s colm $(prefix)/bin/colm + install libcolmp.a libcolmd.a $(prefix)/lib + install ../aapl/astring.h ../aapl/avlcommon.h ../aapl/avlmap.h \ + ../aapl/compare.h ../aapl/dlcommon.h ../aapl/dlist.h \ + ../aapl/dlistval.h ../aapl/resize.h ../aapl/table.h \ + ../aapl/vector.h bytecode.h config.h fsmrun.h input.h \ + pdarun.h $(prefix)/include/colm + +-include $(DEPS) diff --git a/buffer.h b/colm/buffer.h index 9039ad4b..9039ad4b 100644 --- a/buffer.h +++ b/colm/buffer.h diff --git a/bytecode.cpp b/colm/bytecode.cpp index 03474e73..03474e73 100644 --- a/bytecode.cpp +++ b/colm/bytecode.cpp diff --git a/bytecode.h b/colm/bytecode.h index fc326906..fc326906 100644 --- a/bytecode.h +++ b/colm/bytecode.h diff --git a/closure.cpp b/colm/closure.cpp index 5ee6538e..5ee6538e 100644 --- a/closure.cpp +++ b/colm/closure.cpp diff --git a/compile.cpp b/colm/compile.cpp index 19f42293..19f42293 100644 --- a/compile.cpp +++ b/colm/compile.cpp diff --git a/config.h.in b/colm/config.h.in index f9da39b1..f9da39b1 100644 --- a/config.h.in +++ b/colm/config.h.in diff --git a/dotgen.cpp b/colm/dotgen.cpp index eb69ba16..eb69ba16 100644 --- a/dotgen.cpp +++ b/colm/dotgen.cpp diff --git a/dotgen.h b/colm/dotgen.h index e370866c..e370866c 100644 --- a/dotgen.h +++ b/colm/dotgen.h diff --git a/fsmap.cpp b/colm/fsmap.cpp index 45e02f3e..45e02f3e 100644 --- a/fsmap.cpp +++ b/colm/fsmap.cpp diff --git a/fsmattach.cpp b/colm/fsmattach.cpp index 31783ae0..31783ae0 100644 --- a/fsmattach.cpp +++ b/colm/fsmattach.cpp diff --git a/fsmbase.cpp b/colm/fsmbase.cpp index 823a7858..823a7858 100644 --- a/fsmbase.cpp +++ b/colm/fsmbase.cpp diff --git a/fsmcodegen.cpp b/colm/fsmcodegen.cpp index 0f5b1960..fe5a6fb3 100644 --- a/fsmcodegen.cpp +++ b/colm/fsmcodegen.cpp @@ -231,7 +231,7 @@ void FsmCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, ret << " }\n" "\t" - " return;\n"; + " goto _resume;\n"; } void FsmCodeGen::LM_ON_LAST( ostream &ret, InlineItem *item ) @@ -240,7 +240,7 @@ void FsmCodeGen::LM_ON_LAST( ostream &ret, InlineItem *item ) ret << " " << P() << " += 1;\n"; EMIT_TOKEN( ret, item->longestMatchPart->token ); - ret << " return;\n"; + ret << " goto _resume;\n"; } void FsmCodeGen::LM_ON_NEXT( ostream &ret, InlineItem *item ) @@ -248,7 +248,7 @@ void FsmCodeGen::LM_ON_NEXT( ostream &ret, InlineItem *item ) assert( item->longestMatchPart->token != 0 ); EMIT_TOKEN( ret, item->longestMatchPart->token ); - ret << " return;\n"; + ret << " goto _resume;\n"; } void FsmCodeGen::LM_ON_LAG_BEHIND( ostream &ret, InlineItem *item ) @@ -257,7 +257,7 @@ void FsmCodeGen::LM_ON_LAG_BEHIND( ostream &ret, InlineItem *item ) ret << " " << P() << " = " << TOKEND() << ";\n"; EMIT_TOKEN( ret, item->longestMatchPart->token ); - ret << " return;\n"; + ret << " goto _resume;\n"; } diff --git a/fsmcodegen.h b/colm/fsmcodegen.h index 06e998c3..06e998c3 100644 --- a/fsmcodegen.h +++ b/colm/fsmcodegen.h diff --git a/fsmexec.cpp b/colm/fsmexec.cpp index d08158b3..8f5d7600 100644 --- a/fsmexec.cpp +++ b/colm/fsmexec.cpp @@ -68,21 +68,21 @@ void FsmRun::execAction( GenAction *genAction ) emitToken( lmi->token ); } } - returnResult = true; + gotoResume = true; break; case InlineItem::LmOnLast: p += 1; emitToken( item->longestMatchPart->token ); - returnResult = true; + gotoResume = true; break; case InlineItem::LmOnNext: emitToken( item->longestMatchPart->token ); - returnResult = true; + gotoResume = true; break; case InlineItem::LmOnLagBehind: p = tokend; emitToken( item->longestMatchPart->token ); - returnResult = true; + gotoResume = true; break; } } @@ -99,7 +99,7 @@ void FsmRun::execute() unsigned int _nacts; const char *_keys; -//_resume: +_resume: if ( cs == tables->errorState ) goto out; @@ -166,13 +166,13 @@ _match: if ( tables->transActionsWI[_trans] == 0 ) goto _again; - returnResult = false; + gotoResume = false; _acts = tables->actions + tables->transActionsWI[_trans]; _nacts = (unsigned int) *_acts++; while ( _nacts-- > 0 ) execAction( tables->actionSwitch[*_acts++] ); - if ( returnResult ) - return; + if ( gotoResume ) + goto _resume; _again: _acts = tables->actions + tables->toStateActions[cs]; @@ -187,7 +187,7 @@ _again: goto _loop_head; out: if ( p == peof ) { - returnResult = false; + gotoResume = false; _acts = tables->actions + tables->eofActions[cs]; _nacts = (unsigned int) *_acts++; @@ -196,8 +196,8 @@ out: while ( _nacts-- > 0 ) execAction( tables->actionSwitch[*_acts++] ); - if ( returnResult ) - return; + if ( gotoResume ) + goto _resume; } } diff --git a/fsmgraph.cpp b/colm/fsmgraph.cpp index af643721..af643721 100644 --- a/fsmgraph.cpp +++ b/colm/fsmgraph.cpp diff --git a/fsmgraph.h b/colm/fsmgraph.h index f898a3d6..f898a3d6 100644 --- a/fsmgraph.h +++ b/colm/fsmgraph.h diff --git a/fsmmin.cpp b/colm/fsmmin.cpp index 3abc4e88..3abc4e88 100644 --- a/fsmmin.cpp +++ b/colm/fsmmin.cpp diff --git a/fsmrun.cpp b/colm/fsmrun.cpp index 7281c76b..7281c76b 100644 --- a/fsmrun.cpp +++ b/colm/fsmrun.cpp diff --git a/fsmrun.h b/colm/fsmrun.h index 1da1c266..ed25c829 100644 --- a/fsmrun.h +++ b/colm/fsmrun.h @@ -123,7 +123,7 @@ struct FsmRun char *p, *pe, *peof; bool eofSent; RunBuf *runBuf; - bool returnResult; + bool gotoResume; char *mark[MARK_SLOTS]; }; diff --git a/fsmstate.cpp b/colm/fsmstate.cpp index ab5bd93a..ab5bd93a 100644 --- a/fsmstate.cpp +++ b/colm/fsmstate.cpp diff --git a/input.cpp b/colm/input.cpp index 5434b2d6..5434b2d6 100644 --- a/input.cpp +++ b/colm/input.cpp diff --git a/keyops.h b/colm/keyops.h index b5af65e7..b5af65e7 100644 --- a/keyops.h +++ b/colm/keyops.h diff --git a/list.cpp b/colm/list.cpp index 8671fd51..8671fd51 100644 --- a/list.cpp +++ b/colm/list.cpp diff --git a/lmparse.kh b/colm/lmparse.kh index 2cc3e99a..2cc3e99a 100644 --- a/lmparse.kh +++ b/colm/lmparse.kh diff --git a/lmparse.kl b/colm/lmparse.kl index d4618c00..d4618c00 100644 --- a/lmparse.kl +++ b/colm/lmparse.kl diff --git a/lmscan.h b/colm/lmscan.h index 8aa0d6da..8aa0d6da 100644 --- a/lmscan.h +++ b/colm/lmscan.h diff --git a/lmscan.rl b/colm/lmscan.rl index d5e5f0f8..d5e5f0f8 100644 --- a/lmscan.rl +++ b/colm/lmscan.rl diff --git a/main.cpp b/colm/main.cpp index a6170f0d..a6170f0d 100644 --- a/main.cpp +++ b/colm/main.cpp diff --git a/parsedata.cpp b/colm/parsedata.cpp index 32da2e5c..32da2e5c 100644 --- a/parsedata.cpp +++ b/colm/parsedata.cpp diff --git a/parsedata.h b/colm/parsedata.h index 8d4dcb23..8d4dcb23 100644 --- a/parsedata.h +++ b/colm/parsedata.h diff --git a/parsetree.cpp b/colm/parsetree.cpp index 5c951324..5c951324 100644 --- a/parsetree.cpp +++ b/colm/parsetree.cpp diff --git a/parsetree.h b/colm/parsetree.h index 87880364..87880364 100644 --- a/parsetree.h +++ b/colm/parsetree.h diff --git a/pcheck.cpp b/colm/pcheck.cpp index ee1985c7..ee1985c7 100644 --- a/pcheck.cpp +++ b/colm/pcheck.cpp diff --git a/pcheck.h b/colm/pcheck.h index 5be60426..5be60426 100644 --- a/pcheck.h +++ b/colm/pcheck.h diff --git a/pdabuild.cpp b/colm/pdabuild.cpp index d22a7db3..d22a7db3 100644 --- a/pdabuild.cpp +++ b/colm/pdabuild.cpp diff --git a/pdacodegen.cpp b/colm/pdacodegen.cpp index 04a980ba..04a980ba 100644 --- a/pdacodegen.cpp +++ b/colm/pdacodegen.cpp diff --git a/pdacodegen.h b/colm/pdacodegen.h index 7ca32546..7ca32546 100644 --- a/pdacodegen.h +++ b/colm/pdacodegen.h diff --git a/pdagraph.cpp b/colm/pdagraph.cpp index ce3c3a7f..ce3c3a7f 100644 --- a/pdagraph.cpp +++ b/colm/pdagraph.cpp diff --git a/pdagraph.h b/colm/pdagraph.h index 479a60de..479a60de 100644 --- a/pdagraph.h +++ b/colm/pdagraph.h diff --git a/pdarun.cpp b/colm/pdarun.cpp index b85a32c0..b85a32c0 100644 --- a/pdarun.cpp +++ b/colm/pdarun.cpp diff --git a/pdarun.h b/colm/pdarun.h index 240d97a4..240d97a4 100644 --- a/pdarun.h +++ b/colm/pdarun.h diff --git a/redbuild.cpp b/colm/redbuild.cpp index 47b8c60d..47b8c60d 100644 --- a/redbuild.cpp +++ b/colm/redbuild.cpp diff --git a/redbuild.h b/colm/redbuild.h index 2bc2b2f9..2bc2b2f9 100644 --- a/redbuild.h +++ b/colm/redbuild.h diff --git a/redfsm.cpp b/colm/redfsm.cpp index 31995c91..31995c91 100644 --- a/redfsm.cpp +++ b/colm/redfsm.cpp diff --git a/redfsm.h b/colm/redfsm.h index 305b67f9..305b67f9 100644 --- a/redfsm.h +++ b/colm/redfsm.h diff --git a/string.cpp b/colm/string.cpp index d2452862..d2452862 100644 --- a/string.cpp +++ b/colm/string.cpp diff --git a/tree.cpp b/colm/tree.cpp index f856ad3a..f856ad3a 100644 --- a/tree.cpp +++ b/colm/tree.cpp diff --git a/configure b/configure new file mode 100755 index 00000000..f08d8a02 --- /dev/null +++ b/configure @@ -0,0 +1,4177 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="colm/main.cpp" +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +BUILD_PARSERS +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +CXX +CXXFLAGS +ac_ct_CXX +SET_MAKE +RAGEL +KELBT +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CXX C++ compiler command + CXXFLAGS C++ compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers colm/config.h" + + +BUILD_PARSERS=true + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +cat >>confdefs.h <<_ACEOF +#define CC $CC +_ACEOF + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +cat >>confdefs.h <<_ACEOF +#define CXX $CXX +_ACEOF + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# Logging features +# AC_ARG_ENABLE(log, "turn on logging", AC_DEFINE(COLM_LOG)) +# AC_ARG_ENABLE(log-bytecode, "turns on bytecode logging", AC_DEFINE(COLM_LOG_BYTECODE)) +# AC_ARG_ENABLE(log-parse, "turns on parse logging", AC_DEFINE(COLM_LOG_PARSE)) +# AC_ARG_ENABLE(log-match, "turns on match logging", AC_DEFINE(COLM_LOG_MATCH)) +# AC_ARG_ENABLE(log-compile, "turns on compile logging", AC_DEFINE(COLM_LOG_COMPILE)) + +if test $BUILD_PARSERS = true; then + +# Extract the first word of "ragel", so it can be a program name with args. +set dummy ragel; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RAGEL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RAGEL"; then + ac_cv_prog_RAGEL="$RAGEL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RAGEL="ragel" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RAGEL=$ac_cv_prog_RAGEL +if test -n "$RAGEL"; then + { echo "$as_me:$LINENO: result: $RAGEL" >&5 +echo "${ECHO_T}$RAGEL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test -z "$RAGEL"; then + echo + echo "error: ragel is required to build the parsers" + echo + exit 1 +fi + +# Extract the first word of "kelbt", so it can be a program name with args. +set dummy kelbt; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_KELBT+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$KELBT"; then + ac_cv_prog_KELBT="$KELBT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_KELBT="kelbt" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +KELBT=$ac_cv_prog_KELBT +if test -n "$KELBT"; then + { echo "$as_me:$LINENO: result: $KELBT" >&5 +echo "${ECHO_T}$KELBT" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test -z "$KELBT"; then + echo + echo "error: kelbt is required to build the parsers" + echo + exit 1 +fi + +fi # BUILD_PARSERS + +ac_config_files="$ac_config_files Makefile colm/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to <bug-autoconf@gnu.org>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "colm/config.h") CONFIG_HEADERS="$CONFIG_HEADERS colm/config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "colm/Makefile") CONFIG_FILES="$CONFIG_FILES colm/Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +BUILD_PARSERS!$BUILD_PARSERS$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +RAGEL!$RAGEL$ac_delim +KELBT!$KELBT$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 53; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + +echo "configuration of colm complete" diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..94fb7ba2 --- /dev/null +++ b/configure.in @@ -0,0 +1,75 @@ +dnl +dnl Copyright 2001-2008 Adrian Thurston <thurston@complang.org> +dnl + +dnl This file is part of Colm. +dnl +dnl Colm is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl Colm is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with Colm; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +AC_INIT(colm/main.cpp) +AC_CONFIG_HEADER(colm/config.h) + +dnl Set to true if build system should generate parsers from ragel, kelbt, and +dnl gperf sources. Set to false if generated files are included and not to be +dnl built (production). +AC_SUBST(BUILD_PARSERS,true) + +dnl Checks for programs. +AC_PROG_CC +AC_DEFINE_UNQUOTED(CC,$CC) + +dnl Checks for programs. +AC_PROG_CXX +AC_DEFINE_UNQUOTED(CXX,$CXX) + +dnl Set test on c++ compiler. +AC_LANG_CPLUSPLUS + +dnl Check for definition of MAKE. +AC_PROG_MAKE_SET + +# Logging features +# AC_ARG_ENABLE(log, "turn on logging", AC_DEFINE(COLM_LOG)) +# AC_ARG_ENABLE(log-bytecode, "turns on bytecode logging", AC_DEFINE(COLM_LOG_BYTECODE)) +# AC_ARG_ENABLE(log-parse, "turns on parse logging", AC_DEFINE(COLM_LOG_PARSE)) +# AC_ARG_ENABLE(log-match, "turns on match logging", AC_DEFINE(COLM_LOG_MATCH)) +# AC_ARG_ENABLE(log-compile, "turns on compile logging", AC_DEFINE(COLM_LOG_COMPILE)) + +if test $BUILD_PARSERS = true; then + +dnl Check for Ragel +AC_CHECK_PROG(RAGEL, ragel, ragel) +if test -z "$RAGEL"; then + echo + echo "error: ragel is required to build the parsers" + echo + exit 1 +fi + +dnl Check for Kelbt +AC_CHECK_PROG(KELBT, kelbt, kelbt) +if test -z "$KELBT"; then + echo + echo "error: kelbt is required to build the parsers" + echo + exit 1 +fi + +fi # BUILD_PARSERS + +dnl write output files +AC_OUTPUT(Makefile colm/Makefile) + +echo "configuration of colm complete" diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..492bfaf2 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,46 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +SUBDIRS = xml python http dns diff html cxx ruby mediawiki + +all: $(BIN) $(SUBDIRS) + +.PHONY: $(SUBDIRS) + +$(SUBDIRS): + @cd $@ && $(MAKE) + +$(BIN): %.bin: %.lm + ../colm/colm $< + +# clean targets + +CLEAN_SUBDIRS = $(SUBDIRS:%=%-clean) + +.PHONY: $(CLEAN_SUBDIRS) + +$(CLEAN_SUBDIRS): + @cd $(@:%-clean=%) && $(MAKE) clean + +clean: $(CLEAN_SUBDIRS) + rm -f *.cpp *.bin diff --git a/test/backtrack1.lm b/test/backtrack1.lm new file mode 100644 index 00000000..0f3d8e88 --- /dev/null +++ b/test/backtrack1.lm @@ -0,0 +1,24 @@ +# Token names. + +lex start +{ + literal '+', '*' + token number /[0-9]+/ + ignore ws / [ \t\n]+ / +} + +def F + [number '+'] +| [number] +| [F '*' number] + +def E + [E '+' F] +| [F] + +def start + [E] + +start S = parse start( stdin ) +start R = match S ~ 9 + 9 +print_xml( R ) diff --git a/test/backtrack2.lm b/test/backtrack2.lm new file mode 100644 index 00000000..fc63c7a6 --- /dev/null +++ b/test/backtrack2.lm @@ -0,0 +1,24 @@ + +# Token names. +lex start +{ + token id /[a-z]+/ + ignore ws /[ \t\n]+/ +} + +token bang1 /'!'/ +token bang2 /'!'/ + +def one [bang1 id id id] + +def two [bang2 id id id id] + +def prods + [one] +| [two] + +def start + [prods] + +start S = parse start( stdin ) +match S "!aa bb cc dd" diff --git a/test/backtrack3.lm b/test/backtrack3.lm new file mode 100644 index 00000000..1f5e6e81 --- /dev/null +++ b/test/backtrack3.lm @@ -0,0 +1,27 @@ + +# Token names. +lex start +{ + token number /[0-9]+/ + token id /[a-z]+/ + token string /'"' [^"]* '"'/ + ignore ws / [ \t\n]+ / +} + +def prefix [id] + +def choice1 + [number number] +| [number] + +def choice2 + [string id] +| [number number] +| [id number] +| [number] + +def start + [prefix choice1 choice2 string id id] + { + match lhs "id 77 88 \"hello\" dude dude" + } diff --git a/test/btscan.in b/test/btscan.in new file mode 100644 index 00000000..88cec9d5 --- /dev/null +++ b/test/btscan.in @@ -0,0 +1,2 @@ +!abb !abba !aab + diff --git a/test/btscan.lm b/test/btscan.lm new file mode 100644 index 00000000..ac7914c2 --- /dev/null +++ b/test/btscan.lm @@ -0,0 +1,34 @@ +namespace r1 +{ + lex r1 + { + literal '!', 'a', 'b' + ignore /[ \n\t]+/ + } + + def line [ '!' 'a' 'b' 'b' 'a'] +} + +namespace r2 +{ + lex r2 + { + literal '!' + token id /[a-zA-Z_]+/ + ignore /[ \n\t]+/ + } + + def line [ '!' id ] +} + +def item + [r1::line] +| [r2::line] + +def btscan + [item*] + +btscan P = parse btscan( stdin ) + +match P ~!abb !abba !aab +print_xml(P) diff --git a/test/commitbt.in b/test/commitbt.in new file mode 100644 index 00000000..24a7dece --- /dev/null +++ b/test/commitbt.in @@ -0,0 +1 @@ +1 2 3 *
\ No newline at end of file diff --git a/test/commitbt.lm b/test/commitbt.lm new file mode 100644 index 00000000..75172b4b --- /dev/null +++ b/test/commitbt.lm @@ -0,0 +1,110 @@ +# +# Local commit: +# -clears reparse flags underneath +# -must be possible to backtrack after +# Global commit (revertOn) +# -clears all reparse flags +# -must be possible to backtrack after +# Global commit (!revertOn) +# -clears all reparse flags +# -clears all 'parsed' reverse code +# -clears all reverse code +# -clears all alg structures +# + +# This test shows that a global commit with revertOn cannot clear 'parsed' +# items because it must entertain the possibility of backtracking. + +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def expression [term expression_op*] + +def expression_op + ['|' term] +| ['&' term] +| ['-' term] +| ['--' term] + +def term [factor_rep term_rest] + +# This list is done manually to get shortest match. +def term_rest + [] +| [term_op term_rest] + +def term_op + [factor_rep] +| ['.' factor_rep] +| [':>' factor_rep] +| [':>>' factor_rep] +| ['<:' factor_rep] + +def factor_rep + [factor_neg factor_rep_op*] + +def factor_rep_op + ['*'] +| ['**'] +| ['?'] +| ['+'] +| ['{' factor_rep_num '}'] +| ['{' ',' factor_rep_num '}'] +| ['{' factor_rep_num ',' '}'] +| ['{' factor_rep_num ',' factor_rep_num '}'] + +def factor_rep_num [uint] + +def factor_neg + ['!' factor_neg] +| ['^' factor_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] + +global int i + +def suint + int i + [uint] + { + lhs.i = 0 + i = 1 + lhs = construct suint "1" + } + +def sub + [suint* '*'] + +token item + sub S + /[0-9]+/ + { + str M = pull(stdin, match_length) + sub S = parse sub(stdin) + send( make_token( typeid item, M, S ) ) + } + +def stuff + [item* '!'] +| [sub] + +stuff S = parse stuff(stdin) + +print_xml( S ) diff --git a/test/constructex.in b/test/constructex.in new file mode 100644 index 00000000..f458f2ad --- /dev/null +++ b/test/constructex.in @@ -0,0 +1,3 @@ +<person name=adrian hometown=kingston> + <t1 foo=bar2 e=f></t2> +</person>
\ No newline at end of file diff --git a/test/constructex.lm b/test/constructex.lm new file mode 100644 index 00000000..01d71f37 --- /dev/null +++ b/test/constructex.lm @@ -0,0 +1,37 @@ +lex start +{ + token id /[a-zA-Z_][a-zA-Z0-9_]*/ + literal '=', '<', '>', '/' + ignore /[ \t\n\r\v]+/ +} + +def attr + [id '=' id] + +def open_tag + ['<' id attr* '>'] + +def close_tag + ['<' '/' id '>'] + +def tag + [open_tag item* close_tag] + +def item + [tag] +| [id] + +tag PersonTag = parse tag( stdin ) + +match PersonTag + ["<person name=" Val:id attr*">" item* "</person>"] + +tag NameTag1 = construct tag + ["<name type=person>" Val "</name>"] + +tag NameTag2 = construct tag + "<name type=person>[Val]</name>" + +print( NameTag1, '\n' ) +print( NameTag2, '\n' ) + diff --git a/test/counting1.in b/test/counting1.in new file mode 100644 index 00000000..45eeecde --- /dev/null +++ b/test/counting1.in @@ -0,0 +1 @@ +3 1 b c 1 1 0 3 a b c diff --git a/test/counting1.lm b/test/counting1.lm new file mode 100644 index 00000000..bd0154ec --- /dev/null +++ b/test/counting1.lm @@ -0,0 +1,91 @@ + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ +rl rl_num /[0-9]+/ + +# +# Tokens +# + +lex start +{ + # Ignore whitespace. + ignore /rl_ws/ + + # Tokens. + token id /rl_id/ + token number /rl_num/ +} + +# +# Global Data +# + +global int target + +# +# Productions +# + + +def get_target + [number] + { + match lhs [Number:number] + target = Number.data.atoi() + } + +# Arbitrary item. +def item + [number] +| [id] + +# Type definition for the count_items nonterminal. +def count_items + int count + + # List production one. The condition stops the + # greedy list when it has gone too far. + [count_items item] + { + # Pass up the data + lhs.count = r1.count + 1 + if lhs.count > target { + reject + } + } + + # List production two, the base. +| [] + { + lhs.count = 0 + } + +# Wrapper which prevents short lists from getting through if the parser +# encounters an error and needs to backtrack over counted list. +def counted_list + [get_target count_items] + { + if r2.count < target { + reject + } + } + + +def start + [counted_list*] + { + for List:counted_list in lhs { + match List [Count:number Items:count_items] + print( 'num items: ', Count.data.atoi(), '\n' ) + + int i = 1 + for Item:item in Items { + print( ' item ', i, ': ', Item, '\n' ) + i = i + 1 + } + } + } diff --git a/test/counting2.lm b/test/counting2.lm new file mode 100644 index 00000000..1044e5cb --- /dev/null +++ b/test/counting2.lm @@ -0,0 +1,82 @@ + +# +# Regular Definitions +# + +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ +rl rl_num /[0-9]+/ + +# +# Tokens +# + +lex start +{ + # Ignore whitespace. + ignore /rl_ws/ + + # Tokens. + token id /rl_id/ + token number /rl_num/ +} + +# +# Productions +# + +# Arbitrary item. +def item + [id] +| [number] + +# List production one. The condition stops the +# greedy list when it has gone too far. +def count_items + int target + int count + + [count_items item] + { + # Pass up the data + lhs.target = r1.target + lhs.count = r1.count + 1 + + if lhs.count > lhs.target { + reject + } + } + + # List production two, the base. +| [number] + { + match lhs [Number:number] + lhs.target = Number.data.atoi() + lhs.count = 0 + } + + +# Wrapper which prevents short lists from getting through if the parser +# encounters an error and needs to backtrack over counted list. +def counted_list + [count_items] + { + if r1.count < r1.target { + reject + } + } + +def start + [counted_list*] + { + for List:counted_list in lhs { + match List [CountItems:count_items] + print( 'num items: ', CountItems.target, '\n' ) + + int i = 1 + for Item:item in CountItems { + print( ' item ', i, ': ', Item, '\n' ) + i = i + 1 + } + } + } diff --git a/test/counting3.lm b/test/counting3.lm new file mode 100644 index 00000000..d925b732 --- /dev/null +++ b/test/counting3.lm @@ -0,0 +1,92 @@ + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ +rl rl_num /[0-9]+/ + +# +# Tokens +# + +lex start +{ + # Ignore whitespace. + ignore /rl_ws/ + + literal ';' + + # Tokens. + token id /rl_id/ + token number /rl_num/ +} + +# +# Global Data +# + +global int target +global int count + +# +# Productions +# + + +def get_target + [number] + { + count = 0 + target = r1.data.atoi() + print( 'target: ', target, '\n' ) + } + +# Arbitrary item. +def item + [number] +| [id] + +def count_items + [one_item count_items] +| [] + +def one_item + [item] + { + count = count + 1 + if count > target { + reject + } + print( 'ITEM\n' ) + } + + +# Wrapper which prevents short lists from getting through if the parser +# encounters an error and needs to backtrack over counted list. +def counted_list + [get_target count_items] + { + print( 'trying: ', count, ' for: ', target, '\n' ) + if count < target { + reject + } + } + + +def start + [counted_list*] + { + + for List:counted_list in lhs { + match List [Count:number Items:count_items] + print( 'num items: ', Count.data.atoi(), '\n' ) + + int i = 1 + for Item:item in Items { + print( ' item ', i, ': ', Item, '\n' ) + i = i + 1 + } + } + print( '*** SUCCESS ***\n' ) + } diff --git a/test/counting4.lm b/test/counting4.lm new file mode 100644 index 00000000..b1a75130 --- /dev/null +++ b/test/counting4.lm @@ -0,0 +1,89 @@ + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ +rl rl_num /[0-9]+/ + +# +# Tokens +# + +lex start +{ + # Ignore whitespace. + ignore /rl_ws/ + + literal ';' + + # Tokens. + token id /rl_id/ + token number /rl_num/ +} + +# +# Global Data +# + +global int target +global int count + +# +# Productions +# + + +def get_target + [number] + { + count = 0 + target = r1.data.atoi() + print( 'target: ', target, '\n' ) + } + +# Arbitrary item. +def item + [number] +| [id] + +def count_items + [count_inc item count_items] +| [count_end] + +def count_inc + [] + { + if count < target + count = count + 1 + else + reject + } + +def count_end + [] + { + if count < target + reject + } + +def counted_list + [get_target count_items] + +def start + [counted_list*] + { + for List:counted_list in lhs { + match List [Count:number Items:count_items] + print( 'num items: ', Count.data.atoi(), '\n' ) + + int i = 1 + for Item:item in Items { + print( ' item ', i, ': ', Item, '\n' ) + i = i + 1 + } + } + print( '*** SUCCESS ***\n' ) + } + +parse start(stdin) diff --git a/test/cxx/Makefile b/test/cxx/Makefile new file mode 100644 index 00000000..9fb58795 --- /dev/null +++ b/test/cxx/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f cxx.cpp *.bin diff --git a/test/cxx/cxx.lm b/test/cxx/cxx.lm new file mode 100644 index 00000000..31fcc92e --- /dev/null +++ b/test/cxx/cxx.lm @@ -0,0 +1,2168 @@ +# +# Data types for global data. +# + +# Map definition +map object_map [str object_list] + +# Language objects. +def lang_object + int typeId + str name + + # If the object is a typedef, this points to the real object. + ptr lang_object typedefOf + + object_map objectMap + object_list inherited + ptr lang_object lookupParent + ptr lang_object specializationOf + [] + +# This structure is used to keep track of information necessary to make a +# declaration. While parsing a declaration it records the declaration's +# attributes. +def declaration_data + int isTypedef + int isFriend + int isTemplate + + ptr lang_object typeObj + [] + +def declarator_data + ptr lang_object qualObj + ptr lang_object pdcScope + ptr lang_object lookupObj + [] + +list declaration_data_list [declaration_data] +list declarator_data_list [declarator_data] + +# Constants for language object types. +global int NamespaceType = typeid namespace_id +global int ClassType = typeid class_id +global int TemplateClassType = typeid templ_class_id +global int EnumType = typeid enum_id +global int IdType = typeid identifier +global int TypedefType = typeid typedef_id +global int TemplateIdType = typeid template_id + +# Object stack definition. Uses references to objects. +list object_list [ptr lang_object] + +# Stack of integers. +list int_stack [int] + +# +# Global data declarations +# + +# Object stacks. +global object_list curNamespace = construct object_list [] +global object_list declNs = construct object_list [] +global object_list lookupNs = construct object_list [] +global object_list qualNs = construct object_list [] +global object_list templateParamNs = construct object_list [] + +# Declaration, declarator data. +global declaration_data_list declarationData = construct declaration_data_list [] +global declarator_data_list declaratorData = construct declarator_data_list [] + +# Template declarations +global int_stack templDecl = construct int_stack [] + +# Root namespace object +global ptr lang_object rootNamespace = createLangObject( NamespaceType, + '<root_namespace>', nil ) + +# Initialize the namespace and declaration stacks with the root namespace +curNamespace.push( rootNamespace ) +declNs.push( rootNamespace ) +lookupNs.push( rootNamespace ) + +# Start with no qualification (note variables are initialized to zero) +qualNs.push( nil ) + +templDecl.push( 0 ) +declarationData.push( construct declaration_data( + isTypedef: 0, isFriend: 0, isTemplate: 0 ) [] ) + +# +# Identifier lookup. +# + +# Lookup the token in the members of an object. +ptr lang_object lookupInObject( ptr lang_object obj, str name ) +{ + # LOG print( ' looking in ', obj->name, '\n' ) + + object_list ol = obj->objectMap.find( name ) + if ol { + # LOG print( ' * found an object: ', ol.head, '\n' ) + return ol.head + } + + return nil +} + +# Lookup in an object and all the objects beneath it in the inheritance +# tree. +ptr lang_object lookupWithInheritance( ptr lang_object obj, str name ) +{ + ptr lang_object found = lookupInObject( obj, name ) + if found + return found + + object_list localObjInherited = obj->inherited + for II: ptr lang_object in localObjInherited { + ptr lang_object inh = II + + # First check if the inherited object is the one we are after. + if inh->name == name && inh->typeId == ClassType { + # LOG print( ' * found a class name\n' ) + return inh + } + + # Otherwise look inside the inherited object. + found = lookupWithInheritance( inh, name ) + if found + return found + } + + return nil +} + +ptr lang_object unqualifiedLookup( str name ) +{ + ptr lang_object found + + # Start with the objects in the templateParamNs. + object_list localTemplateParamNs = templateParamNs + for TemplParaObjIter: ptr lang_object in rev_child(localTemplateParamNs) { + found = lookupWithInheritance( TemplParaObjIter, name ) + if found + break + } + + if !found { + # Iterator over the objects starting at the head of the lookup stack + # and going up through the lookup parents. + ptr lang_object lookupIn = lookupNs.top + while lookupIn { + found = lookupWithInheritance( lookupIn, name ) + if found + break + lookupIn = lookupIn->lookupParent + } + } + + return found +} + +# The C++ scanner. +lex start +{ + rl fract_const / digit* '.' digit+ | digit+ '.' / + rl exponent / [eE] [+\-]? digit+ / + rl float_suffix / [flFL] / + + # Single and double literals. + token TK_SingleLit /( 'L'? "'" ( [^'\\\n] | '\\' any )* "'" )/ + token TK_DoubleLit /( 'L'? '"' ( [^"\\\n] | '\\' any )* '"' )/ + + literal 'extern', 'namespace', 'friend', 'typedef', 'auto', 'register', + 'static', 'mutable', 'inline', 'virtual', 'explicit', 'const', + 'volatile', 'restrict', 'class', 'struct', 'union', 'template', + 'private', 'protected', 'public', 'using', 'void', 'char', + 'wchar_t', 'bool', 'int', 'float', 'double', 'short', 'long', + 'signed', 'unsigned', 'enum', 'new', 'delete', 'operator', + 'typename', 'export', 'throw', 'try', 'catch', 'sizeof', + 'dynamic_cast', 'static_cast', 'reinterpret_cast', 'const_cast', + 'typeid', 'this', 'true', 'false', 'switch', 'case', 'default', + 'if', 'else', 'while', 'do', 'for', 'break', 'continue', + 'return', 'goto' + + literal '__typeof' + + literal '{', '}', ';', ',', '=', '(', ')', ':', '&', '*', '[', ']', '~', '+', '-', + '/', '<', '>', '|', '^', '%', '!', '?', '.' + + literal '::', '==', '!=', '&&', '||', '*=', '/=', '%=', '+=', '-=', '&=', + '^=', '|=', '++', '--', '->', '->*', '.*', '...', '<<=', '>>=' + + # Token translation targets. + def unknown_id [lookup_id] + def class_id [lookup_id] + def namespace_id [lookup_id] + def templ_class_id [lookup_id] + def enum_id [lookup_id] + def typedef_id [lookup_id] + def identifier [lookup_id] + def template_id [lookup_id] + + # Identifiers + token lookup_id + ptr lang_object obj + ptr lang_object qualObj + + /( [a-zA-Z_] [a-zA-Z0-9_]* )/ + { + str name = match_text + ptr lang_object found = nil + ptr lang_object qualObj = nil + if qualNs.top { + # LOG print( 'qualified lookup of ', name, '\n' ) + + # Transfer the qualification to the token and reset it. + qualObj = qualNs.top + qualNs.top = nil + + # Lookup using the qualification. + found = lookupWithInheritance( qualObj, name ) + } + else { + # No qualification, full search. + # LOG print( 'unqualified lookup of ', name, '\n' ) + found = unqualifiedLookup( name ) + } + + # If no match, return an Unknown ID + int id = typeid unknown_id + if found + id = found->typeId + + any LookupId = make_token( typeid lookup_id, + pull(stdin, match_length), found, qualObj ) + send( make_tree( id, LookupId ) ) + + } + + # Floats. + token TK_Float /( fract_const exponent? float_suffix? | + digit+ exponent float_suffix? )/ + + # Integer decimal. Leading part buffered by float. + token TK_IntegerDecimal /( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )/ + + # Integer octal. Leading part buffered by float. + token TK_IntegerOctal /( '0' [0-9]+ [ulUL]{0,2} )/ + + # Integer hex. Leading 0 buffered by float. + token TK_IntegerHex /( '0x' [0-9a-fA-F]+ [ulUL]{0,2} )/ + + # Preprocessor line. + ignore /'#' [^\n]* '\n'/ + + # Comments and whitespace. + ignore /( '/*' (any | '\n')* :>> '*/' )/ + ignore /( '//' any* :> '\n' )/ + ignore /( any - 33..126 )+/ +} + +# +# Support functions +# + +ptr lang_object createLangObject( int typeId, str name, ptr lang_object lookupParent ) +{ + ptr lang_object obj = new construct lang_object( + typeId: typeId, + name: name, + objectMap: construct object_map [], + inherited: construct object_list [], + lookupParent: lookupParent ) [] + return obj +} + +# Building the language object tree. +int insertObject( ptr lang_object definedIn, str name, ptr lang_object obj ) +{ + object_list ol = definedIn->objectMap.find( name ) + if !ol { + # Element not in the map already + ol = construct object_list [] + } + ol.append( obj ) + definedIn->objectMap.store( name, ol ) +} + +ptr lang_object findClass( ptr lang_object inObj, str name ) +{ + object_list ol = inObj->objectMap.find( name ) + if ol { + for ObjIter: ptr lang_object in ol { + ptr lang_object obj = ObjIter + if obj->typeId == ClassType { + return obj + } + } + } + return nil +} + +ptr lang_object findTemplateClass( ptr lang_object inObj, str name ) +{ + object_list ol = inObj->objectMap.find( name ) + if ol { + for ObjIter: ptr lang_object in ol { + ptr lang_object obj = ObjIter + if obj->typeId == TemplateClassType + return obj + } + } + return nil +} + +def root_qual_opt + [] +| ['::'] + +def nested_name_specifier_opt + [nested_name_specifier_opt qualifying_name '::' designated_qualifying_name '::'] +| [nested_name_specifier_opt qualifying_name '::'] +| [] + +def nested_name_specifier + [nested_name_specifier designated_qualifying_name '::'] +| [nested_name_specifier qualifying_name '::'] +| [qualifying_name '::'] + +def qualifying_name + [class_name] + { + qualNs.top = r1.lookupId.obj + } + +| [namespace_id] + { + match r1 [Id: lookup_id] + qualNs.top = Id.obj + } + +| [typedef_id] + { + match r1 [Id: lookup_id] + qualNs.top = Id.obj->typedefOf + } + +def designated_qualifying_name + ['template' any_id] + { + # FIXME: nulling qualNs is not the right thing to do here. + qualNs.top = nil + } + +| ['template' any_id + templ_arg_open template_argument_list_opt templ_arg_close] + { + # FIXME: nulling qualNs is not the right thing to do here. + qualNs.top = nil + } + +# +# Id Expression +# + +def id_expression + lookup_id lookupId + + [root_qual_opt nested_name_specifier_opt unknown_id] + { + lhs.lookupId = lookup_id in r3 + } + +| [root_qual_opt nested_name_specifier_opt identifier] + { + lhs.lookupId = lookup_id in r3 + } + +| [root_qual_opt nested_name_specifier_opt operator_function_id] + { + # Normally the token translation transfers the qualification. Since + # the operator_function_id does not end in a lookup we must do it ourselves. + ptr lang_object qualObj = qualNs.top + qualNs.top = nil + + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<operator_function_id>' + lhs.lookupId.qualObj = qualObj + } + +| [root_qual_opt nested_name_specifier_opt conversion_function_id] + { + # Normally the token translation transfers the qualification. Since + # the operator_function_id does not } in a lookup we must do it ourselves. + ptr lang_object qualObj = qualNs.top + qualNs.top = nil + + # Do we need qual reset here becauase operator_function_id does not do it? + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<conversion_function_id>' + lhs.lookupId.qualObj = qualObj + } + +| [root_qual_opt nested_name_specifier_opt '~' class_name] + { + lhs.lookupId = r4.lookupId + } + +| [root_qual_opt nested_name_specifier_opt template_name] + { + lhs.lookupId = r3.lookupId + } + +def template_name + lookup_id lookupId + + [template_id templ_arg_open template_argument_list_opt templ_arg_close] + { + lhs.lookupId = lookup_id in r1 + } + +| [template_id] + { + lhs.lookupId = lookup_id in r1 + } + + +# +# Class Names +# + +def class_name + lookup_id lookupId + + [class_id] + { + lhs.lookupId = lookup_id in r1 + } + +| [templ_class_id] + { + lhs.lookupId = lookup_id in r1 + } + +| [templ_class_id templ_arg_open template_argument_list_opt templ_arg_close] + { + # TODO: Look for a specialization. + lhs.lookupId = lookup_id in r1 + } + +def templ_arg_open + ['<'] + { + qualNs.push( nil ) + } + +def templ_arg_close + ['>'] + { + qualNs.pop() + } + +def declaration + [block_declaration] commit +| [function_definition] commit +| [template_declaration] commit +| [explicit_instantiation] commit +| [explicit_specialization] commit +| [linkage_specification] commit +| [namespace_definition] commit + +# +# Declarations +# + +def block_declaration + [simple_declaration] +| [using_declaration] +| [using_directive] + +def simple_declaration + [declaration_start simple_declaration_forms declaration_end ';'] + +# Ordering is important for optimization. The form with the optional +# decl_specifier_sing should go second. +def simple_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt init_declarator_list_opt] + +| [decl_specifier_mult_seq_opt init_declarator_list_opt] + +def declaration_start + [] + { + # LOG print( 'opening new declaration_data with templDecl: ', templDecl.top, '\n' ) + declarationData.push( construct declaration_data ( + isTypedef: 0, isFriend: 0, isTemplate: 0 ) [] ) + + # Transfer the template flag and reset it. + declarationData.top.isTemplate = templDecl.top + templDecl.push( 0 ) + } + +def declaration_end + [] + { + # LOG print( 'closing declaration_data\n' ) + declarationData.pop() + templDecl.pop() + } + +def decl_specifier_sing + [type_specifier_sing] + { + # Store the object type of the declaration (if any) for use + # by typedefs. + declarationData.top.typeObj = r1.lookupId.obj + } + +def type_specifier_seq + lookup_id lookupId + + [type_specifier_mult_seq_opt type_specifier_sing type_specifier_mult_seq_opt] + { + lhs.lookupId = r2.lookupId + } + +def type_specifier_sing + lookup_id lookupId + + [simple_type_specifier] + { + lhs.lookupId = r1.lookupId + } + +| [class_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<class_specifier>' + } + +| [enum_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<enum_specifier>' + } + +| [elaborated_type_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<elaborated_type_specifier>' + } + +# Type specifier sequence without enum specifier or class specifier. +def necs_type_specifier_seq + [type_specifier_mult_seq_opt necs_type_specifier_sing type_specifier_mult_seq_opt] + +# Type specifier singular without enum specifier or class specifier. +def necs_type_specifier_sing + [simple_type_specifier] +| [elaborated_type_specifier] + +def type_specifier_mult_seq_opt + [type_specifier_mult_seq_opt type_specifier_mult] +| [] + +def type_specifier_mult_seq + [type_specifier_mult_seq type_specifier_mult] +| [type_specifier_mult] + +def simple_type_specifier + lookup_id lookupId + + [simple_type_specifier_name] + { + lhs.lookupId = r1.lookupId + } + +| [simple_type_specifier_kw_seq] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<simple_type_specifier_kw_seq>' + } + +| ['typename' root_qual_opt nested_name_specifier type_name] + { + lhs.lookupId = r4.lookupId + } + +| ['typename' root_qual_opt nested_name_specifier identifier] + { + lhs.lookupId = lookup_id in r4 + } + +| ['typename' root_qual_opt nested_name_specifier unknown_id] + { + lhs.lookupId = lookup_id in r4 + } + + # Extension. +| ['__typeof' '(' identifier ')'] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '<simple_type_specifier_kw_seq>' + } + +def simple_type_specifier_name + lookup_id lookupId + + [qual_type_name] + { + lhs.lookupId = r1.lookupId + } + +def simple_type_specifier_kw_seq + [simple_type_specifier_kw_seq simple_type_specifier_kw] +| [simple_type_specifier_kw] + +def simple_type_specifier_kw + ['void'] +| ['char'] +| ['wchar_t'] +| ['bool'] +| ['int'] +| ['float'] +| ['double'] +| ['short'] +| ['long'] +| ['signed'] +| ['unsigned'] + +def qual_type_name + lookup_id lookupId + + [root_qual_opt nested_name_specifier_opt type_name] + { + lhs.lookupId = r3.lookupId + } + +def type_name + lookup_id lookupId + + [class_name] + { + lhs.lookupId = r1.lookupId + } + +| [enum_id] + { + lhs.lookupId = lookup_id in r1 + } + +| [typedef_id] + { + lhs.lookupId = lookup_id in r1 + } + +# NOTE: the typename case is moved to simple type specifier +# to take advantage of its conflict resolution. +def elaborated_type_specifier + [class_key nested_name_specifier_opt class_head_name] + { + lookup_id Id = lookup_id in r3 + str name = Id.data + + # Get the ns the class is declared in. + ptr lang_object parentObj = declNs.top + if Id.qualObj + parentObj = Id.qualObj + + # Look for the class in the given scope. + ptr lang_object declaredClass = findClass( parentObj, name ) + if !declaredClass + declaredClass = findTemplateClass( parentObj, name ) + + if !declaredClass { + # LOG print( 'creating new class: ', name, '\n' ) + + # Class does not exist in the parent scope, create it. + int nsType = declaredClassType() + + declaredClass = createLangObject( nsType, name, lookupNs.top ) + + # FIXME: handle friends. Make the class visible only if we are NOT + # in a friend declaration. The new class object is necessary to + # properly process the body of the class. + if declarationData.top.isFriend == 0 + insertObject( parentObj, name, declaredClass ) + } + } + + # TODO: Lookup type specialization. +| [class_key nested_name_specifier_opt templ_class_id + templ_arg_open template_argument_list_opt templ_arg_close] + +| ['enum' nested_name_specifier_opt enum_head_name] + { + # TODO: should look for existing enums of the same name. + lookup_id Id = lookup_id in r3 + # LOG print( 'creating enumeration ', Id.data, '\n' ) + ptr lang_object enum = createLangObject( EnumType, Id.data, lookupNs.top ) + insertObject( declNs.top, Id.data, enum ) + } + +def decl_specifier_mult_seq_opt + [decl_specifier_mult_seq_opt decl_specifier_mult] +| [] + +def decl_specifier_mult_seq + [decl_specifier_mult_seq decl_specifier_mult] +| [decl_specifier_mult] + +def decl_specifier_mult + [type_specifier_mult] +| [storage_class_specifier] +| [function_specifier] + +| ['friend'] + { + declarationData.top.isFriend = 1 + } + +| ['typedef'] + { + declarationData.top.isTypedef = 1 + } + +def storage_class_specifier + ['auto'] +| ['register'] +| ['static'] +| ['extern'] +| ['mutable'] + +def function_specifier + ['inline'] +| ['virtual'] +| ['explicit'] + +def type_specifier_mult + [cv_qualifier] + +def cv_qualifier + ['const'] +| ['volatile'] +| ['restrict'] + +def cv_qualifier_rep + [cv_qualifier_rep cv_qualifier] +| [] + +def namespace_definition + [named_namespace_definition] +| [unnamed_namespace_definition] + +def named_namespace_definition + [original_namespace_definition] +| [extension_namespace_definition] + +# +# Enumerations +# + +def enum_specifier + ['enum' nested_name_specifier_opt + enum_head_name '{' enumerator_list_opt '}'] + { + # TODO: should look for existing enums of the same name. + lookup_id Id = lookup_id in r3 + # LOG print( 'creating enumeration ', Id.data, '\n' ) + ptr lang_object enum = createLangObject( EnumType, Id.data, lookupNs.top ) + insertObject( declNs.top, Id.data, enum ) + } + +| ['enum' '{' enumerator_list_opt '}'] + +def enum_head_name + [class_id] +| [templ_class_id] +| [namespace_id] +| [typedef_id] +| [enum_id] +| [identifier] +| [template_id] +| [unknown_id] + +def enumerator_list_opt + [enumerator_list] +| [enumerator_list ','] +| [] + +def enumerator_list + [enumerator_list ',' enumerator_definition] +| [enumerator_definition] + +def enumerator_definition + [enumerator_id] + { + lookup_id Id = lookup_id in r1 + ptr lang_object enumId = createLangObject( IdType, Id.data, lookupNs.top ) + insertObject( declNs.top, Id.data, enumId ) + } + +| [enumerator_id '=' constant_expression] + { + lookup_id Id = lookup_id in r1 + ptr lang_object enumId = createLangObject( IdType, Id.data, lookupNs.top ) + insertObject( declNs.top, Id.data, enumId ) + } + +def enumerator_id + [namespace_id] +| [typedef_id] +| [enum_id] +| [class_id] +| [templ_class_id] +| [template_id] +| [identifier] +| [unknown_id] + +# +# Declarators +# + +def init_declarator_list_opt + [init_declarator_list] +| [] + +def init_declarator_list + [init_declarator_list ',' init_declarator] +| [init_declarator] + +def init_declarator + [declarator initializer_opt] + +def initializer_opt + ['=' initializer_clause] +| ['(' expression ')'] +| [] + +def initializer_clause + [assignment_expression] +| ['{' initializer_list '}'] +| ['{' initializer_list ',' '}'] +| ['{' '}'] + +def initializer_list + [initializer_list ',' initializer_clause] +| [initializer_clause] + +# +# Expressions +# + +def expression + [expression ',' assignment_expression] +| [assignment_expression] + +def expression_opt + [expression] +| [] + +def constant_expression + [conditional_expression] + +def constant_expression_opt + [constant_expression] +| [] + +def assignment_expression + [conditional_expression] +| [logical_or_expression assignment_op assignment_expression] +| [throw_expression] + +def assignment_op + ['='] +| ['*='] +| ['/='] +| ['%='] +| ['+='] +| ['-='] +| ['>>='] +| ['<<='] +| ['&='] +| ['^='] +| ['|='] + +def conditional_expression + [logical_or_expression] +| [logical_or_expression '?' expression ':' assignment_expression] + +def logical_or_expression + [logical_or_expression '||' logical_and_expression] +| [logical_and_expression] + +def logical_and_expression + [logical_and_expression '&&' inclusive_or_expression] +| [inclusive_or_expression] + +def inclusive_or_expression + [inclusive_or_expression '|' exclusive_or_expression] +| [exclusive_or_expression] + +def exclusive_or_expression + [exclusive_or_expression '^' and_expression] +| [and_expression] + +def and_expression + [and_expression '&' equality_expression] +| [equality_expression] + +def equality_expression + [equality_expression '==' relational_expression] +| [equality_expression '!=' relational_expression] +| [relational_expression] + +def relational_expression + [relational_expression '<' shift_expression] +| [relational_expression '>' shift_expression] +| [relational_expression lt_eq shift_expression] +| [relational_expression gt_eq shift_expression] +| [shift_expression] + +def shift_expression + [shift_expression shift_left additive_expression] +| [shift_expression shift_right additive_expression] +| [additive_expression] + +def additive_expression + [additive_expression '+' multiplicative_expression] +| [additive_expression '-' multiplicative_expression] +| [multiplicative_expression] + +def multiplicative_expression + [multiplicative_expression '*' pm_expression] +| [multiplicative_expression '/' pm_expression] +| [multiplicative_expression '%' pm_expression] +| [pm_expression] + +def pm_expression + [pm_expression '->*' cast_expression] +| [pm_expression '.*' cast_expression] +| [cast_expression] + +def cast_expression + [unary_expression] +| ['(' type_id ')' cast_expression] + +def delete_expression + [root_qual_opt 'delete' cast_expression] +| [root_qual_opt 'delete' '[' ']' cast_expression] + +def new_initializer_opt + [new_initializer] +| [] + +def new_initializer + ['(' expression_opt ')'] + +def direct_new_declarator + ['[' expression ']'] +| [direct_new_declarator '[' constant_expression ']'] + +def new_declarator_opt + [new_declarator] +| [] + +def new_declarator + [direct_new_declarator] +| [ptr_operator_seq direct_new_declarator] +| [ptr_operator_seq] + +def new_type_id + [necs_type_specifier_seq new_declarator_opt] + +def new_placement + ['(' expression ')'] + +def new_expression + [root_qual_opt 'new' new_type_id new_initializer_opt] +| [root_qual_opt 'new' new_placement new_type_id new_initializer_opt] +| [root_qual_opt 'new' '(' type_id ')' new_initializer_opt] +| [root_qual_opt 'new' new_placement '(' type_id ')' new_initializer_opt] + +def unary_operator + ['*'] +| ['&'] +| ['+'] +| ['-'] +| ['!'] +| ['~'] + +def unary_expression + [postfix_expression] +| ['++' cast_expression] +| ['--' cast_expression] +| [unary_operator cast_expression] +| ['sizeof' '(' type_id ')'] +| ['sizeof' unary_expression] +| [new_expression] +| [delete_expression] + +def function_style_type_conv + [simple_type_specifier] + + +def postfix_expression + [primary_expression] +| [postfix_expression '[' expression ']'] +| [postfix_expression '(' expression_opt ')'] +| [function_style_type_conv '(' expression_opt ')'] +| [member_request_expr dot_arrow id_expression] +| [member_request_expr dot_arrow pseudo_destructor_call] +| [postfix_expression '++'] +| [postfix_expression '--'] +| ['dynamic_cast' templ_arg_open type_id templ_arg_close '(' expression ')'] +| ['static_cast' templ_arg_open type_id templ_arg_close '(' expression ')'] +| ['reinterpret_cast' templ_arg_open type_id templ_arg_close '(' expression ')'] +| ['const_cast' templ_arg_open type_id templ_arg_close '(' expression ')'] +| ['typeid' '(' expression ')'] +| ['typeid' '(' type_id ')'] + +def pseudo_destructor_call + [root_qual_opt nested_name_specifier_opt '~' pdc_type_name] + +def primary_expression + [expr_lit] +| ['this'] +| ['(' expression ')'] +| [id_expression] +# This is an GNU extension. +| ['(' '{' statement_rep '}' ')'] + +def expr_lit + [TK_IntegerDecimal] +| [TK_IntegerOctal] +| [TK_IntegerHex] +| [TK_SingleLit] +| [TK_Float] +| [double_lit_list] +| ['true'] +| ['false'] + +def double_lit_list + [TK_DoubleLit double_lit_list] +| [TK_DoubleLit] + +def member_request_expr + [postfix_expression] +# { +# # FIXME: If no proper type is found, we must fail. +# # LOG print( 'setting member request scope\n' ) +# # qualNs.set( $1->type != 0 ? $1->type->getObject() : 0 ); +# } + +def dot_arrow + ['->'] +| ['.'] + +def pdc_type_name + [enum_id] +| [typedef_id] + +# +# Statements +# + +def statement_rep + [statement_rep statement] +| [] + +def statement + [declaration_statement] +| [labeled_statement] +| [expression_statement] +| [compound_statement] +| [selection_statement] +| [iteration_statement] +| [jump_statement] +| [try_block] + +def labeled_statement + [label_id ':' statement] +| ['case' constant_expression ':' statement] +| ['default' ':' statement] + +def label_id + [unknown_id] +| [identifier] +| [class_id] +| [templ_class_id] +| [namespace_id] +| [typedef_id] +| [enum_id] +| [template_id] + +def compound_statement + ['{' compound_begin statement_rep compound_end '}'] + +def compound_begin + [] + { + ptr lang_object newCompound = createLangObject( 0, '<compound_begin>', lookupNs.top ) + lookupNs.push( newCompound ) + declNs.push( newCompound ) + # LOG print( 'opening <compound>\n' ) + } + +def compound_end + [] + { + lookupNs.pop() + declNs.pop() + # LOG print( 'closing <compound>\n' ) + } + +def selection_statement + ['if' '(' condition ')' statement elseif_clauses else_clause] +| ['switch' '(' condition ')' statement] + +def elseif_clauses + [elseif_clauses 'else' 'if' '(' condition ')' statement] +| [] + +def else_clause + ['else' statement] +| [] + +def iteration_statement + ['while' '(' condition ')' statement] +| ['do' statement 'while' '(' expression ')' ';'] +| ['for' '(' for_init_statement condition_opt ';' expression_opt ')' statement] + +def jump_statement + ['break' ';'] +| ['continue' ';'] +| ['return' expression_opt ';'] +| ['goto' any_id ';'] + +def any_id + [unknown_id] +| [class_id] +| [namespace_id] +| [templ_class_id] +| [enum_id] +| [typedef_id] +| [identifier] +| [template_id] + + +def for_init_statement + [expression_statement] +| [stmt_block_declaration_forms ';'] + +def condition + [expression] +| [type_specifier_seq declarator '=' assignment_expression] + +def condition_opt + [condition] +| [] + +def expression_statement + [expression ';'] +| [';'] + +def declaration_statement + [stmt_block_declaration] + +def stmt_block_declaration + [declaration_start stmt_block_declaration_forms declaration_end ';'] +| [using_declaration] +| [using_directive] + +def stmt_block_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt + init_declarator_list_opt] +| [decl_specifier_mult_seq init_declarator_list_opt] + +# +# Declarators +# + +def declarator + ptr lang_object lookupObj + + [ptr_operator_seq_opt declarator_id decl_array_or_param_rep declarator_end] + { + lhs.lookupObj = r4.lookupObj + } + +| [ptr_operator_seq_opt '(' sub_declarator ')' decl_array_or_param_rep declarator_end] + { + lhs.lookupObj = r6.lookupObj + } + +def sub_declarator + [ptr_operator_seq declarator_id decl_array_or_param_rep] +| [ptr_operator_seq '(' sub_declarator ')' decl_array_or_param_rep] +| ['(' sub_declarator ')' decl_array_or_param_rep] +| [declarator_id decl_array_or_param_rep] + +def decl_array_or_param_rep + [decl_array_or_param_rep decl_array_or_param] +| [] + +def decl_array_or_param + ['[' constant_expression_opt ']'] +| ['(' parameter_declaration_clause ')' cv_qualifier_rep exception_specification_opt] + +def declarator_id + [declarator_id_forms] + { + str name = r1.lookupId.data + ptr lang_object qualObj = r1.lookupId.qualObj + + ptr lang_object parentObj = declNs.top + if qualObj { + parentObj = qualObj + } + + # Decide if we are declaring a constructor/destructor. + bool isConstructor + if parentObj == r1.lookupId.obj { + isConstructor = true + # LOG print( 'making declarator ', name, ' a constructor/destructor\n' ) + } + + if parentObj->specializationOf && + parentObj->specializationOf == r1.lookupId.obj + { + isConstructor = true + # LOG print( 'making declarator ', name, ' a constructor/destructor\n' ) + } + + ptr lang_object obj = nil + if name && !isConstructor && declarationData.top.isFriend == 0 { + if declarationData.top.isTypedef { + obj = createLangObject( TypedefType, name, lookupNs.top ) + obj->typedefOf = declarationData.top.typeObj + insertObject( parentObj, name, obj ) + + # LOG print( 'making declarator ', name, ' a typedef\n' ) + } + else { + if !qualObj { + if declarationData.top.isTemplate { + # If in a template declaration and the name is not qualified then + # create the template id. + obj = createLangObject( TemplateIdType, name, lookupNs.top ) + #object->objType = declarationData.top.type + insertObject( declNs.top, name, obj ) + + # LOG print( 'making declarator ', name, ' a template id\n' ) + } + else { + obj = createLangObject( IdType, name, lookupNs.top ) + #object->objType = declarationData.top().type; + insertObject( declNs.top, name, obj ) + + # LOG print( 'making declarator ', name, ' an id\n' ) + } + } + } + } + + declaratorData.push( construct declarator_data ( + qualObj: qualObj, lookupObj: lookupNs.top ) [] ) + + # If the declarator is qualified, push the qualification to the lookup + # stack. Also save it in the declarator data so it can be passed to a + # function body if needed. + if qualObj { + lookupNs.push( qualObj ) + declaratorData.top.lookupObj = qualObj + } + + # LOG print( 'reduced declarator_id: ', name, '\n' ) + } + +# Undoes the setup done by declarator_id and pdc_start. +def declarator_end + ptr lang_object lookupObj + + [] + { + # Get the lookupObject from the scope and pass it up. If we are about to + # parse a function body it will be needed. + lhs.lookupObj = declaratorData.top.lookupObj + + ptr lang_object pdcScope = declaratorData.top.pdcScope + ptr lang_object qualObj = declaratorData.top.qualObj + + declaratorData.pop() + + if pdcScope { + # LOG print( 'closing <pdc_scope>\n' ) + lookupNs.pop() + declNs.pop() + } + + if qualObj { + # LOG print( 'popping lookupNs\n' ) + lookupNs.pop() + } + } + +def declarator_id_forms + lookup_id lookupId + + [id_expression] + { + lhs.lookupId = r1.lookupId + } + +| [root_qual_opt nested_name_specifier_opt type_name] + { + lhs.lookupId = r3.lookupId + } + +| [root_qual_opt nested_name_specifier_opt '~' class_id] + { + lhs.lookupId = lookup_id in r4 + } + +| [root_qual_opt nested_name_specifier_opt '~' templ_class_id] + { + lhs.lookupId = lookup_id in r4 + } +| [root_qual_opt nested_name_specifier_opt '~' unknown_id] + { + lhs.lookupId = lookup_id in r4 + } + +def type_id + lookup_id lookupId + + [type_specifier_seq abstract_declarator_opt] + { + lhs.lookupId = r1.lookupId + } + +def abstract_declarator_opt + [abstract_declarator] +| [] + +def abstract_declarator + [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt declarator_end] +| [ptr_operator_seq '(' sub_abstract_declarator ')' + abstract_decl_array_or_param_seq_opt declarator_end] +| [abstract_noid abstract_decl_array_or_param_seq declarator_end] +| ['(' sub_abstract_declarator ')' abstract_decl_array_or_param_seq_opt declarator_end] + +def sub_abstract_declarator + [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt] + +| [ptr_operator_seq '(' sub_abstract_declarator ')' + abstract_decl_array_or_param_seq_opt] + +| ['(' sub_abstract_declarator ')' abstract_decl_array_or_param_seq_opt] + +def abstract_noid + [] + { + # Make scope for declarator. + declaratorData.push( construct declarator_data [] ) + } + +def abstract_decl_array_or_param_seq_opt + [abstract_decl_array_or_param_seq_opt abstract_decl_array_or_param] +| [] + +def abstract_decl_array_or_param_seq + [abstract_decl_array_or_param_seq abstract_decl_array_or_param] +| [abstract_decl_array_or_param] + +def abstract_decl_array_or_param + ['[' constant_expression_opt ']'] +| ['(' parameter_declaration_clause ')' cv_qualifier_rep + exception_specification_opt] + +def parameter_declaration_clause + [pdc_start parameter_declaration_list] +| [pdc_start parameter_declaration_list '...'] +| [pdc_start parameter_declaration_list ',' '...'] +| [pdc_start '...'] +| [pdc_start] + +def pdc_start + [] + { + if !declaratorData.top.pdcScope { + # We are going to need a scope for the declarator. + ptr lang_object pdcScope = createLangObject( 0, '<pdc_scope>', lookupNs.top ) + lookupNs.push( pdcScope ) + declNs.push( pdcScope ) + + declaratorData.top.pdcScope = pdcScope + declaratorData.top.lookupObj = pdcScope + # LOG print( 'opening <pdc_scope>\n' ) + } + } + +def parameter_declaration_list + [parameter_declaration_list ',' parameter_declaration] +| [parameter_declaration] + +def parameter_declaration + [declaration_start parameter_declaration_forms declaration_end] + +# Ordering the productions such that decl_specifier_sing is tried first is good +# for performance. +def parameter_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt + param_maybe_declarator maybe_parameter_init] + +| [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init] + +def param_maybe_declarator + [abstract_declarator] +| [declarator] +| [] + +def maybe_parameter_init + ['=' constant_expression] +| [] + +def ptr_operator + ['&'] +| [root_qual_opt nested_name_specifier_opt '*' cv_qualifier_rep] + +def ptr_operator_seq + [ptr_operator_seq ptr_operator] +| [ptr_operator] + +def ptr_operator_seq_opt + [ptr_operator_seq_opt ptr_operator] +| [] + +# +# Functions +# + +def function_definition + [function_def_declaration ctor_initializer_opt function_body function_def_end] + +def function_def_declaration + [declaration_start function_def_declaration_forms declaration_end] + +def function_def_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt function_def_declarator] +| [decl_specifier_mult_seq function_def_declarator] +| [function_def_declarator] + +def function_def_declarator + [declarator] + { + # The lookupObj from the declarator is the deepest lookup object found + # while parsing the declarator. Make it visible in the function body. + # This could be the args, the qualObj, or the parent to the function. + lookupNs.push( r1.lookupObj ) + } + +def function_def_end + [] + { + # Pop the lookup object. + lookupNs.pop() + } + +def function_body + [function_body_begin '{' statement_rep function_body_end '}'] + +def function_body_begin + [] + { + ptr lang_object newFunctionBody = createLangObject( 0, + '<function_body_begin>', lookupNs.top ) + lookupNs.push( newFunctionBody ) + declNs.push( newFunctionBody ) + templDecl.push( 0 ) + # LOG print( 'opening <function_body>\n' ) + } + +def function_body_end + [] + { + # First undoes the function body begin work. Then undoes the setup in + # function_def_declarator. + declNs.pop() + lookupNs.pop() + templDecl.pop() + # LOG print( 'closing <function_body>\n' ) + } + + + +# +# Classs +# + +int declaredClassType() +{ + if declarationData.top.isTemplate { + return TemplateClassType + } else { + return ClassType + } +} + +def class_specifier + [class_head base_clause_opt '{' class_member_rep class_body_end '}'] + { +# FIXME: reparse not implemented yet +# # Visit class function bodies, but skip nested classes. +# for CFB: class_function_body in lhs { +# skipping class_specifier +# +# # Reparse the text of the class function body as a function body +# function_body FB = reparse function_body( CFB ) +# +# # Replace the class function body with the parsed function body. +# CFB = construct class_function_body +# [FB] +# } + } + +def class_head + [class_key] + { + int nsType = declaredClassType() + + # LOG print( 'creating new anonymous class\n' ) + ptr lang_object newClass = createLangObject( nsType, + '<anon_class>', lookupNs.top ) + lookupNs.push( newClass ) + declNs.push( newClass ) + } + +| [class_key nested_name_specifier_opt class_head_name] + { + lookup_id Id = lookup_id in r3 + str name = Id.data + + # Get the ns the class is declared in. + ptr lang_object parentObj = declNs.top + if Id.qualObj + parentObj = Id.qualObj + + # Look for the class in the given scope. + ptr lang_object declaredClass = findClass( parentObj, name ) + if !declaredClass + declaredClass = findTemplateClass( parentObj, name ) + + if !declaredClass { + # LOG print( 'creating new class: ', name, '\n' ) + + # Class does not exist in the parent scope, create it. + int nsType = declaredClassType() + + declaredClass = createLangObject( nsType, name, lookupNs.top ) + + # FIXME: handle friends. Make the class visible only if we are NOT + # in a friend declaration. The new class object is necessary to + # properly process the body of the class. + if declarationData.top.isFriend == 0 + insertObject( parentObj, name, declaredClass ) + } + + # Push the found/new class. + lookupNs.push( declaredClass ) + declNs.push( declaredClass ) + } + +| [class_key nested_name_specifier_opt templ_class_id + templ_arg_open template_argument_list_opt templ_arg_close] + { + match r3 [Id: lookup_id] + str id = Id.data + ptr lang_object classObj = Id.obj + + # TODO: Try to find the specializaition in the template class object. + # TypeList typeList; + # makeTypeList( typeList, $6->last ); + + ptr lang_object declaredClass + #declaredClass = classObj->findSpecExact( typeList ); + if !declaredClass { + # LOG print( 'making new template specialization\n' ) + int nsType = declaredClassType() + declaredClass = createLangObject( nsType, id, lookupNs.top ) + # LOG print( 'declaredClass: ', declaredClass, '\n' ) + declaredClass->specializationOf = classObj + # $$->typeListMapEl = classObj->typeListMap.insert( typeList, declaredClass ); + } + + # Push the found/new class. + lookupNs.push( declaredClass ) + declNs.push( declaredClass ) + } + +def class_body_end + [] + { + # Pop the class ns. + lookupNs.pop() + declNs.pop() + + # LOG print( 'closing off class\n' ) + } + +def class_head_name + [class_id] +| [templ_class_id] +| [namespace_id] +| [typedef_id] +| [enum_id] +| [unknown_id] +| [identifier] +| [template_id] + +def class_key + ['class'] +| ['struct'] +| ['union'] + +def class_member_rep + [class_member_rep class_member] +| [] + +def class_member + [member_declaration] +| [access_specifier ':'] + +def member_declaration + [declaration_start member_declaration_forms declaration_end ';'] +| [class_function_definition] +| [using_declaration] +| [template_declaration] + +def class_function_definition + [function_def_declaration ctor_initializer_opt class_function_body function_def_end] + +lex cfb_conts +{ + token cfb_open /'{'/ + token cfb_close /'}'/ + token cfb_string / + "'" ( [^'\\\n] | '\\' any )* "'" | + '"' ( [^"\\\n] | '\\' any )* '"'/ + token cfb_comment / + ( '/*' (any | '\n')* :>> '*/' ) | + ( '//' any* :> '\n' )/ + token cfb_data /[^{}'"/]+ | '/'/ +} + +def cfb_item + [cfb_data] +| [cfb_string] +| [cfb_comment] +| [cfb_open cfb_item* cfb_close] + +def cfb_conts + [cfb_item* cfb_close] + + + +def class_function_body +# ['{' cfb_conts] +#| [function_body] + [function_body] + +# Get better performance if the form with decl_specifier_sing comes first. +def member_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt member_declarator_list_opt] +| [decl_specifier_mult_seq_opt member_declarator_list_opt] + +def member_declarator_list_opt + [member_declarator_list] +| [] + +def member_declarator_list + [member_declarator_list ',' member_declarator] +| [member_declarator] + +def member_declarator + [declarator] +| [declarator '=' constant_expression] +| [declarator ':' constant_expression] +| [':' constant_expression] + +def access_specifier + ['private'] +| ['protected'] +| ['public'] + +def access_specifier_opt + [access_specifier] +| [] + +def using_declaration + ['using' id_expression ';'] + { + ptr lang_object obj = r2.lookupId.obj + if obj + insertObject( declNs.top, obj->name, obj ) + } + +| ['using' type_id ';'] + { + ptr lang_object obj = r2.lookupId.obj + if obj + insertObject( declNs.top, obj->name, obj ) + } + +def using_directive + ['using' 'namespace' root_qual_opt nested_name_specifier_opt + namespace_id ';'] + { + # This uses a simple, incomplete guard against cycles in the graph of + # using namespaces. A more sophisticated and complete guard would look + # for longer cycles as well. Note that even gcc 3.3.5 does not bother. + match r5 [Id: lookup_id] + ptr lang_object usingObject = Id.obj + ptr lang_object inObject = declNs.top + if usingObject != inObject + inObject->inherited.append( usingObject ) + } + + +# +# Derived classes +# + +def base_clause_opt + [base_clause] +| [] + +def base_clause + [':' base_specifier_list] + +def base_specifier_list + [base_specifier_list ',' base_specifier] +| [base_specifier] + +int addBaseSpecifier( ptr lang_object inObject, ptr lang_object inheritedObject ) +{ + # Resolve typedefs. + if inheritedObject->typeId == TypedefType + inheritedObject = inheritedObject->typedefOf + + inObject->inherited.append( inheritedObject ) +} + +def base_specifier + [root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs.top, r3.lookupId.obj ) + } + +| ['virtual' access_specifier_opt root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs.top, r5.lookupId.obj ) + } + +| [access_specifier virtual_opt root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs.top, r5.lookupId.obj ) + } + +def virtual_opt + ['virtual'] +| [] + +# +# Special member functions +# + +def conversion_function_id + ['operator' conversion_type_id] + +def conversion_type_id + [necs_type_specifier_seq ptr_operator_seq_opt] + +def ctor_initializer_opt + [ctor_initializer] +| [] + +def ctor_initializer + [':' mem_initializer_list] + +def mem_initializer_list + [mem_initializer_list ',' mem_initializer] +| [mem_initializer] + +def mem_initializer + [mem_initializer_id '(' expression_opt ')'] + +def mem_initializer_id + [root_qual_opt nested_name_specifier_opt unknown_id] +| [root_qual_opt nested_name_specifier_opt identifier] +| [root_qual_opt nested_name_specifier_opt type_name] +| [root_qual_opt nested_name_specifier_opt template_name] + + +# +# Overloading +# +def operator_function_id + ['operator' operator] + +def operator + ['+'] | ['-'] | ['*'] | ['/'] | ['='] | ['<'] | ['>'] | ['&'] | ['|'] | + ['^'] | ['%'] | ['~'] | ['!'] | ['(' ')'] | ['[' ']'] | ['new'] | + ['delete'] | ['->'] | ['++'] | ['--'] | ['*='] | ['/='] | ['%='] | + ['+='] | ['-='] | ['>>='] | ['<<='] | ['&='] | ['^='] | ['|='] | ['=='] | + ['!='] | ['&&'] | ['||'] | [lt_eq] | [gt_eq] | [shift_left] | [shift_right] + +def lt_eq + ['<' '='] +# try { +# if ( $2->leader != 0 ) { +# #ifdef LOG_REDUCE +# cerr << "rejecting less-than equals-to" << endl; +# #endif +# reject(); +# } +# }; + +def gt_eq + ['>' '='] +# try { +# if ( $2->leader != 0 ) { +# #ifdef LOG_REDUCE +# cerr << "rejecting greater-than equals-to" << endl; +# #endif +# reject(); +# } +# }; + +def shift_left + ['<' '<'] +# try { +# if ( $2->leader != 0 ) { +# #ifdef LOG_REDUCE +# cerr << "rejecting shift left" << endl; +# #endif +# reject(); +# } +# }; + +def shift_right + ['>' '>'] +# try { +# if ( $2->leader != 0 ) { +# #ifdef LOG_REDUCE +# cerr << "rejecting shift right" << endl; +# #endif +# reject(); +# } +# }; + +# +# Templates +# + +def template_declaration + [template_declaration_params declaration] + { + templDecl.pop() + templateParamNs.pop() + } + +def template_declaration_params + ['template' '<' tpl_start template_parameter_list '>'] + { + templDecl.push( 1 ) + } + +| ['export' 'template' '<' tpl_start template_parameter_list '>'] + { + templDecl.push( 1 ) + } + +def tpl_start + [] + { + # Create a new scope for the template parameters. + ptr lang_object newTemplateParamScope = + createLangObject( 0, '<tpl_start>', lookupNs.top ) + templateParamNs.push( newTemplateParamScope ) + } + +def template_parameter_list + [template_parameter_list ',' template_parameter] +| [template_parameter] + +def template_parameter + [type_parameter] +| [template_parameter_declaration] + +def template_parameter_declaration + [declaration_start template_parameter_declaration_forms declaration_end] + +def template_parameter_declaration_forms + [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init] + +| [temp_param_decl_specifier_sing decl_specifier_mult_seq_opt + param_maybe_declarator maybe_parameter_init] + +| [decl_specifier_mult_seq temp_param_decl_specifier_sing + decl_specifier_mult_seq_opt param_maybe_declarator maybe_parameter_init] + +def temp_param_decl_specifier_sing + [temp_param_type_specifier_sing] + +# Template parameters cannot support elaborated type specifer or class specifier. +def temp_param_type_specifier_sing + [templ_simple_type_specifier] +| [enum_specifier] + +def templ_simple_type_specifier + [simple_type_specifier_name] +| [simple_type_specifier_kw_seq] + +def type_parameter + ['class' type_param_id type_param_init_opt] + { + lookup_id Id = lookup_id in r2 + if Id { + # The lookup ns should be a template param scope. + ptr lang_object newClass = + createLangObject( ClassType, Id.data, lookupNs.top ) + insertObject( templateParamNs.top, Id.data, newClass ) + } + } + +| ['typename' type_param_id type_param_init_opt] + { + lookup_id Id = lookup_id in r2 + if Id { + # The lookup ns should be a template param scope. + ptr lang_object newClass = + createLangObject( ClassType, Id.data, lookupNs.top ) + insertObject( templateParamNs.top, Id.data, newClass ) + } + } + +| ['template' '<' tpl_start template_parameter_list '>' + 'class' type_param_id templ_type_param_init_opt] + { + lookup_id Id = lookup_id in r7 + if Id { + ptr lang_object newClass = + createLangObject( TemplateClassType, Id.data, lookupNs.top ) + insertObject( templateParamNs.top, Id.data, newClass ) + } + } + +def templ_type_param_init_opt + ['=' id_expression] +| [] + +def type_param_init_opt + ['=' type_id] +| [] + +def type_param_id + [namespace_id] +| [typedef_id] +| [enum_id] +| [class_id] +| [templ_class_id] +| [identifier] +| [template_id] +| [unknown_id] +| [] + +def template_argument_list_opt + [template_argument_list] +| [] + +def template_argument_list + [template_argument_list ',' template_argument] +| [template_argument] + +def template_argument + [type_id] +| [assignment_expression] + +def explicit_instantiation + ['template' declaration] +| [declaration_start decl_specifier_mult_seq 'template' declaration declaration_end] + +def explicit_specialization + ['template' '<' '>' declaration] + +## Not sure what this one is about? +#explicit_specialization: +# declaration_start decl_specifier_mult_seq KW_Template '<' '>' +# declaration declaration_end; + + +# +# Original namespace definition +# + +def original_namespace_definition + [orig_namespace_def_name '{' declaration* namespace_end '}'] + +def orig_namespace_def_name ['namespace' unknown_id] + { + match r2 [Id: lookup_id] + ptr lang_object nspace = createLangObject( + NamespaceType, Id.data, lookupNs.top ) + + # Insert the new object into the dictionary of the parent. + insertObject( curNamespace.top, Id.data, nspace ) + + # Push the namespace + curNamespace.push( nspace ) + declNs.push( nspace ) + lookupNs.push( nspace ) + + # LOG print( 'created original namespace: ', Id.data, '\n' ) + } + +def namespace_end [] + { + # Pop the namespace. + curNamespace.pop() + declNs.pop() + lookupNs.pop() + + # LOG print( 'closed namespace\n' ) + } + +# +# Extension namespace definition +# + +def extension_namespace_definition + [ext_namespace_def_name '{' declaration* namespace_end '}'] + +def ext_namespace_def_name ['namespace' namespace_id] + { + match r2 [Id: lookup_id] + ptr lang_object nspace = Id.obj + + # Push the namespace + curNamespace.push( nspace ) + declNs.push( nspace ) + lookupNs.push( nspace ) + + # LOG print( 'found extended namespace: ', Id.data, '\n' ) + } + +# +# Unnamed namespace definition +# +def unnamed_namespace_definition + [unnamed_namespace_def_name '{' declaration* namespace_end '}'] + +def unnamed_namespace_def_name ['namespace'] + { + ptr lang_object nspace = createLangObject( + NamespaceType, '<unnamed_namespace>', + lookupNs.top ) + + # Push the namespace + curNamespace.push( nspace ) + declNs.push( nspace ) + lookupNs.push( nspace ) + + # LOG print( 'parsed unnamed namespace\n' ) + } + +# +# linkage_specification +# +def linkage_specification + ['extern' TK_DoubleLit '{' declaration* '}'] +| ['extern' TK_DoubleLit declaration] + +# +# Exception Handling. +# + +def try_block + ['try' compound_statement handler_seq] + +def handler_seq + [handler_seq handler] +| [handler] + +def handler + ['catch' '(' exception_declaration ')' compound_statement] + +def exception_declaration + [type_specifier_seq declarator] +| [type_specifier_seq abstract_declarator] +| [type_specifier_seq] +| ['...'] + +def throw_expression + ['throw' assignment_expression] +| ['throw'] + +def exception_specification_opt + [exception_specification] +| [] + +def exception_specification + ['throw' '(' type_id_list_opt ')'] + +def type_id_list_opt + [type_id_list] +| [] + +def type_id_list + [type_id_list ',' type_id] +| [type_id] + +def start + [declaration*] + +# +# Grammar done. +# + +int printObject( str indent, ptr lang_object obj ) +{ + print( indent, obj->name ) + + if obj->objectMap.length > 0 + print( ' {\n' ) + + object_map ChildNames = obj->objectMap + for MapEl: object_list in child( ChildNames ) { + for Obj: ptr lang_object in MapEl + printObject( indent + ' ', Obj ) + } + + if obj->objectMap.length > 0 + print( indent, '}' ) + + print( '\n' ) +} + +int printNamespace() +{ + printObject( '', rootNamespace ) +} + +start S = parse start( stdin ) +#printNamespace() +#print( '***** SUCCESS *****\n' ) +#print_xml( S ) +#for DI: declarator_id in S { +# if match DI +# [root_qual_opt nested_name_specifier_opt '~' UID:unknown_id] +# { +# print( UID, '\n' ) +# } +#} diff --git a/test/cxx/input01.cpp b/test/cxx/input01.cpp new file mode 100644 index 00000000..e2b125f4 --- /dev/null +++ b/test/cxx/input01.cpp @@ -0,0 +1,17 @@ +namespace ns1 +{ + namespace sub1 { class A {}; } + namespace sub2 { class B {}; } +} + +namespace ns2 +{ +// int i = b; + class C + { + }; + + using namespace ns1; +} + +ns2::sub1::A a; diff --git a/test/cxx/input02.cpp b/test/cxx/input02.cpp new file mode 100644 index 00000000..65ebe0db --- /dev/null +++ b/test/cxx/input02.cpp @@ -0,0 +1,16 @@ + +struct A +{ + struct B {}; +}; + +struct C +{ + struct D : virtual public A {}; +}; + +C::D::A d; + +C c; + + diff --git a/test/cxx/input03.cpp b/test/cxx/input03.cpp new file mode 100644 index 00000000..bccfbf0e --- /dev/null +++ b/test/cxx/input03.cpp @@ -0,0 +1,19 @@ + +struct C +{ + +}; + +enum E +{ + C, + b +}; + +E e; + +enum E +{ + C, + b +}; diff --git a/test/cxx/input04.cpp b/test/cxx/input04.cpp new file mode 100644 index 00000000..9741a82b --- /dev/null +++ b/test/cxx/input04.cpp @@ -0,0 +1,17 @@ + + +int i; +class C +{ + int j; +}; + +class D +{ + int ~D(); +}; + +int C::k; +int C::~C; + +typedef int Int; diff --git a/test/cxx/input05.cpp b/test/cxx/input05.cpp new file mode 100644 index 00000000..7936ce09 --- /dev/null +++ b/test/cxx/input05.cpp @@ -0,0 +1,8 @@ + +class C {}; +void ~C( ); +void C::operator +( int i ); + +int i; + +//void operator C( void k ); diff --git a/test/cxx/input06.cpp b/test/cxx/input06.cpp new file mode 100644 index 00000000..008edd4b --- /dev/null +++ b/test/cxx/input06.cpp @@ -0,0 +1,7 @@ + +class C +{ + +}; + +int C::f( int i, int j( void v ) ); diff --git a/test/cxx/input07.cpp b/test/cxx/input07.cpp new file mode 100644 index 00000000..474ba9a1 --- /dev/null +++ b/test/cxx/input07.cpp @@ -0,0 +1,18 @@ +class C +{ + class D {}; + + typedef C I; + + I::D i; +}; + +C c; + +void function( int i, int j ); +{ + asdlkf +} + + + diff --git a/test/cxx/input08.cpp b/test/cxx/input08.cpp new file mode 100644 index 00000000..2e9ec7a0 --- /dev/null +++ b/test/cxx/input08.cpp @@ -0,0 +1,13 @@ +class B { class Find {}; }; + +typedef B T; + +class C : public T +{ + Find find; +}; + + + + + diff --git a/test/cxx/input09.cpp b/test/cxx/input09.cpp new file mode 100644 index 00000000..373f4373 --- /dev/null +++ b/test/cxx/input09.cpp @@ -0,0 +1,7 @@ +template <class X> struct C +{ + X t; + void f(); +}; + +template <class X> void C<X>::f(); diff --git a/test/cxx/input10.cpp b/test/cxx/input10.cpp new file mode 100644 index 00000000..98b6a96a --- /dev/null +++ b/test/cxx/input10.cpp @@ -0,0 +1,11 @@ +template <class X> struct C +{ + class Y {}; +}; + +class C<int> +{ + int i; +}; + +//void f( class C<int> i, int j ); diff --git a/test/cxx/input11.cpp b/test/cxx/input11.cpp new file mode 100644 index 00000000..d9714571 --- /dev/null +++ b/test/cxx/input11.cpp @@ -0,0 +1,2 @@ + +int f( int (*) [](), void ); diff --git a/test/cxx/input12.cpp b/test/cxx/input12.cpp new file mode 100644 index 00000000..c135c8da --- /dev/null +++ b/test/cxx/input12.cpp @@ -0,0 +1,8 @@ +void f(); +class C +{ + class D {}; + void g(); +}; + +typename C c; diff --git a/test/cxx/input13.cpp b/test/cxx/input13.cpp new file mode 100644 index 00000000..67fd42fd --- /dev/null +++ b/test/cxx/input13.cpp @@ -0,0 +1,14 @@ + +class C +{ + class D {}; + int f(); +}; + +int f() +{ +} +int C::f() +{ + D d; +} diff --git a/test/cxx/preproc b/test/cxx/preproc new file mode 100755 index 00000000..2661a197 --- /dev/null +++ b/test/cxx/preproc @@ -0,0 +1,5 @@ +#!/bin/bash +# + +echo 'struct __builtin_va_list {};' +g++ -E -undef -D'__attribute__(xyz)=' "$@" | sed 's/#.*$//' | grep -v '^[ \t]*$' diff --git a/test/diff/Makefile b/test/diff/Makefile new file mode 100644 index 00000000..d647261a --- /dev/null +++ b/test/diff/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/diff/diff.lm b/test/diff/diff.lm new file mode 100644 index 00000000..37232025 --- /dev/null +++ b/test/diff/diff.lm @@ -0,0 +1,84 @@ + + +token newline / '\n' / +token index / 'Index:' [ \t]* / +token consume_line / [^\n]* / + + +def index_stmt [index consume_line newline] + +token separator_line / '='+ '\n' / + +# Whitespace separated word list +lex word_list +{ + token word /[^\t \n]+/ + ignore /[\t ]+/ + + def word_list + [word word_list] + | [] +} + +token old_file_start / '---' [\t ]+ / +token new_file_start / '+++' [\t ]+ / + +def old_file + [old_file_start word_list newline] + +def new_file + [new_file_start word_list newline] + +def file_header + [index_stmt separator_line old_file new_file] + +token hunk_header / '@@' any* :>> '@@' '\n' / +token hunk_line / ( ' ' | '-' | '+' ) [^\n]* '\n' / + +def hunk_body + [hunk_line*] + +def hunk + [hunk_header hunk_body] + +# diff of a single file: header followed by a hunk list. +def file_diff + [file_header hunk*] + +def start + [file_diff*] + + +start S = parse start( stdin ) + +for OF:old_file in S { + print( 'old file: ', OF ) + # Get the first word and check if it is + # the file we are interested in. + if match OF [ + "--- fsmrun.cpp" + Rest: word_list + "\n" + ] + { + OF = construct old_file + ["--- newfilename.cpp" Rest "\n"] + print_xml( OF ) + } +} + +print( S ) + +# for Header: file_header in lhs { +# old_file OF = old_file in Header +# if match OF +# [old_file_start "lmparse.kl" word_list newline] +# { +# Header = construct file_header +# ~Index: rewritten +# ~=================================================================== +# ~--- this is the file (asldkfj) +# ~+++ this is the file (ewir) +# } +# } + diff --git a/test/diff/input1.diff b/test/diff/input1.diff new file mode 100644 index 00000000..b0021f67 --- /dev/null +++ b/test/diff/input1.diff @@ -0,0 +1,86 @@ +Index: fsmrun.cpp +=================================================================== +--- fsmrun.cpp (revision 4555) ++++ fsmrun.cpp (working copy) +@@ -150,7 +150,7 @@ + peof = 0; + if ( parser != 0 ) { + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + } + else { + region = 0; +@@ -189,7 +189,7 @@ + + tokstart = 0; + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + } + + void FsmRun::sendToken( int id ) +@@ -222,7 +222,7 @@ + parser = newParser; + + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + } + else { + #ifdef LOG_ACTIONS +@@ -355,7 +355,7 @@ + + /* Set the current state from the next region. */ + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + } + } + +@@ -452,7 +452,7 @@ + /* First thing check for error. */ + if ( cs == tables->errorState ) { + if ( parser != 0 ) { +- if ( getStateFromNextRegion( 1 ) != 0 ) { ++ if ( parser->getNextRegion( 1 ) != 0 ) { + #ifdef LOG_BACKTRACK + cerr << "scanner failed, trying next region" << endl; + #endif +@@ -462,7 +462,7 @@ + + parser->nextRegionInd += 1; + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + cerr << "new token region: " << + parser->tables->gbl->regionInfo[region].name << endl; + continue; +@@ -495,7 +495,7 @@ + } + else { + region = parser->getNextRegion(); +- cs = getStateFromNextRegion(); ++ cs = tables->entryByRegion[region]; + cerr << "new token region: " << + parser->tables->gbl->regionInfo[region].name << endl; + continue; +Index: junk.cpp +=================================================================== +--- ++++ junk.cpp (working copy) +Index: fsmrun.h +=================================================================== +--- fsmrun.h (revision 4557) ++++ fsmrun.h (working copy) +@@ -197,10 +197,6 @@ + void runOnInputStream( PdaRun *parser, InputStream &in ); + void execute(); + +- /* Offset can be used to look at the next nextRegionInd. */ +- int getStateFromNextRegion( int offset = 0 ) +- { return tables->entryByRegion[parser->getNextRegion(offset)]; } +- + FsmTables *tables; + PdaRun *parser; + InputStream *inputStream; diff --git a/test/dns/Makefile b/test/dns/Makefile new file mode 100644 index 00000000..86e11071 --- /dev/null +++ b/test/dns/Makefile @@ -0,0 +1,20 @@ +# +# Copyright 2007 Adrian Thurston <thurston@complang.org> +# + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +extract: extract.c + gcc -Wall -o extract extract.c -lpcap + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f dns.cpp dns.bin extract diff --git a/test/dns/dns.lm b/test/dns/dns.lm new file mode 100644 index 00000000..29f0cdbe --- /dev/null +++ b/test/dns/dns.lm @@ -0,0 +1,488 @@ + +# Used for most of the grammar. +token octet /any/ + +# Filled in during the parsing of resource records. Determine what RR_UNKNOWN +# translates to. +global int rr_type_value +global int rr_class_value + +# Tokens generated from RR_UNKNOWN. Used to pick the kind +# of resource record to attempt to parse. +token RR_A // # 1 a host address +token RR_NS // # 2 an authoritative name server +token RR_MD // # 3 a mail destination (Obsolete - use MX) +token RR_MF // # 4 a mail forwarder (Obsolete - use MX) +token RR_CNAME // # 5 the canonical name for an alias +token RR_SOA // # 6 marks the start of a zone of authority +token RR_MB // # 7 a mailbox domain name (EXPERIMENTAL) +token RR_MG // # 8 a mail group member (EXPERIMENTAL) +token RR_MR // # 9 a mail rename domain name (EXPERIMENTAL) +token RR_NULL // # 10 a null RR (EXPERIMENTAL) +token RR_WKS // # 11 a well known service description +token RR_PTR // # 12 a domain name pointer +token RR_HINFO // # 13 host information +token RR_MINFO // # 14 mailbox or mail list information +token RR_MX // # 15 mail exchange +token RR_TXT // # 16 text strings + +token RR_UNKNOWN + /''/ + { + int id = typeid RR_UNKNOWN + if rr_type_value == 1 + id = typeid RR_A + elsif rr_type_value == 2 + id = typeid RR_NS + elsif rr_type_value == 5 + id = typeid RR_CNAME + elsif rr_type_value == 12 + id = typeid RR_PTR + elsif rr_type_value == 15 + id = typeid RR_MX + elsif rr_type_value == 16 + id = typeid RR_TXT + + send( make_token( id, '' ) ) + } + +# Convert two octets in network order into an unsigned 16 bit value. +int network_uord16( octet o1, octet o2 ) +{ + return o1.data.uord8() * 256 + o2.data.uord8() +} + + +def message + [header questions answers authorities additionals] + +global int question_count +global int answer_count +global int authority_count +global int additional_count + +# Message Header +# +# 1 1 1 1 1 1 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | ID | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | QDCOUNT | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | ANCOUNT | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | NSCOUNT | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | ARCOUNT | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +def header + [header_id header_fields count count count count] + { + question_count = r3.count + answer_count = r4.count + authority_count = r5.count + additional_count = r6.count + } + +def header_id + [octet octet] + +def header_fields + [octet octet] + +def count + int count + + [octet octet] + { + lhs.count = network_uord16( r1, r2 ) + } + +# +# Counting Primitives +# +# Uses a global stack of lengths. Using a stack allows for counted lists to be +# nested. As the list is consumed it brings the count down to zero. To use it, +# push a new count value to the list and include it in a right-recursive list +# like so: +# +# def LIST +# [count_inc ITEM LIST] +# [count_end] +# end +# + +list count_stack [int] +global count_stack CL = construct count_stack [] + +int start_list( int count ) +{ + CL.push( count ) +} + +def count_inc + [] + { + if CL.top == 0 { + reject + } else { + CL.top = CL.top - 1 + } + } + +def count_end + [] + { + if CL.top != 0 { + reject + } else { + CL.pop() + } + } + +# +# Octet List +# + +# General octet list. Length must be set to use this. +def octet_list + [count_inc octet octet_list] +| [count_end] + + +# +# Names +# + +def name + [name_part* name_end] + +# Name part lists are terminated by a zero length or a pointer. +def name_end + # Zero length ending + [octet] + { + int val = r1.data.uord8() + if val != 0 { + reject + } + } + + # Pointer ending + # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + # | 1 1| OFFSET | + # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +| [octet octet] + { + int val = r1.data.uord8() + if val < 64 { + reject + } + } + +# +# Get some number of bytes. +# + +# How many to get +global int nbytes + +# We use this token to eliminate the lookahead that would be needed to cause a +# reduce of part_len. This forces whatever comes before nbytes to be reduced before +# nbytes_data token is fetched from the scanner. We need this because nbytes_data +# depends on the nbytes global and we need to ensure that it is set. +token nb_empty /''/ + +# Fetch nbytes bytes. +token nbytes_data + /''/ + { + send( make_token( typeid nbytes_data, pull(stdin, nbytes) ) ) + } + +def nbytes + [nb_empty nbytes_data] + +def name_part + [part_len nbytes] + + +def part_len + [octet] + { + # A name part list is terminated either by a zero length or a pointer, + # which must have the two high bits set. + int count = r1.data.uord8() + if count == 0 || count >= 64 { + reject + } else { + # Set the number of bytes to get for the name part. + nbytes = count + } + } + +# +# Resource Records +# + +# 1 1 1 1 1 1 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | | +# / / +# / NAME / +# | | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | TYPE | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | CLASS | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | TTL | +# | | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | RDLENGTH | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +# / RDATA / +# / / +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +def resource_record + [name rr_type rr_class ttl rdlength rdata] + +def rr_type + [octet octet] + { + rr_type_value = network_uord16( r1, r2 ) + } + +def rr_class + int value + [octet octet] + { + rr_class_value = network_uord16( r1, r2 ) + } + +def ttl + [octet octet octet octet] + +token rdata_bytes + /''/ + { + send( make_token( typeid rdata_bytes, pull(stdin, rdata_length) ) ) + } + +def rdlength + [octet octet] + { + rdata_length = network_uord16( r1, r2 ) + } + +global int rdata_length + +def rdata + [RR_UNKNOWN rdata_bytes] +| [RR_A address] +| [RR_NS name] +| [RR_CNAME name] +| [RR_PTR name] +| [RR_MX octet octet name] +| [RR_TXT rdata_bytes] + + +# +# Address +# +def address [octet octet octet octet] + +# +# List of Questions +# + +def questions + [load_question_count question_list] + +def load_question_count + [] + { + start_list( question_count ) + } + +def question_list + [count_inc question question_list] +| [count_end] + +# +# Question +# + +# 1 1 1 1 1 1 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | | +# / QNAME / +# / / +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | QTYPE | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | QCLASS | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +def question + [name qtype qclass] + +def qtype + [octet octet] + +def qclass + [octet octet] + +# +# List of Answers +# + +def answers + [load_answer_count answer_list] + +def load_answer_count + [] + { + start_list( answer_count ) + } + +def answer_list + [count_inc answer answer_list] +| [count_end] + +# +# Answer +# + +def answer + [resource_record] + +# +# List of Authorities +# + +def authorities + [load_authority_count authority_list] + +def load_authority_count + [] + { + start_list( authority_count ) + } + +def authority_list + [count_inc authority authority_list] +| [count_end] + +# +# Authority +# + +def authority + [resource_record] + +# +# List of Additionals +# + +def additionals + [load_additional_count additional_list] + +def load_additional_count + [] + { + start_list( additional_count ) + } + +def additional_list + [count_inc additional additional_list] +| [count_end] + +# +# Additional +# + +def additional + [resource_record] + + +def start + [message*] + +# +# Grammar End. +# + +int print_RR_UNKNOWN( start s ) +{ + for I:rdata in s { + if match I [u:RR_UNKNOWN rdata_bytes] { + print( 'UNKNOWN TYPE\n' ) + } + } +} + +int print_RR_A( start s ) +{ + for I:rdata in s { + if match I [RR_A o1:octet o2:octet o3:octet o4:octet] { + print( 'RR_A: ', o1.data.uord8(), '.', o2.data.uord8(), '.', + o3.data.uord8(), '.', o4.data.uord8(), '\n' ) + } + } +} + +map name_map [int name] + +int print_name( name n, name_map m ) +{ + for P: name_part in n { + match P [part_len D:nbytes] + print( D, '.' ) + } + + for E:name_end in n { + if match E [o1:octet o2:octet] { + int val = (o1.data.uord8() - 192) * 256 + o2.data.uord8() + print( '[', val, ']' ) + name nameInMap = m.find( val ) + print_name( nameInMap, m ) + } + } +} + +int print_all_names( start s ) +{ + for M:message in s { + name_map m = construct name_map [] + + octet O = octet in M + + for N:name in M { + match N [name_part* E:name_end] + + for NP: name_part* in N { + if match NP [L:octet nbytes name_part*] { + int messageOffset = L.pos - O.pos + name n = construct name [NP E] + m.insert( messageOffset, n ) + } + } + } + + for I:name in M { + print_name( I, m ) + print( '\n' ) + } + } +} + +start S = parse start( stdin ) +print_all_names( S ) +print( '*** SUCCESS ***\n' ) diff --git a/test/dns/dumpdns b/test/dns/dumpdns new file mode 100644 index 00000000..3409afee --- /dev/null +++ b/test/dns/dumpdns @@ -0,0 +1,11 @@ +#!/bin/bash +# + +# Use this script to capture dns packets to a dump file. Then use extract to +# break up the packets and strip the headers, leaving just dns packets. +# +# usage: bash dumpdns <dumpfile> + +[ -z "$1" ] && exit + +tcpdump -s 0 -w $1 udp port 53 diff --git a/test/dns/extract.c b/test/dns/extract.c new file mode 100644 index 00000000..8af026a3 --- /dev/null +++ b/test/dns/extract.c @@ -0,0 +1,48 @@ +#include <pcap.h> + +/* + * Break up a dump file and strip headers, leaving just + * the dns portion of packets. + */ + +char outname[1024]; +char errbuf[PCAP_ERRBUF_SIZE]; + +int main( int argc, char **argv ) +{ + int packet; + pcap_t *p; + if ( argc != 3 ) { + fprintf( stderr, "usage: get <dumpfile> <rootname>\n" ); + return 1; + } + + p = pcap_open_offline( argv[1], errbuf ); + + for ( packet = 0; ; packet++ ) { + FILE *file; + unsigned long len; + struct pcap_pkthdr h; + const u_char *data; + + data = pcap_next( p, &h ); + if ( data == 0 ) + break; + + if ( h.caplen < h.len ) + fprintf( stderr, "warning: packet number %02d is short\n", packet ); + + /* The magic number is the size of the headers we want to strip. */ + data += 42; + len = h.caplen - 42; + + sprintf( outname, "%s-%04d", argv[2], packet ); + file = fopen( outname, "wb" ); + fwrite( data, 1, len, file ); + fclose( file ); + } + + pcap_close( p ); + + return 0; +} diff --git a/test/heredoc.in b/test/heredoc.in new file mode 100644 index 00000000..c9638ca9 --- /dev/null +++ b/test/heredoc.in @@ -0,0 +1,3 @@ +hello +random 9392af j9 stuff +hello diff --git a/test/heredoc.lm b/test/heredoc.lm new file mode 100644 index 00000000..54dcc33d --- /dev/null +++ b/test/heredoc.lm @@ -0,0 +1,45 @@ +rl ident_char /[a-zA-Z_]/ + +lex start +{ + # Tokens + token other /(^(ident_char|0|'\n'))+/ + + token here_close // + token id + /ident_char+/ + { + if HereId && HereId == match_text { + send( make_token( + typeid here_close, + pull(stdin, match_length - 1) ) ) + } else { + send( make_token( typeid id, pull(stdin, match_length) ) ) + } + } + + token nl /'\n'/ +} + +def here_name + [id] + { + HereId = r1.data + } + +global str HereId + +def here_data + [here_data_item*] + +def here_data_item + [id] +| [other] +| [nl] + +def heredoc + [here_name here_data here_close id nl] + + +heredoc S = parse heredoc( stdin ) +print_xml(S) diff --git a/test/html/Makefile b/test/html/Makefile new file mode 100644 index 00000000..d647261a --- /dev/null +++ b/test/html/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/html/html-lextag.lm b/test/html/html-lextag.lm new file mode 100644 index 00000000..0869538c --- /dev/null +++ b/test/html/html-lextag.lm @@ -0,0 +1,324 @@ +# +# Regular Definitions +# +rl def_name_char /[\-A-Za-z0-9._:?]/ +rl def_name /[A-Za-z_:] def_name_char*/ +rl def_system_literal /'"' [^"]* '"' | "'" [^']* "'"/ + +# +# Scanner for tag names. +# +lex TAG_NAME +{ + ignore /space+/ + token tag_id /def_name/ +} + +# +# Scanner for attributes names +# +lex ATTR_NAME +{ + ignore /space+/ + token attr_name /def_name_char+/ + literal '=' +} + +# Scanner for attribute values. +lex ATTR_VAL +{ + ignore /space+/ + literal '>', '/>' + token dquote_val /'"' ([^"] | '\\' any)* '"'/ + token squote_val /"'" ([^'] | '\\' any)* "'"/ + token unq_val /[^ \t\r\n<>"'] [^ \t\r\n<>]*/ +} + +# +# Tokens +# + +lex START +{ + ignore /space+/ + + literal '<', '</', '<!DOCTYPE' + token close_tag + /'</' [\t ]* id: [a-zA-Z]+ '>'/ + + token doc_data /[^<]+/ + token comment /'<!--' any* :>> '-->'/ +} + +# +# Tags +# + +bool inTagStack( str id ) +{ + tag_stack LocalTagStack = TagStack + for Tag:tag_id in LocalTagStack { + if id == Tag.data + return true + } + return false +} + +# This scanner is just for the id in close tags. The id needs to be looked up +# in the tag stack so we can determine if it is a stray. +lex close_id +{ + # Ignore whitespace. + ignore /space+/ + + token stray_close_id // + token missing_close_id // + + token close_id /def_name/ + { + # If it is in the tag stack then it is a close_id. If not then it's a + # stray_close_id. + int send_id = typeid stray_close_id + + if ( inTagStack( match_text ) ) { + print( 'CLOSE \'', match_text, '\' IN TAG STACK\n' ) + + # The tag is in the stack, send missing close tags until we get to it. + match TagStack [Top:tag_id Rest:tag_stack] + TagStack = Rest + while ( Top.data != match_text ) { + print( 'SENDING missing close\n' ) + send( make_token( typeid missing_close_id, '' ) ) + match TagStack [Top2:tag_id Rest2:tag_stack] + Top = Top2 + TagStack = Rest2 + } + + print( 'SENDING close\n' ) + send( make_token( typeid close_id, pull( stdin, match_length ) ) ) + } + else { + print( 'CLOSE \'', match_text, '\' NOT IN TAG STACK\n' ) + # The tag is not in the tag stack so send the id as a stray close. + send( make_token( typeid stray_close, pull( stdin, match_length ) ) ) + } + } +} + +# +# Tag Stack +# + +def tag_stack + [tag_id tag_stack] +| [] + +global tag_stack TagStack = construct tag_stack [] + +# +# Document Type +# +# This scanner handles inside DOCTYPE tags (except keywords). +lex DOCTYPE +{ + ignore /space+/ + token dt_name /def_name/ + token dt_literal /def_system_literal/ + token dt_bl /"[" [^\]]* "]"/ + token dt_close /'>'/ +} + +# Using a separate scanner for the keywords in DOCTYPE prevents them from +# covering dt_name +lex DOCTYPE_KW +{ + ignore /space+/ + literal 'SYSTEM', 'PUBLIC' +} + +def DOCTYPE ['<!DOCTYPE' dt_name external_id dt_bl? dt_close] + +def external_id + ['SYSTEM' dt_literal?] +| ['PUBLIC' dt_literal dt_literal?] + +# +# Tags, with optionanal close. +# + +def tag + [open_tag item* close_tag] + +def unclosed_tag + [open_tag item* missing_close_id] + +def open_tag + ['<' tag_id attr* '>'] + { + TagStack = construct tag_stack + [r2 TagStack] + } + +# +# Empty tags +# +def empty_tag + ['<' tag_id attr* '/>'] + +# +# Stray close tags +# +def stray_close + [close_tag] + + +# +# Attributes +# + +def attr + [attr_name eql_attr_val?] + +def eql_attr_val ['=' attr_val] + +def attr_val + [squote_val] +| [dquote_val] +| [unq_val] +| [] + +# +# Items +# + +def item + [DOCTYPE] +| [tag] +| [unclosed_tag] +| [empty_tag] +| [stray_close] +| [doc_data] +| [comment] + + +token trailing /any*/ + +def start + [item* trailing] + +# +# END GRAMMAR +# + +int addDefaultAltTags( ref start Start ) +{ + for T: open_tag in Start { + require T + ["<img" AttrList: attr* '>'] + + bool haveAlt = false + for A: attr in T { + if match A ["alt=" attr_val] + haveAlt = true + } + + if !haveAlt { + for AL: attr* in T { + if match AL [] { + AL = construct attr* + [" alt=\"default alt\""] + break + } + } + } + } +} + +int printLinks( start Start ) +{ + for A:tag in Start { + require A + ["<a" AttrList: attr* ">" I: item* "</a>"] + + for Attr: attr in AttrList { + if match Attr ["href = " AttrVal: attr_val] + print( 'link: ', I, '\ntarget: ', AttrVal, '\n\n' ) + } + } +} + + +bool should_close( tag_id TI ) +{ + return true +} + +bool should_flatten( tag_id TI ) +{ + return true +} + +# Finds unclosed tags and puts the content after the tag. Afterwards +# all unclosed tags will be empty 'inside'. +#int flatten( ref start Start ) +#{ +# for TL: item* in Start { +# require TL +# [OT: open_tag Inside: item* Trailing: item*] +# +# match OT +# ['<' TagId: tag_id attr* '>'] +# +# if should_flatten( TagId ) +# { +# require Inside +# [item item*] +# +# # Put Trailing at the end of inside. +# for END: item* in Inside { +# if match END [] { +# END = Trailing +# break +# } +# } +# +# str empty = '' +# missing_close_id Missing = construct missing_close_id [empty] +# opt_close_tag EmptyCloseTag = +# construct opt_close_tag [Missing] +# +# # Close the tag and put inside after it. +# TL = construct item* +# [OT EmptyCloseTag Inside] +# } +# } +#} +# +#int close( ref start Start ) +#{ +# for TL: item in Start { +# require TL +# [OpenTag: open_tag Inside: item*] +# +# match OpenTag +# ['<' TagId: tag_id attr* '>'] +# +# if should_close( TagId ) +# { +# close_id CloseId = construct close_id +# [TagId.data] +# +# opt_close_tag CloseTag = +# construct opt_close_tag ['</' CloseId '>'] +# +# # Close the tag and put inside after it. +# TL = construct item +# [OpenTag Inside CloseTag] +# } +# } +#} + +start HTML = parse start( stdin ) +print_xml( HTML ) +for C: close_tag in HTML + print( C.id, '\n' ) diff --git a/test/html/html.lm b/test/html/html.lm new file mode 100644 index 00000000..98573f2e --- /dev/null +++ b/test/html/html.lm @@ -0,0 +1,307 @@ +# +# Regular Definitions +# +rl def_name_char /[\-A-Za-z0-9._:?]/ +rl def_name /[A-Za-z_:] def_name_char*/ +rl def_system_literal /'"' [^"]* '"' | "'" [^']* "'"/ + +# +# Scanner for tag names. +# +lex TAG_NAME +{ + ignore /space+/ + token tag_id /def_name/ +} + +# +# Scanner for attributes names +# +lex ATTR_NAME +{ + ignore /space+/ + token attr_name /def_name_char+/ + literal '=' +} + +# Scanner for attribute values. +lex ATTR_VAL +{ + ignore /space+/ + literal '>', '/>' + token dquote_val /'"' ([^"] | '\\' any)* '"'/ + token squote_val /"'" ([^'] | '\\' any)* "'"/ + token unq_val /[^ \t\r\n<>"'] [^ \t\r\n<>]*/ +} + +# +# Tokens +# + +lex START +{ + ignore /space+/ + literal '<', '</', '<!DOCTYPE' + token doc_data /[^<]+/ + token comment /"<!--" any* :>> "-->"/ +} + +# +# Tags +# + +# This scanner is just for the id in close tags. The id needs to be looked up +# in the tag stack so we can determine if it is a stray. +lex close_id +{ + # Ignore whitespace. + ignore /space+/ + + token stray_close_id // + token close_id /def_name/ + { + # If it is in the tag stack then it is a close_id. If not then it's a + # stray_close_id. + int send_id = typeid stray_close_id + + tag_stack LocalTagStack = TagStack + for Tag:tag_id in LocalTagStack { + tag_id T = Tag + if match_text == T.data { + send_id = typeid close_id + break + } + } + + send( make_token( send_id, pull(stdin, match_length) ) ) + } +} + +# +# Tag Stack +# + +def tag_stack + [tag_id tag_stack] +| [] + +global tag_stack TagStack = construct tag_stack [] + +# +# Document Type +# +# This scanner handles inside DOCTYPE tags (except keywords). +lex DOCTYPE +{ + ignore /space+/ + token dt_name /def_name/ + token dt_literal /def_system_literal/ + token dt_bl /"[" [^\]]* "]"/ + token dt_close /'>'/ +} + +# Using a separate scanner for the keywords in DOCTYPE prevents them from +# covering dt_name +lex DOCTYPE_KW +{ + ignore /space+/ + literal 'SYSTEM', 'PUBLIC' +} + +def DOCTYPE ['<!DOCTYPE' dt_name external_id dt_bl? dt_close] + +def external_id + ['SYSTEM' dt_literal?] +| ['PUBLIC' dt_literal dt_literal?] + +# +# Tags, with optionanal close. +# + +def tag + [open_tag item* opt_close_tag] + +def open_tag + ['<' tag_id attr* '>'] + { + TagStack = construct tag_stack + [r2 TagStack] + } + +def opt_close_tag + ['</' close_id '>'] + { + match TagStack [Top:tag_id Rest:tag_stack] + if r2.data == Top.data + TagStack = Rest + else + reject + } + +| [] + { + match TagStack [Top:tag_id Rest:tag_stack] + TagStack = Rest + } + +# +# Empty tags +# +def empty_tag + ['<' tag_id attr* '/>'] + +# +# Stray close tags +# +def stray_close + ['</' stray_close_id '>'] + + +# +# Attributes +# + +def attr + [attr_name eql_attr_val?] + +def eql_attr_val ['=' attr_val] + +def attr_val + [squote_val] +| [dquote_val] +| [unq_val] +| [] + +# +# Items +# + +def item + [DOCTYPE] +| [tag] +| [empty_tag] +| [stray_close] +| [doc_data] +| [comment] + + +token trailing /any*/ + +def start + [item* trailing] + +# +# END GRAMMAR +# + +int addDefaultAltTags( ref start Start ) +{ + for T: open_tag in Start { + require T + ["<img" AttrList: attr* '>'] + + bool haveAlt = false + for A: attr in T { + if match A ["alt=" attr_val] + haveAlt = true + } + + if !haveAlt { + for AL: attr* in T { + if match AL [] { + AL = construct attr* + [" alt=\"default alt\""] + break + } + } + } + } +} + +int printLinks( start Start ) +{ + for A:tag in Start { + require A + ["<a" AttrList: attr* ">" I: item* "</a>"] + + for Attr: attr in AttrList { + if match Attr ["href = " AttrVal: attr_val] + print( 'link: ', I, '\ntarget: ', AttrVal, '\n\n' ) + } + } +} + + +bool should_close( tag_id TI ) +{ + return true +} + +bool should_flatten( tag_id TI ) +{ + return true +} + +# Finds unclosed tags and puts the content after the tag. Afterwards +# all unclosed tags will be empty 'inside'. +int flatten( ref start Start ) +{ + for TL: item* in Start { + require TL + [OT: open_tag Inside: item* Trailing: item*] + + match OT + ['<' TagId: tag_id attr* '>'] + + if should_flatten( TagId ) + { + require Inside + [item item*] + + # Put Trailing at the end of inside. + for END: item* in Inside { + if match END [] { + END = Trailing + break + } + } + + opt_close_tag EmptyCloseTag = + construct opt_close_tag [] + + # Close the tag and put inside after it. + TL = construct item* + [OT EmptyCloseTag Inside] + } + } +} + +int close( ref start Start ) +{ + for TL: item in Start { + require TL + [OpenTag: open_tag Inside: item*] + + match OpenTag + ['<' TagId: tag_id attr* '>'] + + if should_close( TagId ) + { + close_id CloseId = construct close_id + [TagId.data] + + opt_close_tag CloseTag = + construct opt_close_tag ['</' CloseId '>'] + + # Close the tag and put inside after it. + TL = construct item + [OpenTag Inside CloseTag] + } + } +} + +start HTML = parse start( stdin ) +flatten( HTML ) +#print_xml( HTML ) +printLinks( HTML ) + diff --git a/test/html/input01.html b/test/html/input01.html new file mode 100644 index 00000000..cf783d63 --- /dev/null +++ b/test/html/input01.html @@ -0,0 +1,8 @@ +<t1> + + <t2> + <a href="foo">FOO</a> + <t3> + </t3> + +</t1> diff --git a/test/http/Makefile b/test/http/Makefile new file mode 100644 index 00000000..d647261a --- /dev/null +++ b/test/http/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/http/http.lm b/test/http/http.lm new file mode 100644 index 00000000..d914ab6f --- /dev/null +++ b/test/http/http.lm @@ -0,0 +1,68 @@ +# +# Character classes +# +rl CTL /0..31 | 127/ +rl CR /13/ +rl LF /10/ +rl SP /32/ +rl HT /9/ +rl CHAR /0..127/ + +rl separators / '(' | ')' | '<' | '>' + | '@' | ',' | ';' | ':' | '\\' + | '"' | '/' | '[' | ']' | '?' + | '=' | '{' | '}' | SP | HT / + +rl token_char /CHAR - CTL - separators/ + +# +# Literal tokens +# + +literal 'HTTP/', ' ', ':' +token CRLF /CR LF/ + +# +# Request Line +# + +token method /token_char+/ + +token request_uri /(^SP)+/ + +token http_number /digit+ '.' digit+/ + +def http_version + [ 'HTTP/' http_number ] + +def request_line + [method ' ' request_uri + ' ' http_version CRLF] + +# +# Header +# + +token field_name /token_char+/ + +token field_value + /(^(CR|LF) | CR LF (SP|HT))* CR LF/ + +def header + [field_name ':' field_value] + +# +# Request +# + +def request + [request_line header* CRLF] + +request R = parse_stop request( stdin ) + +print( 'HTTP/1.0 200 OK\r\n' ) +print( 'Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n' ) +print( 'Content-Type: text/plain\r\n' ) +print( '\r\n' ) +print_xml( R ) + diff --git a/test/http/input1 b/test/http/input1 new file mode 100644 index 00000000..c1416f84 --- /dev/null +++ b/test/http/input1 @@ -0,0 +1,2 @@ +GET /hi/there/ HTTP/1.1
+
diff --git a/test/http/input2 b/test/http/input2 new file mode 100644 index 00000000..076222d5 --- /dev/null +++ b/test/http/input2 @@ -0,0 +1,13 @@ +GET /hithere/ HTTP/1.1
+Host: localhost:3535
+User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12
+Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Keep-Alive: 300
+Connection: keep-alive
+Cache-Control: max-age=0
+
+adslfkj
+alkfj
diff --git a/test/http/input3 b/test/http/input3 new file mode 100644 index 00000000..16b817f1 --- /dev/null +++ b/test/http/input3 @@ -0,0 +1,8 @@ +GET foo HTTP/1.1
+hello: foo
+hi: there
+ my
+ friend
+
+ from outter space
+
diff --git a/test/http/xinetd.conf b/test/http/xinetd.conf new file mode 100644 index 00000000..5c95545c --- /dev/null +++ b/test/http/xinetd.conf @@ -0,0 +1,10 @@ +service colm_http +{ + type = unlisted + socket_type = stream + protocol = tcp + port = 3535 + wait = no + user = thurston + server = /home/thurston/devel/colm/test/http/http.bin +} diff --git a/test/island.in b/test/island.in new file mode 100644 index 00000000..d34467bb --- /dev/null +++ b/test/island.in @@ -0,0 +1,19 @@ +class +{ + 1; + "string"; + foo; + func() + { + func() + { + 1+{2} + } + } +} + +func() +{ + "data" + {a} +} diff --git a/test/island.lm b/test/island.lm new file mode 100644 index 00000000..c407aa28 --- /dev/null +++ b/test/island.lm @@ -0,0 +1,57 @@ + +lex function_body +{ + token func_chr /[^{}]+/ + token func_open /'{'/ + token func_close /'}'/ +} + +def func_item + [func_chr] +| [func_open func_body func_close] + +def func_body + [func_item*] + +def func + [ident '(' ')' '{' func_body func_close ] + +lex start +{ + token ident /[a-zA-Z_]+/ + token number /[0-9]+/ + + rl s_string / "'" ([^'\\\n] | '\\' any )* "'" / + rl d_string / '"' ([^"\\\n] | '\\' any )* '"' / + token string /s_string | d_string/ + + literal '+', '*', ';', '(', ')', '{', '}' + + ignore wp / [ \t\n]+ / +} + +def class_item + [func] +| [class] +| [ident ';'] +| [number ';'] +| [string ';'] + +def class_body + [class_item*] + +def class + [ident '{' class_body '}' ] + +def top_item + [func] +| [class] + +def start + [top_item*] + { + print_xml(lhs) + } + +#pattern start +# ~class { func() { func() { 1+{2}} } } func() {{a}} diff --git a/test/liftattrs.in b/test/liftattrs.in new file mode 100644 index 00000000..5a50f377 --- /dev/null +++ b/test/liftattrs.in @@ -0,0 +1,3 @@ +<t1 a=b foo=bar1 c=d> + <t2 foo=bar2 e=f></t2> +</t1> diff --git a/test/liftattrs.lm b/test/liftattrs.lm new file mode 100644 index 00000000..305a805b --- /dev/null +++ b/test/liftattrs.lm @@ -0,0 +1,74 @@ + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ + +# +# Tokens +# + +lex start +{ + literal '=', '<', '>', '/' + + # Ignore whitespace. + ignore /rl_ws/ + + # Open and close id + token id /rl_id/ +} + +# +# Productions +# + +def attr [id '=' id] + +def attr_list + [attr_list attr] +| [] + +def open_tag + ['<' id attr_list '>'] + +def close_tag + ['<' '/' id '>'] + +def tag + [open_tag item_list close_tag] + +def item_list + [item_list tag] +| [] + +item_list IL = parse item_list(stdin) + +# Get the item list +match IL [RootItemList: item_list] + +# List for collecting the attrs we pull out. +attr_list CollectedAttrs = construct attr_list [] + +# Iterate through all attributes +for AttrListIter:attr_list in RootItemList { + # If the name of the attr is foo, remove it. + if match AttrListIter + [SubAttrList:attr_list "foo=" Val:id] + { + # Remove the attribute + AttrListIter = construct attr_list + [SubAttrList] + + # Add it to the colection + CollectedAttrs = construct attr_list + [CollectedAttrs " foo=" Val] + } +} + +# Reconstruct the left hand side with the +IL = construct item_list + ["<wrapper" CollectedAttrs ">" RootItemList "</wrapper>"] + +print( IL, '\n' ) diff --git a/test/mailbox.in b/test/mailbox.in new file mode 100644 index 00000000..412f8bed --- /dev/null +++ b/test/mailbox.in @@ -0,0 +1,29 @@ +From thurston Tue Jan 2 21:16:50 2007 +Return-Path: <unknown> +X-Spam-Level: * +Received: from [109.111.71.111] (helo=twfmtr) + by zifreax with smtp (Exim 4.43) + id 1H1vfs-0005LN-HW; Tue, 2 Jan 2007 21:16:16 -0500 +Message-ID: <459B113F.8050903@immoarthabitatge.com> +X-Keywords: +X-UID: 1 + +Content-Type: text/html; charset=ISO-8859-1 +</body> +</html> + +From thurston Wed Jan 3 02:35:48 2007 +Return-Path: <unknown> +X-Spam-Checker-Version: SpamAssassin 3.1.1 (2006-03-10) on mambo.cs.queensu.ca +X-Spam-Level: ** +X-Spam-Status: No, score=2.9 required=5.0 tests=BAYES_20,EXTRA_MPART_TYPE, + HTML_40_50,HTML_IMAGE_ONLY_16,HTML_MESSAGE,RCVD_IN_BL_SPAMCOP_NET + autolearn=no version=3.1.1 +X-Bogosity: Unsure, tests=bogofilter, spamicity=0.971708, version=1.0.2 +Status: RO +X-UID: 2 + +------=_NextPart_000_0010_01C72F11.F137BD60 + charset="windows-1252" +Content-Transfer-Encoding: quoted-printable + diff --git a/test/mailbox.lm b/test/mailbox.lm new file mode 100644 index 00000000..3387fcff --- /dev/null +++ b/test/mailbox.lm @@ -0,0 +1,44 @@ + +# lines, and fromlines +lex lines +{ + rl day /[A-Z][a-z][a-z]/ + rl month /[A-Z][a-z][a-z]/ + rl year /[0-9][0-9][0-9][0-9]/ + rl time /[0-9][0-9] ':' [0-9][0-9] ( ':' [0-9][0-9] )? / + rl letterZone /[A-Z][A-Z][A-Z]/ + rl numZone /[+\-][0-9][0-9][0-9][0-9]/ + rl zone / letterZone | numZone/ + rl dayNum /[0-9 ][0-9]/ + + # These are the different formats of the date minus an obscure + # type that has a funny string 'remote from xxx' on the end. Taken + # from c-client in the imap-2000 distribution. + rl date / day ' ' month ' ' dayNum ' ' time ' ' + ( year | year ' ' zone | zone ' ' year ) / + + # From lines separate messages. We will exclude from_line from a message + # body line. This will cause us to stay in message line up until an + # entirely correct from line is matched. + token from_line / 'From ' (any-'\n')* ' ' date '\n' / + token simple_line / [^\n]* '\n' / +} + +rl hchar /print - [ :]/ +token header_name /hchar+/ + +token colon /':' ' '*/ +token header_content / ([^\n] | '\n' [ \t])* '\n'/ +token blank_line / '\n' / + +def header + [header_name colon header_content] + +def message + [from_line header* blank_line simple_line*] + +def start + [message*] + { + print_xml( lhs ) + } diff --git a/test/matchex.in b/test/matchex.in new file mode 100644 index 00000000..f458f2ad --- /dev/null +++ b/test/matchex.in @@ -0,0 +1,3 @@ +<person name=adrian hometown=kingston> + <t1 foo=bar2 e=f></t2> +</person>
\ No newline at end of file diff --git a/test/matchex.lm b/test/matchex.lm new file mode 100644 index 00000000..67b69238 --- /dev/null +++ b/test/matchex.lm @@ -0,0 +1,34 @@ +lex start +{ + token id /[a-zA-Z_][a-zA-Z0-9_]*/ + literal '=', '<', '>', '/' + ignore /[ \t\n\r\v]+/ +} + +def attr + [id '=' id] + +def open_tag + ['<' id attr* '>'] + +def close_tag + ['<' '/' id '>'] + +def tag + [open_tag item* close_tag] + +def item + [tag] +| [id] + +tag Tag = parse tag( stdin ) + +# Style: List of literal text and types. +match Tag ["<person name=" Val1:id attr*">" item* "</person>"] + +# Style: Literal text with embedded lists of types. +match Tag "<person name=[Val2:id attr*]>[item*]</person>" + +print( Val1, '\n' ) +print( Val2, '\n' ) + diff --git a/test/maxlen.lm b/test/maxlen.lm new file mode 100644 index 00000000..19869634 --- /dev/null +++ b/test/maxlen.lm @@ -0,0 +1,44 @@ + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ + +# +# Tokens +# + +lex start +{ + ignore /rl_ws/ + token id /rl_id/ +} + +global int num +global int allow = 3 + +def item + [id] + { + num = num + 1 + int toomuch = allow+1 + if num == toomuch { + reject + } + } + +def open + [] + { + num = 0 + } + +def close [] + +def restricted_list + [open item*] + +def start + [restricted_list id*] + diff --git a/test/mediawiki/Makefile b/test/mediawiki/Makefile new file mode 100644 index 00000000..3e6bf661 --- /dev/null +++ b/test/mediawiki/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2008 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: pdump garticle mediawiki.bin + +pdump.cpp: pdump.rl + ragel -G2 -o pdump.cpp pdump.rl + +pdump: pdump.cpp + g++ -O3 -Wall -o pdump pdump.cpp + +garticle.cpp: garticle.rl + ragel -G2 -o garticle.cpp garticle.rl + +garticle: garticle.cpp + g++ -O3 -Wall -o garticle garticle.cpp + +mediawiki.bin: mediawiki.lm + $(COLM) mediawiki.lm + +clean: + rm -f mediawiki.cpp *.bin garticle.cpp garticle pdump.cpp pdump diff --git a/test/mediawiki/garticle.rl b/test/mediawiki/garticle.rl new file mode 100644 index 00000000..cc101364 --- /dev/null +++ b/test/mediawiki/garticle.rl @@ -0,0 +1,135 @@ +#include <iostream> +#include <fstream> +#include <stdlib.h> +#include <string.h> + +using std::cout; +using std::cerr; +using std::endl; +using std::ifstream; +using std::ofstream; + +%%{ + machine garticle; + write data; +}%% + + +int main( int argc, char **argv ) +{ + std::ios::sync_with_stdio(false); + + if ( argc != 5 ) { + cerr << "usage: garticle <dump-file> <article-index> <section> <article>" << endl; + return -1; + } + + char *dumpFile = argv[1]; + char *articleIndex = argv[2]; + char *section = argv[3]; + char *article = argv[4]; + + ifstream dump( dumpFile ); + if ( !dump.is_open() ) { + cerr << "error: unable to open " << dumpFile << " for reading" << endl; + return -1; + } + + ifstream index( articleIndex ); + if ( !index.is_open() ) { + cerr << "error: unable to open " << articleIndex << " for writing" << endl; + return -1; + } + + long long articleNum = atoll(article); + index.seekg( articleNum * sizeof(long long) ); + + long long start, end; + index.read( (char*)&start, sizeof(long long) ); + index.read( (char*)&end, sizeof(long long) ); + + long long len = end - start; + char *buf = new char[len]; + dump.seekg( start-5 ); + dump.read( buf, len ); + + char tn[2048]; + long ptn = 0; + bool emit = false; + + char *p = buf, *pe = buf+len; + int cs; + + %%{ + newline = '\n'; + sp = [ \t\n\r]; + + name = [a-zA-Z:_0-9]+; + + # Tag names. + tag_name = name + >{ ptn = 0; } + ${ tn[ptn++] = *p; } + %{ tn[ptn++] = 0; } + ; + + attr_name = name; + + # Attributes + attr_val = '"' ( [^"\\] | newline | ( '\\' any ) )* '"'; + attr = attr_name '=' attr_val; + attrs = ( sp attr )*; + + action maybe_open { + if ( strcmp( tn, section ) == 0 ) + emit = true; + } + + action maybe_close { + if ( strcmp( tn, section ) == 0 ) + emit = false; + } + + # Tags + tag = '<' tag_name %maybe_open attrs sp? ( '>' | '/>' ); + close_tag = '</' tag_name %maybe_close '>'; + + # Character data, not spaces and not tag starts. + char_data_char = ^('<'|'&'); + char_data = char_data_char+ + ${ + if ( emit ) + cout << *p; + } ; + + defined_entities = + 'quot' %{if (emit) cout << '"';} | + 'amp' %{if (emit) cout << '&';} | + 'apos' %{if (emit) cout << '\'';} | + 'lt' %{if (emit) cout << '<';} | + 'gt' %{if (emit) cout << '>';}; + + entity_ref = '&' defined_entities ';'; + + main := ( + tag | + close_tag | + entity_ref | + char_data + )* + ; + + write init; + write exec; + }%% + + if ( cs < garticle_first_final ) { + cerr << endl << endl << "garticle: error parsing dump file" << endl; + return 1; + } + + //cout.write( buf, len ); + cout << endl; + + return 0; +} diff --git a/test/mediawiki/mediawiki.lm b/test/mediawiki/mediawiki.lm new file mode 100644 index 00000000..e8dd3a27 --- /dev/null +++ b/test/mediawiki/mediawiki.lm @@ -0,0 +1,196 @@ +def open_item + str type + int num + [] + +list open_stack [open_item] +global open_stack OpenStack = construct open_stack [] +open_item Sentinal = construct open_item( type: '** SENTINAL **', num: 1 ) [] +OpenStack.push( Sentinal ) + +lex start +{ + token stray_close // + + token ocurly /'{'+/ + { + open_item OI = construct open_item( type: '{', num: match_length ) [] + OpenStack.push( OI ) + int i = 0 + while ( i < match_length ) { + send( make_token( typeid ocurly, pull(stdin, 1 ) ) ) + i = i + 1 + } + } + + token ccurly1 // + token ccurly2 // + token ccurly3 // + token missing_curly // + + token tmp1 /'}'+/ + { + if OpenStack.length > 0 && OpenStack.tail.type == '{' { + int length = 3 + if ( length > match_length ) + length = match_length + + open_item Tail = OpenStack.pop() + if ( length > Tail.num ) + length = Tail.num + + if ( length == 1 ) + send( make_token( typeid ccurly1, pull( stdin, 1 ) ) ) + else if ( length == 2 ) + send( make_token( typeid ccurly2, pull( stdin, 2 ) ) ) + else if ( length == 3 ) + send( make_token( typeid ccurly3, pull( stdin, 3 ) ) ) + + Tail.num = Tail.num - length + + if ( Tail.num > 0 ) + OpenStack.push( Tail ) + } + else { + send( make_token( typeid stray_close, pull( stdin, match_length ) ) ) + } + } + + token osquare /'['+/ + { + open_item OI = construct open_item( type: '[', num: match_length ) [] + OpenStack.push( OI ) + int i = 0 + while ( i < match_length ) { + send( make_token( typeid osquare, pull(stdin, 1 ) ) ) + i = i + 1 + } + } + + token csquare1 // + token csquare2 // + token missing_square // + + token tmp2 /']'+/ + { + if OpenStack.length > 0 && OpenStack.tail.type == '[' { + int length = 2 + if ( length > match_length ) + length = match_length + + open_item Tail = OpenStack.pop() + if ( length > Tail.num ) + length = Tail.num + + if ( length == 1 ) + send( make_token( typeid csquare1, pull( stdin, 1 ) ) ) + else if ( length == 2 ) + send( make_token( typeid csquare2, pull( stdin, 2 ) ) ) + + Tail.num = Tail.num - length + + if ( Tail.num > 0 ) + OpenStack.push( Tail ) + } + else { + send( make_token( typeid stray_close, pull( stdin, match_length ) ) ) + } + } + + literal '|' + token char /any/ + + preeof { + while ( OpenStack.length > 0 ) { + open_item Tail = OpenStack.pop() + int i + if ( Tail.type == '{' ) { + i = 0 + while ( i < Tail.num ) { + send( make_token( typeid missing_curly, '}' ) ) + i = i + 1 + } + } + else if ( Tail.type == '[' ) { + i = 0 + while ( i < Tail.num ) { + send( make_token( typeid missing_square, ']' ) ) + i = i + 1 + } + } + } + } +} + +# +# Internal Links +# + + +lex el_prefix +{ + literal 'http:' + literal 'ftp:' + literal 'mailto:' +} + +def el_prefix + ['http:'] +| ['ftp:'] +| ['mailto:'] + +def external_link + [osquare item* csquare1] + +def internal_link + [osquare osquare item* csquare2] + +def unclosed_square + [osquare item* missing_square] + +# +# Templates +# + +def sing_template + [ocurly item* ccurly1] + +def template + [ocurly ocurly item* ccurly2] + +def parameter + [ocurly ocurly ocurly item* ccurly3] + +def unclosed_curly + [ocurly item* missing_curly] + +# +# Template Parameters +# + + +def U1 [] +def U2 [] +def U3 [] + +def item + [external_link] +| [internal_link] +| [unclosed_curly] +| [sing_template] +| [template] +| [parameter] +| [unclosed_curly] +| [stray_close] +| [osquare] +| ['|'] +| [char] + +def start + [item*] + +start S = parse start(stdin) +for I: internal_link in S + print( I, '\n' ) +print_xml( S ) +#print_xml( OpenStack ) diff --git a/test/mediawiki/pdump.rl b/test/mediawiki/pdump.rl new file mode 100644 index 00000000..8b19bf37 --- /dev/null +++ b/test/mediawiki/pdump.rl @@ -0,0 +1,115 @@ +#include <iostream> +#include <fstream> + +using std::cout; +using std::cerr; +using std::endl; +using std::ifstream; +using std::ofstream; + + +#define RBS 65536 + +%%{ + machine pdump; + write data; +}%% + +int main( int argc, char **argv ) +{ + std::ios::sync_with_stdio(false); + + if ( argc != 3 ) { + cerr << "usage: pdump <dump-file> <article-index>" << endl; + return -1; + } + + ifstream input( argv[1] ); + if ( !input.is_open() ) { + cerr << "error: unable to open " << argv[1] << " for reading" << endl; + return -1; + } + + ofstream output( argv[2] ); + if ( !output.is_open() ) { + cerr << "error: unable to open " << argv[2] << " for writing" << endl; + return -1; + } + + long cs; + %% write init; + + long long line = 1; + long long total = 0; + static char buf[RBS]; + while ( true ) { + if ( input.eof() ) + break; + + input.read( buf, RBS ); + long ss = input.gcount(); + + char *p = buf, *pe = buf + ss; + + %%{ + + action newline { line++; } + newline = '\n'@newline; + any_nl = any | newline; + + sp_char = [ \t\n\r]; + sp = sp_char | newline; + + # Tag names. + any_tag_name = [a-zA-Z:0-9]+ ; + + page_tag_name = 'page' + %{ + long inbuf = p - buf; + long long pos = total + inbuf; + output.write( (char*)&pos, sizeof(long long) ); + }; + + tag_name = any_tag_name | page_tag_name; + + attr_name = [a-zA-Z:0-9]+; + + # Attributes + attr_val = '"' ( [^"\\] | newline | ( '\\' any_nl ) )* '"'; + attr = attr_name '=' attr_val; + attrs = ( sp attr )*; + + # Tags + tag = '<' tag_name attrs sp? ( '>' | '/>' ); + close_tag = '</' any_tag_name '>'; + + # Character data, not spaces and not tag starts. + char_data_char = ^(sp_char | '<'); + char_data = char_data_char+; + + main := ( + tag | + close_tag | + newline | + sp | + char_data + )* + ; + + write exec; + + }%% + + if ( cs == pdump_error ) { + cerr << "error:" << line << ": parse error" << endl; + return -1; + } + + total += ss; + } + + input.close(); + output.close(); + + return 0; +} diff --git a/test/nestedcomm.in b/test/nestedcomm.in new file mode 100644 index 00000000..11789576 --- /dev/null +++ b/test/nestedcomm.in @@ -0,0 +1 @@ +hello there ( (this is a nested comment /*sdf;asd_++_stuff) ) and this is not diff --git a/test/nestedcomm.lm b/test/nestedcomm.lm new file mode 100644 index 00000000..cc28726e --- /dev/null +++ b/test/nestedcomm.lm @@ -0,0 +1,41 @@ +# +# Tokens +# + +# Any single character can be a literal +lex start +{ + # Ignore whitespace. + ignore /[ \t\n\r\v]+/ + + # Open and close id + token id /[a-zA-Z_][a-zA-Z0-9_]*/ + + token open_paren /'('/ + { + send_ignore( parse_stop nested_comment( stdin ) ) + } +} + +# +# Token translation +# + +lex nc_scan +{ + literal '(', ')' + token nc_data /[^()]+/ +} + +def nc_item + [nc_data] +| [nested_comment] + +def nested_comment + ['(' nc_item* ')'] + +def nested [id*] + +nested P = parse nested( stdin ) +print_xml( P ) +print( P, '\n' ) diff --git a/test/python/Makefile b/test/python/Makefile new file mode 100644 index 00000000..6ee0fde1 --- /dev/null +++ b/test/python/Makefile @@ -0,0 +1,33 @@ +# +# Copyright 2007 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/python/input1.py b/test/python/input1.py new file mode 100644 index 00000000..22ffd2e1 --- /dev/null +++ b/test/python/input1.py @@ -0,0 +1,18 @@ + +# dude, this is a comment + # some more +hello +def dude(): + yes + awesome; + + # Here we have a comment + def realy_awesome(): # hi there + in_more + + same_level + def one_liner(): first; second # both inside one_liner + + back_down + +last_statement diff --git a/test/python/input2.py b/test/python/input2.py new file mode 100644 index 00000000..063825e1 --- /dev/null +++ b/test/python/input2.py @@ -0,0 +1,20 @@ + +# dude, this is a comment + # some more +hello +if 1: + yes + awesome; + + # Here we have a comment + if ('hello'): # hi there + in_more + + same_level + if ['dude', 'dudess'].horsie(): first; second # both inside one_liner + 1 + + back_down + +last_statement + diff --git a/test/python/input3.py b/test/python/input3.py new file mode 100644 index 00000000..90ecf3f9 --- /dev/null +++ b/test/python/input3.py @@ -0,0 +1 @@ +hello = 1.1(20); diff --git a/test/python/input4.py b/test/python/input4.py new file mode 100644 index 00000000..1a281c46 --- /dev/null +++ b/test/python/input4.py @@ -0,0 +1,10 @@ + +# subscription +a[1] = b[2]; + +# simple slicing +a[1:1] = b[2:2]; + +# simple slicing +a[1:1, 2:2] = b[3:3, 4:4]; + diff --git a/test/python/python.lm b/test/python/python.lm new file mode 100644 index 00000000..d4e8a692 --- /dev/null +++ b/test/python/python.lm @@ -0,0 +1,727 @@ +# Regular definitions +rl ident_char /[a-zA-Z_]/ + +# List used as a stack of indentations. +list indent_stack [int] +global indent_stack IndentStack = construct indent_stack [] +IndentStack.push( 0 ) + +# Has a newline been sent for this '\n' .. whitespace match. +global int newline_sent = 0 + +# Tokens. +lex start +{ + # Python keywords. + literal 'and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or', + 'with', 'assert', 'else', 'if', 'pass', 'yield', 'break', 'except', + 'import', 'print', 'class', 'exec', 'in', 'raise', 'continue', + 'finally', 'is', 'return', 'def', 'for', 'lambda', 'try' + + # Identifiers + rl lowercase /'a'..'z'/ + rl uppercase /'A'..'Z'/ + rl letter /lowercase | uppercase/ + token identifier /(letter|'_') (letter | digit | '_')*/ + + # Literals + rl escapeseq /'\\' any / + rl longstringchar /[^\\]/ + rl shortstringchar_s /[^\\\n']/ + rl shortstringchar_d /[^\\\n"]/ + rl longstringitem /longstringchar | escapeseq/ + rl shortstringitem_s /shortstringchar_s | escapeseq/ + rl shortstringitem_d /shortstringchar_d | escapeseq/ + rl longstring /"'''" longstringitem* :>> "'''" | '"""' longstringitem* :>> '"""'/ + rl shortstring /"'" shortstringitem_s* "'" | '"' shortstringitem_d* '"'/ + rl stringprefix /"r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"/ + token stringliteral /stringprefix? (shortstring | longstring)/ + + # Integers + rl hexdigit /digit | 'a'..'f' | 'A'..'F'/ + rl octdigit /'0'..'7'/ + rl nonzerodigit /'1'..'9'/ + rl hexinteger /'0' ('x' | 'X') hexdigit+/ + rl octinteger /'0' octdigit+/ + rl decimalinteger /nonzerodigit digit* | '0'/ + token integer /decimalinteger | octinteger | hexinteger/ + token longinteger /integer ('l' | 'L')/ + + # Floats. + rl exponent /('e' | 'E') ('+' | '-')? digit+/ + rl fraction /'.' digit+/ + rl intpart /digit+/ + rl pointfloat /intpart? fraction | intpart '.'/ + rl exponentfloat /(intpart | pointfloat) exponent/ + token floatnumber /pointfloat | exponentfloat/ + + # Imaginaries. + token imagnumber /(floatnumber | intpart) ("j" | "J")/ + + # Operators. + literal '+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&', '|', '^', + '~', '<', '>', '<=', '>=', '==', '!=', '<>' + + # Delimiters + literal '(', ')', '[', ']', '{', '}', '@', ',', ':', '.', '`', '=', ';', + '+=', '-=', '*=', '/=', '//=', '%=', '&=', '|=', '^=', '>>=', '<<=', + '**=' + + literal '...' + + # In general whitespace is ignored. + ignore WS /' '+/ + + # Find and ignore entire blank lines. + token BLANK_LINE + / '\n' [ \t]* ('#' [^\n]*)? '\n' / + { + # Need to shorten to take off the newline. + # Turn it into ignore. + send_ignore( make_token( typeid WS, pull(stdin, match_length - 1) ) ) + } + + # Find and ignore comments. + token COMMENT + / '#' [^\n]* '\n' / + { + # Need to shorten to take off the newline. Turn it into ignore. + send_ignore( make_token( typeid WS, pull(stdin, match_length - 1) ) ) + } + + # These tokens are generated + token INDENT // + token DEDENT // + token NEWLINE // + ignore IND_WS // + + token INDENTATION + /'\n' [ \t]*/ + { + # First the newline. + send( make_token( typeid NEWLINE, '' ) ) + + # We have already sent the newline, compute the indentation level. + int data_length = match_length - 1 + + if data_length > IndentStack.top { + # The indentation level is more than the level on the top + # of the stack. This is an indent event. Send as an INDENT. + send( make_token( typeid INDENT, '' ) ) + + # Push to the stack as per python manual. + IndentStack.push( data_length ) + } else { + while data_length < IndentStack.top { + # The indentation level is less than the level on the top of + # the stack. Pop the level and send one dedent. This flow of + # control will execute until we find the right indentation level + # to match up with. + IndentStack.pop() + + # Send as a DEDENT + send( make_token( typeid DEDENT, '' ) ) + } + } + + # FIXME: if data.length is now > top of stack then error. This + # means the outdent does not match anything. + + # We have squared up INDENTs and DEDENTs. Ignore the entire match. + send_ignore( make_token( typeid WS, pull(stdin, match_length) ) ) + } +} + +# Blank lines or comment lines at the beginning of the file. +token LEADER / ( [ \t]* ('#' [^\n]*)? '\n' )* / + +int print_target_subscriptions_and_slicings( start Start ) +{ + for TI: target_ext in Start { + if match TI [subscription] { + print( 'TARGET SUBSCRIPTION: ', TI, '\n' ) + } + + if match TI [simple_slicing] { + print( 'TARGET SIMPLE SLICING: ', TI, '\n' ) + } + + if match TI [extended_slicing] { + print( 'TARGET EXTENDED SLICING: ', TI, '\n' ) + } + } + +} + +int print_primary_subscriptions_and_slicings( start Start ) +{ + for PI:primary_ext in Start { + if match PI [subscription] { + print( 'PRIMARY SUBSCRIPTION: ', PI, '\n' ) + } + + if match PI [simple_slicing] { + print( 'PRIMARY SIMPLE SLICING: ', PI, '\n' ) + } + + if match PI [extended_slicing] { + print( 'PRIMARY EXTENDED SLICING: ', PI, '\n' ) + } + } +} + +def start + [file_input] + +def file_input + [file_input_forms*] + +def file_input_forms + [statement] +| [NEWLINE] + +def statement + [stmt_list NEWLINE] +| [compound_stmt] + +def stmt_list + [simple_stmt another_stmt* opt_semi] + +def another_stmt + [';' simple_stmt] + +def opt_semi + [';'] +| [] + +def suite + [stmt_list NEWLINE] +| [NEWLINE INDENT statement_seq DEDENT] + +def statement_seq + [statement_seq statement] +| [statement] + +def compound_stmt + [if_stmt] +| [while_stmt] +| [for_stmt] +| [try_stmt] +| [with_stmt] +| [funcdef] +| [classdef] + +def if_stmt + ['if' expression ':' suite elif_part* opt_else_part] + +def elif_part + ['elif' expression ':' suite] + +def opt_else_part + ['else' ':' suite] +| [] + +def while_stmt + ['while' expression ':' suite opt_else_part] + +def for_stmt + ['for' target_list 'in' expression_list ':' suite opt_else_part] + +def try_stmt + ['try' ':' suite except_list opt_else_part opt_finally_part] +| ['try' ':' suite 'finally' ':' suite] + +def except_list + [except_list except_part] +| [except_part] + +def except_part + ['except' ':' suite] +| ['except' expression ':' suite] +| ['except' expression ',' target ':' suite] + +def opt_finally_part + ['finally' ':' suite] +| [] + +def with_stmt + ['with' expression ':' suite] +| ['with' expression 'as' target ':' suite] + +def funcdef + [decorators 'def' funcname '(' opt_parameter_list ')' ':' suite] + +def funcname + [identifier] + +def decorators + [decorators decorator] +| [] + +def decorator + ['@' dotted_name opt_decorator_pal NEWLINE] + +def opt_decorator_pal + [] +| ['(' ')'] +| ['(' argument_list ')'] +| ['(' argument_list ',' ')'] + +def dotted_name + [dotted_name '.' identifier] +| [identifier] + +def opt_parameter_list + [parameter_list] +| [] + +def parameter_list + [defparameter_list defparameter opt_comma] +| [defparameter_list '*' identifier] +| [defparameter_list '*' identifier '**' identifier] +| [defparameter_list '**' identifier] + +def defparameter_list + [defparameter_list defparameter ','] +| [] + +def defparameter + [parameter] +| [parameter '=' expression] + +def sublist + [sublist_pl opt_comma] + +def sublist_pl + [sublist_pl ',' parameter] +| [parameter] + +def parameter + [identifier] +| ['(' sublist ')'] + +def classdef + ['class' classname opt_inheritance ':' suite] + +def classname + [identifier] + +def opt_inheritance + ['(' ')'] +| ['(' expression_list ')'] +| [] + +def simple_stmt + [expression_stmt] +| [assert_stmt] +| [assignment_stmt] +| [augmented_assignment_stmt] +| [pass_stmt] +| [del_stmt] +| [print_stmt] +| [return_stmt] +| [yield_stmt] +| [raise_stmt] +| [break_stmt] +| [continue_stmt] +| [import_stmt] +| [global_stmt] +| [exec_stmt] + +def expression_stmt + [expression_list] + +def assert_stmt + ['assert' expression_list_core] + +def assignment_stmt + [target_equals_list expression_list] + +def target_equals_list + [target_equals_list target_equals] +| [target_equals] + +def target_equals + [target_list '='] + +def target_list + [target_list_core opt_comma] + +def target_list_core + [target_list_core ',' target] +| [target] + +def target + [target_atom target_ext_rep] + +def target_atom + [identifier] +| ['(' target_list ')'] +| ['[' target_list ']'] + +def target_ext_rep + [target_ext target_ext_rep] +| [] + +def target_ext + [attributeref] +| [subscription] +| [slicing] + +def augmented_assignment_stmt + [target augop expression_list] + +def augop + ['+='] | ['-='] | ['*='] | ['/='] +| ['\%='] | ['**='] | ['>>='] | ['<<='] | ['\&='] +| ['^'] | ['|='] + +def pass_stmt + ['pass'] + +def del_stmt + ['del' target_list] + +def print_stmt + ['print' opt_expression_list] +| ['print' '>>' expression_list] + +def return_stmt + ['return' opt_expression_list] + +def yield_stmt + ['yield' expression_list] + +def raise_stmt + ['raise'] +| ['raise' expression] +| ['raise' expression ',' expression] +| ['raise' expression ',' expression ',' expression] + +def break_stmt + ['break'] + +def continue_stmt + ['continue'] + +def import_stmt + ['import' module opt_as_name more_imports] +| ['from' module 'import' identifier opt_as_name more_imports] +| ['from' module 'import' '(' identifier opt_as_name more_imports opt_comma ')'] +| ['from' module 'import' '*'] + +def more_imports + [more_imports ',' identifier opt_as_name] +| [] + +def module + [module '.' identifier] +| [identifier] + +def opt_as_name + ['as' identifier] +| [] + +def global_stmt + ['global' identifer_list] + +def identifer_list + [identifer_list ',' identifier] +| [identifier] + +def exec_stmt + ['exec' expression] +| ['exec' expression 'in' expression] +| ['exec' expression 'in' expression ',' expression] + +def opt_expression_list + [expression_list] +| [] + +def expression_list + [expression_list_core opt_comma] + +def expression_list_core + [expression_list_core ',' expression] +| [expression] + +def opt_comma + [','] +| [] + +def expression + [or_test 'if' or_test 'else' test] +| [or_test] +| [lambda_form] + +def or_test + [or_test 'or' and_test] +| [and_test] + +def and_test + [and_test 'and' not_test] +| [not_test] + +def not_test + [comparison] +| ['not' not_test] + +def lambda_form + ['lambda' opt_parameter_list ':' expression] + +def test + [or_test] +| [lambda_form] + +def comparison + [or_expr comparison_part*] + +def comparison_part + [comp_operator or_expr] + +def comp_operator + ['<'] | ['>'] | ['=='] | ['>='] | ['<='] | ['<>'] | ['!='] | ['is'] | + ['is' 'not'] | ['in'] | ['not' 'in'] + +def or_expr + [or_expr '|' xor_expr] +| [xor_expr] + +def xor_expr + [xor_expr '^' and_expr] +| [and_expr] + +def and_expr + [and_expr '&' shift_expr] +| [shift_expr] + +def shift_expr + [shift_expr '<<' a_expr] +| [shift_expr '>>' a_expr] +| [a_expr] + +def a_expr + [a_expr '+' m_expr] +| [a_expr '-' m_expr] +| [m_expr] + +def m_expr + [m_expr '*' u_expr] +| [m_expr '//' u_expr] +| [m_expr '/' u_expr] +| [m_expr '\%' u_expr] +| [u_expr] + +def u_expr + [power] +| ['-' u_expr] +| ['+' u_expr] +| ['\~' u_expr] + +def power + [primary '**' u_expr] +| [primary] + +def primary + [atom primary_ext_rep] + +def atom + [identifier] +| [pyliteral] +| [enclosure] + +def primary_ext_rep + [primary_ext primary_ext_rep] +| [] + +def primary_ext + [attributeref] +| [subscription] +| [slicing] +| [call] + +def pyliteral + [stringliteral] +| [integer] +| [longinteger] +| [floatnumber] +| [imagnumber] + +def enclosure + [parenth_form] +| [list_display] +| [generator_expression] +| [dict_display] +| [string_conversion] + +def parenth_form + ['(' opt_expression_list ')'] + +def list_display + ['[' opt_listmaker ']'] + +def opt_listmaker + [listmaker] +| [] + +def listmaker + [expression list_for] +| [expression listmaker_ext* opt_comma] + +def listmaker_ext + [',' expression] + +def opt_list_iter + [list_iter] +| [] + +def list_iter + [list_for] +| [list_if] + +def list_if + ['if' test opt_list_iter] + +def list_for + ['for' expression_list 'in' testlist opt_list_iter] + +def testlist + [test testlist_ext* opt_comma] + +def testlist_ext + [',' test ] + +def generator_expression + ['(' test genexpr_for ')'] + +def genexpr_for + ['for' expression_list 'in' test opt_genexpr_iter] + +def opt_genexpr_iter + [genexpr_iter] +| [] + +def genexpr_iter + [genexpr_for] +| [genexpr_if] + +def genexpr_if + ['if' test opt_genexpr_iter] + +def dict_display + ['\{' opt_key_datum_list '\}'] + +def opt_key_datum_list + [key_datum_list] +| [] + +def key_datum_list + [key_datum key_datum_list_ext* opt_comma] + +def key_datum_list_ext + [',' key_datum] + +def key_datum + [expression ':' expression] + +def string_conversion + ['`' expression_list '`'] + +def attributeref + ['.' identifier] + +def subscription + ['[' expression_list ']'] + +# The natural ordered choice does not suffice here. Must force it. + +def slicing + [simple_slicing] +| [extended_slicing] + +def simple_slicing + ['[' short_slice ']'] + +def extended_slicing + ['[' slice_list ']'] + +def slice_list + [slice_item slice_list_ext* opt_comma] + +def slice_list_ext + [',' slice_item] + +def slice_item + [expression] +| [proper_slice] +| [ellipsis] + +def proper_slice + [short_slice] +| [long_slice] + +def short_slice + [':'] +| [':' upper_bound] +| [lower_bound ':'] +| [lower_bound ':' upper_bound] + +def long_slice + [short_slice ':' stride] +| [short_slice ':'] + +def lower_bound + [expression] + +def upper_bound + [expression] + +def stride + [expression] + +def ellipsis + ['...'] + +def call + ['(' opt_argument_list ')'] + +def opt_argument_list + [argument_list opt_comma] +| [] + +def argument_list + [positional_arguments opt_comma_keyword_arguments + opt_comma_star_expr opt_comma_dstar_expr] +| [keyword_arguments opt_comma_star_expr opt_comma_dstar_expr] +| ['*' expression opt_comma_dstar_expr] +| ['**' expression] + +def opt_comma_star_expr + [',' '*' expression] +| [] + +def opt_comma_dstar_expr + [',' '**' expression] +| [] + +def positional_arguments + [positional_arguments ',' expression] +| [expression] + +def opt_comma_keyword_arguments + [',' keyword_arguments] +| [] + +def keyword_arguments + [keyword_arguments ',' keyword_item] +| [keyword_item] + +def keyword_item + [identifier '=' expression] + + +start S = parse start( stdin ) +#print_xml( S ) +print_target_subscriptions_and_slicings( S ) +print_primary_subscriptions_and_slicings( S ) +print( '*** SUCCESS ***\n' ) diff --git a/test/ragelambig.in b/test/ragelambig.in new file mode 100644 index 00000000..0b4439e5 --- /dev/null +++ b/test/ragelambig.in @@ -0,0 +1 @@ +1 - 1 diff --git a/test/ragelambig1.lm b/test/ragelambig1.lm new file mode 100644 index 00000000..1c292fd1 --- /dev/null +++ b/test/ragelambig1.lm @@ -0,0 +1,65 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start + [expression] + { + print_xml( lhs ) + } + +def expression + [expression '|' term] +| [expression '&' term] +| [expression '-' term] +| [expression '--' term] +| [term] + +def term + [term factor_with_rep] + { + if match lhs [term '-' uint] { + reject + } + } +| [term '.' factor_with_rep] +| [term ':>' factor_with_rep] +| [term ':>>' factor_with_rep] +| [term '<:' factor_with_rep] +| [factor_with_rep] + +def factor_with_rep + [factor_with_rep '*'] +| [factor_with_rep '**'] +| [factor_with_rep '?'] +| [factor_with_rep '+'] +| [factor_with_rep '{' factor_rep_num '}'] +| [factor_with_rep '{' ',' factor_rep_num '}'] +| [factor_with_rep '{' factor_rep_num ',' '}'] +| [factor_with_rep '{' factor_rep_num ',' factor_rep_num '}'] +| [factor_with_neg] + +def factor_rep_num [uint] + +def factor_with_neg + ['!' factor_with_neg] +| ['^' factor_with_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] +| ['-' uint] diff --git a/test/ragelambig2.lm b/test/ragelambig2.lm new file mode 100644 index 00000000..70e97c66 --- /dev/null +++ b/test/ragelambig2.lm @@ -0,0 +1,65 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start + [expression] + { + print_xml( lhs ) + } + +def expression + [expression '|' term] +| [expression '&' term] +| [expression '-' term] +| [expression '--' term] +| [term] + +def term + [factor_with_rep more_term] + +# Can resolve the ambiguity by making more_term shortest match. +def more_term + [] +| [factor_with_rep more_term] +| ['.' factor_with_rep more_term] +| [':>' factor_with_rep more_term] +| [':>>' factor_with_rep more_term] +| ['<:' factor_with_rep more_term] + +def factor_with_rep + [factor_with_rep '*'] +| [factor_with_rep '**'] +| [factor_with_rep '?'] +| [factor_with_rep '+'] +| [factor_with_rep '{' factor_rep_num '}'] +| [factor_with_rep '{' ',' factor_rep_num '}'] +| [factor_with_rep '{' factor_rep_num ',' '}'] +| [factor_with_rep '{' factor_rep_num ',' factor_rep_num '}'] +| [factor_with_neg] + +def factor_rep_num + [uint] + +def factor_with_neg + ['!' factor_with_neg] +| ['^' factor_with_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] +| ['-' uint] diff --git a/test/ragelambig3.lm b/test/ragelambig3.lm new file mode 100644 index 00000000..649038e5 --- /dev/null +++ b/test/ragelambig3.lm @@ -0,0 +1,64 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start + [expression] + { + print_xml( lhs ) + } + +def expression + [expression '|' term_short] +| [expression '&' term_short] +| [expression '-' term_short] +| [expression '--' term_short] +| [term_short] + +def term_short + reducefirst + [term] + +def term + [term factor_with_rep] +| [term '.' factor_with_rep] +| [term ':>' factor_with_rep] +| [term ':>>' factor_with_rep] +| [term '<:' factor_with_rep] +| [factor_with_rep] + +def factor_with_rep + [factor_with_rep '*'] +| [factor_with_rep '**'] +| [factor_with_rep '?'] +| [factor_with_rep '+'] +| [factor_with_rep '{' factor_rep_num '}'] +| [factor_with_rep '{' ',' factor_rep_num '}'] +| [factor_with_rep '{' factor_rep_num ',' '}'] +| [factor_with_rep '{' factor_rep_num ',' factor_rep_num '}'] +| [factor_with_neg] + +def factor_rep_num [uint] + +def factor_with_neg + ['!' factor_with_neg] +| ['^' factor_with_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] +| ['-' uint] diff --git a/test/ragelambig4.lm b/test/ragelambig4.lm new file mode 100644 index 00000000..d489bca3 --- /dev/null +++ b/test/ragelambig4.lm @@ -0,0 +1,69 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start + [expression] + { + print_xml( lhs ) + } + +def expression [term expression_op*] + +def expression_op + ['|' term] +| ['&' term] +| ['-' term] +| ['--' term] + +def term [factor_rep term_op_list_short] + +# This list is done manually to get shortest match. +def term_op_list_short + [] +| [term_op term_op_list_short] + +def term_op + [factor_rep] +| ['.' factor_rep] +| [':>' factor_rep] +| [':>>' factor_rep] +| ['<:' factor_rep] + +def factor_rep + [factor_neg factor_rep_op*] + +def factor_rep_op + ['*'] +| ['**'] +| ['?'] +| ['+'] +| ['{' factor_rep_num '}'] +| ['{' ',' factor_rep_num '}'] +| ['{' factor_rep_num ',' '}'] +| ['{' factor_rep_num ',' factor_rep_num '}'] + +def factor_rep_num [uint] + +def factor_neg + ['!' factor_neg] +| ['^' factor_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] +| ['-' uint] diff --git a/test/rediv.in b/test/rediv.in new file mode 100644 index 00000000..f1ef2a38 --- /dev/null +++ b/test/rediv.in @@ -0,0 +1 @@ +2 / /[^gu-zy].*o[\d-xa]*/; diff --git a/test/rediv.lm b/test/rediv.lm new file mode 100644 index 00000000..c3750351 --- /dev/null +++ b/test/rediv.lm @@ -0,0 +1,92 @@ +# Or-literal scanner +lex orlit +{ + token orlit_dash /'-' / + token orlit_close /']'/ + + rl orlit_specials /[\-\]]/ + token orlit_chr /^orlit_specials | '\\' any/ +} + +def orlit_item + [orlit_chr] +| [orlit_chr orlit_dash orlit_chr] + +def orlit + [orlit_item*] + +# Regex scanner +lex regex +{ + token orlit_open /'['/ + token orlit_neg_open /'[^'/ + token regex_dot /'.'/ + token regex_star /'*'/ + token regex_close /'/'/ + + rl regex_specials /[\[\.\*\/\\]/ + token regex_chr /(^regex_specials)* | '\\' any/ +} + +def regex_rep + [regex_star] +| [] + +def regex_base + [regex_chr] +| [regex_dot] +| [orlit_open orlit orlit_close] +| [orlit_neg_open orlit orlit_close] + +def regex_item + [regex_base regex_rep] + +def regex_body + [regex_item*] + +rl s_string /"'" ([^'\\\n] | '\\' any )* "'"/ +rl d_string /'"' ([^"\\\n] | '\\' any )* '"'/ + +# Root scanner +lex start +{ + token ident /[a-zA-Z_]+/ + token number /[0-9]+/ + token string /s_string | d_string/ + + literal '+', '-', '*', ';', '/' + token slash /'/'/ + token semi /';'/ + + ignore wp /[ \t\n]+/ +} + +def factor + [ident] +| [number] +| [string] +| ['/' regex_body regex_close] + +def term + [term '*' factor] +| [term '/' factor] +| [factor] + +def expr + [expr '+' term] +| [expr '-' term] +| [term] + +def statement + [expr ';'] + +def start + [statement*] + { + for I:orlit_item in lhs { + if match I [orlit_chr] { + print( I, '\n' ) + } + } + print_xml( lhs ) + } diff --git a/test/ruby/Makefile b/test/ruby/Makefile new file mode 100644 index 00000000..16285a0a --- /dev/null +++ b/test/ruby/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2008 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/ruby/ruby.lm b/test/ruby/ruby.lm new file mode 100644 index 00000000..ec35fae4 --- /dev/null +++ b/test/ruby/ruby.lm @@ -0,0 +1,606 @@ +# +# Grammar +# + +# The items in this scanner may have newline in front of them. +lex start +{ + # Reserved Words. + literal '__LINE__', '__FILE__', '__ENCODING__', 'BEGIN', 'END', 'alias', + 'and', 'begin', 'break', 'case', 'class', 'def', 'defined?', 'do', + 'else', 'elsif', 'end', 'ensure', 'false', 'for', 'in', 'module', + 'next', 'nil', 'not', 'or', 'redo', 'rescue', 'retry', 'return', + 'self', 'super', 'then', 'true', 'undef', 'when', 'yield', 'if', + 'unless', 'while', 'until' + + token tNTH_REF /'$' [0-9]+/ + token tBACK_REF /'$' ( '&' | '`' | '\'' | '+' ) / + + literal ')', ',', ']' + literal '{', '}', ':' + literal '.', '::' + literal '->' + + # Unary operators. + literal '!', '~' + token tUPLUS /'+'/ + token tUMINUS /'-'/ + + token tLBRACK /'['/ + token tLPAREN /'('/ + token tSTAR /'*'/ + token tBAR /'|'/ + token tAMPER /'&'/ + + token tIDENTIFIER /[a-z][a-zA-Z_]*/ + token tFID /[a-z][a-zA-Z_]* ('!'|'?')/ + token tCONSTANT /[A-Z][a-zA-Z_]*/ + token tGVAR /'$' [a-zA-Z_]+/ + token tIVAR /'@' [a-zA-Z_]+/ + token tCVAR /'@@' [a-zA-Z_]+/ + + token tINTEGER /[0-9]+/ + token tFLOAT /[0-9]+ '.' [0-9]+/ + + token tDSTRING_BEG /'"'/ + token tSSTRING_BEG /'\''/ + token tXSTRING_BEG /'`'/ + + ignore /[ \t\n]+/ + ignore comment /'#' [^\n]* '\n'/ +} + +# These items cannot appear at the beginning of a line (except maybe the first). +lex expr_cont_ops +{ + ignore /[\t ]+/ + + literal '+', '-', '*', '**', '/', '%', '^' + literal '|', '&', '||', '&&' + literal '[', '(' + literal '=' + literal '<<', '>>' + literal '?' + literal '<=>' + literal '=>' + literal '[]', '[]=' + literal '=~', '!~' + literal '<', '>', '>=', '<=' + literal '!=', '==', '===' + literal '..', '...' +} +lex terms +{ + ignore /[\t ]+/ + ignore /'#' [^\n]*/ + literal ';' + literal '\n' +} + + +lex dstring_contents +{ + token dstring_contents /[^"]+/ + token tDSTRING_END /'"'/ +} + +lex sstring_contents +{ + token sstring_contents /[^']+/ + token tSSTRING_END /'\''/ +} + +lex xstring_contents +{ + token xstring_contents /[^`]+/ + token tXSTRING_END /'`'/ +} + +def ruby + [compstmt] + +def compstmt + [stmts opt_terms] + +def bodystmt + [compstmt opt_rescue opt_else opt_ensure] + +def opt_rescue +# ['rescue' exc_list exc_var then compstmt opt_rescue] | + [] + +def then + [term] +| ['then'] +| [term 'then'] + +def do + [term] +| ['do'] + +def if_tail + [opt_else] +| ['elsif' expr_value then compstmt if_tail] + +def opt_else + ['else' compstmt] +| [] + +def opt_ensure + ['ensure' compstmt] +| [] + +def stmts + [stmts terms stmt] +| [stmt] +| [] + +def opt_terms + [terms] +| [] + +def terms + [term] +| [terms ';'] + +def term + [';'] +| ['\n'] + +def stmt + ['alias' fitem fitem] +| ['undef' undef_list] +| [stmt 'if' expr_value] +| [stmt 'unless' expr_value] +| [stmt 'while' expr_value] +| [stmt 'until' expr_value] +| [stmt 'rescue' stmt] +| ['BEGIN' '{' compstmt '}'] +| ['END' '{' compstmt '}'] +| [lhs '=' mrhs] +| [mlhs '=' arg_value] +| [mlhs '=' mrhs] +| [expr] + +def mlhs + [mlhs_basic] +| [tLPAREN mlhs ')'] + +def mlhs_basic + [mlhs_head] + +def mlhs_head + [mlhs_item ',' mlhs_head] +| [mlhs_item] + +def mlhs_item + [variable] +| ['*' mlhs_item] +| ['*'] +| [primary_value '[' opt_call_args ']'] +| [primary_value '.' tIDENTIFIER] +| [primary_value '.' tCONSTANT] +| [primary_value '::' tIDENTIFIER] +| [primary_value '::' tCONSTANT] +| ['::' tCONSTANT] +| [backref] +| [tLPAREN mlhs ')'] + +def lhs + [variable] +| [primary_value '[' opt_call_args ']'] +| [primary_value '.' tIDENTIFIER] +| [primary_value '.' tCONSTANT] +| [primary_value '::' tIDENTIFIER] +| [primary_value '::' tCONSTANT] +| ['::' tCONSTANT] +| [backref] + +def mrhs + [args ',' arg_value] +| [args ',' '*' arg_value] +| ['*' arg_value] + +def expr + [expr 'and' expr] +| [expr 'or' expr] +| ['not' expr] +| [arg] + +def expr_value + [expr] + +def opt_brace_block + [brace_block] +| [] + +def block_param_def + [tBAR opt_bv_decl tBAR] +| [tBAR block_param opt_bv_decl tBAR] + +def block_param + [block_arg_list] +| [] + +def block_arg_list + [block_arg_list ',' block_arg_item] +| [block_arg_item] + +def block_arg_item + [f_norm_arg] +| [f_rest_arg] +| [f_block_arg] +| ['(' f_args ')'] + +def opt_bv_decl + [';' bv_decls] +| [] + +def bv_decls + [bvar] +| [bv_decls ',' bvar] + +def bvar + [tIDENTIFIER] + +def opt_block_param + [block_param_def] +| [] + +def operation + [tIDENTIFIER] +| [tCONSTANT] +| [tFID] + +def operation2 + [tIDENTIFIER] +| [tCONSTANT] +| [tFID] +| [op] + +def operation3 + [tIDENTIFIER] +| [tFID] +| [op] + +def op + ['|'] | ['^'] | ['&'] | ['<=>'] | ['=='] | ['==='] | ['=~'] | ['!~'] | + ['>'] | ['>='] | ['<'] | ['<='] | ['!='] | ['<<'] | ['>>'] | ['+'] | + ['-'] | ['*'] | ['/'] | ['%'] | ['**'] | ['!'] | ['~'] | ['[]'] | ['[]='] | + [tXSTRING_BEG] + +def opt_call_args + [call_args] +| [] + +def call_args + [args opt_block_arg] +| [assocs opt_block_arg] +| [args ',' assocs opt_block_arg] +| [block_arg] + +def args + [arg_value] +| ['*' arg_value] +| [args ',' arg_value] +| [args ',' '*' arg_value] + +def arg_value + [arg] + +def opt_block_arg + [',' block_arg] +| [] + +def block_arg + [tAMPER arg_value] + +right '=' +left 'rescue' +right '?', ':' +nonassoc '..', '...' +left '||' +left '&&' +nonassoc '<=>', '==', '===', '!=', '=~', '!~' +left '>', '>=', '<', '<=' +left '|', '^' +left '&' +left '<<', '>>' +left '+', '-' +left '*', '/', '%' +#right tUMINUS_NUM tUMINUS +right tUMINUS +right '**' +right '!', '~', tUPLUS + +def arg + [lhs '=' arg] +| [lhs '=' arg 'rescue' arg] +| [arg '?' arg ':' arg] +| [arg '..' arg] +| [arg '...' arg] +| [arg '||' arg] +| [arg '&&' arg] +| [arg '<=>' arg] +| [arg '==' arg] +| [arg '===' arg] +| [arg '!=' arg] +| [arg '=~' arg] +| [arg '!~' arg] +| [arg '>' arg] +| [arg '>=' arg] +| [arg '<' arg] +| [arg '<=' arg] +| [arg '|' arg] +| [arg '^' arg] +| [arg '&' arg] +| [arg '<<' arg] +| [arg '>>' arg] +| [arg '+' arg] +| [arg '-' arg] +| [arg '*' arg] +| [arg '/' arg] +| [arg '%' arg] +| [arg '**' arg] +| ['!' primary] +| ['~' primary] +| [tUMINUS primary] +| [tUPLUS primary] +| ['defined?' arg] +| [primary] + +def primary_value + [primary] + +def primary + [pliteral] +| [strings] +| [xstring] +#| [regexp] +#| [words] +#| [qwords] +| [var_ref] +| [backref] +| [tFID] +| ['begin' bodystmt 'end'] +| [tLPAREN compstmt ')'] +| [primary_value '::' tCONSTANT] +| ['::' tCONSTANT] +| [tLBRACK aref_args ']'] +| ['{' assoc_list '}'] +| ['defined?' '(' expr ')'] +| [operation brace_block] +| [method_call] +| [method_call brace_block] +| ['->' lambda] +| ['if' expr_value then compstmt if_tail 'end'] +| ['unless' expr_value then compstmt opt_else 'end'] +| ['while' expr_value do compstmt 'end'] +| ['until' expr_value do compstmt 'end'] +#| ['case' expr_value opt_terms case_body 'end'] +#| ['case' opt_terms case_body 'end'] +| ['for' for_var 'in' expr_value do compstmt 'end'] +| ['class' cpath superclass bodystmt 'end'] +| ['class' '<<' expr term bodystmt 'end'] +| ['module' cpath bodystmt 'end'] +| ['def' fname f_arglist bodystmt 'end'] +| ['def' singleton dot_or_colon fname f_arglist bodystmt 'end'] +| ['break'] +| ['next'] +| ['redo'] +| ['retry'] + +def for_var + [lhs] +| [mlhs] + +def lambda + [f_larglist lambda_body] + +def f_larglist + ['(' f_args opt_bv_decl ')'] +| [f_args opt_bv_decl] + +def lambda_body + ['{' compstmt '}'] +| ['do' compstmt 'end'] + +def assoc_list + [assocs trailer] +| [] + +def assocs + [assocs ',' assoc] +| [assoc] + +def assoc + [arg_value '=>' arg_value] +| [':' arg_value] + +def singleton + [var_ref] +| ['(' expr ')'] + +def dot_or_colon + ['.'] +| ['::'] + +def aref_args + [args trailer] +| [args ',' assocs trailer] +| [assocs trailer] +| [] + +def trailer + [','] +| [] + +def brace_block + ['{' opt_block_param compstmt '}'] +| ['do' opt_block_param compstmt 'end'] + +def f_arglist + ['(' f_args ')'] +| [f_args term] + +def f_args + [f_arg_list] +| [] + +def f_arg_list + [f_arg_list ',' f_arg_item] +| [f_arg_item] + +def f_arg_item + [f_norm_arg] +| [f_opt] +| [f_rest_arg] +| [f_block_arg] +| ['(' f_args ')'] + +def f_opt + [tIDENTIFIER '=' arg_value] + +def f_rest_arg + ['*' tIDENTIFIER] +| ['*'] + +def f_block_arg + [tAMPER tIDENTIFIER] + +def f_norm_arg + [tIDENTIFIER] + +def backref + [tNTH_REF] | [tBACK_REF] + +def superclass + [term] +| ['<' expr_value term] + +def cpath + ['::' cname] +| [cname] +| [primary_value '::' cname] + +def fname + [tIDENTIFIER] +| [tCONSTANT] +| [tFID] +| [op] +| [reswords] + +def reswords + ['__LINE__'] | ['__FILE__'] | ['__ENCODING__'] | ['BEGIN'] | ['END'] | + ['alias'] | ['and'] | ['begin'] | ['break'] | ['case'] | ['class'] | + ['def'] | ['defined?'] | ['do'] | ['else'] | ['elsif'] | ['end'] | + ['ensure'] | ['false'] | ['for'] | ['in'] | ['module'] | + ['next'] | ['nil'] | ['not'] | ['or'] | ['redo'] | ['rescue'] | + ['retry'] | ['return'] | ['self'] | ['super'] | ['then'] | ['true'] | + ['undef'] | ['when'] | ['yield'] | ['if'] | ['unless'] | ['while'] | + ['until'] + +def cname + [tIDENTIFIER] +| [tCONSTANT] + +def pliteral + [numeric] +| [symbol] +#| [dsym] + +def strings + [string] + +def string +# [tCHAR] + [string1] +| [string string1] + +def string1 + [tSSTRING_BEG sstring_contents? tSSTRING_END] +| [tDSTRING_BEG dstring_contents? tDSTRING_END] + +def xstring + [tXSTRING_BEG xstring_contents? tXSTRING_END] + +def numeric + [tINTEGER] +| [tFLOAT] + +def symbol + [':' sym] + +def sym + [fname] +| [tIVAR] +| [tGVAR] +| [tCVAR] + +def fitem + [fsym] +#| [dsym] + +def undef_list + [fitem] +| [undef_list ',' fitem] + +def fsym + [fname] +| [symbol] + +#def dsym +# [':' xstring_contents tDSTRING_END] + +def var_ref + [variable] + +def variable + [tIDENTIFIER] | [tIVAR] | [tGVAR] | [tCONSTANT] | [tCVAR] | ['nil'] | + ['self'] | ['true'] | ['false'] | ['__FILE__'] | ['__LINE__'] | + ['__ENCODING__'] + + +# Required whitespace, but newline is not allowed. +token ws_no_nl + /[ \t]+[^ \t\n]/ + { + send( make_token( typeid ws_no_nl, pull(stdin, match_length-1) ) ) + } + +def method_call + [operation paren_args] +| [operation ws_no_nl call_args] +| [primary_value '.' operation2 opt_paren_args] +| [primary_value '.' operation2 ws_no_nl call_args] +| [primary_value '::' operation2 opt_paren_args] +| [primary_value '::' operation2 ws_no_nl call_args] +| [primary_value '.' paren_args] +| [primary_value '::' paren_args] +| ['super' paren_args] +| ['super' ws_no_nl call_args] +| ['super'] +| ['yield' paren_args] +| ['yield' ws_no_nl call_args] +| ['yield'] +| ['return' call_args] +| ['return'] +| [primary_value '[' opt_call_args ']'] + +def opt_paren_args + [paren_args] +| [] + +def paren_args + ['(' opt_call_args ')'] + +# +# Grammar finished +# + +ruby R = parse ruby(stdin) + +print_xml( R ) + +#for T: primary in R +# print_xml( T, '\n\n' ) diff --git a/test/rubyhere.in b/test/rubyhere.in new file mode 100644 index 00000000..a23dfead --- /dev/null +++ b/test/rubyhere.in @@ -0,0 +1,8 @@ +print( <<DATA1, more, <<DATA2, 99 ) +"&^#(@ almost +!arbitrary text! +DATA1 +hello +world +DATA2 +. error here diff --git a/test/rubyhere.lm b/test/rubyhere.lm new file mode 100644 index 00000000..33fff4b7 --- /dev/null +++ b/test/rubyhere.lm @@ -0,0 +1,89 @@ +rl ident_pattern /[a-zA-Z_][a-zA-Z_0-9]*/ +rl number_pattern /[0-9]+/ + +lex start +{ + ignore /[ \t\n]+/ + token id /ident_pattern/ + token number /number_pattern/ + literal '<<', '*', ',', '(', ')' +} + +global str HereId + +token rest_of_line /[^\n]*'\n'/ + +lex here_start +{ + ignore /[ \t\n]+/ + token here_id + here_data HereData + /ident_pattern/ + { + # Take the text of the here_id from the input stream. + HereId = pull( stdin, match_length ) + + # Get the data up to the rest of the line. + rest_of_line ROL = parse_stop rest_of_line( stdin ) + + # Parse the heredoc data. + here_data HereData = parse_stop here_data( stdin ) + + # Push the rest-of-line data back to the input stream. + push( stdin, ROL ) + + # Send the here_id token. Attach the heredoc data as an attribute. + send( make_token( typeid here_id, HereId, HereData ) ) + } +} + +lex here_data +{ + token here_close_id + / ident_pattern '\n' / + { + if match_text == HereId + '\n' { + send( make_token( + typeid here_close_id, + pull(stdin, match_length) ) ) + } + else + send( make_token( typeid here_line, pull(stdin, match_length) ) ) + } + + token here_line + / [^\n]* '\n' / +} + +def here_data + [here_line* here_close_id] + +def heredoc + ['<<' here_id] + +def primary + [id] +| [number] +| [heredoc] + +def arglist + [primary arglist_more*] + +def arglist_more + [',' primary] + +def call + [id '(' arglist? ')'] + +def statement + [primary] +| [call] + +token foobar /any*/ + +def start + [statement*] +| [foobar] + +start S = parse start( stdin ) +print_xml(S) diff --git a/test/string.in b/test/string.in new file mode 100644 index 00000000..8aef536f --- /dev/null +++ b/test/string.in @@ -0,0 +1,2 @@ +a + "%{{"; 1 * 2; + diff --git a/test/string.lm b/test/string.lm new file mode 100644 index 00000000..7da88215 --- /dev/null +++ b/test/string.lm @@ -0,0 +1,54 @@ +lex string +{ + token str_escape /'\\' any/ + token str_chr /[^\\"]+/ +} + +def str_item + [str_escape] +| [str_chr] + +def string + ['"' str_item* '"'] + +lex start +{ + token ident /[a-zA-Z_]+/ + token number /[0-9]+/ + + literal '+', '*', ';', '"', '\'', '(', ')' + literal '+=', '-=', '*=' + + ignore wp /[ \t\n]+/ +} + +def expr + [expr '+' term] +| [term] + +def term + [term '*' primary] +| [primary] + +def primary + [number] +| [ident] +| [string] +| ['(' expr ')'] + +def expr_list + [expr_list expr ';'] +| [] + +def start + [expr_list] + { + if match lhs + ~a + "%{{"; 1 * 2; + { + print( 'yes\n' ) + } + } + +start S = parse start(stdin) +print_xml( S ) diff --git a/test/superid.in b/test/superid.in new file mode 100644 index 00000000..4002630f --- /dev/null +++ b/test/superid.in @@ -0,0 +1 @@ +!a b b a; diff --git a/test/superid.lm b/test/superid.lm new file mode 100644 index 00000000..3a3eef59 --- /dev/null +++ b/test/superid.lm @@ -0,0 +1,59 @@ + +lex start +{ + literal '!', 'a', ';\n' + + token id /'a'|'b'/ + { + #tok.id = trans_id_to + } + + token super_id // + token foo // + + ignore ws / [ \n\t]+ / +} + +global int trans_id_to + +def e1 + [] + { + print( 'old_id = ', trans_id_to, '\n' ) + #trans_id_to = type_id foo + print( 'new_id = ', trans_id_to, '\n' ) + } + +def item1 + str msg + + [ e1 '!' 'a' super_id super_id 'a'] + { + lhs.msg = 'this is item1\n' + } + +def e2 + [] + { + print( 'old_id = ', trans_id_to, '\n' ) + #trans_id_to = type_id super_id + print( 'new_id = ', trans_id_to, '\n' ) + } + +def item2 + str msg + + [ e2 '!' 'a' super_id super_id 'a'] + { + lhs.msg = 'this is item2\n' + } + + +def start + [item1 ';\n'] +| [item2 ';\n'] + { + match lhs [Item2:item2 ';\n'] + print( Item2.msg ) + } + diff --git a/test/tags.in b/test/tags.in new file mode 100644 index 00000000..939f9b48 --- /dev/null +++ b/test/tags.in @@ -0,0 +1 @@ +a b b a; diff --git a/test/tags.lm b/test/tags.lm new file mode 100644 index 00000000..9e13ddd8 --- /dev/null +++ b/test/tags.lm @@ -0,0 +1,82 @@ +# Open and close tags by rewriting to generic close tags. Won't work if +# interested in unclosed tags because a token can start as not close_id, but +# then become a close id during the course of parsing. + +# +# Regular Definitions +# +rl rl_ws /[ \t\n\r\v]+/ +rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ + +# +# Tokens +# + +# Any single character can be a literal +lex start +{ + literal '!\n', ';\n' + + # Ignore whitespace. + ignore /rl_ws/ + + # Open and close id + token id /rl_id/ +} + +# +# Global Data +# + +def tag_stack + [id tag_stack] +| [] + +global tag_stack TS = construct tag_stack ["sentinal"] + +# +# Productions +# + +def open_tag + [id] + { + match lhs [Id:id] + match TS [Top:id Rest:tag_stack] + if Id.data == Top.data { + reject + } else { + TS = construct tag_stack [Id TS] + } + } + +def close_tag + [id] + { + match lhs [Id:id] + match TS [Top:id Rest:tag_stack] + + if Id.data == Top.data { + TS = construct tag_stack [Rest] + } else { + reject + } + } + +def tag + [open_tag tag* close_tag] + +def start + [tag* ';\n'] + { + print_xml( TS ) + print_xml( lhs ) + print( 'got structure\n' ) + } + +| [id* ';\n'] + { + print_xml( TS ) + print_xml( lhs ) + print( 'failed\n' ) + } diff --git a/test/til.in b/test/til.in new file mode 100644 index 00000000..19b7bb19 --- /dev/null +++ b/test/til.in @@ -0,0 +1,14 @@ + +var a; +a := 1; + +head: + +a := a + 1; +c := d; + +if a = 10 then + goto head; +end + +hi := there; diff --git a/test/til.lm b/test/til.lm new file mode 100644 index 00000000..24acd4e3 --- /dev/null +++ b/test/til.lm @@ -0,0 +1,168 @@ +lex start +{ + literal 'var', 'if', 'then', 'else', 'while', 'do', 'for', 'read', 'write', + 'end', 'to', 'goto' + literal ':=', '!=', ';', '+', '-', '*', '/', '=', '(', ')', ':' + + ignore /'//' [^\n]* '\n'/ + ignore /[\n\t ]+/ + token id /[a-zA-Z_]+/ + token integernumber /[0-9]+/ + token stringlit /'"' [^"]* '"'/ +} + +def program + [statement*] + +def statement + [declaration] +| [assignment_statement] +| [if_statement] +| [while_statement] +| [do_statement] +| [for_statement] +| [read_statement] +| [write_statement] +| [labelled_statement] +| [goto_statement] + +def declaration + ['var' id ';'] + +def assignment_statement + [id ':=' expression ';'] + +def if_statement + ['if' expression 'then' statement* opt_else_statement 'end'] + +def opt_else_statement + ['else' statement*] +| [] + +def while_statement + ['while' expression 'do' statement* 'end'] + +def do_statement + ['do' statement* 'while' expression ';'] + +def for_statement + ['for' id ':=' expression 'to' expression 'do' statement* 'end'] + +def read_statement + ['read' id ';'] + +def write_statement + ['write' expression ';'] + +def expression + [term] +| [expression eqop term] + +def eqop ['='] | ['!='] + +def term + [factor] +| [term addop factor] + +def addop ['+'] | ['-'] + +def factor + [primary] +| [factor mulop primary] + +def mulop ['*'] | ['/'] + +def primary + [id] +| [lit] +| ['(' expression ')'] + +def lit + [integernumber] +| [stringlit] + +def labelled_statement + [id ':' statement] + +def goto_statement + ['goto' id ';'] + +program P = parse program(stdin) + +#for S:statement* in P +#{ +# if match S [L0: id ':' +# First: statement +# Rest: statement*] +# { +# for Check: statement* in Rest +# { +# if match Check +# ['if' E: expression 'then' +# 'goto' Targ: id ';' +# 'end' +# T: statement*] +# { +# # This truncates Rest +# Check = construct statement* [] +# +# # Replace the labeled statement through to the goto with a +# # do ... while. +# S = construct statement* +# ['do' +# First +# Rest +# 'while' E ';' +# T] +# break +# } +# } +# } +#} + +for S: statement* in P +{ + if match S [Label: id ':' + First: statement + Rest: statement*] + { + expression Expr + statement* Following + + # Look though the remaining statements for a goto back to the label. + # The repeat iterator yields only top-level statement lists. It + # restricts our search to the same nesting depth as the label. + for Check: statement* in Rest + { + if match Check + ['if' E: expression 'then' + 'goto' L:id ';' + 'end' + SL: statement*] + { + Expr = E + Following = SL + + # Check iterates over tails of Rest. Assigning an empty list + # to check truncates the Rest list. What we cut off is saved in + # Following (excluding the if statement). + Check = construct statement* [] + } + } + + # If a goto was found, then perform the rewrite. + if ( Expr ) + { + # Replace the labelled statement through to the goto + # with a do ... while. + S = construct statement* + ['do' + First + Rest + 'while' Expr ';' + Following] + } + } +} + +print(P, '\n') diff --git a/test/travs1.in b/test/travs1.in new file mode 100644 index 00000000..e6cf5020 --- /dev/null +++ b/test/travs1.in @@ -0,0 +1 @@ +1 | 2 3 diff --git a/test/travs1.lm b/test/travs1.lm new file mode 100644 index 00000000..e5820d8f --- /dev/null +++ b/test/travs1.lm @@ -0,0 +1,144 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start [expression] + +def expression [term expression_op*] + +def expression_op + ['|' term] +| ['&' term] +| ['-' term] +| ['--' term] + +def term [factor_rep term_rest] + +# This list is done manually to get shortest match. +def term_rest + [] +| [term_op term_rest] + +def term_op + [factor_rep] +| ['.' factor_rep] +| [':>' factor_rep] +| [':>>' factor_rep] +| ['<:' factor_rep] + +def factor_rep + [factor_neg factor_rep_op*] + +def factor_rep_op + ['*'] +| ['**'] +| ['?'] +| ['+'] +| ['{' factor_rep_num '}'] +| ['{' ',' factor_rep_num '}'] +| ['{' factor_rep_num ',' '}'] +| ['{' factor_rep_num ',' factor_rep_num '}'] + +def factor_rep_num [uint] + +def factor_neg + ['!' factor_neg] +| ['^' factor_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] + +start S = parse start(stdin) + +# +# Top-Down, Left-Right +# + +int do_topdown_leftright( ref any T ) +{ + for C:any in child(T) { + yield C + do_topdown_leftright( C ) + } +} + +iter topdown_leftright( ref any T ) +{ + do_topdown_leftright( T ) +} + +# +# Bottom-Up, Left-Right +# + +int do_bottomup_leftright( ref any T ) +{ + for C:any in child(T) { + do_bottomup_leftright( C ) + yield C + } +} + +iter bottomup_leftright( ref any T ) +{ + do_bottomup_leftright( T ) +} + + +# +# Top-Down, Right-Left +# + +int do_topdown_rightleft( ref any T ) +{ + for C:any in rev_child(T) { + yield C + do_topdown_rightleft( C ) + } +} + +iter topdown_rightleft( ref any T ) +{ + do_topdown_rightleft( T ) +} + +# +# Bottom-Up, Right-Left +# + +int do_bottomup_rightleft( ref any T ) +{ + for C:any in rev_child(T) { + do_bottomup_rightleft( C ) + yield C + } +} + +iter bottomup_rightleft( ref any T ) +{ + do_bottomup_rightleft( T ) +} + +# +# Testing +# + +for C: expression in bottomup_leftright( S ) +{ + print_xml( C ) +} diff --git a/test/travs2.in b/test/travs2.in new file mode 100644 index 00000000..81d197f3 --- /dev/null +++ b/test/travs2.in @@ -0,0 +1 @@ +1 2 | 3 4 diff --git a/test/travs2.lm b/test/travs2.lm new file mode 100644 index 00000000..06facf3b --- /dev/null +++ b/test/travs2.lm @@ -0,0 +1,93 @@ +lex start +{ + ignore /[\t\n ]+/ + literal '^', '|', '-', ',', ':', '!', '?', '.' + literal '(', ')', '{', '}', '*', '&', '+' + + literal '--', ':>', ':>>', '<:', '->', '**' + + token word /[a-zA-Z_][a-zA-Z0-9_]*/ + token uint /[0-9]+/ +} + + +def start + [expression] + +def expression [term expression_op*] + +def expression_op + ['|' term] +| ['&' term] +| ['-' term] +| ['--' term] + +def term [factor_rep term_rest] + +# This list is done manually to get shortest match. +def term_rest + [] +| [term_op term_rest] + +def term_op + [factor_rep] +| ['.' factor_rep] +| [':>' factor_rep] +| [':>>' factor_rep] +| ['<:' factor_rep] + +def factor_rep + [factor_neg factor_rep_op*] + +def factor_rep_op + ['*'] +| ['**'] +| ['?'] +| ['+'] +| ['{' factor_rep_num '}'] +| ['{' ',' factor_rep_num '}'] +| ['{' factor_rep_num ',' '}'] +| ['{' factor_rep_num ',' factor_rep_num '}'] + +def factor_rep_num [uint] + +def factor_neg + ['!' factor_neg] +| ['^' factor_neg] +| [factor] + +def factor + [alphabet_num] +| [word] +| ['(' expression ')'] + +def alphabet_num + [uint] + +start S = parse start(stdin) + +# +# Fixed point iteration +# + +bool this_iter_modified() + { return true } + +iter fixed_point( ref any T ) +{ + bool modified = true + while modified { + modified = false + for S:any in T { + yield S + + if this_iter_modified() { + modified = true + break + } + } + } +} + +print( S, '\n' ) + diff --git a/test/xml/Makefile b/test/xml/Makefile new file mode 100644 index 00000000..d647261a --- /dev/null +++ b/test/xml/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2002-2006 Adrian Thurston <thurston@complang.org> +# + +# This file is part of Colm. +# +# Colm 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. +# +# Colm 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 Colm; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +SRC = $(wildcard *.lm) +BIN = $(SRC:%.lm=%.bin) +COLM = ../../colm/colm + +all: $(BIN) + +$(BIN): $(COLM) + +$(BIN): %.bin: %.lm + $(COLM) $< + +clean: + rm -f *.cpp *.bin diff --git a/test/xml/xml.in b/test/xml/xml.in new file mode 100644 index 00000000..22882c95 --- /dev/null +++ b/test/xml/xml.in @@ -0,0 +1,3962 @@ +<ragel version="5.24" filename="../colm/lmscan.rl" lang="C"> +<ragel_def name="rlscan"> + <alphtype>char</alphtype> + <machine> + <action_list length="166"> + <action id="0" name="inc_nl" line="217" col="16"><text> + lastnl = p; + column = 0; + line++; + </text></action> + <action id="1" name="initts" line="1" col="1"><init_tokstart></init_tokstart></action> + <action id="2" name="tokstart" line="1" col="1"><set_tokstart></set_tokstart></action> + <action id="3" name="tokend" line="1" col="1"><set_tokend>1</set_tokend></action> + <action id="4" name="last1" line="238" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\0' ); </text></sub_action></action> + <action id="5" name="last2" line="239" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\a' ); </text></sub_action></action> + <action id="6" name="last3" line="240" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\b' ); </text></sub_action></action> + <action id="7" name="last4" line="241" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\t' ); </text></sub_action></action> + <action id="8" name="last5" line="242" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\n' ); </text></sub_action></action> + <action id="9" name="last6" line="243" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\v' ); </text></sub_action></action> + <action id="10" name="last7" line="244" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\f' ); </text></sub_action></action> + <action id="11" name="last8" line="245" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, '\r' ); </text></sub_action></action> + <action id="12" name="last9" line="246" col="13"><set_tokend>1</set_tokend><sub_action><text> updateCol(); </text></sub_action></action> + <action id="13" name="last10" line="247" col="15"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, tokstart+1, tokend ); </text></sub_action></action> + <action id="14" name="last11" line="250" col="10"><set_tokend>1</set_tokend><sub_action><text> token( RE_Dash, 0, 0 ); </text></sub_action></action> + <action id="15" name="last12" line="253" col="10"><set_tokend>1</set_tokend><sub_action><text> token( RE_SqClose ); </text><ret></ret><text> </text></sub_action></action> + <action id="16" name="last13" line="255" col="10"><set_tokend>1</set_tokend><sub_action><text> + scan_error() << "unterminated OR literal" << endl; + </text></sub_action></action> + <action id="17" name="last14" line="260" col="12"><set_tokend>1</set_tokend><sub_action><text> token( RE_Char, tokstart, tokend ); </text></sub_action></action> + <action id="18" name="store15" line="265" col="13"><set_act>15</set_act></action> + <action id="19" name="store16" line="266" col="12"><set_act>16</set_act></action> + <action id="20" name="store17" line="267" col="12"><set_act>17</set_act></action> + <action id="21" name="store18" line="268" col="13"><set_act>18</set_act></action> + <action id="22" name="store19" line="269" col="11"><set_act>19</set_act></action> + <action id="23" name="store20" line="270" col="13"><set_act>20</set_act></action> + <action id="24" name="store21" line="273" col="12"><set_act>21</set_act></action> + <action id="25" name="last24" line="281" col="7"><set_tokend>1</set_tokend><sub_action><text> token( TK_Literal, tokstart, tokend ); </text></sub_action></action> + <action id="26" name="last26" line="284" col="11"><set_tokend>1</set_tokend><sub_action><text> token( RE_SqOpenNeg ); </text><call>166</call><text> </text></sub_action></action> + <action id="27" name="last27" line="286" col="10"><set_tokend>1</set_tokend><sub_action><text> token( '/'); </text><ret></ret><text> </text></sub_action></action> + <action id="28" name="last28" line="289" col="20"><set_tokend>1</set_tokend><sub_action><text> updateCol(); </text></sub_action></action> + <action id="29" name="last29" line="291" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_ColonEquals ); </text></sub_action></action> + <action id="30" name="last30" line="294" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartToState ); </text></sub_action></action> + <action id="31" name="last31" line="295" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllToState ); </text></sub_action></action> + <action id="32" name="last32" line="296" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_FinalToState ); </text></sub_action></action> + <action id="33" name="last33" line="297" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotStartToState ); </text></sub_action></action> + <action id="34" name="last34" line="298" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotFinalToState ); </text></sub_action></action> + <action id="35" name="last35" line="299" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_MiddleToState ); </text></sub_action></action> + <action id="36" name="last36" line="302" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartFromState ); </text></sub_action></action> + <action id="37" name="last37" line="303" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllFromState ); </text></sub_action></action> + <action id="38" name="last38" line="304" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_FinalFromState ); </text></sub_action></action> + <action id="39" name="last39" line="305" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotStartFromState ); </text></sub_action></action> + <action id="40" name="last40" line="306" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotFinalFromState ); </text></sub_action></action> + <action id="41" name="last41" line="307" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_MiddleFromState ); </text></sub_action></action> + <action id="42" name="last42" line="310" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartEOF ); </text></sub_action></action> + <action id="43" name="last43" line="311" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllEOF ); </text></sub_action></action> + <action id="44" name="last44" line="312" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_FinalEOF ); </text></sub_action></action> + <action id="45" name="last45" line="313" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotStartEOF ); </text></sub_action></action> + <action id="46" name="last46" line="314" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotFinalEOF ); </text></sub_action></action> + <action id="47" name="last47" line="315" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_MiddleEOF ); </text></sub_action></action> + <action id="48" name="last48" line="318" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartGblError ); </text></sub_action></action> + <action id="49" name="last49" line="319" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllGblError ); </text></sub_action></action> + <action id="50" name="last50" line="320" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_FinalGblError ); </text></sub_action></action> + <action id="51" name="last51" line="321" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotStartGblError ); </text></sub_action></action> + <action id="52" name="last52" line="322" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotFinalGblError ); </text></sub_action></action> + <action id="53" name="last53" line="323" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_MiddleGblError ); </text></sub_action></action> + <action id="54" name="last54" line="326" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartLocalError ); </text></sub_action></action> + <action id="55" name="last55" line="327" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllLocalError ); </text></sub_action></action> + <action id="56" name="last56" line="328" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_FinalLocalError ); </text></sub_action></action> + <action id="57" name="last57" line="329" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotStartLocalError ); </text></sub_action></action> + <action id="58" name="last58" line="330" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotFinalLocalError ); </text></sub_action></action> + <action id="59" name="last59" line="331" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_MiddleLocalError ); </text></sub_action></action> + <action id="60" name="last61" line="337" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StartCond ); </text></sub_action></action> + <action id="61" name="last62" line="338" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AllCond ); </text></sub_action></action> + <action id="62" name="last63" line="339" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_LeavingCond ); </text></sub_action></action> + <action id="63" name="last64" line="341" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_DotDot ); </text></sub_action></action> + <action id="64" name="last65" line="342" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_StarStar ); </text></sub_action></action> + <action id="65" name="last66" line="343" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_DashDash ); </text></sub_action></action> + <action id="66" name="last67" line="344" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_Arrow ); </text></sub_action></action> + <action id="67" name="last69" line="347" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_ColonGtGt ); </text></sub_action></action> + <action id="68" name="last70" line="348" col="12"><set_tokend>1</set_tokend><sub_action><text> token( TK_LtColon ); </text></sub_action></action> + <action id="69" name="last72" line="354" col="9"><set_tokend>1</set_tokend><sub_action><text> updateCol(); </text></sub_action></action> + <action id="70" name="last73" line="357" col="6"><set_tokend>1</set_tokend></action> + <action id="71" name="last74" line="359" col="10"><set_tokend>1</set_tokend><sub_action><text> token( *tokstart ); </text></sub_action></action> + <action id="72" name="next21" line="273" col="12"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Word, tokstart, tokend ); </text></sub_action></action> + <action id="73" name="next22" line="276" col="13"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_UInt, tokstart, tokend ); </text></sub_action></action> + <action id="74" name="next23" line="277" col="17"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Hex, tokstart, tokend ); </text></sub_action></action> + <action id="75" name="next24" line="281" col="7"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Literal, tokstart, tokend ); </text></sub_action></action> + <action id="76" name="next25" line="283" col="10"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( RE_SqOpen ); </text><call>166</call><text> </text></sub_action></action> + <action id="77" name="next60" line="334" col="11"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Middle ); </text></sub_action></action> + <action id="78" name="next68" line="346" col="12"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_ColonGt ); </text></sub_action></action> + <action id="79" name="next71" line="351" col="15"><set_tokend>0</set_tokend><hold></hold><sub_action><text> updateCol(); </text></sub_action></action> + <action id="80" name="next74" line="359" col="10"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( *tokstart ); </text></sub_action></action> + <action id="81" name="lag22" line="276" col="13"><exec><get_tokend></get_tokend></exec><sub_action><text> token( TK_UInt, tokstart, tokend ); </text></sub_action></action> + <action id="82" name="switch" line="1" col="1"><lm_switch> + <sub_action id="15"><exec><get_tokend></get_tokend></exec><text> token( KW_When ); </text></sub_action> + <sub_action id="16"><exec><get_tokend></get_tokend></exec><text> token( KW_Eof ); </text></sub_action> + <sub_action id="17"><exec><get_tokend></get_tokend></exec><text> token( KW_Err ); </text></sub_action> + <sub_action id="18"><exec><get_tokend></get_tokend></exec><text> token( KW_Lerr ); </text></sub_action> + <sub_action id="19"><exec><get_tokend></get_tokend></exec><text> token( KW_To ); </text></sub_action> + <sub_action id="20"><exec><get_tokend></get_tokend></exec><text> token( KW_From ); </text></sub_action> + <sub_action id="21"><exec><get_tokend></get_tokend></exec><text> token( TK_Word, tokstart, tokend ); </text></sub_action> + </lm_switch></action> + <action id="83" name="last75" line="363" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\a' ); </text></sub_action></action> + <action id="84" name="last76" line="364" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\b' ); </text></sub_action></action> + <action id="85" name="last77" line="365" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\t' ); </text></sub_action></action> + <action id="86" name="last78" line="366" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\n' ); </text></sub_action></action> + <action id="87" name="last79" line="367" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\v' ); </text></sub_action></action> + <action id="88" name="last80" line="368" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\f' ); </text></sub_action></action> + <action id="89" name="last81" line="369" col="12"><set_tokend>1</set_tokend><sub_action><text> litBuf.append( '\r' ); </text></sub_action></action> + <action id="90" name="last82" line="371" col="12"><set_tokend>1</set_tokend><sub_action><text> + litBuf.append( tokstart[1] ); + </text></sub_action></action> + <action id="91" name="last83" line="374" col="10"><set_tokend>1</set_tokend><sub_action><text> + if ( litBuf.length > 0 ) { + token( TK_LitPat, litBuf.data, litBuf.data+litBuf.length ); + litBuf.clear(); + } + token( '"' ); + </text><ret></ret><text> + </text></sub_action></action> + <action id="92" name="last84" line="382" col="9"><set_tokend>1</set_tokend><sub_action><text> + if ( litBuf.length > 0 ) { + litBuf.append( '\n' ); + token( TK_LitPat, litBuf.data, litBuf.data+litBuf.length ); + litBuf.clear(); + } + token( '"' ); + </text><ret></ret><text> + </text></sub_action></action> + <action id="93" name="last85" line="391" col="10"><set_tokend>1</set_tokend><sub_action><text> + if ( litBuf.length > 0 ) { + token( TK_LitPat, litBuf.data, litBuf.data+litBuf.length ); + litBuf.clear(); + } + token( '[' ); + </text><call>10</call><text> + </text></sub_action></action> + <action id="94" name="last86" line="399" col="10"><set_tokend>1</set_tokend><sub_action><text> + litBuf.append( *tokstart ); + </text></sub_action></action> + <action id="95" name="store87" line="406" col="12"><set_act>87</set_act></action> + <action id="96" name="store88" line="407" col="15"><set_act>88</set_act></action> + <action id="97" name="store89" line="408" col="17"><set_act>89</set_act></action> + <action id="98" name="store90" line="409" col="15"><set_act>90</set_act></action> + <action id="99" name="store91" line="410" col="13"><set_act>91</set_act></action> + <action id="100" name="store92" line="411" col="14"><set_act>92</set_act></action> + <action id="101" name="store93" line="412" col="18"><set_act>93</set_act></action> + <action id="102" name="store94" line="413" col="14"><set_act>94</set_act></action> + <action id="103" name="store95" line="414" col="16"><set_act>95</set_act></action> + <action id="104" name="store96" line="415" col="16"><set_act>96</set_act></action> + <action id="105" name="store97" line="416" col="13"><set_act>97</set_act></action> + <action id="106" name="store98" line="417" col="15"><set_act>98</set_act></action> + <action id="107" name="store99" line="418" col="16"><set_act>99</set_act></action> + <action id="108" name="store101" line="420" col="14"><set_act>101</set_act></action> + <action id="109" name="store102" line="421" col="12"><set_act>102</set_act></action> + <action id="110" name="store103" line="422" col="12"><set_act>103</set_act></action> + <action id="111" name="store104" line="424" col="11"><set_act>104</set_act></action> + <action id="112" name="store105" line="425" col="12"><set_act>105</set_act></action> + <action id="113" name="store106" line="426" col="15"><set_act>106</set_act></action> + <action id="114" name="store107" line="427" col="12"><set_act>107</set_act></action> + <action id="115" name="store108" line="428" col="16"><set_act>108</set_act></action> + <action id="116" name="store109" line="429" col="18"><set_act>109</set_act></action> + <action id="117" name="store110" line="430" col="12"><set_act>110</set_act></action> + <action id="118" name="store112" line="432" col="16"><set_act>112</set_act></action> + <action id="119" name="store113" line="433" col="17"><set_act>113</set_act></action> + <action id="120" name="store114" line="434" col="11"><set_act>114</set_act></action> + <action id="121" name="store115" line="435" col="13"><set_act>115</set_act></action> + <action id="122" name="store116" line="436" col="15"><set_act>116</set_act></action> + <action id="123" name="store117" line="437" col="14"><set_act>117</set_act></action> + <action id="124" name="store118" line="438" col="13"><set_act>118</set_act></action> + <action id="125" name="store119" line="439" col="18"><set_act>119</set_act></action> + <action id="126" name="store120" line="440" col="13"><set_act>120</set_act></action> + <action id="127" name="store121" line="441" col="14"><set_act>121</set_act></action> + <action id="128" name="store122" line="442" col="12"><set_act>122</set_act></action> + <action id="129" name="store123" line="443" col="13"><set_act>123</set_act></action> + <action id="130" name="store124" line="444" col="13"><set_act>124</set_act></action> + <action id="131" name="store125" line="445" col="13"><set_act>125</set_act></action> + <action id="132" name="store126" line="446" col="18"><set_act>126</set_act></action> + <action id="133" name="store127" line="447" col="13"><set_act>127</set_act></action> + <action id="134" name="store128" line="448" col="11"><set_act>128</set_act></action> + <action id="135" name="store129" line="449" col="18"><set_act>129</set_act></action> + <action id="136" name="store130" line="450" col="16"><set_act>130</set_act></action> + <action id="137" name="store131" line="453" col="12"><set_act>131</set_act></action> + <action id="138" name="last133" line="457" col="10"><set_tokend>1</set_tokend><sub_action><text> + token( '/' ); + </text><call>168</call><text> + </text></sub_action></action> + <action id="139" name="last134" line="462" col="20"><set_tokend>1</set_tokend><sub_action><text> + token( '"' ); + token( TK_LitPat, tokstart+1, tokend ); + token( '"' ); + </text></sub_action></action> + <action id="140" name="last135" line="468" col="16"><set_tokend>1</set_tokend><sub_action><text> + token( TK_Literal, tokstart, tokend ); + </text></sub_action></action> + <action id="141" name="last136" line="472" col="10"><set_tokend>1</set_tokend><sub_action><text> + token( '"' ); + litBuf.clear(); + </text><call>203</call><text> + </text></sub_action></action> + <action id="142" name="last137" line="477" col="10"><set_tokend>1</set_tokend><sub_action><text> + token( '[' ); + </text><call>10</call><text> + </text></sub_action></action> + <action id="143" name="last138" line="482" col="10"><set_tokend>1</set_tokend><sub_action><text> + token( ']' ); + if ( top > 0 ) + </text><ret></ret><text> + </text></sub_action></action> + <action id="144" name="last139" line="489" col="20"><set_tokend>1</set_tokend><sub_action><text> updateCol(); </text></sub_action></action> + <action id="145" name="last140" line="491" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_ColonEquals ); </text></sub_action></action> + <action id="146" name="last141" line="492" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_DoubleArrow ); </text></sub_action></action> + <action id="147" name="last142" line="493" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_DoubleEquals ); </text></sub_action></action> + <action id="148" name="last143" line="494" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_NotEquals ); </text></sub_action></action> + <action id="149" name="last144" line="495" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_DoubleColon ); </text></sub_action></action> + <action id="150" name="last145" line="496" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_LessEquals ); </text></sub_action></action> + <action id="151" name="last146" line="497" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_GreaterEquals ); </text></sub_action></action> + <action id="152" name="last147" line="498" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_LeftArrow ); </text></sub_action></action> + <action id="153" name="last148" line="499" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_AmpAmp ); </text></sub_action></action> + <action id="154" name="last149" line="500" col="11"><set_tokend>1</set_tokend><sub_action><text> token( TK_BarBar ); </text></sub_action></action> + <action id="155" name="last150" line="502" col="43"><set_tokend>1</set_tokend><sub_action><text> token( *tokstart ); </text></sub_action></action> + <action id="156" name="last152" line="509" col="9"><set_tokend>1</set_tokend><sub_action><text> updateCol(); </text></sub_action></action> + <action id="157" name="last153" line="512" col="6"><set_tokend>1</set_tokend></action> + <action id="158" name="last154" line="514" col="10"><set_tokend>1</set_tokend><sub_action><text> token( *tokstart ); </text></sub_action></action> + <action id="159" name="next100" line="419" col="12"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( KW_Pri ); </text></sub_action></action> + <action id="160" name="next111" line="431" col="14"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( KW_Print ); </text></sub_action></action> + <action id="161" name="next131" line="453" col="12"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Word, tokstart, tokend ); </text></sub_action></action> + <action id="162" name="next132" line="455" col="13"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( TK_Number, tokstart, tokend ); </text></sub_action></action> + <action id="163" name="next151" line="506" col="15"><set_tokend>0</set_tokend><hold></hold><sub_action><text> updateCol(); </text></sub_action></action> + <action id="164" name="next154" line="514" col="10"><set_tokend>0</set_tokend><hold></hold><sub_action><text> token( *tokstart ); </text></sub_action></action> + <action id="165" name="switch" line="1" col="1"><lm_switch> + <sub_action id="87"><exec><get_tokend></get_tokend></exec><text> token( KW_Lex ); </text></sub_action> + <sub_action id="88"><exec><get_tokend></get_tokend></exec><text> token( KW_Action ); </text></sub_action> + <sub_action id="89"><exec><get_tokend></get_tokend></exec><text> token( KW_AlphType ); </text></sub_action> + <sub_action id="90"><exec><get_tokend></get_tokend></exec><text> token( KW_Commit ); </text></sub_action> + <sub_action id="91"><exec><get_tokend></get_tokend></exec><text> token( KW_Undo ); </text></sub_action> + <sub_action id="92"><exec><get_tokend></get_tokend></exec><text> token( KW_Final ); </text></sub_action> + <sub_action id="93"><exec><get_tokend></get_tokend></exec><text> token( KW_Translate ); </text></sub_action> + <sub_action id="94"><exec><get_tokend></get_tokend></exec><text> token( KW_Token ); </text></sub_action> + <sub_action id="95"><exec><get_tokend></get_tokend></exec><text> token( KW_Literal ); </text></sub_action> + <sub_action id="96"><exec><get_tokend></get_tokend></exec><text> token( KW_NonTerm ); </text></sub_action> + <sub_action id="97"><exec><get_tokend></get_tokend></exec><text> token( KW_Uses ); </text></sub_action> + <sub_action id="98"><exec><get_tokend></get_tokend></exec><text> token( KW_Parser ); </text></sub_action> + <sub_action id="99"><exec><get_tokend></get_tokend></exec><text> token( KW_Include ); </text></sub_action> + <sub_action id="101"><exec><get_tokend></get_tokend></exec><text> token( KW_Write ); </text></sub_action> + <sub_action id="102"><exec><get_tokend></get_tokend></exec><text> token( KW_Nfa ); </text></sub_action> + <sub_action id="103"><exec><get_tokend></get_tokend></exec><text> token( KW_Pda ); </text></sub_action> + <sub_action id="104"><exec><get_tokend></get_tokend></exec><text> token( KW_Rl ); </text></sub_action> + <sub_action id="105"><exec><get_tokend></get_tokend></exec><text> token( KW_Cfl ); </text></sub_action> + <sub_action id="106"><exec><get_tokend></get_tokend></exec><text> token( KW_Ignore ); </text></sub_action> + <sub_action id="107"><exec><get_tokend></get_tokend></exec><text> token( KW_End ); </text></sub_action> + <sub_action id="108"><exec><get_tokend></get_tokend></exec><text> token( KW_Pattern ); </text></sub_action> + <sub_action id="109"><exec><get_tokend></get_tokend></exec><text> token( KW_Construct ); </text></sub_action> + <sub_action id="110"><exec><get_tokend></get_tokend></exec><text> token( KW_Red ); </text></sub_action> + <sub_action id="112"><exec><get_tokend></get_tokend></exec><text> token( KW_TypeId ); </text></sub_action> + <sub_action id="113"><exec><get_tokend></get_tokend></exec><text> token( KW_TypeDef ); </text></sub_action> + <sub_action id="114"><exec><get_tokend></get_tokend></exec><text> token( KW_If ); </text></sub_action> + <sub_action id="115"><exec><get_tokend></get_tokend></exec><text> token( KW_Init ); </text></sub_action> + <sub_action id="116"><exec><get_tokend></get_tokend></exec><text> token( KW_Reject ); </text></sub_action> + <sub_action id="117"><exec><get_tokend></get_tokend></exec><text> token( KW_While ); </text></sub_action> + <sub_action id="118"><exec><get_tokend></get_tokend></exec><text> token( KW_Else ); </text></sub_action> + <sub_action id="119"><exec><get_tokend></get_tokend></exec><text> token( KW_SubParser ); </text></sub_action> + <sub_action id="120"><exec><get_tokend></get_tokend></exec><text> token( KW_Next ); </text></sub_action> + <sub_action id="121"><exec><get_tokend></get_tokend></exec><text> token( KW_Match ); </text></sub_action> + <sub_action id="122"><exec><get_tokend></get_tokend></exec><text> token( KW_For ); </text></sub_action> + <sub_action id="123"><exec><get_tokend></get_tokend></exec><text> token( KW_Iter ); </text></sub_action> + <sub_action id="124"><exec><get_tokend></get_tokend></exec><text> token( KW_Find ); </text></sub_action> + <sub_action id="125"><exec><get_tokend></get_tokend></exec><text> token( KW_Root ); </text></sub_action> + <sub_action id="126"><exec><get_tokend></get_tokend></exec><text> token( KW_PrintXML ); </text></sub_action> + <sub_action id="127"><exec><get_tokend></get_tokend></exec><text> token( KW_Then ); </text></sub_action> + <sub_action id="128"><exec><get_tokend></get_tokend></exec><text> token( KW_Do ); </text></sub_action> + <sub_action id="129"><exec><get_tokend></get_tokend></exec><text> token( KW_Namespace ); </text></sub_action> + <sub_action id="130"><exec><get_tokend></get_tokend></exec><text> token( KW_Scanner ); </text></sub_action> + <sub_action id="131"><exec><get_tokend></get_tokend></exec><text> token( TK_Word, tokstart, tokend ); </text></sub_action> + </lm_switch></action> + </action_list> + <action_table_list length="166"> + <action_table id="0" length="2">0 144</action_table> + <action_table id="1" length="1">0</action_table> + <action_table id="2" length="1">140</action_table> + <action_table id="3" length="2">0 139</action_table> + <action_table id="4" length="2">0 28</action_table> + <action_table id="5" length="1">81</action_table> + <action_table id="6" length="1">1</action_table> + <action_table id="7" length="1">2</action_table> + <action_table id="8" length="1">158</action_table> + <action_table id="9" length="1">157</action_table> + <action_table id="10" length="2">0 156</action_table> + <action_table id="11" length="1">141</action_table> + <action_table id="12" length="1">3</action_table> + <action_table id="13" length="1">155</action_table> + <action_table id="14" length="1">138</action_table> + <action_table id="15" length="2">3 137</action_table> + <action_table id="16" length="1">142</action_table> + <action_table id="17" length="1">143</action_table> + <action_table id="18" length="1">163</action_table> + <action_table id="19" length="1">164</action_table> + <action_table id="20" length="1">148</action_table> + <action_table id="21" length="1">153</action_table> + <action_table id="22" length="1">162</action_table> + <action_table id="23" length="1">149</action_table> + <action_table id="24" length="1">145</action_table> + <action_table id="25" length="1">152</action_table> + <action_table id="26" length="1">150</action_table> + <action_table id="27" length="1">147</action_table> + <action_table id="28" length="1">146</action_table> + <action_table id="29" length="1">151</action_table> + <action_table id="30" length="1">165</action_table> + <action_table id="31" length="1">161</action_table> + <action_table id="32" length="2">3 96</action_table> + <action_table id="33" length="2">3 97</action_table> + <action_table id="34" length="2">3 112</action_table> + <action_table id="35" length="2">3 98</action_table> + <action_table id="36" length="2">3 116</action_table> + <action_table id="37" length="2">3 134</action_table> + <action_table id="38" length="2">3 124</action_table> + <action_table id="39" length="2">3 114</action_table> + <action_table id="40" length="2">3 130</action_table> + <action_table id="41" length="2">3 100</action_table> + <action_table id="42" length="2">3 128</action_table> + <action_table id="43" length="2">3 120</action_table> + <action_table id="44" length="2">3 113</action_table> + <action_table id="45" length="2">3 107</action_table> + <action_table id="46" length="2">3 121</action_table> + <action_table id="47" length="2">3 129</action_table> + <action_table id="48" length="2">3 95</action_table> + <action_table id="49" length="2">3 103</action_table> + <action_table id="50" length="2">3 127</action_table> + <action_table id="51" length="2">3 135</action_table> + <action_table id="52" length="2">3 126</action_table> + <action_table id="53" length="2">3 109</action_table> + <action_table id="54" length="2">3 104</action_table> + <action_table id="55" length="2">3 106</action_table> + <action_table id="56" length="2">3 115</action_table> + <action_table id="57" length="2">3 110</action_table> + <action_table id="58" length="1">159</action_table> + <action_table id="59" length="1">160</action_table> + <action_table id="60" length="2">3 132</action_table> + <action_table id="61" length="2">3 111</action_table> + <action_table id="62" length="2">3 117</action_table> + <action_table id="63" length="2">3 122</action_table> + <action_table id="64" length="2">3 131</action_table> + <action_table id="65" length="2">3 136</action_table> + <action_table id="66" length="2">3 125</action_table> + <action_table id="67" length="2">3 133</action_table> + <action_table id="68" length="2">3 102</action_table> + <action_table id="69" length="2">3 101</action_table> + <action_table id="70" length="2">3 119</action_table> + <action_table id="71" length="2">3 118</action_table> + <action_table id="72" length="2">3 99</action_table> + <action_table id="73" length="2">3 105</action_table> + <action_table id="74" length="2">3 123</action_table> + <action_table id="75" length="2">3 108</action_table> + <action_table id="76" length="1">154</action_table> + <action_table id="77" length="1">17</action_table> + <action_table id="78" length="1">16</action_table> + <action_table id="79" length="1">14</action_table> + <action_table id="80" length="1">15</action_table> + <action_table id="81" length="1">13</action_table> + <action_table id="82" length="1">12</action_table> + <action_table id="83" length="1">4</action_table> + <action_table id="84" length="1">5</action_table> + <action_table id="85" length="1">6</action_table> + <action_table id="86" length="1">10</action_table> + <action_table id="87" length="1">8</action_table> + <action_table id="88" length="1">11</action_table> + <action_table id="89" length="1">7</action_table> + <action_table id="90" length="1">9</action_table> + <action_table id="91" length="1">71</action_table> + <action_table id="92" length="1">70</action_table> + <action_table id="93" length="2">0 69</action_table> + <action_table id="94" length="1">27</action_table> + <action_table id="95" length="2">3 24</action_table> + <action_table id="96" length="1">79</action_table> + <action_table id="97" length="1">75</action_table> + <action_table id="98" length="1">25</action_table> + <action_table id="99" length="1">80</action_table> + <action_table id="100" length="1">49</action_table> + <action_table id="101" length="1">37</action_table> + <action_table id="102" length="1">43</action_table> + <action_table id="103" length="1">61</action_table> + <action_table id="104" length="1">55</action_table> + <action_table id="105" length="1">31</action_table> + <action_table id="106" length="1">50</action_table> + <action_table id="107" length="1">38</action_table> + <action_table id="108" length="1">44</action_table> + <action_table id="109" length="1">62</action_table> + <action_table id="110" length="1">56</action_table> + <action_table id="111" length="1">32</action_table> + <action_table id="112" length="1">64</action_table> + <action_table id="113" length="1">65</action_table> + <action_table id="114" length="1">66</action_table> + <action_table id="115" length="1">63</action_table> + <action_table id="116" length="1">73</action_table> + <action_table id="117" length="1">74</action_table> + <action_table id="118" length="1">29</action_table> + <action_table id="119" length="1">78</action_table> + <action_table id="120" length="1">67</action_table> + <action_table id="121" length="1">51</action_table> + <action_table id="122" length="1">39</action_table> + <action_table id="123" length="1">45</action_table> + <action_table id="124" length="1">68</action_table> + <action_table id="125" length="1">57</action_table> + <action_table id="126" length="1">33</action_table> + <action_table id="127" length="1">77</action_table> + <action_table id="128" length="1">53</action_table> + <action_table id="129" length="1">41</action_table> + <action_table id="130" length="1">47</action_table> + <action_table id="131" length="1">59</action_table> + <action_table id="132" length="1">35</action_table> + <action_table id="133" length="1">48</action_table> + <action_table id="134" length="1">36</action_table> + <action_table id="135" length="1">42</action_table> + <action_table id="136" length="1">60</action_table> + <action_table id="137" length="1">54</action_table> + <action_table id="138" length="1">30</action_table> + <action_table id="139" length="1">52</action_table> + <action_table id="140" length="1">40</action_table> + <action_table id="141" length="1">46</action_table> + <action_table id="142" length="1">58</action_table> + <action_table id="143" length="1">34</action_table> + <action_table id="144" length="1">82</action_table> + <action_table id="145" length="1">76</action_table> + <action_table id="146" length="1">26</action_table> + <action_table id="147" length="1">72</action_table> + <action_table id="148" length="2">3 19</action_table> + <action_table id="149" length="2">3 20</action_table> + <action_table id="150" length="2">3 23</action_table> + <action_table id="151" length="2">3 21</action_table> + <action_table id="152" length="2">3 22</action_table> + <action_table id="153" length="2">3 18</action_table> + <action_table id="154" length="1">94</action_table> + <action_table id="155" length="2">0 92</action_table> + <action_table id="156" length="1">91</action_table> + <action_table id="157" length="1">93</action_table> + <action_table id="158" length="1">90</action_table> + <action_table id="159" length="1">83</action_table> + <action_table id="160" length="1">84</action_table> + <action_table id="161" length="1">88</action_table> + <action_table id="162" length="1">86</action_table> + <action_table id="163" length="1">89</action_table> + <action_table id="164" length="1">85</action_table> + <action_table id="165" length="1">87</action_table> + </action_table_list> + <start_state>10</start_state> + <entry_points> + <entry name="or_literal">166</entry> + <entry name="regular_type">168</entry> + <entry name="literal_pattern">203</entry> + <entry name="main">10</entry> + </entry_points> + <state_list length="205"> + <state id="0"> + <trans_list length="3"> + <t>-128 9 0 x</t> + <t>10 10 10 0</t> + <t>11 127 0 x</t> + </trans_list> + </state> + + <state id="1"> + <trans_list length="7"> + <t>-128 9 1 x</t> + <t>10 10 1 1</t> + <t>11 38 1 x</t> + <t>39 39 10 2</t> + <t>40 91 1 x</t> + <t>92 92 2 x</t> + <t>93 127 1 x</t> + </trans_list> + </state> + + <state id="2"> + <trans_list length="3"> + <t>-128 9 1 x</t> + <t>10 10 1 1</t> + <t>11 127 1 x</t> + </trans_list> + </state> + + <state id="3"> + <trans_list length="3"> + <t>-128 9 3 x</t> + <t>10 10 10 3</t> + <t>11 127 3 x</t> + </trans_list> + </state> + + <state id="4"> + <trans_list length="7"> + <t>-128 9 4 x</t> + <t>10 10 4 1</t> + <t>11 33 4 x</t> + <t>34 34 171 x</t> + <t>35 91 4 x</t> + <t>92 92 5 x</t> + <t>93 127 4 x</t> + </trans_list> + </state> + + <state id="5"> + <trans_list length="3"> + <t>-128 9 4 x</t> + <t>10 10 4 1</t> + <t>11 127 4 x</t> + </trans_list> + </state> + + <state id="6"> + <trans_list length="3"> + <t>-128 9 6 x</t> + <t>10 10 168 4</t> + <t>11 127 6 x</t> + </trans_list> + </state> + + <state id="7"> + <trans_list length="7"> + <t>-128 9 7 x</t> + <t>10 10 7 1</t> + <t>11 38 7 x</t> + <t>39 39 171 x</t> + <t>40 91 7 x</t> + <t>92 92 8 x</t> + <t>93 127 7 x</t> + </trans_list> + </state> + + <state id="8"> + <trans_list length="3"> + <t>-128 9 7 x</t> + <t>10 10 7 1</t> + <t>11 127 7 x</t> + </trans_list> + </state> + + <state id="9"> + <trans_list length="7"> + <t>-128 47 168 5</t> + <t>48 57 181 x</t> + <t>58 64 168 5</t> + <t>65 70 181 x</t> + <t>71 96 168 5</t> + <t>97 102 181 x</t> + <t>103 127 168 5</t> + </trans_list> + </state> + + <state id="10" final="t"> + <state_actions>6 7 x</state_actions> + <trans_list length="61"> + <t>-128 -1 10 8</t> + <t>0 0 10 9</t> + <t>1 8 10 8</t> + <t>9 9 11 x</t> + <t>10 10 10 10</t> + <t>11 12 10 8</t> + <t>13 13 11 x</t> + <t>14 31 10 8</t> + <t>32 32 11 x</t> + <t>33 33 12 x</t> + <t>34 34 10 11</t> + <t>35 35 13 12</t> + <t>36 37 10 8</t> + <t>38 38 14 x</t> + <t>39 39 15 12</t> + <t>40 43 10 13</t> + <t>44 44 10 8</t> + <t>45 45 10 13</t> + <t>46 46 10 8</t> + <t>47 47 10 14</t> + <t>48 57 16 x</t> + <t>58 58 17 x</t> + <t>59 59 10 8</t> + <t>60 60 18 x</t> + <t>61 61 19 x</t> + <t>62 62 20 x</t> + <t>63 64 10 8</t> + <t>65 90 21 15</t> + <t>91 91 10 16</t> + <t>92 92 10 8</t> + <t>93 93 10 17</t> + <t>94 94 10 8</t> + <t>95 95 21 15</t> + <t>96 96 10 8</t> + <t>97 97 22 x</t> + <t>98 98 21 15</t> + <t>99 99 33 x</t> + <t>100 100 45 x</t> + <t>101 101 46 x</t> + <t>102 102 50 x</t> + <t>103 104 21 15</t> + <t>105 105 55 x</t> + <t>106 107 21 15</t> + <t>108 108 68 x</t> + <t>109 109 75 x</t> + <t>110 110 79 x</t> + <t>111 111 21 15</t> + <t>112 112 95 x</t> + <t>113 113 21 15</t> + <t>114 114 112 x</t> + <t>115 115 119 x</t> + <t>116 116 132 x</t> + <t>117 117 152 x</t> + <t>118 118 21 15</t> + <t>119 119 157 x</t> + <t>120 122 21 15</t> + <t>123 123 10 8</t> + <t>124 124 164 x</t> + <t>125 125 10 8</t> + <t>126 126 165 12</t> + <t>127 127 10 8</t> + </trans_list> + </state> + + <state id="11" final="t"> + <trans_list length="7"> + <t>-128 8 10 18</t> + <t>9 9 11 x</t> + <t>10 12 10 18</t> + <t>13 13 11 x</t> + <t>14 31 10 18</t> + <t>32 32 11 x</t> + <t>33 127 10 18</t> + </trans_list> + </state> + + <state id="12" final="t"> + <trans_list length="3"> + <t>-128 60 10 19</t> + <t>61 61 10 20</t> + <t>62 127 10 19</t> + </trans_list> + </state> + + <state id="13" final="t"> + <trans_list length="3"> + <t>-128 9 0 x</t> + <t>10 10 10 0</t> + <t>11 127 0 x</t> + </trans_list> + </state> + + <state id="14" final="t"> + <trans_list length="3"> + <t>-128 37 10 19</t> + <t>38 38 10 21</t> + <t>39 127 10 19</t> + </trans_list> + </state> + + <state id="15" final="t"> + <trans_list length="7"> + <t>-128 9 1 x</t> + <t>10 10 1 1</t> + <t>11 38 1 x</t> + <t>39 39 10 2</t> + <t>40 91 1 x</t> + <t>92 92 2 x</t> + <t>93 127 1 x</t> + </trans_list> + </state> + + <state id="16" final="t"> + <trans_list length="3"> + <t>-128 47 10 22</t> + <t>48 57 16 x</t> + <t>58 127 10 22</t> + </trans_list> + </state> + + <state id="17" final="t"> + <trans_list length="5"> + <t>-128 57 10 19</t> + <t>58 58 10 23</t> + <t>59 60 10 19</t> + <t>61 61 10 24</t> + <t>62 127 10 19</t> + </trans_list> + </state> + + <state id="18" final="t"> + <trans_list length="5"> + <t>-128 44 10 19</t> + <t>45 45 10 25</t> + <t>46 60 10 19</t> + <t>61 61 10 26</t> + <t>62 127 10 19</t> + </trans_list> + </state> + + <state id="19" final="t"> + <trans_list length="4"> + <t>-128 60 10 19</t> + <t>61 61 10 27</t> + <t>62 62 10 28</t> + <t>63 127 10 19</t> + </trans_list> + </state> + + <state id="20" final="t"> + <trans_list length="3"> + <t>-128 60 10 19</t> + <t>61 61 10 29</t> + <t>62 127 10 19</t> + </trans_list> + </state> + + <state id="21" final="t"> + <trans_list length="9"> + <t>-128 47 10 30</t> + <t>48 57 21 15</t> + <t>58 64 10 30</t> + <t>65 90 21 15</t> + <t>91 94 10 30</t> + <t>95 95 21 15</t> + <t>96 96 10 30</t> + <t>97 122 21 15</t> + <t>123 127 10 30</t> + </trans_list> + </state> + + <state id="22" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 23 x</t> + <t>100 107 21 15</t> + <t>108 108 27 x</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="23" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 24 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="24" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 25 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="25" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 110 21 15</t> + <t>111 111 26 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="26" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 21 32</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="27" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 111 21 15</t> + <t>112 112 28 x</t> + <t>113 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="28" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 103 21 15</t> + <t>104 104 29 x</t> + <t>105 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="29" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 30 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="30" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 120 21 15</t> + <t>121 121 31 x</t> + <t>122 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="31" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 111 21 15</t> + <t>112 112 32 x</t> + <t>113 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="32" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 33</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="33" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 101 21 15</t> + <t>102 102 34 x</t> + <t>103 110 21 15</t> + <t>111 111 35 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="34" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 21 34</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="35" final="t"> + <trans_list length="12"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 108 21 15</t> + <t>109 109 36 x</t> + <t>110 110 39 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="36" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 108 21 15</t> + <t>109 109 37 x</t> + <t>110 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="37" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 38 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="38" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 35</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="39" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 40 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="40" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 41 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="41" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 42 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="42" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 116 21 15</t> + <t>117 117 43 x</t> + <t>118 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="43" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 44 x</t> + <t>100 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="44" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 36</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="45" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 110 21 15</t> + <t>111 111 21 37</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="46" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 47 x</t> + <t>109 109 21 15</t> + <t>110 110 49 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="47" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 48 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="48" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 38</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="49" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 21 39</t> + <t>101 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="50" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 51 x</t> + <t>106 110 21 15</t> + <t>111 111 54 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="51" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 52 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="52" final="t"> + <trans_list length="12"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 53 x</t> + <t>98 99 21 15</t> + <t>100 100 21 40</t> + <t>101 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="53" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 21 41</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="54" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 21 42</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="55" final="t"> + <trans_list length="16"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 101 21 15</t> + <t>102 102 21 43</t> + <t>103 103 56 x</t> + <t>104 109 21 15</t> + <t>110 110 60 x</t> + <t>111 115 21 15</t> + <t>116 116 66 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="56" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 57 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="57" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 110 21 15</t> + <t>111 111 58 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="58" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 59 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="59" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 44</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="60" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 61 x</t> + <t>100 104 21 15</t> + <t>105 105 65 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="61" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 62 x</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="62" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 116 21 15</t> + <t>117 117 63 x</t> + <t>118 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="63" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 64 x</t> + <t>101 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="64" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 45</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="65" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 46</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="66" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 67 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="67" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 21 47</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="68" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 69 x</t> + <t>102 104 21 15</t> + <t>105 105 70 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="69" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 119 21 15</t> + <t>120 120 21 48</t> + <t>121 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="70" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 71 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="71" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 72 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="72" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 73 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="73" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 74 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="74" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 21 49</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="75" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 76 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="76" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 77 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="77" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 78 x</t> + <t>100 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="78" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 103 21 15</t> + <t>104 104 21 50</t> + <t>105 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="79" final="t"> + <trans_list length="15"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 80 x</t> + <t>98 100 21 15</t> + <t>101 101 87 x</t> + <t>102 102 89 x</t> + <t>103 110 21 15</t> + <t>111 111 90 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="80" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 108 21 15</t> + <t>109 109 81 x</t> + <t>110 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="81" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 82 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="82" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 83 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="83" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 111 21 15</t> + <t>112 112 84 x</t> + <t>113 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="84" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 85 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="85" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 86 x</t> + <t>100 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="86" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 51</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="87" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 119 21 15</t> + <t>120 120 88 x</t> + <t>121 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="88" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 52</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="89" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 21 53</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="90" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 91 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="91" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 92 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="92" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 93 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="93" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 94 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="94" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 108 21 15</t> + <t>109 109 21 54</t> + <t>110 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="95" final="t"> + <trans_list length="14"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 96 x</t> + <t>98 99 21 15</t> + <t>100 100 104 x</t> + <t>101 113 21 15</t> + <t>114 114 105 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="96" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 97 x</t> + <t>115 115 21 15</t> + <t>116 116 100 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="97" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 98 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="98" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 99 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="99" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 21 55</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="100" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 101 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="101" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 102 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="102" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 103 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="103" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 21 56</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="104" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 21 57</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="105" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 106 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="106" final="t"> + <trans_list length="11"> + <t>-128 47 10 58</t> + <t>48 57 21 15</t> + <t>58 64 10 58</t> + <t>65 90 21 15</t> + <t>91 94 10 58</t> + <t>95 95 21 15</t> + <t>96 96 10 58</t> + <t>97 109 21 15</t> + <t>110 110 107 x</t> + <t>111 122 21 15</t> + <t>123 127 10 58</t> + </trans_list> + </state> + + <state id="107" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 108 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="108" final="t"> + <trans_list length="9"> + <t>-128 47 10 59</t> + <t>48 57 21 15</t> + <t>58 64 10 59</t> + <t>65 90 21 15</t> + <t>91 94 10 59</t> + <t>95 95 109 x</t> + <t>96 96 10 59</t> + <t>97 122 21 15</t> + <t>123 127 10 59</t> + </trans_list> + </state> + + <state id="109" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 119 21 15</t> + <t>120 120 110 x</t> + <t>121 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="110" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 108 21 15</t> + <t>109 109 111 x</t> + <t>110 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="111" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 21 60</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="112" final="t"> + <trans_list length="15"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 113 x</t> + <t>102 107 21 15</t> + <t>108 108 21 61</t> + <t>109 110 21 15</t> + <t>111 111 117 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="113" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 21 62</t> + <t>101 105 21 15</t> + <t>106 106 114 x</t> + <t>107 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="114" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 115 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="115" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 116 x</t> + <t>100 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="116" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 63</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="117" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 110 21 15</t> + <t>111 111 118 x</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="118" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 21 64</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="119" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 98 21 15</t> + <t>99 99 120 x</t> + <t>100 116 21 15</t> + <t>117 117 125 x</t> + <t>118 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="120" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 121 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="121" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 122 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="122" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 123 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="123" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 124 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="124" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 21 65</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="125" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 21 15</t> + <t>98 98 126 x</t> + <t>99 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="126" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 111 21 15</t> + <t>112 112 127 x</t> + <t>113 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="127" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 128 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="128" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 129 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="129" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 130 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="130" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 131 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="131" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 113 21 15</t> + <t>114 114 21 66</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="132" final="t"> + <trans_list length="17"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 103 21 15</t> + <t>104 104 133 x</t> + <t>105 110 21 15</t> + <t>111 111 135 x</t> + <t>112 113 21 15</t> + <t>114 114 138 x</t> + <t>115 120 21 15</t> + <t>121 121 145 x</t> + <t>122 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="133" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 134 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="134" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 21 67</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="135" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 106 21 15</t> + <t>107 107 136 x</t> + <t>108 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="136" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 137 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="137" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 21 68</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="138" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 139 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="139" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 140 x</t> + <t>111 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="140" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 141 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="141" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 142 x</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="142" final="t"> + <trans_list length="10"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 97 143 x</t> + <t>98 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="143" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 144 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="144" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 69</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="145" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 111 21 15</t> + <t>112 112 146 x</t> + <t>113 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="146" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 147 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="147" final="t"> + <trans_list length="9"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 148 x</t> + <t>96 96 10 31</t> + <t>97 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="148" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 149 x</t> + <t>101 104 21 15</t> + <t>105 105 151 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="149" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 150 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="150" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 101 21 15</t> + <t>102 102 21 70</t> + <t>103 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="151" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 21 71</t> + <t>101 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="152" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 109 21 15</t> + <t>110 110 153 x</t> + <t>111 114 21 15</t> + <t>115 115 155 x</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="153" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 99 21 15</t> + <t>100 100 154 x</t> + <t>101 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="154" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 110 21 15</t> + <t>111 111 21 72</t> + <t>112 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="155" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 156 x</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="156" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 114 21 15</t> + <t>115 115 21 73</t> + <t>116 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="157" final="t"> + <trans_list length="13"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 103 21 15</t> + <t>104 104 158 x</t> + <t>105 113 21 15</t> + <t>114 114 161 x</t> + <t>115 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="158" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 159 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="159" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 107 21 15</t> + <t>108 108 160 x</t> + <t>109 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="160" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 74</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="161" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 104 21 15</t> + <t>105 105 162 x</t> + <t>106 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="162" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 115 21 15</t> + <t>116 116 163 x</t> + <t>117 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="163" final="t"> + <trans_list length="11"> + <t>-128 47 10 31</t> + <t>48 57 21 15</t> + <t>58 64 10 31</t> + <t>65 90 21 15</t> + <t>91 94 10 31</t> + <t>95 95 21 15</t> + <t>96 96 10 31</t> + <t>97 100 21 15</t> + <t>101 101 21 75</t> + <t>102 122 21 15</t> + <t>123 127 10 31</t> + </trans_list> + </state> + + <state id="164" final="t"> + <trans_list length="3"> + <t>-128 123 10 19</t> + <t>124 124 10 76</t> + <t>125 127 10 19</t> + </trans_list> + </state> + + <state id="165" final="t"> + <trans_list length="3"> + <t>-128 9 3 x</t> + <t>10 10 10 3</t> + <t>11 127 3 x</t> + </trans_list> + </state> + + <state id="166" final="t"> + <state_actions>6 7 x</state_actions> + <trans_list length="8"> + <t>-128 -1 166 77</t> + <t>0 0 166 78</t> + <t>1 44 166 77</t> + <t>45 45 166 79</t> + <t>46 91 166 77</t> + <t>92 92 167 x</t> + <t>93 93 166 80</t> + <t>94 127 166 77</t> + </trans_list> + </state> + + <state id="167" final="t"> + <trans_list length="18"> + <t>-128 9 166 81</t> + <t>10 10 166 82</t> + <t>11 47 166 81</t> + <t>48 48 166 83</t> + <t>49 96 166 81</t> + <t>97 97 166 84</t> + <t>98 98 166 85</t> + <t>99 101 166 81</t> + <t>102 102 166 86</t> + <t>103 109 166 81</t> + <t>110 110 166 87</t> + <t>111 113 166 81</t> + <t>114 114 166 88</t> + <t>115 115 166 81</t> + <t>116 116 166 89</t> + <t>117 117 166 81</t> + <t>118 118 166 90</t> + <t>119 127 166 81</t> + </trans_list> + </state> + + <state id="168" final="t"> + <state_actions>6 7 x</state_actions> + <trans_list length="47"> + <t>-128 -1 168 91</t> + <t>0 0 168 92</t> + <t>1 8 168 91</t> + <t>9 9 169 x</t> + <t>10 10 168 93</t> + <t>11 12 168 91</t> + <t>13 13 169 x</t> + <t>14 31 168 91</t> + <t>32 32 169 x</t> + <t>33 33 168 91</t> + <t>34 34 170 12</t> + <t>35 35 172 12</t> + <t>36 36 173 x</t> + <t>37 37 174 x</t> + <t>38 38 168 91</t> + <t>39 39 175 12</t> + <t>40 41 168 91</t> + <t>42 42 176 x</t> + <t>43 44 168 91</t> + <t>45 45 177 x</t> + <t>46 46 178 x</t> + <t>47 47 168 94</t> + <t>48 48 179 12</t> + <t>49 57 180 x</t> + <t>58 58 182 x</t> + <t>59 59 168 91</t> + <t>60 60 184 x</t> + <t>61 61 168 91</t> + <t>62 62 186 x</t> + <t>63 63 168 91</t> + <t>64 64 187 x</t> + <t>65 90 188 95</t> + <t>91 91 189 x</t> + <t>92 94 168 91</t> + <t>95 95 188 95</t> + <t>96 96 168 91</t> + <t>97 100 188 95</t> + <t>101 101 190 x</t> + <t>102 102 193 x</t> + <t>103 107 188 95</t> + <t>108 108 196 x</t> + <t>109 115 188 95</t> + <t>116 116 199 x</t> + <t>117 118 188 95</t> + <t>119 119 200 x</t> + <t>120 122 188 95</t> + <t>123 127 168 91</t> + </trans_list> + </state> + + <state id="169" final="t"> + <trans_list length="7"> + <t>-128 8 168 96</t> + <t>9 9 169 x</t> + <t>10 12 168 96</t> + <t>13 13 169 x</t> + <t>14 31 168 96</t> + <t>32 32 169 x</t> + <t>33 127 168 96</t> + </trans_list> + </state> + + <state id="170" final="t"> + <trans_list length="7"> + <t>-128 9 4 x</t> + <t>10 10 4 1</t> + <t>11 33 4 x</t> + <t>34 34 171 x</t> + <t>35 91 4 x</t> + <t>92 92 5 x</t> + <t>93 127 4 x</t> + </trans_list> + </state> + + <state id="171" final="t"> + <trans_list length="3"> + <t>-128 104 168 97</t> + <t>105 105 168 98</t> + <t>106 127 168 97</t> + </trans_list> + </state> + + <state id="172" final="t"> + <trans_list length="3"> + <t>-128 9 6 x</t> + <t>10 10 168 4</t> + <t>11 127 6 x</t> + </trans_list> + </state> + + <state id="173" final="t"> + <trans_list length="13"> + <t>-128 32 168 99</t> + <t>33 33 168 100</t> + <t>34 41 168 99</t> + <t>42 42 168 101</t> + <t>43 46 168 99</t> + <t>47 47 168 102</t> + <t>48 62 168 99</t> + <t>63 63 168 103</t> + <t>64 93 168 99</t> + <t>94 94 168 104</t> + <t>95 125 168 99</t> + <t>126 126 168 105</t> + <t>127 127 168 99</t> + </trans_list> + </state> + + <state id="174" final="t"> + <trans_list length="13"> + <t>-128 32 168 99</t> + <t>33 33 168 106</t> + <t>34 41 168 99</t> + <t>42 42 168 107</t> + <t>43 46 168 99</t> + <t>47 47 168 108</t> + <t>48 62 168 99</t> + <t>63 63 168 109</t> + <t>64 93 168 99</t> + <t>94 94 168 110</t> + <t>95 125 168 99</t> + <t>126 126 168 111</t> + <t>127 127 168 99</t> + </trans_list> + </state> + + <state id="175" final="t"> + <trans_list length="7"> + <t>-128 9 7 x</t> + <t>10 10 7 1</t> + <t>11 38 7 x</t> + <t>39 39 171 x</t> + <t>40 91 7 x</t> + <t>92 92 8 x</t> + <t>93 127 7 x</t> + </trans_list> + </state> + + <state id="176" final="t"> + <trans_list length="3"> + <t>-128 41 168 99</t> + <t>42 42 168 112</t> + <t>43 127 168 99</t> + </trans_list> + </state> + + <state id="177" final="t"> + <trans_list length="5"> + <t>-128 44 168 99</t> + <t>45 45 168 113</t> + <t>46 61 168 99</t> + <t>62 62 168 114</t> + <t>63 127 168 99</t> + </trans_list> + </state> + + <state id="178" final="t"> + <trans_list length="3"> + <t>-128 45 168 99</t> + <t>46 46 168 115</t> + <t>47 127 168 99</t> + </trans_list> + </state> + + <state id="179" final="t"> + <trans_list length="5"> + <t>-128 47 168 116</t> + <t>48 57 180 x</t> + <t>58 119 168 116</t> + <t>120 120 9 x</t> + <t>121 127 168 116</t> + </trans_list> + </state> + + <state id="180" final="t"> + <trans_list length="3"> + <t>-128 47 168 116</t> + <t>48 57 180 x</t> + <t>58 127 168 116</t> + </trans_list> + </state> + + <state id="181" final="t"> + <trans_list length="7"> + <t>-128 47 168 117</t> + <t>48 57 181 x</t> + <t>58 64 168 117</t> + <t>65 70 181 x</t> + <t>71 96 168 117</t> + <t>97 102 181 x</t> + <t>103 127 168 117</t> + </trans_list> + </state> + + <state id="182" final="t"> + <trans_list length="4"> + <t>-128 60 168 99</t> + <t>61 61 168 118</t> + <t>62 62 183 x</t> + <t>63 127 168 99</t> + </trans_list> + </state> + + <state id="183" final="t"> + <trans_list length="3"> + <t>-128 61 168 119</t> + <t>62 62 168 120</t> + <t>63 127 168 119</t> + </trans_list> + </state> + + <state id="184" final="t"> + <trans_list length="15"> + <t>-128 32 168 99</t> + <t>33 33 168 121</t> + <t>34 41 168 99</t> + <t>42 42 168 122</t> + <t>43 46 168 99</t> + <t>47 47 168 123</t> + <t>48 57 168 99</t> + <t>58 58 168 124</t> + <t>59 61 168 99</t> + <t>62 62 185 x</t> + <t>63 93 168 99</t> + <t>94 94 168 125</t> + <t>95 125 168 99</t> + <t>126 126 168 126</t> + <t>127 127 168 99</t> + </trans_list> + </state> + + <state id="185" final="t"> + <trans_list length="11"> + <t>-128 32 168 127</t> + <t>33 33 168 128</t> + <t>34 41 168 127</t> + <t>42 42 168 129</t> + <t>43 46 168 127</t> + <t>47 47 168 130</t> + <t>48 93 168 127</t> + <t>94 94 168 131</t> + <t>95 125 168 127</t> + <t>126 126 168 132</t> + <t>127 127 168 127</t> + </trans_list> + </state> + + <state id="186" final="t"> + <trans_list length="13"> + <t>-128 32 168 99</t> + <t>33 33 168 133</t> + <t>34 41 168 99</t> + <t>42 42 168 134</t> + <t>43 46 168 99</t> + <t>47 47 168 135</t> + <t>48 62 168 99</t> + <t>63 63 168 136</t> + <t>64 93 168 99</t> + <t>94 94 168 137</t> + <t>95 125 168 99</t> + <t>126 126 168 138</t> + <t>127 127 168 99</t> + </trans_list> + </state> + + <state id="187" final="t"> + <trans_list length="11"> + <t>-128 32 168 99</t> + <t>33 33 168 139</t> + <t>34 41 168 99</t> + <t>42 42 168 140</t> + <t>43 46 168 99</t> + <t>47 47 168 141</t> + <t>48 93 168 99</t> + <t>94 94 168 142</t> + <t>95 125 168 99</t> + <t>126 126 168 143</t> + <t>127 127 168 99</t> + </trans_list> + </state> + + <state id="188" final="t"> + <trans_list length="9"> + <t>-128 47 168 144</t> + <t>48 57 188 95</t> + <t>58 64 168 144</t> + <t>65 90 188 95</t> + <t>91 94 168 144</t> + <t>95 95 188 95</t> + <t>96 96 168 144</t> + <t>97 122 188 95</t> + <t>123 127 168 144</t> + </trans_list> + </state> + + <state id="189" final="t"> + <trans_list length="3"> + <t>-128 93 168 145</t> + <t>94 94 168 146</t> + <t>95 127 168 145</t> + </trans_list> + </state> + + <state id="190" final="t"> + <trans_list length="13"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 110 188 95</t> + <t>111 111 191 x</t> + <t>112 113 188 95</t> + <t>114 114 192 x</t> + <t>115 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="191" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 101 188 95</t> + <t>102 102 188 148</t> + <t>103 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="192" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 113 188 95</t> + <t>114 114 188 149</t> + <t>115 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="193" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 113 188 95</t> + <t>114 114 194 x</t> + <t>115 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="194" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 110 188 95</t> + <t>111 111 195 x</t> + <t>112 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="195" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 108 188 95</t> + <t>109 109 188 150</t> + <t>110 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="196" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 100 188 95</t> + <t>101 101 197 x</t> + <t>102 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="197" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 113 188 95</t> + <t>114 114 198 x</t> + <t>115 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="198" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 113 188 95</t> + <t>114 114 188 151</t> + <t>115 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="199" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 110 188 95</t> + <t>111 111 188 152</t> + <t>112 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="200" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 103 188 95</t> + <t>104 104 201 x</t> + <t>105 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="201" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 100 188 95</t> + <t>101 101 202 x</t> + <t>102 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="202" final="t"> + <trans_list length="11"> + <t>-128 47 168 147</t> + <t>48 57 188 95</t> + <t>58 64 168 147</t> + <t>65 90 188 95</t> + <t>91 94 168 147</t> + <t>95 95 188 95</t> + <t>96 96 168 147</t> + <t>97 109 188 95</t> + <t>110 110 188 153</t> + <t>111 122 188 95</t> + <t>123 127 168 147</t> + </trans_list> + </state> + + <state id="203" final="t"> + <state_actions>6 7 x</state_actions> + <trans_list length="8"> + <t>-128 9 203 154</t> + <t>10 10 203 155</t> + <t>11 33 203 154</t> + <t>34 34 203 156</t> + <t>35 90 203 154</t> + <t>91 91 203 157</t> + <t>92 92 204 x</t> + <t>93 127 203 154</t> + </trans_list> + </state> + + <state id="204" final="t"> + <trans_list length="14"> + <t>-128 96 203 158</t> + <t>97 97 203 159</t> + <t>98 98 203 160</t> + <t>99 101 203 158</t> + <t>102 102 203 161</t> + <t>103 109 203 158</t> + <t>110 110 203 162</t> + <t>111 113 203 158</t> + <t>114 114 203 163</t> + <t>115 115 203 158</t> + <t>116 116 203 164</t> + <t>117 117 203 158</t> + <t>118 118 203 165</t> + <t>119 127 203 158</t> + </trans_list> + </state> + </state_list> + </machine> +</ragel_def> +<ragel_def name="section_parse"> + <alphtype>int</alphtype> + <machine> + <action_list length="5"> + <action id="0" name="clear_words" line="97" col="21"><text> word = lit = 0; word_len = lit_len = 0; </text></action> + <action id="1" name="store_lit" line="98" col="19"><text> lit = tokdata; lit_len = toklen; </text></action> + <action id="2" name="incl_err" line="101" col="18"><text> scan_error() << "bad include statement" << endl; </text></action> + <action id="3" name="handle_include" line="105" col="2"><text> + #if 0 + char *inclSectionName = word; + char *inclFileName = 0; + + /* Implement defaults for the input file and section name. */ + if ( inclSectionName == 0 ) + inclSectionName = parser->sectionName; + + if ( lit != 0 ) + inclFileName = prepareFileName( lit, lit_len ); + else + inclFileName = fileName; + + /* Check for a recursive include structure. Add the current file/section + * name then check if what we are including is already in the stack. */ + includeStack.append( IncludeStackItem( fileName, parser->sectionName ) ); + + if ( recursiveInclude( inclFileName, inclSectionName ) ) + scan_error() << "include: this is a recursive include operation" << endl; + else { + /* Open the input file for reading. */ + ifstream *inFile = new ifstream( inclFileName ); + if ( ! inFile->is_open() ) { + scan_error() << "include: could not open " << + inclFileName << " for reading" << endl; + } + + Scanner scanner( inclFileName, *inFile, output, parser, + inclSectionName, includeDepth+1 ); + scanner.do_scan( ); + delete inFile; + } + + /* Remove the last element (len-1) */ + includeStack.remove( -1 ); + #endif + </text></action> + <action id="4" name="handle_token" line="152" col="2"><text> + InputLoc loc; + + #ifdef PRINT_TOKENS + cerr << "scanner:" << line << ":" << column << + ": sending token to the parser " << Parser_lelNames[*p]; + cerr << " " << toklen; + if ( tokdata != 0 ) + cerr << " " << tokdata; + cerr << endl; + #endif + + loc.fileName = fileName; + loc.line = line; + loc.col = column; + + parser->token( loc, type, tokdata, toklen ); + </text></action> + </action_list> + <action_table_list length="4"> + <action_table id="0" length="1">2</action_table> + <action_table id="1" length="2">0 1</action_table> + <action_table id="2" length="1">3</action_table> + <action_table id="3" length="1">4</action_table> + </action_table_list> + <start_state>3</start_state> + <error_state>0</error_state> + <entry_points> + <entry name="main">3</entry> + </entry_points> + <state_list length="4"> + <state id="0"> + <trans_list length="0"> + </trans_list> + </state> + + <state id="1"> + <state_actions>x x 0</state_actions> + <trans_list length="3"> + <t>-2147483648 131 x 0</t> + <t>132 132 2 1</t> + <t>133 2147483647 x 0</t> + </trans_list> + </state> + + <state id="2"> + <state_actions>x x 0</state_actions> + <trans_list length="3"> + <t>-2147483648 58 x 0</t> + <t>59 59 3 2</t> + <t>60 2147483647 x 0</t> + </trans_list> + </state> + + <state id="3" final="t"> + <trans_list length="3"> + <t>-2147483648 128 3 3</t> + <t>129 129 1 x</t> + <t>130 2147483647 3 3</t> + </trans_list> + </state> + </state_list> + </machine> +</ragel_def> +<host line="1" col="1">/* + * Copyright 2006-2007 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Ragel. + * + * Ragel 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. + * + * Ragel 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 Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <iostream> +#include <fstream> +#include <string.h> + +#include "colm.h" +#include "lmscan.h" +#include "lmparse.h" +#include "parsedata.h" +#include "avltree.h" +#include "vector.h" + +//#define PRINT_TOKENS + +using std::ifstream; +using std::istream; +using std::ostream; +using std::cout; +using std::cerr; +using std::endl; + +</host> +<write def_name="section_parse" line="45" col="2"><arg>data</arg></write> +<host line="46"> + +void Scanner::sectionParseInit() +{ + </host> +<write def_name="section_parse" line="50" col="5"><arg>init</arg></write> +<host line="51">} + +ostream &Scanner::scan_error() +{ + /* Maintain the error count. */ + gblErrorCount += 1; + cerr << fileName << ":" << line << ":" << column << ": "; + return cerr; +} + +bool Scanner::recursiveInclude( char *inclFileName, char *inclSectionName ) +{ + for ( IncludeStack::Iter si = includeStack; si.lte(); si++ ) { + if ( strcmp( si->fileName, inclFileName ) == 0 && + strcmp( si->sectionName, inclSectionName ) == 0 ) + { + return true; + } + } + return false; +} + +void Scanner::updateCol() +{ + char *from = lastnl; + if ( from == 0 ) + from = tokstart; + //cerr << "adding " << tokend - from << " to column" << endl; + column += tokend - from; + lastnl = 0; +} + +void Scanner::token( int type, char c ) +{ + token( type, &c, &c + 1 ); +} + +void Scanner::token( int type ) +{ + token( type, 0, 0 ); +} + +</host> +<host line="178"> + +void Scanner::token( int type, char *start, char *end ) +{ + char *tokdata = 0; + int toklen = 0; + int *p = &type; + int *pe = &type + 1; + + if ( start != 0 ) { + toklen = end-start; + tokdata = new char[toklen+1]; + memcpy( tokdata, start, toklen ); + tokdata[toklen] = 0; + } + + </host> +<write def_name="section_parse" line="196" col="3"><arg>exec</arg></write> +<host line="197"> + + updateCol(); +} + +void Scanner::endSection( ) +{ + /* Execute the eof actions for the section parser. */ + </host> +<write def_name="section_parse" line="207" col="3"><arg>eof</arg></write> +<host line="208"> +} + +</host> +<host line="516"> + +</host> +<write def_name="rlscan" line="518" col="4"><arg>data</arg></write> +<host line="519"> +void Scanner::do_scan() +{ + int bufsize = 8; + char *buf = new char[bufsize]; + const char last_char = 0; + int cs, act, have = 0; + int top, stack[32]; + bool execute = true; + + sectionParseInit(); + </host> +<write def_name="rlscan" line="530" col="5"><arg>init</arg></write> +<host line="531"> + while ( execute ) { + char *p = buf + have; + int space = bufsize - have; + + if ( space == 0 ) { + /* We filled up the buffer trying to scan a token. Grow it. */ + bufsize = bufsize * 2; + char *newbuf = new char[bufsize]; + + /* Recompute p and space. */ + p = newbuf + have; + space = bufsize - have; + + /* Patch up pointers possibly in use. */ + if ( tokstart != 0 ) + tokstart = newbuf + ( tokstart - buf ); + tokend = newbuf + ( tokend - buf ); + + /* Copy the new buffer in. */ + memcpy( newbuf, buf, have ); + delete[] buf; + buf = newbuf; + } + + input.read( p, space ); + int len = input.gcount(); + + /* If we see eof then append the EOF char. */ + if ( len == 0 ) { + p[0] = last_char, len = 1; + execute = false; + } + + char *pe = p + len; + </host> +<write def_name="rlscan" line="566" col="6"><arg>exec</arg></write> +<host line="567"> + /* Check if we failed. */ + if ( cs == rlscan_error ) { + /* Machine failed before finding a token. I'm not yet sure if this + * is reachable. */ + scan_error() << "scanner error" << endl; + exit(1); + } + + /* Decide if we need to preserve anything. */ + char *preserve = tokstart; + + /* Now set up the prefix. */ + if ( preserve == 0 ) + have = 0; + else { + /* There is data that needs to be shifted over. */ + have = pe - preserve; + memmove( buf, preserve, have ); + unsigned int shiftback = preserve - buf; + if ( tokstart != 0 ) + tokstart -= shiftback; + tokend -= shiftback; + + preserve = buf; + } + } + delete[] buf; + + InputLoc loc; + loc.fileName = "<EOF>"; + loc.line = line; + loc.col = 1; + parser->token( loc, _eof, 0, 0 ); +} + +void scan( char *fileName, istream &input, ostream &output ) +{ + Scanner scanner( fileName, input, output, 0, 0, 0 ); +} +</host> +</ragel> diff --git a/test/xml/xml.lm b/test/xml/xml.lm new file mode 100644 index 00000000..803d4a5d --- /dev/null +++ b/test/xml/xml.lm @@ -0,0 +1,168 @@ +# +# Definitions +# + +rl xml_digit / (0x30..0x39) / + +rl base_char / 0x41..0x5A | 0x61..0x7A / + +rl char / 0x9 | 0xA | 0xD | 0x20..0x7f / + +rl letter / base_char / + +rl name_char / letter | digit | '.' | '-' | '_' | ':' | 0xb7 / + +rl name / (letter | '_' | ':') name_char* / + +# +# Reference definitions. These appear in the +# top level and also in strings. +# + +rl entity_ref_pat / '&' name ';' / + +rl char_ref_pat / '&#' [0-9]+ ';' | '&0x' [0-9a-fA-F]+ ';' / + +# +# Single quotes. +# +lex sq +{ + token sq_close /'\''/ + + # References in single quotes + token sq_entity_ref /entity_ref_pat/ + token sq_char_ref /char_ref_pat/ + + token sq_data / [^<&']+ / + + def sq_item + [ sq_data ] + | [ sq_entity_ref ] + | [ sq_char_ref ] + + # The opening quote belongs to the tag region. + def sq_string + [ '\'' sq_item* sq_close ] +} + +# +# Double quotes. +# +lex dq +{ + token dq_close /'"'/ + + # References in double quotes + token dq_entity_ref /entity_ref_pat/ + token dq_char_ref /char_ref_pat/ + + token dq_data / [^<&"]+ / + + def dq_item + [ dq_data ] + | [ dq_entity_ref ] + | [ dq_char_ref ] + + # The opening quote belongs to the tag region. + def dq_string + [ '"' dq_item* dq_close ] +} + +# +# Tag elements. +# +lex tag +{ + literal '\'', '\"', '=', '\/', '>' + + # Within this region whitespace is not significant. + ignore xml_space / (0x20 | 0x9 | 0xD | 0xA)+ / + + # + # Attributes + # + token attr_name / name / +} + +# +# Top Level +# +lex start +{ + # + # Comments + # + + # Cannot contain '--' + rl char_no_dash / char - '-' / + token comment / '<!--' ( char_no_dash | '-' char_no_dash )* '-->' / + + + # Opening a tag. + literal '<' + + # + # Character Data + # + + token cdata / '<![CDATA[' char* :> ']]>'/ + token char_data / [^<&]+ / + token entity_ref /entity_ref_pat/ + token char_ref /char_ref_pat/ +} + + +def attribute_value + [ sq_string ] +| [ dq_string ] + +def attribute + [ attr_name '=' attribute_value ] + +def empty_tag + [ '<' attr_name attribute* '/' '>' ] + +def close_tag + [ '<' '/' attr_name '>' ] + +def open_tag + [ '<' attr_name attribute* '>' ] + +def tag + [open_tag content close_tag] + +def content_item + [tag] +| [empty_tag] +| [char_data] +| [entity_ref] +| [char_ref] +| [cdata] +| [comment] + +def content + [content_item*] + +def document + [content] + +def start + [document] + +start S = parse start(stdin) + +for Switch:tag in S { + if match Switch + ["<lm_switch>" SwitchContent:content "</lm_switch>"] + { + print( 'SWITCH\n' ) + for Text:tag in SwitchContent { + if match Text + ["<text>" TextContent:content "</text>"] + { + print( ' ', TextContent, '\n' ) + } + } + } +} diff --git a/version.mk b/version.mk new file mode 100644 index 00000000..8272a624 --- /dev/null +++ b/version.mk @@ -0,0 +1,2 @@ +VERSION = 0.1.0 +PUBDATE = June 2008 |