summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2014-10-13 19:14:30 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2014-10-13 19:14:30 +0000
commiteafd7a3974e8605fd02794269db6114a3446e016 (patch)
tree064737b35dbe10f2995753ead92f95bac30ba048
downloadragel-tarball-eafd7a3974e8605fd02794269db6114a3446e016.tar.gz
ragel-6.9ragel-6.9
-rw-r--r--AUTHORS1
-rw-r--r--COPYING340
-rw-r--r--CREDITS50
-rw-r--r--ChangeLog1662
-rw-r--r--DIST6
-rw-r--r--Makefile.am19
-rw-r--r--Makefile.in822
-rw-r--r--README32
-rw-r--r--TODO102
-rw-r--r--aapl/COPYING502
-rw-r--r--aapl/Makefile.am10
-rw-r--r--aapl/Makefile.in474
-rw-r--r--aapl/README6
-rw-r--r--aapl/avlbasic.h65
-rw-r--r--aapl/avlcommon.h1626
-rw-r--r--aapl/avlibasic.h67
-rw-r--r--aapl/avlikeyless.h64
-rw-r--r--aapl/avlimap.h77
-rw-r--r--aapl/avlimel.h79
-rw-r--r--aapl/avlimelkey.h76
-rw-r--r--aapl/avliset.h75
-rw-r--r--aapl/avlitree.h78
-rw-r--r--aapl/avlkeyless.h58
-rw-r--r--aapl/avlmap.h74
-rw-r--r--aapl/avlmel.h74
-rw-r--r--aapl/avlmelkey.h71
-rw-r--r--aapl/avlset.h70
-rw-r--r--aapl/avltree.h73
-rw-r--r--aapl/bstcommon.h814
-rw-r--r--aapl/bstmap.h113
-rw-r--r--aapl/bstset.h86
-rw-r--r--aapl/bsttable.h84
-rw-r--r--aapl/bubblesort.h94
-rw-r--r--aapl/compare.h260
-rw-r--r--aapl/dlcommon.h790
-rw-r--r--aapl/dlist.h64
-rw-r--r--aapl/dlistmel.h71
-rw-r--r--aapl/dlistval.h71
-rw-r--r--aapl/insertsort.h94
-rw-r--r--aapl/mergesort.h140
-rw-r--r--aapl/quicksort.h185
-rw-r--r--aapl/resize.h344
-rw-r--r--aapl/sbstmap.h121
-rw-r--r--aapl/sbstset.h94
-rw-r--r--aapl/sbsttable.h93
-rw-r--r--aapl/svector.h1350
-rw-r--r--aapl/table.h252
-rw-r--r--aapl/vector.h1185
-rw-r--r--aclocal.m41149
-rwxr-xr-xcompile347
-rwxr-xr-xconfigure6064
-rw-r--r--configure.in155
-rw-r--r--contrib/Makefile.am2
-rw-r--r--contrib/Makefile.in398
-rw-r--r--contrib/ragel.m453
-rw-r--r--contrib/ragel.make6
-rw-r--r--contrib/unicode2ragel.rb305
-rwxr-xr-xdepcomp791
-rw-r--r--doc/Makefile.am60
-rw-r--r--doc/Makefile.in561
-rw-r--r--doc/bmconcat.fig78
-rw-r--r--doc/bmnull.fig28
-rw-r--r--doc/bmnum.fig38
-rw-r--r--doc/bmor.fig38
-rw-r--r--doc/bmrange.fig38
-rw-r--r--doc/bmregex.fig109
-rw-r--r--doc/comments1.fig167
-rw-r--r--doc/comments2.fig110
-rw-r--r--doc/conds1.fig96
-rw-r--r--doc/conds2.fig107
-rw-r--r--doc/dropdown.fig107
-rw-r--r--doc/entryguard.fig73
-rw-r--r--doc/exaction.fig64
-rw-r--r--doc/exallact.fig48
-rw-r--r--doc/exconcat.fig217
-rw-r--r--doc/exdoneact.fig51
-rw-r--r--doc/exinter.fig75
-rw-r--r--doc/exnegate.fig52
-rw-r--r--doc/exoption.fig84
-rw-r--r--doc/exor.fig128
-rw-r--r--doc/exoutact1.fig62
-rw-r--r--doc/exoutact2.fig78
-rw-r--r--doc/explus.fig51
-rw-r--r--doc/exstact.fig64
-rw-r--r--doc/exstar.fig77
-rw-r--r--doc/exstrongsubtr.fig120
-rw-r--r--doc/exsubtr.fig141
-rw-r--r--doc/finguard.fig119
-rw-r--r--doc/leftguard.fig94
-rw-r--r--doc/lines1.fig164
-rw-r--r--doc/lines2.fig121
-rw-r--r--doc/lmkleene.fig116
-rw-r--r--doc/opconcat.fig39
-rw-r--r--doc/opor.fig40
-rw-r--r--doc/opstar.fig43
-rw-r--r--doc/ragel-guide.pdfbin0 -> 537069 bytes
-rw-r--r--doc/ragel-guide.tex3709
-rw-r--r--doc/ragel.1.in661
-rw-r--r--doc/smallscanner.fig78
-rw-r--r--doc/stembed.fig72
-rw-r--r--examples/Makefile.am91
-rw-r--r--examples/Makefile.in728
-rw-r--r--examples/README40
-rw-r--r--examples/atoi.cpp120
-rw-r--r--examples/atoi.rl59
-rw-r--r--examples/awkemu.c217
-rw-r--r--examples/awkemu.rl116
-rw-r--r--examples/clang.c456
-rw-r--r--examples/clang.rl150
-rw-r--r--examples/concurrent.cpp986
-rw-r--r--examples/concurrent.rl126
-rw-r--r--examples/cppscan.cpp908
-rw-r--r--examples/cppscan.rl208
-rw-r--r--examples/format.c544
-rw-r--r--examples/format.rl191
-rw-r--r--examples/gotocallret.cpp282
-rw-r--r--examples/gotocallret.rl96
-rw-r--r--examples/mailbox.cpp1563
-rw-r--r--examples/mailbox.rl207
-rw-r--r--examples/params.c374
-rw-r--r--examples/params.rl102
-rw-r--r--examples/pullscan.c294
-rw-r--r--examples/pullscan.rl170
-rw-r--r--examples/rlscan.cpp1055
-rw-r--r--examples/rlscan.rl300
-rw-r--r--examples/statechart.cpp187
-rw-r--r--examples/statechart.rl116
-rwxr-xr-xinstall-sh527
-rwxr-xr-xmissing215
-rw-r--r--ragel.vim153
-rw-r--r--ragel/Makefile.am58
-rw-r--r--ragel/Makefile.in1549
-rw-r--r--ragel/buffer.h55
-rw-r--r--ragel/cdcodegen.cpp1006
-rw-r--r--ragel/cdcodegen.h256
-rw-r--r--ragel/cdfflat.cpp384
-rw-r--r--ragel/cdfflat.h85
-rw-r--r--ragel/cdfgoto.cpp296
-rw-r--r--ragel/cdfgoto.h85
-rw-r--r--ragel/cdflat.cpp851
-rw-r--r--ragel/cdflat.h118
-rw-r--r--ragel/cdftable.cpp436
-rw-r--r--ragel/cdftable.h87
-rw-r--r--ragel/cdgoto.cpp801
-rw-r--r--ragel/cdgoto.h119
-rw-r--r--ragel/cdipgoto.cpp444
-rw-r--r--ragel/cdipgoto.h105
-rw-r--r--ragel/cdsplit.cpp526
-rw-r--r--ragel/cdsplit.h80
-rw-r--r--ragel/cdtable.cpp1096
-rw-r--r--ragel/cdtable.h124
-rw-r--r--ragel/common.cpp381
-rw-r--r--ragel/common.h383
-rw-r--r--ragel/config.h.in25
-rw-r--r--ragel/cscodegen.cpp824
-rw-r--r--ragel/cscodegen.h205
-rw-r--r--ragel/csfflat.cpp389
-rw-r--r--ragel/csfflat.h55
-rw-r--r--ragel/csfgoto.cpp296
-rw-r--r--ragel/csfgoto.h55
-rw-r--r--ragel/csflat.cpp890
-rw-r--r--ragel/csflat.h91
-rw-r--r--ragel/csftable.cpp438
-rw-r--r--ragel/csftable.h56
-rw-r--r--ragel/csgoto.cpp801
-rw-r--r--ragel/csgoto.h89
-rw-r--r--ragel/csipgoto.cpp438
-rw-r--r--ragel/csipgoto.h75
-rw-r--r--ragel/cssplit.cpp518
-rw-r--r--ragel/cssplit.h53
-rw-r--r--ragel/cstable.cpp1123
-rw-r--r--ragel/cstable.h100
-rw-r--r--ragel/dotcodegen.cpp320
-rw-r--r--ragel/dotcodegen.h48
-rw-r--r--ragel/fsmap.cpp879
-rw-r--r--ragel/fsmattach.cpp425
-rw-r--r--ragel/fsmbase.cpp602
-rw-r--r--ragel/fsmgraph.cpp1434
-rw-r--r--ragel/fsmgraph.h1531
-rw-r--r--ragel/fsmmin.cpp732
-rw-r--r--ragel/fsmstate.cpp490
-rw-r--r--ragel/gendata.cpp1159
-rw-r--r--ragel/gendata.h188
-rw-r--r--ragel/gocodegen.cpp775
-rw-r--r--ragel/gocodegen.h181
-rw-r--r--ragel/gofflat.cpp380
-rw-r--r--ragel/gofflat.h58
-rw-r--r--ragel/gofgoto.cpp297
-rw-r--r--ragel/gofgoto.h54
-rw-r--r--ragel/goflat.cpp764
-rw-r--r--ragel/goflat.h80
-rw-r--r--ragel/goftable.cpp441
-rw-r--r--ragel/goftable.h59
-rw-r--r--ragel/gogoto.cpp734
-rw-r--r--ragel/gogoto.h83
-rw-r--r--ragel/goipgoto.cpp477
-rw-r--r--ragel/goipgoto.h75
-rw-r--r--ragel/gotable.cpp977
-rw-r--r--ragel/gotable.h76
-rw-r--r--ragel/gotablish.cpp111
-rw-r--r--ragel/gotablish.h48
-rw-r--r--ragel/inputdata.cpp277
-rw-r--r--ragel/inputdata.h106
-rw-r--r--ragel/javacodegen.cpp1684
-rw-r--r--ragel/javacodegen.h197
-rw-r--r--ragel/main.cpp569
-rw-r--r--ragel/mlcodegen.cpp744
-rw-r--r--ragel/mlcodegen.h206
-rw-r--r--ragel/mlfflat.cpp419
-rw-r--r--ragel/mlfflat.h55
-rw-r--r--ragel/mlfgoto.cpp311
-rw-r--r--ragel/mlfgoto.h51
-rw-r--r--ragel/mlflat.cpp911
-rw-r--r--ragel/mlflat.h91
-rw-r--r--ragel/mlftable.cpp462
-rw-r--r--ragel/mlftable.h56
-rw-r--r--ragel/mlgoto.cpp821
-rw-r--r--ragel/mlgoto.h89
-rw-r--r--ragel/mltable.cpp1131
-rw-r--r--ragel/mltable.h102
-rw-r--r--ragel/parsedata.cpp1466
-rw-r--r--ragel/parsedata.h391
-rw-r--r--ragel/parsetree.cpp2141
-rw-r--r--ragel/parsetree.h772
-rw-r--r--ragel/pcheck.h48
-rw-r--r--ragel/ragel.h120
-rw-r--r--ragel/rbxgoto.cpp831
-rw-r--r--ragel/rbxgoto.h97
-rw-r--r--ragel/redfsm.cpp583
-rw-r--r--ragel/redfsm.h530
-rw-r--r--ragel/rlparse.cpp6934
-rw-r--r--ragel/rlparse.h210
-rw-r--r--ragel/rlparse.kh141
-rw-r--r--ragel/rlparse.kl1513
-rw-r--r--ragel/rlscan.cpp7229
-rw-r--r--ragel/rlscan.h132
-rw-r--r--ragel/rlscan.rl1270
-rw-r--r--ragel/rubycodegen.cpp831
-rw-r--r--ragel/rubycodegen.h174
-rw-r--r--ragel/rubyfflat.cpp488
-rw-r--r--ragel/rubyfflat.h65
-rw-r--r--ragel/rubyflat.cpp873
-rw-r--r--ragel/rubyflat.h99
-rw-r--r--ragel/rubyftable.cpp563
-rw-r--r--ragel/rubyftable.h64
-rw-r--r--ragel/rubytable.cpp1033
-rw-r--r--ragel/rubytable.h124
-rw-r--r--ragel/version.h2
-rw-r--r--ragel/xmlcodegen.cpp1429
-rw-r--r--ragel/xmlcodegen.h192
-rwxr-xr-xtest-driver139
-rw-r--r--test/Makefile.am46
-rw-r--r--test/Makefile.in818
-rw-r--r--test/README13
-rw-r--r--test/atoi1.rl69
-rw-r--r--test/atoi2.rl81
-rw-r--r--test/atoi3.rl75
-rw-r--r--test/awkemu.rl155
-rw-r--r--test/builtin.rl1209
-rw-r--r--test/call1.rl101
-rw-r--r--test/call2.rl116
-rw-r--r--test/call3.rl122
-rw-r--r--test/checkeofact.txl95
-rw-r--r--test/clang1.rl283
-rw-r--r--test/clang2.rl324
-rw-r--r--test/clang3.rl321
-rw-r--r--test/clang4.rl188
-rw-r--r--test/cond1.rl69
-rw-r--r--test/cond2.rl91
-rw-r--r--test/cond3.rl59
-rw-r--r--test/cond4.rl54
-rw-r--r--test/cond5.rl59
-rw-r--r--test/cond6.rl61
-rw-r--r--test/cond7.rl82
-rw-r--r--test/cppscan1.h112
-rw-r--r--test/cppscan1.rl283
-rw-r--r--test/cppscan2.rl404
-rw-r--r--test/cppscan3.rl285
-rw-r--r--test/cppscan4.rl302
-rw-r--r--test/cppscan5.rl275
-rw-r--r--test/cppscan6.rl358
-rw-r--r--test/element1.rl108
-rw-r--r--test/element2.rl83
-rw-r--r--test/element3.rl144
-rw-r--r--test/eofact.h9
-rw-r--r--test/eofact.rl51
-rw-r--r--test/erract1.rl145
-rw-r--r--test/erract2.rl92
-rw-r--r--test/erract3.rl104
-rw-r--r--test/erract4.rl135
-rw-r--r--test/erract5.rl146
-rw-r--r--test/erract6.rl82
-rw-r--r--test/erract7.rl42
-rw-r--r--test/erract8.rl44
-rw-r--r--test/erract9.rl43
-rw-r--r--test/export1.rl59
-rw-r--r--test/export2.rl57
-rw-r--r--test/export3.rl53
-rw-r--r--test/export4.rl59
-rw-r--r--test/fnext1.rl81
-rw-r--r--test/forder1.rl98
-rw-r--r--test/forder2.rl133
-rw-r--r--test/forder3.rl107
-rw-r--r--test/gotocallret1.rl114
-rw-r--r--test/gotocallret2.rl77
-rw-r--r--test/high1.rl180
-rw-r--r--test/high2.rl103
-rw-r--r--test/high3.rl111
-rw-r--r--test/import1.rl73
-rw-r--r--test/include1.rl28
-rw-r--r--test/include2.rl52
-rw-r--r--test/java1.rl48
-rw-r--r--test/java2.rl50
-rw-r--r--test/keller1.rl1075
-rwxr-xr-xtest/langtrans_c.sh111
-rw-r--r--test/langtrans_c.txl335
-rwxr-xr-xtest/langtrans_csharp.sh109
-rw-r--r--test/langtrans_csharp.txl358
-rwxr-xr-xtest/langtrans_d.sh110
-rw-r--r--test/langtrans_d.txl299
-rwxr-xr-xtest/langtrans_java.sh106
-rw-r--r--test/langtrans_java.txl365
-rwxr-xr-xtest/langtrans_ruby.sh96
-rw-r--r--test/langtrans_ruby.txl392
-rw-r--r--test/lmgoto.rl198
-rw-r--r--test/mailbox1.h33
-rw-r--r--test/mailbox1.rl253
-rw-r--r--test/mailbox2.rl173
-rw-r--r--test/mailbox3.rl247
-rw-r--r--test/minimize1.rl81
-rw-r--r--test/patact.rl100
-rw-r--r--test/range.rl74
-rw-r--r--test/recdescent1.rl128
-rw-r--r--test/recdescent2.rl116
-rw-r--r--test/recdescent3.rl117
-rw-r--r--test/repetition.rl293
-rw-r--r--test/rlscan.rl289
-rw-r--r--test/ruby1.rl56
-rwxr-xr-xtest/runtests.in335
-rw-r--r--test/scan1.rl64
-rw-r--r--test/scan2.rl34
-rw-r--r--test/scan3.rl32
-rw-r--r--test/scan4.rl33
-rw-r--r--test/stateact1.rl48
-rw-r--r--test/statechart1.rl100
-rw-r--r--test/strings1.rl193
-rw-r--r--test/strings2.h9
-rw-r--r--test/strings2.rl1349
-rw-r--r--test/testcase.txl192
-rw-r--r--test/tokstart1.rl238
-rw-r--r--test/union.rl193
-rw-r--r--test/xml.rl107
-rw-r--r--test/xmlcommon.rl205
353 files changed, 126944 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..7ca82d0
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+See CREDITS.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..ec0507b
--- /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/CREDITS b/CREDITS
new file mode 100644
index 0000000..67d1875
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,50 @@
+
+ Ragel State Machine Compiler -- CREDITS
+ =======================================
+
+
+* Ragel was designed and written by Adrian Thurston <thurston@complang.org>.
+
+Many others have helped out along the way. My apolgies to anyone who has been
+missed.
+
+* Many thanks to Arbor Networks for supporting development of Ragel.
+
+* Objective-C output and valuable feedback contributed by Erich Ocean.
+
+* D output and many great ideas contributed by Alan West.
+
+* Conditionals inspired by David Helder.
+
+* Java code generation contributions, bug reports, fixes, test cases
+ and suggestions from Colin Fleming.
+
+* Useful discussions and bug reports due to Carlos Antunes.
+
+* Ruby code generation contributed by Victor Hugo Borja.
+
+* C# code generation contributed by Daniel Tang.
+
+* Go code generation contributed by Justine Tunney. Significantly expanded by
+ Anton Ageev
+
+* D2 patch from Johannes Pfau.
+
+* OCaml patch from ygrek.
+
+* Feedback, Packaging, and Fixes provided by:
+
+ Bob Tennent, Robert Lemmen, Tobias Jahn, Cris Bailiff, Buddy Betts,
+ Scott Dixon, Steven Handerson, Michael Somos, Bob Paddock, Istvan Buki,
+ David Drai, Matthias Rahlf, Zinx Verituse, Markus W. Weissmann,
+ Marc Liyanage, Erich Ocean, Alan West, Steven Kibbler, Laurent Boulard,
+ Jon Oberheide, David Helder, Lexington Luthor, Jason Jobe, Colin Fleming,
+ Carlos Antunes, Steve Horne, Matt Mower, Josef Goettgens, Zed Shaw,
+ Marcus Rueckert, Jeremy Hinegardner, Aaron Campbell, Josh Purinton,
+ Judson Lester, Barry Arthur, Tim Potter, Ryan Phelps, David Waite,
+ Kenny MacDermid, MenTaLguY, Manoj Rajagopalan, Tim Chklovski,
+ Mikkel Fahnøe Jørgensen, Andrei Polushin, Evan Phoenix, David Balmain,
+ Ross Thomas, Mitchell Foral, John D. Mitchell, Diego 'Flameeyes' Pettenò,
+ Jose Quinteiro, William Morgan, _why, Iñaki Baz Castillo, Attila Sztupák,
+ Ismael Luceno, Josh Stern, Denis Naumov, Anton Ageev, Kamil Klimkiewicz,
+ Hesham Wahba
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..2d28e52
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1662 @@
+Ragel 6.9 - Oct 13, 2014
+========================
+ -updated command-line synopsis
+ -ocaml: fix missing semicolon
+ -ocaml: support -G1
+ -ocaml: choose a unique name for type state
+ -ruby: reduce the amount of calls to GET_WIDE_KEY()
+ -union test case: warning fix
+ -omit line directives around expression-oriented write statements
+ -use AS_IF and test command to check if the DIST file is present
+ -added missing std:: using
+ -go: added '//line' directive support
+
+Ragel 6.8 - Feb 11, 2013
+========================
+
+ -The -G2 code generator for Go1 was rewritten. Table, flat and switch-based
+ code generators were added. (Anton Ageev)
+ -The CXXFLAGS variable is not longer set in the configure script.
+
+Ragel 6.7 - May 22, 2011
+========================
+ -The C vim file now supports L,l on the end of literal numbers, other syntax
+ highlighting fixes.
+ -Added an explicit cast when modifying _trans to eliminate compiler warnings
+ on Windows/VC++
+ -Fix for ruby 1.9 compatibility.
+ -Fix for include directories (-I option) on Windows/VC++
+ -Can now rename data variable in C# code generator.
+ -Fix for non-char alphtype in C# code generator.
+ -Fix for signedness of wide char in C code generator. when comparing the wide
+ type against a literal we need to pick the right signedness for the literal.
+ -Fixed arithmetic overflow in generated C# code. The C# _acts and _nacts vars
+ should not be typed based on the size of the array elements they point to.
+ Fixes a bug reported by Attila Sztupák.
+ -Made the -L option work for Ruby.
+ -Enhanced ragel.m4 (from Diego).
+ -Applied GO patch from Justine Tunney.
+ -Applied D2 patch from Johannes Pfau.
+ -Applied Ocaml patch from ygrek.
+
+Ragel 6.6 - Dec 2, 2009
+=======================
+ -Applied a number of patches from Diego Elio 'Flameeyes' Pettenò. Should not
+ be modifying the program's arguments. Problem raised by const correctness in
+ gcc 4.4. Other const-correctness and include fixes provided.
+ -Fixed improper allocation of checks in makeIncludePathChecks.
+ -Fixed segfault when there are no machine instantiations.
+ -Fixed wrong line directives. Line directives need to use the fileName stored
+ in the InputLoc stuctures from the parse trees, not the root source file,
+ otherwise actions in included files will have the wrong source file names
+ associated with the text.
+ -Made a number of build system improvements. We locate the DIST file using
+ $srcdir and source it. It contains settings for build_parsers and
+ build_manual. This allows the user of a dist to enable only one.
+ -Added missing files to doc/Makefile.am and examples/Makefile.am.
+ -Added checks for pdflatex and fig2dev is build_manual is on.
+ -Use automake --foreign so we don't need to have INSTALL and NEWS present.
+ -Ragel VIM syntax files should be specialized by host language. Updated the
+ VIM syntax files.
+ -Added examples to the dist. Added unicode2ragel.rb to EXTRA_DIST in contrib.
+ -Moved unicode2ragel.rb to the contrib directory.
+
+Ragel 6.5 - May 18, 2009
+========================
+ -Fixed a bug in graphviz generation. Ragel crashed when using -V and -M and
+ the specified machine referenced another machine that wasn't included in the
+ build.
+ -The name "CS" is in use on OpenSolaris, changed to vCS to ease compiling
+ Ragel there.
+ -Converted to automake.
+ -REALLY fixed a bug that was intended to be fixed in 6.4:
+ Fixed a problem reading hex numbers that have the high bit set when the
+ alphabet is signed and we are on 64 bit. This was reported by _why. The
+ fix was provided by Wialliam Morgan. The literal 0xffffffff was used for
+ a fully set long when -1L should be used instead.
+ A null patch (whitespace changes) must have gotten checked after I was
+ testing with and without the critical one-line patch and I forgot to enable
+ make sure it was enabled in the final checkin version.
+
+Ragel 6.4 - Mar 22, 2009
+========================
+ -Moved back to a single executable. The old intermediate format can still be
+ generated using the -x option. Ragel was split into frontend and backend
+ programs in version 5.0. This was done to encourage interoperability with
+ other tools. Since then, ragel has been made to work with qfsm, with ragel
+ producing the intermediate format and qfsm consuming it. However, there has
+ been no use of Ragel as a consumer of state machine data, with Ragel used as
+ a code generator for DFAs. This is not surprising given that much of the
+ complexity of Ragel is in the frontend, where the regular language to DFA
+ compilation happens. Since the full benefits of the split have not
+ materialized, and the split increases the complexity for users, Ragel has
+ been made once again into a single executable.
+ -Applied a fix to the documentation Makefile from John D. Mitchell.
+ -Use CXXFLAGS instead of CFLAGS for C++ compiling. Patch from Diego
+ 'Flameeyes' Pettenò.
+ -Added support for DESTDIR variable. Patch from Diego 'Flameeyes' Pettenò.
+ -Added a script called unicode2ragel.rb for generating unicode machines to
+ the examples directory. From Rakan El-Khalil.
+ -Fixed a copy-paste error in the documentation that was reported by Jose
+ Quinteiro.
+ -Added three new write commands:
+ write start;
+ write first_final;
+ write error;
+ These generate a reference to the start, first final and error state. When
+ there are many different machine specifications in one file it is easy to
+ get the prefix for these wrong (especially when you do a lot of copy-pasting
+ of boilerplate). The problem can be avoided by using write commands.
+ -Fixed a problem reading hex numbers that have the high bit set when the
+ alphabet is signed and we are on 64 bit. This was reported by _why. The fix
+ was provided by Wialliam Morgan. The literal 0xffffffff was used for a fully
+ set long when -1L should be used instead.
+
+Ragel 6.3 - Aug 29, 2008
+========================
+ -Fixed an assertion that is too strong. In the condition code we need to copy
+ transitions that have non-empty lmActionTable arrays so we don't assert
+ emptiness in the constructor. Lift out the assertion and copy the array in
+ the constructor.
+ -Fixed and improved multiple include prevention. We now track the entire
+ include history of a parser state to prevent duplicates.
+ -Fixed crash on failed lookup of goto/call/etc target.
+
+Ragel 6.2 - May 9, 2008
+=======================
+ -Bug fix: The lm_switch actions needs to set p from tokend when there is no
+ user action.
+ -Bug fix: when not using indicies we can't use a transitions's id to identify
+ the eof transition to take. Instead add the transition to the end of the
+ transition list and store its position in a new var called pos. The pos var
+ is then used as the index.
+ -Bug fix: an fnext followed by an fbreak in -G2 was not working. The fbreak
+ was not aware that the fnext causes the cs variable to be forced active. In
+ this case fbreak does not need to save cs because it is already current.
+ -Bug fix: need to compute the low and high character-space keys from the
+ condition-trans overlap when computing an expansion. Can't use the range
+ supplied from the condition overlap since they may not match. An incorrect
+ machine that accepted 1(!cond1, !cond2) was generated for the following
+ grammar. This bug was reported by Tim Chklovski.
+ c = 2 @matched_c;
+ sc1 = 1..2 when cond1;
+ sc2 = 1..2 when cond2;
+ main := sc1 | c | sc2;
+ -Bug fix: error messages in start label analysis of join operations were
+ causing assertion failures because location info was not set. Fixed by
+ adding locations.
+ -Include and import file searching now searches for the file name given based
+ on the location of the current file, not ragel's current path.
+ Additional search locations can be given using the -I option.
+ -Rubinius code generation was updated to the latest Rubinius. Patch from Evan
+ Phoenix.
+ -Switched from strcasecmp to strcmp for testing long arguments.
+ -Applied a patch from Andrei Polushin for setting the error message format.
+ --error-format=gnu (default)
+ --error-fromat=msvc
+ -Now using the _WIN32 define instead of _WIN32. Other MSVC compilation
+ improvments from Andrei Polushin.
+ -Added the hyperref package to the manual.
+
+Ragel 6.1 - Mar 26, 2008
+========================
+ -Scanners now ensure that any leaving actions at the end of a pattern are
+ executed. They are always executed before the pattern action.
+ -Added an option -d for turning off the removal of duplicate actions from
+ actions lists.
+ -Need to unset the final state status of the start state in kleene star if it
+ is set. It is possible to crash ragel when the warning is ignored.
+ -In the dot file generation we need to print any actions that are in
+ State::eofTrans. These come from scanners only.
+ -Use @docdir@ for the docdir Makefile variable.
+ -Check for ar and ranlib in the configure script.
+
+Ragel 6.0 - Jan 12, 2008
+========================
+ -Removed the 'noend' write option from examples/atoi.rl. This example is
+ referenced a lot as a first example and as such it shouldn't contain a
+ special purpose write option like 'noend'.
+ -Introcuded the "eof" variable for indicating the end of file. The p variable
+ is checked against eof when the processing loop reaches the end of a block.
+ If p == eof at this time then the EOF actions are executed. The variable is
+ required only when EOF actions have been emebedded.
+ -The "write eof" command is no longer needed and was removed.
+ -Scanners now use EOF actions to generate tokens. This eliminates the need to
+ flush the last token.
+ -Restructured the Java driver; a switch statement with fallthrough cases are
+ now used to emulate gotos.
+ -Ruby code generation was also restructured. Gotos are elmulated using a
+ series of if tests.
+ -Went back to 3.X semantics for >, % and error actions. The > operator also
+ embeds a leaving action/priority into the start state if it is final. If EOF
+ happens in a state with a leaving operator then the leaving action is
+ executed. If EOF happens in a non-final state that has an error action, the
+ error action is executed.
+ -The "ragel" program now executes frontend and backend processes separately,
+ connecting them with a temporary file in the current directory. Without the
+ -x option the "ragel" program marshals arguments and calls the frontend and
+ backend. With the -x option the "ragel" program acts as the frontend only.
+ -Added name finding for executables. If any forward slash is found in argv0
+ then it is assumed that the path is explicit and the path to the backend
+ executable should be derived from that. Whe check that location and also go
+ up one then inside a directory of the same name in case we are executing
+ from the source tree. If no forward slash is found it is assumed the file is
+ being run from the installed location. The PREFIX supplied during
+ configuration is used.
+ -On windows GetModuleFileNameEx is used to find out where the the current
+ process's binary is. That location is searched first. If that fails then we
+ go up one directory and look for the executable inside a directory of the
+ same name in case we are executing from the source tree.
+ -Changed the -l option in rlgen-cd to -L because it is covered in the
+ frontend. Added a passthrough in the frontend for the backend options.
+ -Dot file generation can now be invoked using the -V option to ragel. We
+ now require an input file. If standard in is used then we don't have a file
+ name on which to base the output.
+ -Able to build native windows executables using Cygwin+MinGW.
+ -Patch from David Waite: Large arrays are now created by copying in the data
+ from smaller arrays using System.arraycopy(). This eliminates the debug data
+ associated with explicit initialization statements. It is also much easier
+ on the java compiler which can run out of memory compiling very large
+ machines. The downside is that it takes slightly longer to initialize static
+ data at run time.
+ -The fbreak statement now advances p.
+ -In the :> :>> and <: operators it was possible for the priority assignment
+ to be bypassed via the zero length string. In :> this was fixed
+ automatically with the semantics change to the entering priority operator.
+ If the start state is final it now embeds a leaving action into it,
+ preventing persistance through the zero length string. In :>> and <: this
+ was fixed explicitly. With <: the entering priority operator was used and
+ with :> a special exception was added. Since it uses the finishing
+ transition operator it also adds a leaving priority to the start state if it
+ is final.
+ -Ranlib is now run on the archives. Patch from Kenny MacDermid.
+ -The case statement syntax in ruby code generation used a form depreciated in
+ Ruby 1.9. Updated it.
+ -Made a number of fixes that eliminate warnings in GCC 4.3. Mostly concern
+ the now depreciate automatic conversion of string contsants to "char*" type.
+ Other fixes include adding parenthesis around && within ||.
+ -The "tokstart" and "tokend" variables were changed to "ts" and "te".
+
+Ragel 5.25 - Dec 24, 2007
+=========================
+ -Fixed segfault reported by Ryan Phelps. Affected Java and Ruby code
+ generation. The dataExpr variable was not initialized.
+ -Fixed incorrect case label in test/runtests. Caused Objective-C tests to be
+ ignored.
+ -Added missing include to common.cpp.
+
+Ragel 5.24 - Sep 16, 2007
+=========================
+ -Applied patch from Victor Hugo Borja <vic@rubyforge.org>. This patch
+ implements -T1 -F0 -F1 and -G0 in the ruby code generator. Goto-driven code
+ generation is experimental and requires rubinius asm directives (specify
+ with --rbx option). These code generators pass all the ruby tests.
+ -If the condition embedding code runs out of available characters in the
+ keyspace an error message is emitted.
+ -The first example that appeared in the manual used the special-purpose
+ 'noend' write option. This caused confusion. Now a basic example appears
+ first.
+ -Added two new statements: prepush and postpop. These are code blocks that
+ are written out during call and return statements. The prepush code is
+ written immediately before pushing the current state to the state stack
+ during a call. The postpop code is written immediately after popping the
+ current state during return. These can be used to implement a dynamically
+ resizable stack.
+
+Ragel 5.23 - Jul 24, 2007
+=========================
+ -Eliminated the use of callcc as an alternative to goto. Instead, the named
+ breaks implementation used in the Java code generator is imitated using
+ control flow variables.
+ -Improved the error message given when there is a write statement but no
+ machine instantiations and hence no state machine.
+ -Documentation improvements: updates to "Machine Instantiation", "Write Init"
+ and "Write Exports" sectons. Added the "Variables Used by Ragel" section.
+ -Renamed "Entering Actions" to "Starting Actions."
+ -Other documentation updates.
+
+Ragel 5.22 - June 14, 2007
+==========================
+ -Bug fix: need to isolate the start state of a scanner before setting the
+ to-state and from-state actions which clear and set tokstart. This affected
+ very simple scanners only. Most scanners have an isolated start state due to
+ the pattern structure.
+ -Bug fix: when -S or -M was given the ragel version number was not emitted,
+ causing the backend to reject the intermediate format. From Tim Potter.
+ -The p varialbe is now set up at the beginning of a scanner action, rather
+ than at the end. This leaves scanner actions free to manipulate p and
+ removes the need for the special holdTE and execTE (TE for tokend) versions
+ of hold and exec. It also removes the need to set p = tokend-1 immediately
+ before any control flow. We loose the ability to determine where in the
+ input stream a scanner action is executed, however this information is of
+ little use because it is primarily an artifact of the scanner implementation
+ (sometimes the last char, other times later on). The gains of this change
+ are consistency and simplicity.
+ -The "data" variable (used in Java and Ruby code generation only) can now be
+ overridden using the variable statement.
+
+Ragel 5.21 - May 9, 2007
+========================
+ -Fixed an inconsistency in the value of p following an error. In the C
+ directly executable code (rlgen-cd -G2) p is left at the character where
+ the error occurred, which is correct. In all other code generators it was
+ left at the following character. This was fixed. Now in all code generators
+ p is left at the character where the error occurred.
+ -Bug fix: when fhold was used in scanner pattern actions which get executed
+ on the last character of the pattern (pattern matches which do not require
+ any lookahead), fhold was modifying p instead of tokend. This was fixed and
+ the patact.rl test was modified to cover the case.
+ -Fixed typos in the guide, improved the state action embedding operator
+ section and added subsections on the variable, import, and export
+ statements.
+ -Implemented a better solution than the pri hack for resolving the '-'
+ ambiguity: force a shortest match of term.
+ -Fixed bugs in the binary searching for condition keys in both the Ruby and
+ Java code generation.
+ -Can now embed the negative sense of a condition. Added a language-
+ independent test case for this feature and the necessary transformation
+ support.
+ -Added new condition embedding syntax:
+ expr inwhen cond - The transitions into the machine (starting transitions).
+ expr outwhen cond - The pending transitions out of the machine.
+ -The argument to the variable statement which affects the name of the current
+ state variable was changed from "curstate" to "cs" (the default name used
+ for the current state)
+ -Implemented the other variables names in the variable statement. Now all
+ variables (p, pe, cs, top, stack, act, tokstart, tokend) can be renamed.
+ -Parse errors in the intermediate XML file now cause the backend to exit
+ immediately rather then forge on. The recovery infrastructure isn't there
+ and segfaults are likely.
+ -When no input is given to the backend program, it should not print an error
+ message, it should just return a non-zero exit status. The assumption is
+ that the frontend printed an error.
+ -The version number is now included in the intermediate file. An error is
+ emitted if there is a mismatch.
+ -The alphabet type is now communicated from the frontend to the backend using
+ a one-word internal name instead of an array offset.
+ -The Ruby host language types had been just copied from Java. Reduced them to
+ two basic types: char and int, both signed with the usual C sizes.
+
+Ragel 5.20 - Apr 7, 2007
+========================
+ -The cs variable is now always initialized, unless the "nocs" option is given
+ to the write init command. If there is no main machine, cs is initialized to
+ the entry point defined by the last machine instantiation.
+ -A number of fixes were made to the Ruby code generator.
+ -The frontend now scans ruby comments and regular expressions.
+ -A transformation for Ruby was added to the language-independent test suite.
+ The Ruby code generator passes on all the language-independent tests.
+ -A new Ruby test and two language-independent tests were added.
+ -Some portability fixes were made (Patches from Josef Goettgens and Aaron
+ Campbell).
+ -Fixed a make dependency bug which caused a problem for parallel building
+ (Patch from Jeremy Hinegardner).
+
+Ragel 5.19 - Mar 14, 2007
+=========================
+ -Added an import statement to ragel. This statement takes a literal string as
+ an argument, interprets it as a file name, then scrapes the file for
+ sequences of tokens that match the following forms. Tokens inside ragel
+ sections are ignored. An example is in test/import1.rl
+ name = number
+ name = lit_string
+ "define" name number
+ "define" name lit_string
+ -Added an export mechanism which writes defines for single character machines
+ that have been tagged with the export keyword in their definition. Defines
+ are used for C, ints for D, Java and Ruby. Examples of the export feature
+ are in test/export*.rl.
+ -All machine instantiations are now always generated, even if they are not
+ referenced. In the backend, entry points for all instantiations are written
+ out alongside start, error and first final states.
+ -If the main machine is not present then do not emit an error. Generate the
+ machine without a start state and do not initialize cs in the write init
+ code.
+ -Added an option -l to rlgen-cd which inhibits the writing of #line
+ directives.
+ -Added a new syntax for verbose embeddings. This adds parentheses:
+ $from(action_name);
+ Verbose embeddings without parentheses can make code difficult to read
+ because they force a space in the middle of an action embedding. There is a
+ tendency to associtate spaces with concatenation. Without syntax
+ highlighting to make it clear that the embedding type is a keyword, the
+ problem is especially bad. The danger is that a verbose embedding could be
+ read as an embedding of the keyword representing the empbedding type. With
+ parentheses, verbose embeddings read much more clearly.
+ -Conditions now have a forced order when more than one is executed on a
+ single character. Previously ordering relied on pointers, which caused
+ results to vary by compiler. Ordering is now done using conditon action
+ declaration order. This fixes the failure of cond4.rl which occured with
+ g++ 4.1 and other compiler versions.
+ -In the port from flex to ragel, the name separator :: in Ragel code was
+ lost. Added it back.
+ -In the examples directory switched from rlcodegen to rlgen-cd. Silenced a
+ warning in statechart.rl.
+ -In the root makefile the distclean target was fixed. It was calling clean in
+ the subdirs. In docs, the clean target was not deleting the new manpages for
+ the rlgen-* programs. Fixed.
+ -Portability and other fixes from Josef Goettgens were applied.
+ -The @datadir@ and @mandir@ variables are made use of in doc/Makefile.in for
+ specifying where documentation should be installed. Patch from Marcus
+ Rueckert.
+
+Ragel 5.18 - Feb 13, 2007
+=========================
+ -There is now a 100% correspondence between state id numbers in the
+ intermediate XML file, Graphviz dot files and generated code. This was
+ achieved by moving code which determines if the error state is necessary
+ into the frontend, and then assigning state numbers before writing out the
+ intermediate file.
+ -Backened class structure was reorganized to make it easier to add new code
+ generators without having to also modify the existing code generators.
+ -The C and D code generation executable was changed to rlgen-cd.
+ -The Java code generation was split out into it's own exectuable (rlgen-java)
+ to allow it to freely diverge from the C/D-based code generation.
+ -The graphviz dot file generation was also split out to it's own executable
+ (rlgen-dot).
+ -The Ruby code generation patch from Victor Hugo Borja was added. This is
+ highly experimental code and is not yet completely functional. It is in the
+ executable rlgen-ruby.
+ -The problem with large state machine machines in Java was fixed. This
+ problem was discovered by Colin Fleming, who also contributed a patch.
+ Rather than specify arrays as comma-separated lists of literals, array
+ initialization is now done in a static function. This is the approach used
+ by the Java compiler. Unlike the compiler Ragel is careful split large
+ initilization functions.
+ -The manual was expanded and reorganized somewhat.
+ -Eliminated per-example directories in examples/.
+ -Made some fixes to the pullscan.rl example.
+ -In the frontend CR characters are now treated as whitespace.
+ -Updated to the latest aapl. This completely eliminates the shallowCopy
+ function. With that, a definitive memory leak is fixed.
+ -Control codes with escape sequences are now printable characters (-p
+ option). Also, the space character is now printed as SP.
+ -Fixed the null dereference and consequential segfault which occurred when
+ trying to create empty machines with [] and // and /a[]b/.
+ -Fixed the segfault which occured when a machine reference failed.
+ -Discontinuing ragel.spec. It is more appropriate for this to be written by
+ package maintenance developers.
+
+Ragel 5.17 - Jan 28, 2007
+=========================
+ -The scanners and parsers in both the frontend and backend programs were
+ completely rewritten using Ragel and Kelbt.
+ -The '%when condition' syntax was functioning like '$when condition'. This
+ was fixed.
+ -In the Vim syntax file fixes to the matching of embedding operators were
+ made. Also, improvements to the sync patterns were made.
+ -Added pullscan.rl to the examples directory. It is an example of doing
+ pull-based scanning. Also, xmlscan.rl in rlcodegen is a pull scanner.
+ -The introduction chapter of the manual was improved. The manually-drawn
+ figures for the examples were replaced with graphviz-drawn figures.
+
+Ragel 5.16 - Nov 20, 2006
+=========================
+ -Policy change: the fhold and fexec directives did not function correctly in
+ scanner pattern actions. In this context manipulations of p may be lost or
+ made invalid. In the previous version of Ragel they were banned because of
+ this. Instead of banning these directives they have been fixed. The fexec
+ and fhold directives now manipulate tokend, which is now always used to
+ update p when the action terminates.
+
+Ragel 5.15 - Oct 31, 2006
+=========================
+ -A language independent test harness was introduced. Test cases can be
+ written using a custom mini-language in the embedded actions. This
+ mini-language is then translated to C, D and Java when generating the
+ language-specific test cases.
+ -Several existing tests have been ported to the language-independent format
+ and a number of new language-independent test cases have been added.
+ -The state-based embedding operators which access states that are not the
+ start state and are not final (the 'middle' states) have changed. They
+ were:
+ <@/ eof action into middle states
+ <@! error action into middle states
+ <@^ local error action into middle states
+ <@~ to-state action into middle states
+ <@* from-state action into middle states
+ They are now:
+ <>/ eof action into middle states
+ <>! error action into middle states
+ <>^ local error action into middle states
+ <>~ to-state action into middle states
+ <>* from-state action into middle states
+ -The verbose form of embeddings using the <- operator have been removed.
+ This syntax was difficult to remember.
+ -A new verbose form of state-based embedding operators have been added.
+ These are like the symbol versions, except they replace the symbols:
+ / ! ^ ~ *
+ with literal keywords:
+ eof err lerr to from
+ -The following words have been promoted to keywords:
+ when eof err lerr to from
+ -The write statment now gets its own lexical scope in the scanner to ensure
+ that commands are passed through as is (not affected by keywords).
+ -Bug fix: in the code generation of fret in scanner actions the adjustment to
+ p that is needed in some cases (dependent on content of patterns) was not
+ happening.
+ -The fhold directive, which decrements p, cannot be permitted in the pattern
+ action of a scanner item because it will not behave consistently. At the end
+ of a pattern action p could be decremented, set to a new value or left
+ alone. This depends on the contents of the scanner's patterns. The user
+ cannot be expected to predict what will happen to p.
+ -Conditions in D code require a cast to the widec type when computing widec.
+ -Like Java, D code also needs if (true) branches for control flow in actions
+ in order to fool the unreachable code detector. This is now abstracted in
+ all code generators using the CTRL_FLOW() function.
+ -The NULL_ITEM value in java code should be -1. This is needed for
+ maintaining tokstart.
+
+Ragel 5.14 - Oct 1, 2006
+========================
+ -Fixed the check for use of fcall in actions embedded within longest match
+ items. It was emitting an error if an item's longest-match action had an
+ fcall, which is allowed. This bug was introduced while fixing a segfault in
+ version 5.8.
+ -A new minimization option was added: MinimizeMostOps (-l). This option
+ minimizes at every operation except on chains of expressions and chains of
+ terms (eg, union and concat). On these chains it minimizes only at the last
+ operation. This makes test cases with many states compile faster, without
+ killing the performance on grammars like strings2.rl.
+ -The -l minimiziation option was made the default.
+ -Fixes to Java code: Use of the fc value did not work, now fixed. Static data
+ is now declared with the final keyword. Patch from Colin Fleming. Conditions
+ now work when generating Java code.
+ -The option -p was added to rlcodegen which causes printable characters to be
+ printed in GraphViz output. Patch from Colin Fleming.
+ -The "element" keyword no longer exists, removed from vim syntax file.
+ Updated keyword highlighting.
+ -The host language selection is now made in the frontend.
+ -Native host language types are now used when specifying the alphtype.
+ Previously all languages used the set defined by C, and these were mapped to
+ the appropriate type in the backend.
+
+Ragel 5.13 - Sep 7, 2006
+========================
+ -Fixed a careless error which broke Java code generation.
+
+Ragel 5.12 - Sep 7, 2006
+========================
+ -The -o flag did not work in combination with -V. This was fixed.
+ -The split code generation format uses only the required number of digits
+ when writing out the number in the file name of each part.
+ -The -T0, -F0 and -G0 codegens should write out the action list iteration
+ variables only when there are regular, to state or from state actions. The
+ code gens should not use anyActions().
+ -If two states have the same EOF actions, they are written out in the finish
+ routine as one case.
+ -The split and in-place goto formats would sometimes generate _out when it is
+ not needed. This was fixed.
+ -Improved the basic partitioning in the split code gen. The last partition
+ would sometimes be empty. This was fixed.
+ -Use of 'fcall *' was not causing top to be initialized. Fixed.
+ -Implemented a Java backend, specified with -J. Only the table-based format
+ is supported.
+ -Implemented range compression in the frontend. This has no effect on the
+ generated code, however it reduces the work of the backend and any programs
+ that read the intermediate format.
+
+Ragel 5.11 - Aug 10, 2006
+=========================
+ -Added a variable to the configure.in script which allows the building of
+ the parsers to be turned off (BUILD_PARSERS). Parser building is off by
+ default for released versions.
+ -Removed configure tests for bison defines header file. Use --defines=file
+ instead.
+ -Configure script doesn't test for bison, flex and gperf when building of the
+ parsers is turned off.
+ -Removed check for YYLTYPE structure from configure script. Since shipped
+ code will not build parsers by default, we don't need to be as accomodating
+ of other versions of bison.
+ -Added a missing include that showed up with g++ 2.95.3.
+ -Failed configure test for Objective-C compiler is now silent.
+
+Ragel 5.10 - Jul 31, 2006
+=========================
+ -Moved the check for error state higher in the table-based processing loop.
+ -Replaced naive implementations of condition searching with proper ones. In
+ the table-based formats the searching is also table-based. In the directly
+ executed formats the searching is also directly executable.
+ -The minimization process was made aware of conditions.
+ -A problem with the condition implementation was fixed. Previously we were
+ taking pointers to transitions and then using them after a call to
+ outTransCopy, which was a bad idea because they may be changed by the call.
+ -Added test mailbox3.rl which is based on mailbox2.rl but includes conditions
+ for restricting header and message body lengths.
+ -Eliminated the initial one-character backup of p just before resuming
+ execution.
+ -Added the -s option to the frontend for printing statistics. This currently
+ includes just the number of states.
+ -Sped up the generation of the in-place goto-driven (-G2) code style.
+ -Implemented a split version of in-place goto-driven code style. This code
+ generation style is suitable for producing fast implementations of very
+ large machines. Partitioning is currently naive. In the future a
+ high-quality partitioning program will be employed. The flag for accessing
+ this feature is -Pn, where n is the number of partitions.
+ -Converted mailbox1.rl, strings2.rl and cppscan1.rl tests to support the
+ split code generation.
+ -Fixes and updates were made to the runtests script: added -c for compiling
+ only, changed the -me option to -e, and added support for testing the split
+ code style.
+
+Ragel 5.9 - Jul 19, 2006
+========================
+ -Fixed a bug in the include system which caused malformed output from the
+ frontend when the include was made from a multi-line machine spec and the
+ included file ended in a single line spec (or vice versa).
+ -Static data is now const.
+ -Actions which referenced states but were not embedded caused the frontend to
+ segfault, now fixed.
+ -Manual now built with pdflatex.
+ -The manual was reorganized and expanded. Chapter sequence is now:
+ Introduction, Constructing Machines, Embedding Actions, Controlling
+ Nondeterminism and Interfacing to the Host program.
+
+Ragel 5.8 - Jun 17, 2006
+========================
+ -The internal representation of the alphabet type has been encapsulated
+ into a class and all operations on it have been defined as C++ operators.
+ -The condition implementation now supports range transitions. This allows
+ conditions to be embedded into arbitrary machines. Conditions are still
+ exprimental.
+ -More condition embedding operators were added
+ 1. Isolate the start state and embed a condition into all transitions
+ leaving it:
+ >when cond OR >?cond
+ 2. Embed a condition into all transitions:
+ when cond OR $when cond OR $?cond
+ 3. Embed a condition into pending out transitions:
+ %when cond OR %?cond
+ -Improvements were made to the determinization process to support pending out
+ conditions.
+ -The Vim sytax file was fixed so that :> doesn't cause the match of a label.
+ -The test suite was converted to a single-file format which uses less disk
+ space than the old directory-per-test format.
+
+Ragel 5.7 - May 14, 2006
+========================
+ -Conditions will not be embedded like actions because they involve a
+ manipulation of the state machine they are specified in. They have therefore
+ been taken out of the verbose action embedding form (using the <- compound
+ symbol). A new syntax for specifying conditions has been created:
+ m = '\n' when {i==4};
+ -Fixed a bug which prevented state machine commands like fcurs, fcall, fret,
+ etc, from being accounted for in from-state actions and to-state actions.
+ This prevented some necessary support code from being generated.
+ -Implemented condition testing in remaining code generators.
+ -Configure script now checks for gperf, which is required for building.
+ -Added support for case-insensitive literal strings (in addition to regexes).
+ A case-insensitive string is made by appending an 'i' to the literal, as in
+ 'cmd'i or "cmd"i.
+ -Fixed a bug which caused all or expressions inside of all regular
+ expressions to be case-insensitive. For example /[fo]o bar/ would make the
+ [fo] part case-insensitive even though no 'i' was given following the
+ regular expression.
+
+Ragel 5.6 - Apr 1, 2006
+=======================
+ -Added a left-guarded concatenation operator. This operator <: is equivalent
+ to ( expr1 $1 . expr2 >0 ). It is useful if you want to prefix a sequence
+ with a sequence of a subset of the characters it matches. For example, one
+ can consume leading whitespace before tokenizing a sequence of whitespace
+ separated words: ( ' '* <: ( ' '+ | [a-z]+ )** )
+ -Removed context embedding code, which has been dead since 5.0.
+
+Ragel 5.5 - Mar 28, 2006
+========================
+ -Implemented a case-insensitive option for regular expressions: /get/i.
+ -If no input file is given to the ragel program it reads from standard input.
+ -The label of the start state has been changed from START to IN to save on
+ required screen space.
+ -Bug fix: \0 was not working in literal strings, due to a change that reduced
+ memory usage by concatenating components of literal strings. Token data
+ length is now passed from the scanner to the paser so that we do not need to
+ rely on null termination.
+
+Ragel 5.4 - Mar 12, 2006
+========================
+ -Eliminated the default transition from the frontend implementation. This
+ default transition was a space-saving optimization that at best could reduce
+ the number of allocated transitions by one half. Unfortunately it
+ complicated the implementation and this stood in the way of introducing
+ conditionals. The default transition may be reintroduced in the future.
+ -Added entry-guarded concatenation. This operator :>, is syntactic sugar
+ for expr1 $0 . expr >1. This operator terminates the matching of the first
+ machine when a first character of the second machine is matched. For
+ example in any* . ';' we never leave the any* machine. If we use any* :> ';'
+ then the any* machine is terminiated upon matching the semi-colon.
+ -Added finish-guarded concatenation. This operator :>>, is syntactic sugar
+ for expr1 $0 . expr @1. This operator is like entry guarded concatenation
+ except the first machine is terminated when the second machine enters a
+ final state. This is useful for delaying the guard until a full pattern is
+ matched. For example as in '/*' any* :>> '*/'.
+ -Added strong subtraction. Where regular subtraction removes from the first
+ machine any strings that are matched by the second machine, strong
+ subtraction removes any strings from the first that contain any strings of
+ the second as a substring. Strong subtraction is syntactic sugar for
+ expr1 - ( any* expr2 any* ).
+ -Eliminated the use of priorities from the examples. Replaced with
+ subtraction, guarded concatenation and longest-match kleene star.
+ -Did some initial work on supporting conditional transitions. Far from
+ complete and very buggy. This code will only be active when conditionals are
+ used.
+
+Ragel 5.3 - Jan 27, 2006
+========================
+ -Added missing semi-colons that cause the build to fail when using older
+ versions of Bison.
+ -Fix for D code: if the contents of an fexec is a single word, the generated
+ code will get interpreted as a C-style cast. Adding two brackets prevents
+ this. Can now turn eliminate the "access this.;" in cppscan5 that was used to
+ get around this problem.
+ -Improved some of the tag names in the intermediate format.
+ -Added unsigned long to the list of supported alphabet types.
+ -Added ids of actions and action lists to XML intermediate format. Makes it
+ more human readable.
+ -Updated to latest Aapl package.
+
+Ragel 5.2 - Jan 6, 2006
+========================
+ -Ragel emits an error if the target of fentry, fcall, fgoto or fnext is inside
+ a longest match operator, or if an action embedding in a longest match
+ machine uses fcall. The fcall command can still be used in pattern actions.
+ -Made improvements to the clang, rlscan, awkemu and cppscan examples.
+ -Some fixes to generated label names: they should all be prefixed with _.
+ -A fix to the Vim syntax highlighting script was made
+ -Many fixes and updates to the documentation. All important features and
+ concepts are now documented. A second chapter describing Ragel's use
+ was added.
+
+Ragel 5.1 - Dec 22, 2005
+========================
+ -Fixes to the matching of section delimiters in Vim syntax file.
+ -If there is a longest match machine, the tokend var is now initialized by
+ write init. This is not necessary for correct functionality, however
+ prevents compiler warnings.
+ -The rlscan example was ported to the longest match operator and changed to
+ emit XML data.
+ -Fix to the error handling in the frontend: if there are errors in the lookup
+ of names at machine generation time then do not emit anything.
+ -If not compiling the full machine in the frontend (by using -M), avoid
+ errors and segfaults caused by names that are not part of the compiled
+ machine.
+ -Longest match bug fix: need to init tokstart when returing from fsm calls
+ that are inside longest match actions.
+ -In Graphviz drawing, the arrow into the start state is not a real
+ transition, do not draw to-state actions on the label.
+ -A bug fix to the handling of non-tag data within an XML tag was made.
+ -Backend exit value fixed: since the parser now accepts nothing so as to
+ avoid a redundant parse error when the frontend dies, we must force an
+ error. The backend should now be properly reporting errors.
+ -The longest match machine now has it's start state set final. An LM machine
+ is in a final state when it has not matched anything, when it has matched
+ and accepted a token and is ready for another, and when it has matched a
+ token but is waiting for some lookahead before determining what to do about
+ it (similar to kleene star).
+ -Element statement removed from some tests.
+ -Entry point names are propagated to the backend and used to label the entry
+ point arrows in Graphviz output.
+
+Ragel 5.0 - Dec 17, 2005
+========================
+ (additional details in V5 release notes)
+ -Ragel has been split into two executables: A frontend which compiles
+ machines and emits them in an XML format, and a backend which generates code
+ or a Graphviz dot file from the XML input. The purpose of this split is to
+ allow Ragel to interface with other tools by means of the XML intermediate
+ format and to reduce complexity by strictly separating the previously
+ entangled phases. The intermediate format will provide a better platform
+ inspecting compiled machines and for extending Ragel to support other host
+ languages.
+ -The host language interface has been reduced significantly. Ragel no longer
+ expects the machine to be implemented as a structure or class and does not
+ generate functions corresponding to initialization, execution and EOF.
+ Instead, Ragel just generates the code of these components, allowing all of
+ them to be placed in a single function if desired. The user specifies a
+ machine in the usual manner, then indicates at which place in the program
+ text the state machine code is to be generated. This is done using the write
+ statement. It is possible to specify to Ragel how it should access the
+ variables it needs (such as the current state) using the access statement.
+ -The host language embedding delimiters have been changed. Single line
+ machines start with '%%' and end at newline. Multiline machines start with
+ '%%{' and end with '}%%'. The machine name is given with the machine
+ statement at the very beginning of the specification. This purpose of this
+ change is to make it easier separate Ragel code from the host language. This
+ will ease the addition of supported host languages.
+ -The structure and class parsing which was previously able to extract a
+ machine's name has been removed since this feature is dependent on the host
+ language and inhibits the move towards a more language-independent frontend.
+ -The init, element and interface statements have been made obsolete by the
+ new host language interface and have been removed.
+ -The fexec action statement has been changed to take only the new position to
+ move to. This statement is more useful for moving backwards and reparsing
+ input than for specifying a whole new buffer entirely and has been shifted
+ to this new use. Giving it only one argument also simplifies the parsing of
+ host code embedded in a Ragel specification. This will ease the addition of
+ supported host languages.
+ -Introduced the fbreak statement, which allows one to stop processing data
+ immediately. The machine ends up in the state that the current transition
+ was to go to. The current character is not changed.
+ -Introduced the noend option for writing the execute code. This inhibits
+ checking if we have reached pe. The machine will run until it goes into the
+ error state or fbreak is hit. This allows one to parse null-terminate
+ strings without first computing the length.
+ -The execute code now breaks out of the processing loop when it moves into
+ the error state. Previously it would run until pe was hit. Breaking out
+ makes the noend option useful when an error is encountered and allows
+ user code to determine where in the input the error occured. It also
+ eliminates needlessly iterating the input buffer.
+ -Introduced the noerror, nofinal and noprefix options for writing the machine
+ data. The first two inhibit the writing of the error state and the
+ first-final state should they not be needed. The noprefix eliminates the
+ prefixing of the data items with the machine name.
+ -Support for the D language has been added. This is specified in the backend
+ with the -D switch.
+ -Since the new host language interface has been reduced considerably, Ragel
+ no longer needs to distinguish between C-based languages. Support for C, C++
+ and Objective-C has been folded into one option in the backend: -C
+ -The code generator has been made independent of the languages that it
+ supports by pushing the language dependent apsects down into the lower
+ levels of the code generator.
+ -Many improvements to the longest match construction were made. It is no
+ longer considered experimental. A longest match machine must appear at the
+ top level of a machine instantiation. Since it does not generate a pure
+ state machine (it may need to backtrack), it cannot be used as an operand to
+ other operators.
+ -References to the current character and current state are now completely
+ banned in EOF actions.
+
+Ragel 4.2 - Sep 16, 2005
+========================
+ (additional details in V4 release notes)
+ -Fixed a bug in the longest match operator. In some states it's possible that
+ we either match a token or match nothing at all. In these states we need to
+ consult the LmSwitch on error so it must be prepared to execute an error
+ handler. We therefore need to init act to this error value (which is zero).
+ We can compute if we need to do this and the code generator emits the
+ initialization only if necessary.
+ -Changed the definition of the token end of longest match actions. It now
+ points to one past the last token. This makes computing the token length
+ easier because you don't have to add one. The longest match variables token
+ start, action identifier and token end are now properly initialized in
+ generated code. They don't need to be initialized in the user's code.
+ -Implemented to-state and from-state actions. These actions are executed on
+ transitions into the state (after the in transition's actions) and on
+ transitions out of the state (before the out transition's actions). See V4
+ release notes for more information.
+ -Since there are no longer any action embedding operators that embed both on
+ transitions and on EOF, any actions that exist in both places will be there
+ because the user has explicitly done so. Presuming this case is rare, and
+ with code duplication in the hands of the user, we therefore give the EOF
+ actions their own action switch in the finish() function. This is further
+ motivated by the fact that the best solution is to do the same for to-state
+ and from-state actions in the main loop.
+ -Longest match actions can now be specified using a named action. Since a
+ word following a longest match item conflicts with the concatenation of a
+ named machine, the => symbol must come immediately before a named action.
+ -The longest match operator permits action and machine definitions in the
+ middle of a longest match construction. These are parsed as if they came
+ before the machine definition they are contained in. Permitting action and
+ machine definitions in a longest match construction allows objects to be
+ defined closer to their use.
+ -The longest match operator can now handle longest match items with no
+ action, where previously Ragel segfaulted.
+ -Updated to Aapl post 2.12.
+ -Fixed a bug in epsilon transition name lookups. After doing a name lookup
+ the result was stored in the parse tree. This is wrong because if a machine
+ is used more than once, each time it may resolve to different targets,
+ however it will be stored in the same place. We now store name resolutions
+ in a separated data structure so that each walk of a parse tree uses the
+ name resolved during the corresponding walk in the name lookup pass.
+ -The operators used to embed context and actions into states have been
+ modified. The V4 release notes contain the full details.
+ -Added zlen builtin machine to represent the zero length machine. Eventually
+ the name "null" will be phased out in favour of zlen because it is unclear
+ whether null matches the zero length string or if it does not match any
+ string at all (as does the empty builtin).
+ -Added verbose versions of action, context and priority embedding. See the V4
+ release notes for the full details. A small example:
+ machine <- all exec { foo(); } <- final eof act1
+ -Bugfix for machines with epsilon ops, but no join operations. I had
+ wrongfully assumed that because epsilon ops can only increase connectivity,
+ that no states are ever merged and therefore a call to fillInStates() is not
+ necessary. In reality, epsilon transitions within one machine can induce the
+ merging of states. In the following, state 2 follows two paths on 'i':
+ main := 'h' -> i 'i h' i: 'i';
+ -Changed the license of the guide from a custom "do not propagate modified
+ versions of this document" license to the GPL.
+
+Ragel 4.1 - Jun 26, 2005
+========================
+ (additional details in V4 release notes)
+ -A bug in include processing was fixed. Surrounding code in an include file
+ was being passed through to the output when it should be ignored. Includes
+ are only for including portions of another machine into he current. This
+ went unnoticed because all tested includes were wrapped in #ifndef ...
+ #endif directives and so did not affect the compilation of the file making
+ the include.
+ -Fixes were made to Vim syntax highlighting file.
+ -Duplicate actions are now removed from action lists.
+ -The character-level negation operator ^ was added. This operator produces a
+ machine that matches single characters that are not matched by the machine
+ it is applied to. This unary prefix operator has the same precedence level
+ as !.
+ -The use of + to specify the a positive literal number was discontinued.
+ -The parser now assigns the subtraction operator a higher precedence than
+ the negation of literal number.
+
+Ragel 4.0 - May 26, 2005
+========================
+ (additional details in V4 release notes)
+ -Operators now strictly embed into a machine either on a specific class of
+ characters or on EOF, but never both. This gives a cleaner association
+ between the operators and the physical state machine entitites they operate
+ on. This change is made up of several parts:
+ 1. '%' operator embeds only into leaving characters.
+ 2. All global and local error operators only embed on error character
+ transitions, their action will not be triggerend on EOF in non-final
+ states.
+ 3. EOF action embedding operators have been added for all classes of states
+ to make up for functionality removed from other operators. These are
+ >/ $/ @/ %/.
+ 4. Start transition operator '>' no longer implicitly embeds into leaving
+ transtions when start state is final.
+ -Ragel now emits warnings about the improper use of statements and values in
+ action code that is embedded as an EOF action. Warnings are emitted for fpc,
+ fc, fexec, fbuf and fblen.
+ -Added a longest match construction operator |* machine opt-action; ... *|.
+ This is for repetition where an ability to revert to a shorter, previously
+ matched item is required. This is the same behaviour as flex and re2c. The
+ longest match operator is not a pure FSM construction, it introduces
+ transitions that implicitly hold the current character or reset execution to
+ a previous location in the input. Use of this operator requires the caller
+ of the machine to occasionally hold onto data after a call to the exectute
+ routine. Use of machines generated with this operator as the input to other
+ operators may have undefined results. See examples/cppscan for an example.
+ This is very experimental code.
+ -Action ids are only assigned to actions that are referenced in the final
+ constructed machine, preventing gaps in the action id sequence. Previously
+ an action id was assigned if the action was referenced during parsing.
+ -Machine specifications now begin with %% and are followed with an optional
+ name and either a single Ragel statement or a sequence of statements
+ enclosed in {}.
+ -Ragel no longer generates the FSM's structure or class. It is up to the user
+ to declare the structure and to give it a variable named curs of type
+ integer. If the machine uses the call stack the user must also declare a
+ array of integers named stack and an integer variable named top.
+ -In the case of Objective-C, Ragel no longer generates the interface or
+ implementation directives, allowing the user to declare additional methods.
+ -If a machine specification does not have a name then Ragel tries to find a
+ name for it by first checking if the specification is inside a struct, class
+ or interface. If it is not then it uses the name of the previous machine
+ specification. If still no name is found then this is an error.
+ -Fsm specifications now persist in memory and statements accumulate.
+ -Ragel now has an include statement for including the statements of a machine
+ spec in another file (perhaps because it is the corresponding header file).
+ The include statement can also be used to draw in the statements of another
+ fsm spec in the current file.
+ -The fstack statement is now obsolete and has been removed.
+ -A new statement, simply 'interface;', indicates that ragel should generate
+ the machine's interface. If Ragel sees the main machine it generates the
+ code sections of the machine. Previously, the header portion was generated
+ if the (now removed) struct statement was found and code was generated if
+ any machine definition was found.
+ -Fixed a bug in the resolution of fsm name references in actions. The name
+ resolution code did not recurse into inline code items with children
+ (fgoto*, fcall*, fnext*, and fexec), causing a segfault at code generation
+ time.
+ -Cleaned up the code generators. FsmCodeGen was made into a virtual base
+ class allowing for the language/output-style specific classes to inherit
+ both a language specific and style-specific base class while retaining only
+ one copy of FsmCodeGen. Language specific output can now be moved into the
+ language specific code generators, requiring less duplication of code in the
+ language/output-style specific leaf classes.
+ -Fixed bugs in fcall* implementation of IpgGoto code generation.
+ -If the element type has not been defined Ragel now uses a constant version
+ of the alphtype, not the exact alphtype. In most cases the data pointer of
+ the execute routine should be const. A non-const element type can still be
+ defined with the element statement.
+ -The fc special value now uses getkey for retrieving the current char rather
+ than *_p, which is wrong if the element type is a structure.
+ -User guide converted to TeX and updated for new 4.0 syntax and semantics.
+
+Ragel 3.7 - Oct 31, 2004
+========================
+ -Bug fix: unreferenced machine instantiations causing segfault due to name
+ tree and parse tree walk becomming out of syncronization.
+ -Rewrote representation of inline code blocks using a tree data structure.
+ This allows special keywords such as fbuf to be used as the operatands of
+ other fsm commands.
+ -Documentation updates.
+ -When deciding whether or not to generate machine instantiations, search the
+ entire name tree beneath the instantiation for references, not just the
+ root.
+ -Removed stray ';' in keller2.rl
+ -Added fexec for restarting the machine with new buffer data (state stays the
+ same), fbuf for retrieving the the start of the buf, and fblen for
+ retrieving the orig buffer length.
+ -Implemented test/cppscan2 using fexec. This allows token emitting and restart
+ to stay inside the execute routine, instead of leaving and re-entering on
+ every token.
+ -Changed examples/cppscan to use fexec and thereby go much faster.
+ -Implemented flex and re2c versions of examples/cppscan. Ragel version
+ goes faster than flex version but not as fast as re2c version.
+ -Merged in Objective-C patch from Erich Ocean.
+ -Turned off syncing with stdio in C++ tests to make them go faster.
+ -Renamed C++ code generaion classes with the Cpp Prefix instead of CC to make
+ them easier to read.
+ -In the finish function emit fbuf as 0 cast to a pointer to the element type
+ so it's type is not interpreted as an integer.
+ -The number -128 underflows char alphabets on some architectures. Removed
+ uses of it in tests.
+ -Disabled the keller2 test because it causes problems on many architectures
+ due to its large size and compilation requirements.
+
+Ragel 3.6 - Jul 10, 2004
+========================
+ -Many documentation updates.
+ -When resolving names, return a set of values so that a reference in an
+ action block that is embedded more than once won't report distinct entry
+ points that are actually the same.
+ -Implemented flat tables. Stores a linear array of indicies into the
+ transition array and only a low and high key value. Faster than binary
+ searching for keys but not usable for large alphabets.
+ -Fixed bug in deleting of transitions leftover from converstion from bst to
+ list implementation of transitions. Other code cleanup.
+ -In table based output calculate the cost of using an index. Don't use if
+ cheaper.
+ -Changed fstate() value available in init and action code to to fentry() to
+ reflect the fact that the values returned are intended to be used as targets
+ in fgoto, fnext and fcall statements. The returned state is not a unique
+ state representing the label. There can be any number of states representing
+ a label.
+ -Added keller2 test, C++ scanning tests and C++ scanning example.
+ -In table based output split up transitions into targets and actions. This
+ allows actions to be omitted.
+ -Broke the components of the state array into separate arrays. Requires
+ adding some fields where they could previously be omitted, however allows
+ finer grained control over the sizes of items and an overal size reduction.
+ Also means that state numbers are not an offset into the state array but
+ instead a sequence of numbers, meaning the context array does not have any
+ wasted bits.
+ -Action lists and transition also have their types chosen to be the smallest
+ possible for accomodating the contained values.
+ -Changed curs state stored in fsm struct from _cs to curs. Keep fsm->curs ==
+ -1 while in machine. Added tests curs1 and curs2.
+ -Implemented the notion of context. Context can be embedded in states using
+ >:, $:, @: and %: operators. These embed a named context into start states,
+ all states, non-start/non-final and final states. If the context is declared
+ using a context statment
+ context name;
+ then the context can be quered for any state using fsm_name_ctx_name(state)
+ in C code and fsm_name::ctx_name(state) in C++ code. This feature makes it
+ possible to determine what "part" of the machine is currently active.
+ -Fixed crash on machine generation of graphs with no final state. If there
+ is no reference to a final state in a join operation, don't generate one.
+ -Updated Vim sytax: added labels to inline code, added various C++ keywords.
+ Don't highlight name separations as labels. Added switch labels, improved
+ alphtype, element and getkey.
+ -Fixed line info in error reporting of bad epsilon trans.
+ -Fixed fstate() for tab code gen.
+ -Removed references to malloc.h.
+
+Ragel 3.5 - May 29, 2004
+========================
+ -When parse errors occur, the partially generated output file is deleted and
+ an non-zero exit status is returned.
+ -Updated Vim syntax file.
+ -Implemented the setting of the element type that is passed to the execute
+ routine as well as method for specifying how ragel should retrive the key
+ from the element type. This lets ragel process arbitrary structures inside
+ of which is the key that is parsed.
+ element struct Element;
+ getkey fpc->character;
+ -The current state is now implemented with an int across all machines. This
+ simplifies working with current state variables. For example this allows a
+ call stack to be implemented in user code.
+ -Implemented a method for retrieving the current state, the target state, and
+ any named states.
+ fcurs -retrieve the current state
+ ftargs -retrieve the target state
+ fstate(name) -retrieve a named state.
+ -Implemented a mechanism for jumping to and calling to a state stored in a
+ variable.
+ fgoto *<expr>; -goto the state returned by the C/C++ expression.
+ fcall *<expr>; -call the state returned by the C/C++ expression.
+ -Implemented a mechanism for specifying the next state without immediately
+ transfering control there (any code following statement is executed).
+ fnext label; -set the state pointed to by label as the next state.
+ fnext *<expr>; -set the state returned by the C/C++ expression as the
+ next.
+ -Action references are determined from the final machine instead of during
+ the parse tree walk. Some actions can be referenced in the parse tree but not
+ show up in the final machine. Machine analysis is now done based on this new
+ computation.
+ -Named state lookup now employs a breadth-first search in the lookup and
+ allows the user to fully qualify names, making it possible to specify
+ jumps/calls into parts of the machine deep in the name hierarchy. Each part
+ of name (separated by ::) employs a breadth first search from it's starting
+ point.
+ -Name references now must always refer to a single state. Since references to
+ multiple states is not normally intended, it no longer happens
+ automatically. This frees the programmer from thinking about whether or not
+ a state reference is unique. It also avoids the added complexity of
+ determining when to merge the targets of multiple references. The effect of
+ references to multiple states can be explicitly created using the join
+ operator and epsilon transitions.
+ -M option was split into -S and -M. -S specifies the machine spec to generate
+ for graphviz output and dumping. -M specifies the machine definition or
+ instantiation.
+ -Machine function parameters are now prefixed with and underscore to
+ avoid the hiding of class members.
+
+Ragel 3.4 - May 8, 2004
+=======================
+ -Added the longest match kleene star operator **, which is synonymous
+ with ( ( <machine> ) $0 %1 ) *.
+ -Epsilon operators distinguish between leaving transitions (going to an
+ another expression in a comma separated list) and non-leaving transitions.
+ Leaving actions and priorities are appropriately transferred.
+ -Relative priority of following ops changed to:
+ 1. Action/Priority
+ 2. Epsilon
+ 3. Label
+ If label is done first then the isolation of the start state in > operators
+ will cause the label to point to the old start state that doesn't have the
+ new action/priority.
+ -Merged >! and >~, @! and @~, %! and %~, and $! and $~ operators to have one
+ set of global error action operators (>!, @!, %! and $!) that are invoked on
+ error by unexpected characters as well as by unexepected EOF.
+ -Added the fpc keyword for use in action code. This is a pointer to the
+ current character. *fpc == fc. If an action is invoked on EOF then fpc == 0.
+ -Added >^, @^, %^, and $^ local error operators. Global error operators (>!,
+ @!, $!, and %!) cause actions to be invoked if the final machine fails.
+ Local error actions cause actions to be invoked if if the current machine
+ fails.
+ -Changed error operators to mean embed global/local error actions in:
+ >! and !^ -the start state.
+ @! and @^ -states that are not the start state and are not final.
+ %! and %^ -final states.
+ $! and $^ -all states.
+ -Added >@! which is synonymous >! then @!
+ -Added >@^ which is synonymous >^ then @^
+ -Added @%! which is synonymous @! then %!
+ -Added @%^ which is synonymous >^ then @^
+ -FsmGraph representation of transition lists was changed from a mapping of
+ alphabet key -> transition objects using a BST to simply a list of
+ transition objects. Since the transitions are no longer divided by
+ single/range, the fast finding of transition objects by key is no longer
+ required functionality and can be eliminated. This new implementation uses
+ the same amount of memory however causes less allocations. It also make more
+ sense for supporting error transitions with actions. Previously an error
+ transition was represented by a null value in the BST.
+ -Regular expression ranges are checked to ensure that lower <= upper.
+ -Added printf-like example.
+ -Added atoi2, erract2, and gotcallret to the test suite.
+ -Improved build test to support make -jN and simplified the compiling and
+ running of tests.
+
+Ragel 3.3 - Mar 7, 2004
+=======================
+ -Portability bug fixes were made. Minimum and maximum integer values are
+ now taken from the system. An alignment problem on 64bit systems
+ was fixed.
+
+Ragel 3.2 - Feb 28, 2004
+========================
+ -Added a Vim syntax file.
+ -Eliminated length var from generated execute code in favour of an end
+ pointer. Using length requires two variables be read and written. Using an
+ end pointer requires one variable read and written and one read. Results in
+ more optimizable code.
+ -Minimization is now on by default.
+ -States are ordered in output by depth first search.
+ -Bug in minimization fixed. States were not being distinguished based on
+ error actions.
+ -Added null and empty builtin machines.
+ -Added EOF error action operators. These are >~, >@, $~, and %~. EOF error
+ operators embed actions to take if the EOF is seen and interpreted as an
+ error. The operators correspond to the following states:
+ -the start state
+ -any state with a transition to a final state
+ -any state with a transiion out
+ -a final state
+ -Fixed bug in generation of unreference machine vars using -M. Unreferenced
+ vars don't have a name tree built underneath when starting from
+ instantiations. Need to instead build the name tree starting at the var.
+ -Calls, returns, holds and references to fc in out action code are now
+ handled for ipgoto output.
+ -Only actions referenced by an instantiated machine expression are put into
+ the action index and written out.
+ -Added rlscan, an example that lexes Ragel input.
+
+Ragel 3.1 - Feb 18, 2004
+========================
+ -Duplicates in OR literals are removed and no longer cause an assertion
+ failure.
+ -Duplicate entry points used in goto and call statements are made into
+ deterministic entry points.
+ -Base FsmGraph code moved from aapl into ragel, as an increasing amount
+ of specialization is required. Too much time was spent attempting to
+ keep it as a general purpose template.
+ -FsmGraph code de-templatized and heirarchy squashed to a single class.
+ -Single transitions taken out of FsmGraph code. In the machine construction
+ stage, transitions are now implemented only with ranges and default
+ transtions. This reduces memory consumption, simplifies code and prevents
+ covered transitions. However it requires the automated selection of single
+ transitions to keep goto-driven code lean.
+ -Machine reduction completely rewritten to be in-place. As duplicate
+ transitions and actions are found and the machine is converted to a format
+ suitable for writing as C code or as GraphViz input, the memory allocated
+ for states and transitions is reused, instead of newly allocated.
+ -New reduction code consolodates ranges, selects a default transition, and
+ selects single transitions with the goal of joining ranges that are split by
+ any number of single characters.
+ -Line directive changed from "# <num> <file>" to the more common format
+ "#line <num> <file>".
+ -Operator :! changed to @!. This should have happened in last release.
+ -Added params example.
+
+Ragel 3.0 - Jan 22, 2004
+========================
+ -Ragel now parses the contents of struct statements and action code.
+ -The keyword fc replaces the use of *p to reference the current character in
+ action code.
+ -Machine instantiations other than main are allowed.
+ -Call, jump and return statements are now available in action code. This
+ facility makes it possible to jump to an error handling machine, call a
+ sub-machine for parsing a field or to follow paths through a machine as
+ determined by arbitrary C code.
+ -Added labels to the language. Labels can be used anywhere in a machine
+ expression to define an entry point. Also references to machine definitions
+ cause the implicit creation of a label.
+ -Added epsilon transitions to the language. Epsilon operators may reference
+ labels in the current name scope resolved when join operators are evaluated
+ and at the root of the expression tree of machine assignment/instantiation.
+ -Added the comma operator, which joins machines together without drawing any
+ transitions between them. This operator is useful in combination with
+ labels, the epsilon operator and user code transitions for defining machines
+ using the named state and transition list paradigm. It is also useful for
+ invoking transitions based on some analysis of the input or on the
+ environment.
+ -Added >!, :!, $!, %! operators for specifying actions to take should the
+ machine fail. These operators embed actions to execute if the machine
+ fails in
+ -the start state
+ -any state with a transition to a final state
+ -any state with a transiion out
+ -a final state
+ The general rule is that if an action embedding operator embeds an action
+ into a set of transitions T, then the error-counterpart with a ! embeds an
+ action into the error transition taken when any transition T is a candidate,
+ but does not match the input.
+ -The finishing augmentation operator ':' has been changed to '@'. This
+ frees the ':' symbol for machine labels and avoids hacks to the parser to
+ allow the use of ':' for both labels and finishing augmentations. The best
+ hack required that label names be distinct from machine definition names as
+ in main := word : word; This restriction is not good because labels are
+ local to the machine that they are used in whereas machine names are global
+ entities. Label name choices should not be restricted by the set of names
+ that are in use for machines.
+ -Named priority syntax now requires parenthesis surrounding the name and
+ value pair. This avoids grammar ambiguities now that the ',' operator has
+ been introduced and makes it more clear that the name and value are an
+ asscociated pair.
+ -Backslashes are escaped in line directive paths.
+
+Ragel 2.2 - Oct 6, 2003
+=======================
+ -Added {n}, {,n}, {n,} {n,m} repetition operators.
+ <expr> {n} -- exactly n repetitions
+ <expr> {,n} -- zero to n repetitions
+ <expr> {n,} -- n or more repetitions
+ <expr> {n,m} -- n to m repetitions
+ -Bug in binary search table in Aapl fixed. Fixes crashing on machines that
+ add to action tables that are implicitly shared among transitions.
+ -Tests using obsolete minimization algorithms are no longer built and run by
+ default.
+ -Added atoi and concurrent from examples to the test suite.
+
+Ragel 2.1 - Sep 22, 2003
+========================
+ -Bug in priority comparison code fixed. Segfaulted on some input with many
+ embedded priorities.
+ -Added two new examples.
+
+Ragel 2.0 - Sep 7, 2003
+=======================
+ -Optional (?), One or More (+) and Kleene Star (*) operators changed from
+ prefix to postfix. Rationale is that postfix version is far more common in
+ regular expression implementations and will be more readily understood.
+ -All priority values attached to transitions are now accompanied by a name.
+ Transitions no longer have default priority values of zero assigned
+ to them. Only transitions that have different priority values assigned
+ to the same name influence the NFA-DFA conversion. This scheme reduces
+ side-effects of priorities.
+ -Removed the %! statement for unsetting pending out priorities. With
+ named priorities, it is not necessary to clear the priorities of a
+ machine with $0 %! because non-colliding names can be used to avoid
+ side-effects.
+ -Removed the clear keyword, which was for removing actions from a machine.
+ Not required functionality and it is non-intuitive to have a language
+ feature that undoes previous definitions.
+ -Removed the ^ modifier to repetition and concatenation operators. This
+ undocumented feature prevented out transitions and out priorities from being
+ transfered from final states to transitions leaving machines. Not required
+ functionality and complicates the language unnecessarily.
+ -Keyword 'func' changed to 'action' as a part of the phasing out of the term
+ 'function' in favour of 'action'. Rationale is that the term 'function'
+ implies that the code is called like a C function, which is not necessarily
+ the case. The term 'action' is far more common in state machine compiler
+ implementations.
+ -Added the instantiation statement, which looks like a standard variable
+ assignment except := is used instead of =. Instantiations go into the
+ same graph dictionary as definitions. In the the future, instantiations
+ will be used as the target for gotos and calls in action code.
+ -The main graph should now be explicitly instantiated. If it is not,
+ a warning is issued.
+ -Or literal basic machines ([] outside of regular expressions) now support
+ negation and ranges.
+ -C and C++ interfaces lowercased. In the C interface an underscore now
+ separates the fsm machine and the function name. Rationale is that lowercased
+ library and generated routines are more common.
+ C output:
+ int fsm_init( struct clang *fsm );
+ int fsm_execute( struct clang *fsm, char *data, int dlen );
+ int fsm_finish( struct clang *fsm );
+ C++ output:
+ int fsm::init( );
+ int fsm::execute( char *data, int dlen );
+ int fsm::finish( );
+ -Init, execute and finish all return -1 if the machine is in the error state
+ and can never accept, 0 if the machine is in a non-accepting state that has a
+ path to a final state and 1 if the machine is in an accepting state.
+ -Accept routine eliminated. Determining whether or not the machine accepts is
+ done by examining the return value of the finish routine.
+ -In C output, fsm structure is no longer a typedef, so referencing requires
+ the struct keyword. This is to stay in line with C language conventions.
+ -In C++ output, constructor is no longer written by ragel. As a consequence,
+ init routine is not called automatically. Allows constructor to be supplied
+ by user as well as the return value of init to be examined without calling it
+ twice.
+ -Static start state and private structures are taken out of C++ classes.
+
+Ragel 1.5.4 - Jul 14, 2003
+==========================
+ -Workaround for building with bison 1.875, which produces an
+ optimization that doesn't build with newer version gcc.
+
+Ragel 1.5.3 - Jul 10, 2003
+==========================
+ -Fixed building with versions of flex that recognize YY_NO_UNPUT.
+ -Fixed version numbers in ragel.spec file.
+
+Ragel 1.5.2 - Jul 7, 2003
+=========================
+ -Transition actions and out actions displayed in the graphviz output.
+ -Transitions on negative numbers handled in graphviz output.
+ -Warning generated when using bison 1.875 now squashed.
+
+Ragel 1.5.1 - Jun 21, 2003
+==========================
+ -Bugs fixed: Don't delete the output objects when writing to standard out.
+ Copy mem into parser buffer with memcpy, not strcpy. Fixes buffer mem errror.
+ -Fixes for compiling with Sun WorkShop 6 compilers.
+
+Ragel 1.5.0 - Jun 10, 2003
+==========================
+ -Line directives written to the output so that errors in the action code
+ are properly reported in the ragel input file.
+ -Simple graphviz dot file output format is supported. Shows states and
+ transitions. Does not yet show actions.
+ -Options -p and -f dropped in favour of -d output format.
+ -Added option -M for specifying the machine to dump with -d or the graph to
+ generate with -V.
+ -Error recovery implemented.
+ -Proper line and column number tracking implemented in the scanner.
+ -All action/function code is now embedded in the main Execute routine. Avoids
+ duplication of action code in the Finish routine and the need to call
+ ExecFuncs which resulted in huge code bloat. Will also allow actions to
+ modify cs when fsm goto, call and return is supported in action code.
+ -Fsm spec can have no statements, nothing will be generated.
+ -Bug fix: Don't accept ] as the opening of a .-. range a reg exp.
+ -Regular expression or set ranges (ie /[0-9]/) are now handled by the parser
+ and consequently must be well-formed. The following now generates a parser
+ error: /[+-]/ and must be rewritten as /[+\-]/. Also fixes a bug whereby ]
+ might be accepted as the opening of a .-. range causing /[0-9]-[0-9]/ to
+ parse incorrectly.
+ -\v, \f, and \r are now treated as whitespace in an fsm spec.
+
+Ragel 1.4.1 - Nov 19, 2002
+==========================
+ -Compile fixes. The last release (integer alphabets) was so exciting
+ that usual portability checks got bypassed.
+
+Ragel 1.4.0 - Nov 19, 2002
+==========================
+ -Arbitrary integer alphabets are now fully supported! A new language
+ construct:
+ 'alphtype <type>' added for specifying the type of the alphabet. Default
+ is 'char'. Possible alphabet types are:
+ char, unsigned char, short, unsigned short, int, unsigned int
+ -Literal machines specified in decimal format can now be negative when the
+ alphabet is a signed type.
+ -Literal machines (strings, decimal and hex) have their values checked for
+ overflow/underflow against the size of the alphabet type.
+ -Table driven and goto driven output redesigned to support ranges. Table
+ driven uses a binary search for locating single characters and ranges. Goto
+ driven uses a switch statement for single characters and nested if blocks for
+ ranges.
+ -Switch driven output removed due to a lack of consistent advantages. Most of
+ the time the switch driven FSM is of no use because the goto FSM makes
+ smaller and faster code. Under certain circumstances it can produce smaller
+ code than a goto driven fsm and be almost as fast, but some sporadic case
+ does not warrant maintaining it.
+ -Many warnings changed to errors.
+ -Added option -p for printing the final fsm before minimization. This lets
+ priorities be seen. Priorties are all reset to 0 before minimization. The
+ exiting option -f prints the final fsm after minimization.
+ -Fixed a bug in the clang test and example that resulted in redundant actions
+ being executed.
+
+Ragel 1.3.4 - Nov 6, 2002
+=========================
+ -Fixes to Chapter 1 of the guide.
+ -Brought back the examples and made them current.
+ -MSVC is no longer supported for compiling windows binaries because its
+ support for the C++ standard is frustratingly inadequate, it will cost money
+ to upgrade if it ever gets better, and MinGW is a much better alternative.
+ -The build system now supports the --host= option for building ragel
+ for another system (used for cross compiling a windows binary with MinGW).
+ -Various design changes and fixes towards the goal of arbitrary integer
+ alphabets and the handling of larger state machines were made.
+ -The new shared vector class is now used for action lists in transitions and
+ states to reduce memory allocations.
+ -An avl tree is now used for the reduction of transitions and functions of an
+ fsm graph before making the final machine. The tree allows better scalability
+ and performance by not requiring consecutively larger heap allocations.
+ -Final stages in the separation of fsm graph code from action embedding and
+ priority assignment is complete. Makes the base graph leaner and easier to reuse
+ in other projects (like Keller).
+
+Ragel 1.3.3 - Oct 22, 2002
+==========================
+ -More diagrams were added to section 1.7.1 of the user guide.
+ -FSM Graph code was reworked to spearate the regex/nfa/minimizaion graph
+ algorithms from the manipulation of state and transition properties.
+ -An rpm spec file from Cris Bailiff was added. This allows an rpm for ragel
+ to be built with the command 'rpm -ta ragel-x.x.x.tar.gz'
+ -Fixes to the build system and corresponding doc updates in the README.
+ -Removed autil and included the one needed source file directly in the top
+ level ragel directory.
+ -Fixed a bug that nullified the 20 times speedup in large compilations
+ claimed by the last version.
+ -Removed awk from the doc build (it was added with the last release -- though
+ not mentioned in the changelog).
+ -Install of man page was moved to the doc dir. The install also installs the
+ user guide to $(PREFIX)/share/doc/ragel/
+
+Ragel 1.3.2 - Oct 16, 2002
+==========================
+ -Added option -v (or --version) to show version information.
+ -The subtract operator no longer removes transition data from the machine
+ being subtracted. This is left up to the user for the purpose of making it
+ possible to transfer transitions using subtract and also for speeding up the
+ subtract routine. Note that it is possible to explicitly clear transition
+ data before a doing a subtract.
+ -Rather severe typo bug fixed. Bug was related to transitions with higher
+ priorities taking precedence. A wrong ptr was being returned. It appears to
+ have worked most of the time becuase the old ptr was deleted and the new one
+ allocated immediatly after so the old ptr often pointed to the same space.
+ Just luck though.
+ -Bug in the removing of dead end paths was fixed. If the start state
+ has in transitions then those paths were not followed when finding states to
+ keep. Would result in non-dead end states being removed from the graph.
+ -In lists and in ranges are no longer maintained as a bst with the key as the
+ alphabet character and the value as a list of transitions coming in on that
+ char. There is one list for each of inList, inRange and inDefault. Now that
+ the required functionality of the graph is well known it is safe to remove
+ these lists to gain in speed and footprint. They shouldn't be needed.
+ -IsolateStartState() runs on modification of start data only if the start
+ state is not already isolated, which is now possible with the new in list
+ representation.
+ -Concat, Or and Star operators now use an approximation to
+ removeUnreachableStates that does not require a traversal of the entire
+ graph. This combined with an 'on-the-fly' management of final bits and final
+ state status results is a dramatic speed increase when compiling machines
+ that use those operators heavily. The strings2 test goes 20 times faster.
+ -Before the final minimization, after all fsm operations are complete,
+ priority data is reset which enables better minimization in cases where
+ priorities would otherwise separate similar states.
+
+Ragel 1.3.1 - Oct 2, 2002
+=========================
+ -Range transitions are now used to implement machines made with /[a-z]/ and
+ the .. operator as well as most of the builtin machines. The ranges are not
+ yet reflected in the output code, they are expanded as if they came from the
+ regular single transitions. This is one step closer to arbitrary integer
+ output.
+ -The builtin machine 'any' was added. It is equiv to the builtin extend,
+ matching any characters.
+ -The builtin machine 'cntrl' now includes newline.
+ -The builtin machine 'space' now includes newline.
+ -The builtin machine 'ascii' is now the range 0-127, not all characters.
+ -A man page was written.
+ -A proper user guide was started. Chapter 1: Specifying Ragel Programs
+ was written. It even has some diagrams :)
+
+Ragel 1.3.0 - Sep 4, 2002
+=========================
+ -NULL keyword no longer used in table output.
+ -Though not yet in use, underlying graph structure changed to support range
+ transitions. As a result, most of the code that walks transition lists is now
+ implemented with an iterator that hides the complexity of the transition
+ lists and ranges. Range transitions will be used to implement /[a-z]/ style
+ machines and machines made with the .. operator. Previously a single
+ transition would be used for each char in the range, which is very costly.
+ Ranges eliminate much of the space complexity and allow for the .. operator
+ to be used with very large (integer) alphabets.
+ -New minimization similar to Hopcroft's alg. It does not require n^2 space and
+ runs close to O(n*log(n)) (an exact analysis of the alg is very hard). It is
+ much better than the stable and approx minimization and obsoletes them both.
+ An exact implementation of Hopcroft's alg is desirable but not possible
+ because the ragel implementation does not assume a finite alphabet, which
+ Hopcroft's requires. Ragel will support arbitrary integer alphabets which
+ must be treated as an infinite set for implementation considerations.
+ -New option -m using above described minimization to replace all previous
+ minimization options. Old options sill work but are obsolete and not
+ advertised with -h.
+ -Bug fixed in goto style output. The error exit set the current state to 0,
+ which is actually a valid state. If the machine was entered again it would go
+ into the first state, very wrong. If the first state happened to be final then
+ an immediate finish would accept when in fact it should fail.
+ -Slightly better fsm minimization now capable due to clearing of the
+ transition ordering numbers just prior to minimization.
+
+Ragel 1.2.2 - May 25, 2002
+==========================
+ -Configuration option --prefix now works when installing.
+ -cc file extension changed to cpp for better portability.
+ -Unlink of output file upon error no longer happens, removes dependency on
+ unlink system command.
+ -All multiline strings removed: not standard c++.
+ -Awk build dependency removed.
+ -MSVC 6.0 added to the list of supported compilers (with some tweaking of
+ bison and flex output).
+
+Ragel 1.2.1 - May 13, 2002
+==========================
+ -Automatic dependencies were fixed, they were not working correctly.
+ -Updated AUTHORS file to reflect contributors.
+ -Code is more C++ standards compliant: compiles with g++ 3.0
+ -Fixed bugs that only showed up in g++ 3.0
+ -Latest (unreleased) Aapl.
+ -Configuration script bails out if bison++ is installed. Ragel will not
+ compile with bison++ because it is coded in c++ and bison++ automatically
+ generates a c++ parser. Ragel uses a c-style bison parser.
+
+Ragel 1.2.0 - May 3, 2002
+=========================
+ -Underlying graph structure now supports default transitions. The result is
+ that a transition does not need to be made for each char of the alphabet
+ when making 'extend' or '/./' machines. Ragel compiles machines that
+ use the aforementioned primitives WAY faster.
+ -The ugly hacks needed to pick default transitions now go away due to
+ the graph supporting default transitions directly.
+ -If -e is given, but minimization is not turned on, print a warning.
+ -Makefiles use automatic dependencies.
+
+Ragel 1.1.0 - Apr 15, 2002
+==========================
+ -Added goto fsm: much faster than any other fsm style.
+ -Default operator (if two machines are side by side with no operator
+ between them) is concatenation. First showed up in 1.0.4.
+ -The fsm machine no longer auotmatically builds the flat table for
+ transition indicies. Instead it keeps the key,ptr pair. In tabcodegen
+ the flat table is produced. This way very large alphabets with sparse
+ transitions will not consume large amounts of mem. This is also in prep
+ for fsm graph getting a default transition.
+ -Generated code contains a statement explicitly stating that ragel fsms
+ are NOT covered by the GPL. Technically, Ragel copies part of itself
+ to the output to make the generic fsm execution routine (for table driven
+ fsms only) and so the output could be considered under the GPL. But this
+ code is very trivial and could easlily be rewritten. The actual fsm data
+ is subject to the copyright of the source. To promote the use of Ragel,
+ a special exception is made for the part of the output copied from Ragel:
+ it may be used without restriction.
+ -Much more elegant code generation scheme is employed. Code generation
+ class members need only put the 'codegen' keyword after their 'void' type
+ in order to be automatically registerd to handle macros of the same name.
+ An awk script recognises this keyword and generates an appropriate driver.
+ -Ragel gets a test suite.
+ -Postfunc and prefunc go away because they are not supported by non
+ loop-driven fsms (goto, switch) and present duplicate functionality.
+ Universal funcs can be implemented by using $ operator.
+ -Automatic dependencies used in build system, no more make depend target.
+ -Code generation section in docs.
+ -Uses the latests aapl.
+
+Ragel 1.0.5 - Mar 3, 2002
+=========================
+ -Bugfix in SetErrorState that caused an assertion failure when compiling
+ simple machines that did not have full transition tables (and thus did
+ not show up on any example machines). Assertion failure did not occur
+ when using the switch statement code as ragel does not call SetErrorState
+ in that case.
+ -Fixed some missing includes, now compiles on redhat.
+ -Moved the FsmMachTrans Compare class out of FsmMachTrans. Some compilers
+ don't deal with nested classes in templates too well.
+ -Removed old unused BASEREF in fsmgraph and ragel now compiles using
+ egcs-2.91.66 and presumably SUNWspro. The baseref is no longer needed
+ because states do not support being elements in multiple lists. I would
+ rather be able to support more compilers than have this feature.
+ -Started a README with compilation notes. Started an AUTHORS file.
+ -Started the user documentation. Describes basic machines and operators.
+
+Ragel 1.0.4 - Mar 1, 2002
+=========================
+ -Ported to the version of Aapl just after 2.2.0 release. See
+ http://www.ragel.ca/aapl/ for details on aapl.
+ -Fixed a bug in the clang example: the newline machine was not stared.
+ -Added explanations to the clang and mailbox examples. This should
+ help people that want to learn the lanuage as the manual is far from
+ complete.
+
+Ragel 1.0.3 - Feb 2, 2002
+=========================
+ -Added aapl to the ragel tree. No longer requires you to download
+ and build aapl separately. Should avoid discouraging impatient users
+ from compiling ragel.
+ -Added the examples to the ragel tree.
+ -Added configure script checks for bison and flex.
+ -Fixed makefile so as not to die with newer versions of bison that
+ write the header of the parser to a .hh file.
+ -Started ChangeLog file.
+
+Ragel 1.0.2 - Jan 30, 2002
+==========================
+ -Bug fix in calculating highIndex for table based code. Was using
+ the length of out tranisition table rather than the value at the
+ end.
+ -If high/low index are at the limits, output a define in their place,
+ not the high/low values themselves so as not to cause compiler warnings.
+ -If the resulting machines don't have any indicies or functions, then
+ omit the empty unrefereced static arrays so as not to cause compiler
+ warnings about unused static vars.
+ -Fixed variable sized indicies support. The header cannot have any
+ reference to INDEX_TYPE as that info is not known at the time the header
+ data is written. Forces us to use a void * for pointers to indicies. In
+ the c++ versions we are forced to make much of the data non-member
+ static data in the code portion for the same reason.
+
+Ragel 1.0.1 - Jan 28, 2002
+==========================
+ -Exe name change from reglang to ragel.
+ -Added ftabcodegen output code style which uses a table for states and
+ transitions but uses a switch statement for the function execution.
+ -Reformatted options in usage dump to look better.
+ -Support escape sequences in [] sections of regular expressions.
+
+Ragel 1.0 - Jan 25, 2002
+========================
+ -Initial release.
diff --git a/DIST b/DIST
new file mode 100644
index 0000000..85d0524
--- /dev/null
+++ b/DIST
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Change to yes to enable building of parsers or manual. Reconfigure
+# afterwards.
+build_parsers=no;
+build_manual=no;
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..bbed893
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,19 @@
+
+SUBDIRS = ragel doc
+DIST_SUBDIRS = $(SUBDIRS) aapl contrib examples test
+
+dist_doc_DATA = CREDITS ChangeLog
+EXTRA_DIST = ragel.vim
+
+# This file is checked for by the configure script and its existence causes the
+# parsers and the manual to not be built when the distribution is built.
+dist-hook:
+ ( \
+ echo "#!/bin/sh"; \
+ echo ""; \
+ echo "# Change to yes to enable building of parsers or manual. Reconfigure"; \
+ echo "# afterwards."; \
+ echo "build_parsers=no;"; \
+ echo "build_manual=no;"; \
+ ) > $(distdir)/DIST
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..7c0f717
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,822 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) $(dist_doc_DATA) \
+ AUTHORS COPYING ChangeLog README TODO compile depcomp \
+ install-sh missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(docdir)"
+DATA = $(dist_doc_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = ragel doc
+DIST_SUBDIRS = $(SUBDIRS) aapl contrib examples test
+dist_doc_DATA = CREDITS ChangeLog
+EXTRA_DIST = ragel.vim
+all: all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-cscope clean-generic \
+ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+ dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \
+ dist-zip distcheck distclean distclean-generic distclean-tags \
+ distcleancheck distdir distuninstallcheck dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
+ tags-am uninstall uninstall-am uninstall-dist_docDATA
+
+
+# This file is checked for by the configure script and its existence causes the
+# parsers and the manual to not be built when the distribution is built.
+dist-hook:
+ ( \
+ echo "#!/bin/sh"; \
+ echo ""; \
+ echo "# Change to yes to enable building of parsers or manual. Reconfigure"; \
+ echo "# afterwards."; \
+ echo "build_parsers=no;"; \
+ echo "build_manual=no;"; \
+ ) > $(distdir)/DIST
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/README b/README
new file mode 100644
index 0000000..d05b863
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+
+ Ragel State Machine Compiler -- README
+ ======================================
+
+1. Build Requirements
+---------------------
+
+ * Make
+ * g++
+
+If you would like to modify Ragel and need to build Ragel's scanners and
+parsers from the specifications then set "build_parsers=yes" the DIST file and
+reconfigure. This variable is normally set to "no" in the distribution tarballs
+and "yes" in version control. You will need the following programs:
+
+ * ragel (the most recent version)
+ * kelbt (the most recent version)
+
+To build the user guide set "build_manual=yes" in the DIST file and
+reconfigure. You will need the following extra programs:
+
+ * fig2dev
+ * pdflatex
+
+2. Compilation and Installation
+-------------------------------
+
+Ragel uses autoconf and automake.
+
+$ ./configure --prefix=PREFIX
+$ make
+$ make install
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..85c5440
--- /dev/null
+++ b/TODO
@@ -0,0 +1,102 @@
+Guard against including a ragel file more than once (newsgroup).
+
+Line numbers in included files refer to the master file. This needs to be
+fixed -- from Manoj.
+
+Remove old action embedding and condition setting syntax.
+
+fbreak should advance the current char. Depreciate fbreak and add
+ fctl_break;
+ fctl_return <expr>;
+ fctl_goto <label>;
+This is needed for better support of pull scanners.
+
+Eliminate tokend, replace it with the marker variable and add ftokend/ftoklen.
+
+Add the accept action embedding operator: like eof but only for states that end
+up final. Add the combined pending/accept action. This becomes a good idea when
+eof action execution is moved into the main loop.
+
+Add a prefix operator which sets every state final.
+
+Minimization should remove a condition when the character allows both
+the positive and negative sense of the condition. This happens in:
+test_every_10_chars = ( ( c when test_len ) c{0,9} )**;
+In this example there is non-determinsm that is killed by the priorities, but
+since conditions are expanded before priorities are tested, many transitions
+end up with test_len || !test_len.
+
+Should be possible to include scanner definitions in another scanner.
+
+Need an "entry name;" feature, causing name to get written out with the other
+entry points in the data.
+
+Possibly bring back the old semantics of > in a new operator, or allow it to be
+defined somehow.
+
+When priorities are embedded without a name, the name of the current machine is
+used. Perhaps a unique name for each instance of the current machine should be
+used instead. This idea could work well if applied to user-defined embeddings.
+
+User defined embeddings <-name(a1,a2,...).
+User defined operators expr1 <name> expr2.
+
+Doesn't make make sense for [] to be the lambda (zero-length) machine. This
+should be the empty set (the empty machine). But then would it be invalid in a
+regular expression?
+
+The |> guarded operator and the <| guarded operator need to be added.
+
+An option to turn off the removal of duplicate actions might be useful for
+analyzing unintentional nondeterminism.
+
+Might be a good idea to add in some protection against using up all of a
+system's memory. This protection could then be removed by people when someone
+is sure they want to use a lot of memory.
+
+
+If a scanner can be optimized into a pure state machine, maybe permit it to be
+referenced as a machine definition. Alternately: inline scanners with an
+explicit exit pattern.
+
+The split codegen needs a profiler connected to a graph partitioning algorithm.
+
+Die a graceful death when rlcodegen -F receives large alphabets.
+
+It's not currently possible to have more than one machine in a single function
+because of label conflicts. Labels should have a unique prefix.
+
+Emit a warning when a subtraction has no effect.
+
+Emit a warning when unnamed priorities are used in longest match machines.
+These priorities may unexpectedly interact across longest-match items. Changing
+the language such that unwated interaction cannot happen would require naming
+longest-match items.
+
+Testing facilities: Quick easy way to query which strings are accepted.
+Enumerate all accepted strings. From Nicholas Maxwell Lester.
+
+Add more examples, add more tests and write more documentation.
+
+A debugger would be nice. Ragel could emit a special debug version that
+prompted for debug commands that allowed the user to step through the machine
+and get details about where they are in their RL.
+
+A quick and easy alternative would be a trace code generation option. This
+would open a trace file and list all the active machines at each step of the
+input.
+
+Frontend should allow the redefinition of fsm section delimiters.
+
+Do more to obscure ragel's private variables. Just a leading underscore is not
+enough. Maybe something more like __ri__.
+
+Some talk about capturing data:
+
+Separate tokstart/tokend from the backtracking. One var for preservation,
+called preserve. Write delcarations; produces the necessary variables used by
+ragel. Move pattern start pattern end concepts into the general? The
+variables which may need to influence the preserve is dependent on the state.
+States have a concept of which variables are in use. Can be used for length
+restrictions. If there is an exit pattern, it is the explicit way out,
+otherwise the start state and all final states are a way out.
diff --git a/aapl/COPYING b/aapl/COPYING
new file mode 100644
index 0000000..c6ed510
--- /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/Makefile.am b/aapl/Makefile.am
new file mode 100644
index 0000000..4a7f30f
--- /dev/null
+++ b/aapl/Makefile.am
@@ -0,0 +1,10 @@
+noinst_HEADERS = \
+ avlbasic.h avlimel.h avlmap.h bstcommon.h compare.h insertsort.h \
+ sbstset.h avlcommon.h avlimelkey.h avlmel.h bstmap.h dlcommon.h \
+ mergesort.h sbsttable.h avlibasic.h avliset.h avlmelkey.h bstset.h \
+ dlist.h quicksort.h svector.h avlikeyless.h avlitree.h avlset.h \
+ bsttable.h dlistmel.h resize.h table.h avlimap.h avlkeyless.h avltree.h \
+ bubblesort.h dlistval.h sbstmap.h vector.h
+
+EXTRA_DIST = README COPYING
+
diff --git a/aapl/Makefile.in b/aapl/Makefile.in
new file mode 100644
index 0000000..9b47901
--- /dev/null
+++ b/aapl/Makefile.in
@@ -0,0 +1,474 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = aapl
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(noinst_HEADERS) COPYING README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = \
+ avlbasic.h avlimel.h avlmap.h bstcommon.h compare.h insertsort.h \
+ sbstset.h avlcommon.h avlimelkey.h avlmel.h bstmap.h dlcommon.h \
+ mergesort.h sbsttable.h avlibasic.h avliset.h avlmelkey.h bstset.h \
+ dlist.h quicksort.h svector.h avlikeyless.h avlitree.h avlset.h \
+ bsttable.h dlistmel.h resize.h table.h avlimap.h avlkeyless.h avltree.h \
+ bubblesort.h dlistval.h sbstmap.h vector.h
+
+EXTRA_DIST = README COPYING
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign aapl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign aapl/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/aapl/README b/aapl/README
new file mode 100644
index 0000000..a2fa5e6
--- /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/avlbasic.h b/aapl/avlbasic.h
new file mode 100644
index 0000000..ed826f3
--- /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 0000000..2cee80c
--- /dev/null
+++ b/aapl/avlcommon.h
@@ -0,0 +1,1626 @@
+/*
+ * 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)
+#ifdef WALKABLE
+:
+ /* Make an empty list, copyBranch will fill in the details for us. */
+ 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 = this->compare( *element, *curEl );
+#else
+ keyRelation = this->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 = this->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 = this->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 = this->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 = this->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 0000000..b916f74
--- /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 0000000..0c60608
--- /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 0000000..c207dc5
--- /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 0000000..bceddcd
--- /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 0000000..52d3a40
--- /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 0000000..9594e7d
--- /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 0000000..28394bb
--- /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 0000000..fecf8bd
--- /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 0000000..378613c
--- /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 0000000..6d0deb7
--- /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 0000000..5a66c9c
--- /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 0000000..579378a
--- /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 0000000..2aa8e15
--- /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 0000000..624b072
--- /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 = this->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 &&
+ this->compare(key, GET_KEY(*lower)) == 0 )
+ lower--;
+
+ upper = mid + 1;
+ while ( upper != highEnd &&
+ this->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 = this->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 = this->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 = this->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 0000000..30c8e3c
--- /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 0000000..4a0f88e
--- /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 0000000..4e4babc
--- /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 0000000..f0f4ce5
--- /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 ( this->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 0000000..3106df9
--- /dev/null
+++ b/aapl/compare.h
@@ -0,0 +1,260 @@
+/*
+ * 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 "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.
+ */
+struct CmpStr
+{
+ /**
+ * \brief Compare two null terminated string types.
+ */
+ static inline long compare(const char *k1, const char *k2)
+ { return strcmp(k1, k2); }
+};
+
+/**
+ * \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 0000000..91dff25
--- /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 0000000..e34c8da
--- /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 0000000..17de543
--- /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 0000000..4fcf33f
--- /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 0000000..94aef7b
--- /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 0000000..8cefa73
--- /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 ( this->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 0000000..bb6941e
--- /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 0000000..9e8491a
--- /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 0000000..e3975a1
--- /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 0000000..3487ee7
--- /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 0000000..348f1fd
--- /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 0000000..7dcae62
--- /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 0000000..c218281
--- /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 0000000..b29c749
--- /dev/null
+++ b/aapl/vector.h
@@ -0,0 +1,1185 @@
+/*
+ * 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 );
+
+
+ /*@{*/
+ /**
+ * \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/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..3a9a040
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1149 @@
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.14'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.14.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.14.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/compile b/compile
new file mode 100755
index 0000000..531136b
--- /dev/null
+++ b/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..da9a33c
--- /dev/null
+++ b/configure
@@ -0,0 +1,6064 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for ragel 6.9.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 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=:
+ # Pre-4.2 versions of Zsh do 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_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+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.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+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
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do 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_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_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 ||
+$as_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" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+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
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# 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
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # 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" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # 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
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+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 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ 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 -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+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='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# 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'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/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=
+
+# Identity of this package.
+PACKAGE_NAME='ragel'
+PACKAGE_TARNAME='ragel'
+PACKAGE_VERSION='6.9'
+PACKAGE_STRING='ragel 6.9'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+GOBIN
+GMCS
+RUBY
+TXL
+JAVAC
+GOBJC
+GDC
+PDFLATEX
+FIG2DEV
+KELBT
+RAGEL
+RANLIB
+AR
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+BUILD_MANUAL_FALSE
+BUILD_MANUAL_TRUE
+BUILD_PARSERS_FALSE
+BUILD_PARSERS_TRUE
+PUBDATE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_manual
+enable_dependency_tracking
+'
+ 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
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# 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_TARNAME}'
+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= ;;
+ *) 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_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=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_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$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_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=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 ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_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'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+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
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+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
+ 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 .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# 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 -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ 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 .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ 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 ragel 6.9 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/ragel]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of ragel 6.9:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-manual do we want to build the manual?
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+
+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 (Objective) C/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.
+
+Report bugs to the package provider.
+_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" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && 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=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_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
+ $as_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
+ragel configure 6.9
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 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
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+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 ragel $as_me 6.9, which was
+generated by GNU Autoconf 2.69. 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=.
+ $as_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=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append 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
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset 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
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ 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_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; 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
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_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'; as_fn_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
+
+$as_echo "/* confdefs.h */" > 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
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ 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. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_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,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_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
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_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.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+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
+
+
+PUBDATE="Oct 2014"
+
+am__api_version='1.14'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='ragel'
+ VERSION='6.9'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
+
+ac_config_headers="$ac_config_headers ragel/config.h"
+
+
+
+if test -r $srcdir/DIST; then :
+ . $srcdir/DIST
+else
+ build_parsers=yes;
+ build_manual=yes
+fi
+
+# Check whether --enable-manual was given.
+if test "${enable_manual+set}" = set; then :
+ enableval=$enable_manual;
+ if test "x$enableval" = "xyes"; then
+ build_manual=yes;
+ else
+ build_manual=no;
+ fi
+
+fi
+
+
+
+ if test "x$build_parsers" = "xyes"; then
+ BUILD_PARSERS_TRUE=
+ BUILD_PARSERS_FALSE='#'
+else
+ BUILD_PARSERS_TRUE='#'
+ BUILD_PARSERS_FALSE=
+fi
+
+
+ if test "x$build_manual" = "xyes"; then
+ BUILD_MANUAL_TRUE=
+ BUILD_MANUAL_FALSE='#'
+else
+ BUILD_MANUAL_TRUE='#'
+ BUILD_MANUAL_FALSE=
+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
+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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$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"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM 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.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; 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 | *.dSYM | *.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
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; 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 | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; 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 | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ 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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* 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"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+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)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+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_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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+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
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ 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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+ $as_echo_n "(cached) " >&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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+else
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$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
+
+depcc="$CXX" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+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
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+# Checks to carry out if we are building parsers.
+if test "x$build_parsers" = "xyes"; then
+
+# Extract the first word of "ragel", so it can be a program name with args.
+set dummy ragel; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RAGEL+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RAGEL="ragel"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAGEL" >&5
+$as_echo "$RAGEL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_KELBT+:} false; then :
+ $as_echo_n "(cached) " >&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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_KELBT="kelbt"
+ $as_echo "$as_me:${as_lineno-$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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $KELBT" >&5
+$as_echo "$KELBT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test -z "$KELBT"; then
+ echo
+ echo "error: kelbt is required to build the parsers"
+ echo
+ exit 1
+fi
+
+fi
+
+# Checks to carry out if we are building the manual.
+if test "x$build_manual" = "xyes"; then
+
+# Extract the first word of "fig2dev", so it can be a program name with args.
+set dummy fig2dev; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_FIG2DEV+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$FIG2DEV"; then
+ ac_cv_prog_FIG2DEV="$FIG2DEV" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_FIG2DEV="fig2dev"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+FIG2DEV=$ac_cv_prog_FIG2DEV
+if test -n "$FIG2DEV"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIG2DEV" >&5
+$as_echo "$FIG2DEV" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test -z "$FIG2DEV"; then
+ echo
+ echo "error: fig2dev is required to build the manual (maybe use --disable-manual)"
+ echo
+ exit 1
+fi
+
+# Extract the first word of "pdflatex", so it can be a program name with args.
+set dummy pdflatex; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PDFLATEX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PDFLATEX"; then
+ ac_cv_prog_PDFLATEX="$PDFLATEX" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PDFLATEX="pdflatex"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PDFLATEX=$ac_cv_prog_PDFLATEX
+if test -n "$PDFLATEX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5
+$as_echo "$PDFLATEX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test -z "$PDFLATEX"; then
+ echo
+ echo "error: pdflatex is required to build the manual (maybe use --disable-manual)"
+ echo
+ exit 1
+fi
+
+fi
+
+# Extract the first word of "gdc", so it can be a program name with args.
+set dummy gdc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_GDC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GDC"; then
+ ac_cv_prog_GDC="$GDC" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GDC="gdc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GDC=$ac_cv_prog_GDC
+if test -n "$GDC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5
+$as_echo "$GDC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Objective-C compiler" >&5
+$as_echo_n "checking for the Objective-C compiler... " >&6; }
+cat > conftest.m <<EOF
+int main() { return 0; }
+EOF
+GOBJC=""
+if gcc -x objective-c conftest.m -o conftest.bin 2>/dev/null; then
+ GOBJC="gcc -x objective-c"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# Extract the first word of "javac", so it can be a program name with args.
+set dummy javac; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_JAVAC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$JAVAC"; then
+ ac_cv_prog_JAVAC="$JAVAC" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_JAVAC="javac"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+JAVAC=$ac_cv_prog_JAVAC
+if test -n "$JAVAC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5
+$as_echo "$JAVAC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "txl", so it can be a program name with args.
+set dummy txl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_TXL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$TXL"; then
+ ac_cv_prog_TXL="$TXL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_TXL="txl"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+TXL=$ac_cv_prog_TXL
+if test -n "$TXL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TXL" >&5
+$as_echo "$TXL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "ruby", so it can be a program name with args.
+set dummy ruby; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RUBY+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RUBY"; then
+ ac_cv_prog_RUBY="$RUBY" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RUBY="ruby"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RUBY=$ac_cv_prog_RUBY
+if test -n "$RUBY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
+$as_echo "$RUBY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "gmcs", so it can be a program name with args.
+set dummy gmcs; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_GMCS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GMCS"; then
+ ac_cv_prog_GMCS="$GMCS" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GMCS="gmcs"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GMCS=$ac_cv_prog_GMCS
+if test -n "$GMCS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMCS" >&5
+$as_echo "$GMCS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "go", so it can be a program name with args.
+set dummy go; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_GOBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GOBIN"; then
+ ac_cv_prog_GOBIN="$GOBIN" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GOBIN="go build"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GOBIN=$ac_cv_prog_GOBIN
+if test -n "$GOBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOBIN" >&5
+$as_echo "$GOBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile ragel/Makefile aapl/Makefile doc/Makefile doc/ragel.1 contrib/Makefile test/Makefile test/runtests examples/Makefile"
+
+ac_config_commands="$ac_config_commands default"
+
+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_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; 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
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_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=
+U=
+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=`$as_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.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${BUILD_PARSERS_TRUE}" && test -z "${BUILD_PARSERS_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_PARSERS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_MANUAL_TRUE}" && test -z "${BUILD_MANUAL_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_MANUAL\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $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}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## 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=:
+ # Pre-4.2 versions of Zsh do 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_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+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.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+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
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+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
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# 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
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+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 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ 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 -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_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 ||
+$as_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" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# 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
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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 ragel $as_me 6.9, which was
+generated by GNU Autoconf 2.69. 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
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ 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
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+ragel config.status 6.9
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 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'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+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=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ 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 )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_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.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append 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 || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "ragel/config.h") CONFIG_HEADERS="$CONFIG_HEADERS ragel/config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "ragel/Makefile") CONFIG_FILES="$CONFIG_FILES ragel/Makefile" ;;
+ "aapl/Makefile") CONFIG_FILES="$CONFIG_FILES aapl/Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "doc/ragel.1") CONFIG_FILES="$CONFIG_FILES doc/ragel.1" ;;
+ "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
+ "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
+ "test/runtests") CONFIG_FILES="$CONFIG_FILES test/runtests" ;;
+ "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
+ "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ 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
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+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= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries 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[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # 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.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[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="$ac_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 ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append 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 '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ 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 ||
+$as_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"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_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
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# 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=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ 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 || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;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
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_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 "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "default":C) chmod +x test/runtests
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# 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 || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo "configuration of ragel complete"
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..34a994a
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,155 @@
+dnl
+dnl Copyright 2001-2009 Adrian Thurston <thurston@complang.org>
+dnl
+
+dnl This file is part of Ragel.
+dnl
+dnl Ragel 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 Ragel 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 Ragel; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+AC_INIT(ragel, 6.9)
+PUBDATE="Oct 2014"
+
+AM_INIT_AUTOMAKE([foreign])
+AC_SUBST(PUBDATE)
+AC_CONFIG_HEADER(ragel/config.h)
+
+dnl Choose defaults for the build_parsers and build_manual vars. If the dist
+dnl file is present in the root then default to no, otherwise go for it.
+
+AS_IF([test -r $srcdir/DIST], [. $srcdir/DIST], [build_parsers=yes;
+ build_manual=yes])
+
+dnl
+dnl Enable arg to explicitly control the building of the manual
+dnl
+AC_ARG_ENABLE(manual,
+ [ --enable-manual do we want to build the manual?],
+ [
+ if test "x$enableval" = "xyes"; then
+ build_manual=yes;
+ else
+ build_manual=no;
+ fi
+ ],
+)
+
+
+dnl Set to true if the build system should generate parsers from ragel and kelbt
+dnl sources. Set to false if generated files are included and not to be built
+dnl (production).
+AM_CONDITIONAL(BUILD_PARSERS, [test "x$build_parsers" = "xyes"])
+
+dnl Set to true if the manual should be built.
+AM_CONDITIONAL(BUILD_MANUAL, [test "x$build_manual" = "xyes"])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CXX
+AC_CHECK_TOOL(AR, ar)
+AC_PROG_RANLIB
+
+dnl Set test on c++ compiler.
+AC_LANG_CPLUSPLUS
+
+dnl Check for definition of MAKE.
+AC_PROG_MAKE_SET
+
+# Checks to carry out if we are building parsers.
+if test "x$build_parsers" = "xyes"; then
+
+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
+
+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
+
+# Checks to carry out if we are building the manual.
+if test "x$build_manual" = "xyes"; then
+
+AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev)
+if test -z "$FIG2DEV"; then
+ echo
+ echo "error: fig2dev is required to build the manual (maybe use --disable-manual)"
+ echo
+ exit 1
+fi
+
+AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex)
+if test -z "$PDFLATEX"; then
+ echo
+ echo "error: pdflatex is required to build the manual (maybe use --disable-manual)"
+ echo
+ exit 1
+fi
+
+fi
+
+dnl Check for the D compiler
+AC_CHECK_PROG(GDC, gdc, gdc)
+
+dnl Check for the Objective-C compiler
+AC_MSG_CHECKING([for the Objective-C compiler])
+cat > conftest.m <<EOF
+int main() { return 0; }
+EOF
+GOBJC=""
+if gcc -x objective-c conftest.m -o conftest.bin 2>/dev/null; then
+ GOBJC="gcc -x objective-c"
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+AC_SUBST(GOBJC)
+
+dnl Check for the Java compiler.
+AC_CHECK_PROG(JAVAC, javac, javac)
+
+dnl Check for TXL.
+AC_CHECK_PROG(TXL, txl, txl)
+
+dnl Check for Ruby.
+AC_CHECK_PROG(RUBY, ruby, ruby)
+
+dnl Check for the C# compiler.
+AC_CHECK_PROG(GMCS, gmcs, gmcs)
+
+dnl Check for the Go compiler.
+AC_CHECK_PROG(GOBIN, go, go build)
+
+dnl write output files
+AC_OUTPUT(
+ [
+ Makefile ragel/Makefile aapl/Makefile
+ doc/Makefile doc/ragel.1
+ contrib/Makefile
+ test/Makefile test/runtests
+ examples/Makefile
+ ],
+ [chmod +x test/runtests]
+)
+
+echo "configuration of ragel complete"
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
new file mode 100644
index 0000000..7ef7e8d
--- /dev/null
+++ b/contrib/Makefile.am
@@ -0,0 +1,2 @@
+
+EXTRA_DIST = ragel.make ragel.m4 unicode2ragel.rb
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
new file mode 100644
index 0000000..1dffb01
--- /dev/null
+++ b/contrib/Makefile.in
@@ -0,0 +1,398 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = contrib
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = ragel.make ragel.m4 unicode2ragel.rb
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
+ ctags-am distclean distclean-generic distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/ragel.m4 b/contrib/ragel.m4
new file mode 100644
index 0000000..72ce4b9
--- /dev/null
+++ b/contrib/ragel.m4
@@ -0,0 +1,53 @@
+dnl Check for presence of the Ragel State Machine generator.
+dnl
+dnl This macro checks for the presence of the ragel tool in the system,
+dnl and whether the ragel tool is absolutely needed for a complete
+dnl build.
+dnl
+dnl To check for the need for Ragel, you have to provide the relative
+dnl path of a source file generated through Ragel: if the file is
+dnl present in the source tree, a missing ragel command will not cause
+dnl the configure to abort.
+
+AC_DEFUN([_RAGEL_VARS], [
+ AC_ARG_VAR([RAGEL], [Ragel generator command])
+ AC_ARG_VAR([RAGELFLAGS], [Ragel generator flags])
+])
+
+AC_DEFUN([CHECK_RAGEL], [
+ AC_REQUIRE([_RAGEL_VARS])
+ AC_CHECK_PROG([RAGEL], [ragel], [ragel], [no])
+
+ dnl We set RAGEL to false so that it would execute the "false"
+ dnl command if needed.
+ AS_IF([test x"$RAGEL" = x"no"],
+ [RAGEL=false],
+ AS_IF([test x"$2" != "x"],
+ [ragel_version=`$RAGEL --version | sed -n -e '1s:.*version \(@<:@0-9@:>@\.@<:@0-9@:>@\) .*:\1:p'`
+ ragel_version_compare=`echo $ragel_version | tr -d .`
+ ragel_wanted_version=`echo $2 | tr -d .`
+ AS_IF([test $ragel_version_compare -lt $ragel_wanted_version],
+ [AC_MSG_WARN([Found Ragel $ragel_version but Ragel $2 requested])
+ RAGEL=false
+ ])
+ ]))
+
+ dnl Only test the need if not found
+ AS_IF([test x"$RAGEL" = x"false"], [
+ AC_MSG_CHECKING([whether we need ragel to regenerate sources])
+ AS_IF([test -a "${srcdir}/$1"], [ragel_needed=no], [ragel_needed=yes])
+ AC_MSG_RESULT([$ragel_needed])
+
+ AS_IF([test x"$ragel_needed" = x"yes"],
+ [AC_MSG_ERROR([dnl
+You need Ragel to build from development sources.
+You can find Ragel at http://www.complang.org/ragel/dnl
+ ])])
+ ])
+])
+
+AC_DEFUN([CHECK_RAGEL_AM], [
+ CHECK_RAGEL([$1], [$2])
+
+ AM_CONDITIONAL([HAVE_RAGEL], [test x"$RAGEL" != x"false"])
+])
diff --git a/contrib/ragel.make b/contrib/ragel.make
new file mode 100644
index 0000000..f7a71b5
--- /dev/null
+++ b/contrib/ragel.make
@@ -0,0 +1,6 @@
+# -*- Makefile -*-
+
+SUFFIXES = .rl
+
+.rl.c:
+ $(RAGEL) $(RAGELFLAGS) -C $< -o $@
diff --git a/contrib/unicode2ragel.rb b/contrib/unicode2ragel.rb
new file mode 100644
index 0000000..d64e601
--- /dev/null
+++ b/contrib/unicode2ragel.rb
@@ -0,0 +1,305 @@
+#!/usr/bin/env ruby
+#
+# This script uses the unicode spec to generate a Ragel state machine
+# that recognizes unicode alphanumeric characters. It generates 5
+# character classes: uupper, ulower, ualpha, udigit, and ualnum.
+# Currently supported encodings are UTF-8 [default] and UCS-4.
+#
+# Usage: unicode2ragel.rb [options]
+# -e, --encoding [ucs4 | utf8] Data encoding
+# -h, --help Show this message
+#
+# This script was originally written as part of the Ferret search
+# engine library.
+#
+# Author: Rakan El-Khalil <rakan@well.com>
+
+require 'optparse'
+require 'open-uri'
+
+ENCODINGS = [ :utf8, :ucs4 ]
+ALPHTYPES = { :utf8 => "unsigned char", :ucs4 => "unsigned int" }
+CHART_URL = "http://www.unicode.org/Public/5.1.0/ucd/DerivedCoreProperties.txt"
+
+###
+# Display vars & default option
+
+TOTAL_WIDTH = 80
+RANGE_WIDTH = 23
+@encoding = :utf8
+
+###
+# Option parsing
+
+cli_opts = OptionParser.new do |opts|
+ opts.on("-e", "--encoding [ucs4 | utf8]", "Data encoding") do |o|
+ @encoding = o.downcase.to_sym
+ end
+ opts.on("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+end
+
+cli_opts.parse(ARGV)
+unless ENCODINGS.member? @encoding
+ puts "Invalid encoding: #{@encoding}"
+ puts cli_opts
+ exit
+end
+
+##
+# Downloads the document at url and yields every alpha line's hex
+# range and description.
+
+def each_alpha( url, property )
+ open( url ) do |file|
+ file.each_line do |line|
+ next if line =~ /^#/;
+ next if line !~ /; #{property} #/;
+
+ range, description = line.split(/;/)
+ range.strip!
+ description.gsub!(/.*#/, '').strip!
+
+ if range =~ /\.\./
+ start, stop = range.split '..'
+ else start = stop = range
+ end
+
+ yield start.hex .. stop.hex, description
+ end
+ end
+end
+
+###
+# Formats to hex at minimum width
+
+def to_hex( n )
+ r = "%0X" % n
+ r = "0#{r}" unless (r.length % 2).zero?
+ r
+end
+
+###
+# UCS4 is just a straight hex conversion of the unicode codepoint.
+
+def to_ucs4( range )
+ rangestr = "0x" + to_hex(range.begin)
+ rangestr << "..0x" + to_hex(range.end) if range.begin != range.end
+ [ rangestr ]
+end
+
+##
+# 0x00 - 0x7f -> 0zzzzzzz[7]
+# 0x80 - 0x7ff -> 110yyyyy[5] 10zzzzzz[6]
+# 0x800 - 0xffff -> 1110xxxx[4] 10yyyyyy[6] 10zzzzzz[6]
+# 0x010000 - 0x10ffff -> 11110www[3] 10xxxxxx[6] 10yyyyyy[6] 10zzzzzz[6]
+
+UTF8_BOUNDARIES = [0x7f, 0x7ff, 0xffff, 0x10ffff]
+
+def to_utf8_enc( n )
+ r = 0
+ if n <= 0x7f
+ r = n
+ elsif n <= 0x7ff
+ y = 0xc0 | (n >> 6)
+ z = 0x80 | (n & 0x3f)
+ r = y << 8 | z
+ elsif n <= 0xffff
+ x = 0xe0 | (n >> 12)
+ y = 0x80 | (n >> 6) & 0x3f
+ z = 0x80 | n & 0x3f
+ r = x << 16 | y << 8 | z
+ elsif n <= 0x10ffff
+ w = 0xf0 | (n >> 18)
+ x = 0x80 | (n >> 12) & 0x3f
+ y = 0x80 | (n >> 6) & 0x3f
+ z = 0x80 | n & 0x3f
+ r = w << 24 | x << 16 | y << 8 | z
+ end
+
+ to_hex(r)
+end
+
+def from_utf8_enc( n )
+ n = n.hex
+ r = 0
+ if n <= 0x7f
+ r = n
+ elsif n <= 0xdfff
+ y = (n >> 8) & 0x1f
+ z = n & 0x3f
+ r = y << 6 | z
+ elsif n <= 0xefffff
+ x = (n >> 16) & 0x0f
+ y = (n >> 8) & 0x3f
+ z = n & 0x3f
+ r = x << 10 | y << 6 | z
+ elsif n <= 0xf7ffffff
+ w = (n >> 24) & 0x07
+ x = (n >> 16) & 0x3f
+ y = (n >> 8) & 0x3f
+ z = n & 0x3f
+ r = w << 18 | x << 12 | y << 6 | z
+ end
+ r
+end
+
+###
+# Given a range, splits it up into ranges that can be continuously
+# encoded into utf8. Eg: 0x00 .. 0xff => [0x00..0x7f, 0x80..0xff]
+# This is not strictly needed since the current [5.1] unicode standard
+# doesn't have ranges that straddle utf8 boundaries. This is included
+# for completeness as there is no telling if that will ever change.
+
+def utf8_ranges( range )
+ ranges = []
+ UTF8_BOUNDARIES.each do |max|
+ if range.begin <= max
+ return ranges << range if range.end <= max
+
+ ranges << range.begin .. max
+ range = (max + 1) .. range.end
+ end
+ end
+ ranges
+end
+
+def build_range( start, stop )
+ size = start.size/2
+ left = size - 1
+ return [""] if size < 1
+
+ a = start[0..1]
+ b = stop[0..1]
+
+ ###
+ # Shared prefix
+
+ if a == b
+ return build_range(start[2..-1], stop[2..-1]).map do |elt|
+ "0x#{a} " + elt
+ end
+ end
+
+ ###
+ # Unshared prefix, end of run
+
+ return ["0x#{a}..0x#{b} "] if left.zero?
+
+ ###
+ # Unshared prefix, not end of run
+ # Range can be 0x123456..0x56789A
+ # Which is equivalent to:
+ # 0x123456 .. 0x12FFFF
+ # 0x130000 .. 0x55FFFF
+ # 0x560000 .. 0x56789A
+
+ ret = []
+ ret << build_range(start, a + "FF" * left)
+
+ ###
+ # Only generate middle range if need be.
+
+ if a.hex+1 != b.hex
+ max = to_hex(b.hex - 1)
+ max = "FF" if b == "FF"
+ ret << "0x#{to_hex(a.hex+1)}..0x#{max} " + "0x00..0xFF " * left
+ end
+
+ ###
+ # Don't generate last range if it is covered by first range
+
+ ret << build_range(b + "00" * left, stop) unless b == "FF"
+ ret.flatten!
+end
+
+def to_utf8( range )
+ utf8_ranges( range ).map do |r|
+ build_range to_utf8_enc(r.begin), to_utf8_enc(r.end)
+ end.flatten!
+end
+
+##
+# Perform a 3-way comparison of the number of codepoints advertised by
+# the unicode spec for the given range, the originally parsed range,
+# and the resulting utf8 encoded range.
+
+def count_codepoints( code )
+ code.split(' ').inject(1) do |acc, elt|
+ if elt =~ /0x(.+)\.\.0x(.+)/
+ if @encoding == :utf8
+ acc * (from_utf8_enc($2) - from_utf8_enc($1) + 1)
+ else
+ acc * ($2.hex - $1.hex + 1)
+ end
+ else
+ acc
+ end
+ end
+end
+
+def is_valid?( range, desc, codes )
+ spec_count = 1
+ spec_count = $1.to_i if desc =~ /\[(\d+)\]/
+ range_count = range.end - range.begin + 1
+
+ sum = codes.inject(0) { |acc, elt| acc + count_codepoints(elt) }
+ sum == spec_count and sum == range_count
+end
+
+##
+# Generate the state maching to stdout
+
+def generate_machine( name, property )
+ pipe = " "
+ puts " #{name} = "
+ each_alpha( CHART_URL, property ) do |range, desc|
+
+ codes = (@encoding == :ucs4) ? to_ucs4(range) : to_utf8(range)
+
+ raise "Invalid encoding of range #{range}: #{codes.inspect}" unless
+ is_valid? range, desc, codes
+
+ range_width = codes.map { |a| a.size }.max
+ range_width = RANGE_WIDTH if range_width < RANGE_WIDTH
+
+ desc_width = TOTAL_WIDTH - RANGE_WIDTH - 11
+ desc_width -= (range_width - RANGE_WIDTH) if range_width > RANGE_WIDTH
+
+ if desc.size > desc_width
+ desc = desc[0..desc_width - 4] + "..."
+ end
+
+ codes.each_with_index do |r, idx|
+ desc = "" unless idx.zero?
+ code = "%-#{range_width}s" % r
+ puts " #{pipe} #{code} ##{desc}"
+ pipe = "|"
+ end
+ end
+ puts " ;"
+ puts ""
+end
+
+puts <<EOF
+# The following Ragel file was autogenerated with #{$0}
+# from: #{CHART_URL}
+#
+# It defines ualpha, udigit, ualnum.
+#
+# To use this, make sure that your alphtype is set to #{ALPHTYPES[@encoding]},
+# and that your input is in #{@encoding}.
+
+%%{
+ machine WChar;
+EOF
+generate_machine( :ualpha, "Alphabetic" )
+generate_machine( :ulower, "Lowercase" )
+generate_machine( :uupper, "Uppercase" )
+puts <<EOF
+ udigit = '0'..'9';
+ ualnum = ualpha | udigit;
+}%%
+EOF
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..4ebd5b3
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..3aa7aae
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,60 @@
+#
+# Copyright 2001-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
+
+man_MANS = ragel.1
+
+EXTRA_DIST = ragel-guide.tex \
+ bmconcat.fig bmregex.fig dropdown.fig exdoneact.fig \
+ exoutact1.fig exstrongsubtr.fig lines2.fig smallscanner.fig bmnull.fig \
+ comments1.fig entryguard.fig exinter.fig exoutact2.fig exsubtr.fig \
+ lmkleene.fig stembed.fig bmnum.fig comments2.fig exaction.fig \
+ exnegate.fig explus.fig finguard.fig opconcat.fig bmor.fig conds1.fig \
+ exallact.fig exoption.fig exstact.fig leftguard.fig opor.fig \
+ bmrange.fig conds2.fig exconcat.fig exor.fig exstar.fig lines1.fig \
+ opstar.fig
+
+if BUILD_MANUAL
+
+dist_doc_DATA = ragel-guide.pdf
+
+.fig.pdf:
+ fig2dev -L pdf $< $@
+
+.tex.pdf:
+ pdflatex -interaction=nonstopmode $< >/dev/null
+ pdflatex -interaction=nonstopmode $< >/dev/null
+ pdflatex -interaction=nonstopmode $< >/dev/null
+
+version.tex: Makefile
+ echo '|def|version{$(PACKAGE_VERSION)}' | tr '|' '\\' > version.tex
+ echo '|def|pubdate{$(PUBDATE)}' | tr '|' '\\' >> version.tex
+
+ragel-guide.pdf: version.tex
+
+ragel-guide.pdf: bmconcat.pdf bmregex.pdf dropdown.pdf exdoneact.pdf \
+ exoutact1.pdf exstrongsubtr.pdf lines2.pdf smallscanner.pdf bmnull.pdf \
+ comments1.pdf entryguard.pdf exinter.pdf exoutact2.pdf exsubtr.pdf \
+ lmkleene.pdf stembed.pdf bmnum.pdf comments2.pdf exaction.pdf \
+ exnegate.pdf explus.pdf finguard.pdf opconcat.pdf bmor.pdf conds1.pdf \
+ exallact.pdf exoption.pdf exstact.pdf leftguard.pdf opor.pdf \
+ bmrange.pdf conds2.pdf exconcat.pdf exor.pdf exstar.pdf lines1.pdf \
+ opstar.pdf
+
+endif
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..163f9dd
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,561 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright 2001-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
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = doc
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/ragel.1.in $(am__dist_doc_DATA_DIST)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES = ragel.1
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)"
+NROFF = nroff
+MANS = $(man_MANS)
+am__dist_doc_DATA_DIST = ragel-guide.pdf
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+man_MANS = ragel.1
+EXTRA_DIST = ragel-guide.tex \
+ bmconcat.fig bmregex.fig dropdown.fig exdoneact.fig \
+ exoutact1.fig exstrongsubtr.fig lines2.fig smallscanner.fig bmnull.fig \
+ comments1.fig entryguard.fig exinter.fig exoutact2.fig exsubtr.fig \
+ lmkleene.fig stembed.fig bmnum.fig comments2.fig exaction.fig \
+ exnegate.fig explus.fig finguard.fig opconcat.fig bmor.fig conds1.fig \
+ exallact.fig exoption.fig exstact.fig leftguard.fig opor.fig \
+ bmrange.fig conds2.fig exconcat.fig exor.fig exstar.fig lines1.fig \
+ opstar.fig
+
+@BUILD_MANUAL_TRUE@dist_doc_DATA = ragel-guide.pdf
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .fig .pdf .tex
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+ragel.1: $(top_builddir)/config.status $(srcdir)/ragel.1.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-man1: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
+ ctags-am distclean distclean-generic distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
+ uninstall uninstall-am uninstall-dist_docDATA uninstall-man \
+ uninstall-man1
+
+
+@BUILD_MANUAL_TRUE@.fig.pdf:
+@BUILD_MANUAL_TRUE@ fig2dev -L pdf $< $@
+
+@BUILD_MANUAL_TRUE@.tex.pdf:
+@BUILD_MANUAL_TRUE@ pdflatex -interaction=nonstopmode $< >/dev/null
+@BUILD_MANUAL_TRUE@ pdflatex -interaction=nonstopmode $< >/dev/null
+@BUILD_MANUAL_TRUE@ pdflatex -interaction=nonstopmode $< >/dev/null
+
+@BUILD_MANUAL_TRUE@version.tex: Makefile
+@BUILD_MANUAL_TRUE@ echo '|def|version{$(PACKAGE_VERSION)}' | tr '|' '\\' > version.tex
+@BUILD_MANUAL_TRUE@ echo '|def|pubdate{$(PUBDATE)}' | tr '|' '\\' >> version.tex
+
+@BUILD_MANUAL_TRUE@ragel-guide.pdf: version.tex
+
+@BUILD_MANUAL_TRUE@ragel-guide.pdf: bmconcat.pdf bmregex.pdf dropdown.pdf exdoneact.pdf \
+@BUILD_MANUAL_TRUE@ exoutact1.pdf exstrongsubtr.pdf lines2.pdf smallscanner.pdf bmnull.pdf \
+@BUILD_MANUAL_TRUE@ comments1.pdf entryguard.pdf exinter.pdf exoutact2.pdf exsubtr.pdf \
+@BUILD_MANUAL_TRUE@ lmkleene.pdf stembed.pdf bmnum.pdf comments2.pdf exaction.pdf \
+@BUILD_MANUAL_TRUE@ exnegate.pdf explus.pdf finguard.pdf opconcat.pdf bmor.pdf conds1.pdf \
+@BUILD_MANUAL_TRUE@ exallact.pdf exoption.pdf exstact.pdf leftguard.pdf opor.pdf \
+@BUILD_MANUAL_TRUE@ bmrange.pdf conds2.pdf exconcat.pdf exor.pdf exstar.pdf lines1.pdf \
+@BUILD_MANUAL_TRUE@ opstar.pdf
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/bmconcat.fig b/doc/bmconcat.fig
new file mode 100644
index 0000000..921f131
--- /dev/null
+++ b/doc/bmconcat.fig
@@ -0,0 +1,78 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmconcat
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 2550 383 383 1333 2550 1716 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 139 2550 237 2550 354 2550 485 2550 624 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9400 2550 383 383 9400 2550 9783 2933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9400 2550 450 450 9400 2550 9850 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 9400 2633 5\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 2550 383 383 2966 2550 3349 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2966 2633 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 2550 1837 2550 1946 2550 2060 2550 2175 2550 2289 2550 2400 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2400 2483 2566 2550 2400 2600 2400 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2150 2500 'h'\001
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4566 2550 383 383 4566 2550 4949 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 4566 2633 2\001
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 3366 2550 3467 2550 3571 2550 3677 2550 3783 2550 3891 2550 4000 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 4000 2483 4166 2550 4000 2600 4000 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3766 2500 'e'\001
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6133 2550 383 383 6133 2550 6516 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6133 2633 3\001
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 4966 2550 5060 2550 5159 2550 5260 2550 5362 2550 5465 2550 5566 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5566 2483 5733 2550 5566 2600 5566 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5350 2500 'l'\001
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7700 2550 383 383 7700 2550 8083 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 7700 2633 4\001
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 6533 2550 6627 2550 6725 2550 6827 2550 6929 2550 7032 2550 7133 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 7133 2483 7300 2550 7133 2600 7133 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6916 2500 'l'\001
+# 4 -> 5
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 8100 2550 8202 2550 8309 2550 8420 2550 8534 2550 8650 2550 8766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 8766 2483 8933 2550 8766 2600 8766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 8516 2500 'o'\001
+# end of FIG file
diff --git a/doc/bmnull.fig b/doc/bmnull.fig
new file mode 100644
index 0000000..a56e2ad
--- /dev/null
+++ b/doc/bmnull.fig
@@ -0,0 +1,28 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmnull
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 2550 383 383 1400 2550 1783 2933
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 2550 450 450 1400 2550 1850 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1400 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 132 2550 225 2550 341 2550 474 2550 617 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# end of FIG file
diff --git a/doc/bmnum.fig b/doc/bmnum.fig
new file mode 100644
index 0000000..f00eec4
--- /dev/null
+++ b/doc/bmnum.fig
@@ -0,0 +1,38 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmnum
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 2550 383 383 1333 2550 1716 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 139 2550 237 2550 354 2550 485 2550 624 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3066 2550 383 383 3066 2550 3449 2933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3066 2550 450 450 3066 2550 3516 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3066 2633 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 2550 1838 2550 1951 2550 2070 2550 2192 2550 2314 2550 2433 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2433 2483 2600 2550 2433 2600 2433 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2166 2500 42\001
+# end of FIG file
diff --git a/doc/bmor.fig b/doc/bmor.fig
new file mode 100644
index 0000000..093c4f2
--- /dev/null
+++ b/doc/bmor.fig
@@ -0,0 +1,38 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmor
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 2550 383 383 1333 2550 1716 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 139 2550 237 2550 354 2550 485 2550 624 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3933 2550 383 383 3933 2550 4316 2933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3933 2550 450 450 3933 2550 4383 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3933 2633 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 2550 1960 2550 2217 2550 2491 2550 2771 2550 3045 2550 3300 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 3300 2483 3466 2550 3300 2600 3300 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2600 2500 'e', 'h', 'l', 'o'\001
+# end of FIG file
diff --git a/doc/bmrange.fig b/doc/bmrange.fig
new file mode 100644
index 0000000..7c85d8e
--- /dev/null
+++ b/doc/bmrange.fig
@@ -0,0 +1,38 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmrange
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 2550 383 383 1333 2550 1716 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 139 2550 237 2550 354 2550 485 2550 624 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 2550 383 383 3333 2550 3716 2933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 2550 450 450 3333 2550 3783 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3333 2633 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 2550 1881 2550 2039 2550 2204 2550 2371 2550 2538 2550 2700 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2700 2483 2866 2550 2700 2600 2700 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2300 2500 'a'..'z'\001
+# end of FIG file
diff --git a/doc/bmregex.fig b/doc/bmregex.fig
new file mode 100644
index 0000000..881f534
--- /dev/null
+++ b/doc/bmregex.fig
@@ -0,0 +1,109 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: bmregex
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3850 33 33 33 3850 66 3883
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3850 383 383 1333 3850 1716 4233
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6866 3850 383 383 6866 3850 7249 4233
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6866 3850 450 450 6866 3850 7316 4300
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4866 3850 383 383 4866 3850 5249 4233
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2933 3850 383 383 2933 3850 3316 4233
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3783 933 3850 766 3900 766 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6583 3350 6550 3516 6483 3350 6583 3350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5333 4166 5200 4050 5383 4066 5333 4166
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2366 3783 2533 3850 2366 3900 2366 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2700 3400 2666 3566 2600 3400 2700 3400
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4300 3783 4466 3850 4300 3900 4300 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6233 3783 6400 3850 6233 3883 6233 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4633 3400 4600 3566 4533 3400 4633 3400
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -90 2835 7515 2835 7515 4365 -90 4365 -90 2835
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3850 139 3850 237 3850 354 3850 485 3850 624 3850
+ 766 3850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7183 3516 7208 3410 7201 3312 7162 3227 7093 3159 6994 3115
+ 6866 3100 6772 3108 6691 3131 6625 3168 6575 3218 6544 3279
+ 6533 3350
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 6466 4066 6407 4091 6345 4115 6283 4137 6220 4156 6159 4172
+ 6100 4183 6001 4198 5917 4209 5839 4214 5760 4212 5672 4203
+ 5566 4183 5533 4174 5499 4166 5464 4156 5428 4145 5390 4132
+ 5350 4116
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3850 1834 3850 1938 3850 2043 3850 2150 3850 2258 3850
+ 2366 3850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3200 3566 3220 3467 3216 3374 3185 3291 3128 3225 3044 3182
+ 2933 3166 2849 3174 2782 3197 2729 3233 2690 3280 2664 3336
+ 2650 3400
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3333 3850 3481 3850 3639 3850 3804 3850 3971 3850 4138 3850
+ 4300 3850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 5266 3850 5316 3848 5366 3845 5416 3841 5466 3837 5516 3834
+ 5566 3833 5676 3833 5764 3833 5839 3833 5913 3833 5996 3833
+ 6100 3833 6123 3833 6145 3833 6166 3833 6187 3833 6209 3833
+ 6233 3833
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5133 3566 5154 3467 5149 3374 5118 3291 5061 3225 4977 3182
+ 4866 3166 4783 3174 4715 3197 4662 3233 4623 3280 4597 3336
+ 4583 3400
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3933 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3800 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6866 3933 3\001
+4 1 0 0 0 0 14 0.0000 2 165 540 6866 3050 '1'..'3'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4866 3933 2\001
+4 1 0 0 0 0 14 0.0000 2 150 465 5833 4116 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 120 2933 3933 1\001
+4 1 0 0 0 0 14 0.0000 2 150 195 2133 3800 'a'\001
+4 1 0 0 0 0 14 0.0000 2 150 210 2933 3116 'b'\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3900 3800 'c'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 165 540 5833 3783 '1'..'3'\001
+4 1 0 0 0 0 14 0.0000 2 150 465 4866 3116 DEF\001
diff --git a/doc/comments1.fig b/doc/comments1.fig
new file mode 100644
index 0000000..066de16
--- /dev/null
+++ b/doc/comments1.fig
@@ -0,0 +1,167 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: comments1
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 5833 33 33 33 5833 66 5866
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 5833 383 383 1333 5833 1716 6216
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 12833 5216 383 383 12833 5216 13216 5599
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 12833 5216 450 450 12833 5216 13283 5666
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4533 5833 383 383 4533 5833 4916 6216
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7383 5900 383 383 7383 5900 7766 6283
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2900 5833 383 383 2900 5833 3283 6216
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10333 6300 383 383 10333 6300 10716 6683
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 5766 933 5833 766 5883 766 5766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5033 5583 4866 5616 4983 5483 5033 5583
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7933 5766 7750 5766 7900 5666 7933 5766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2333 5766 2500 5833 2333 5883 2333 5766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3966 5766 4133 5833 3966 5883 3966 5766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4300 5383 4266 5550 4200 5383 4300 5383
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6816 5800 6983 5866 6816 5900 6816 5800
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5000 6150 4866 6033 5050 6050 5000 6150
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7150 5450 7116 5616 7050 5450 7150 5450
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9816 6066 9966 6166 9783 6166 9816 6066
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 12300 5516 12466 5483 12350 5616 12300 5516
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4800 6316 4683 6183 4850 6216 4800 6316
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7833 6250 7716 6116 7883 6150 7833 6250
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 13410 4365 -45 4365 -45 6840 13410 6840 13410 4365
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 5833 139 5833 237 5833 354 5833 485 5833 624 5833
+ 766 5833
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 5 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 12383 5100 11763 4966 10941 4822 9975 4700 8919 4633 7830 4655
+ 6766 4800 6447 4883 6127 4993 5816 5122 5522 5261 5252 5401
+ 5016 5533
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 5 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 12366 5216 11883 5230 11275 5256 10577 5302 9824 5370 9053 5468
+ 8300 5600 8233 5616 8167 5633 8102 5652 8038 5671 7976 5692
+ 7916 5716
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 5833 1827 5833 1925 5833 2027 5833 2129 5833 2232 5833
+ 2333 5833
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3300 5833 3403 5833 3513 5833 3627 5833 3741 5833 3855 5833
+ 3966 5833
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4800 5550 4820 5450 4816 5357 4785 5275 4728 5209 4644 5165
+ 4533 5150 4449 5158 4382 5180 4329 5216 4290 5263 4264 5319
+ 4250 5383
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 4933 5833 4983 5832 5033 5829 5083 5825 5133 5820 5183 5817
+ 5233 5816 5478 5815 5679 5812 5856 5810 6032 5809 6228 5810
+ 6466 5816 6525 5823 6583 5829 6641 5833 6700 5837 6758 5842
+ 6816 5850
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 7016 6033 6930 6065 6840 6093 6747 6118 6653 6139 6559 6155
+ 6466 6166 6228 6204 6032 6233 5856 6247 5679 6244 5478 6218
+ 5233 6166 5199 6158 5166 6149 5131 6139 5095 6128 5057 6115
+ 5016 6100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7650 5616 7670 5517 7666 5424 7635 5341 7578 5275 7494 5232
+ 7383 5216 7299 5224 7232 5247 7179 5283 7140 5330 7114 5386
+ 7100 5450
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7783 5900 8021 5909 8296 5924 8595 5943 8909 5970 9225 6005
+ 9533 6050 9576 6059 9620 6070 9666 6083 9712 6095 9757 6107
+ 9800 6116
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 4 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 10716 6200 10908 6150 11125 6085 11360 6008 11601 5919 11840 5821
+ 12066 5716 12108 5691 12149 5666 12191 5641 12233 5616 12274 5591
+ 12316 5566
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 4 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 10000 6516 9933 6529 9864 6537 9791 6541 9713 6546 9628 6553
+ 9533 6566 8997 6655 8556 6719 8162 6758 7765 6769 7316 6750
+ 6766 6700 6483 6658 6150 6602 5793 6533 5438 6453 5109 6363
+ 4833 6266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 4 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 9950 6383 9722 6416 9462 6446 9181 6464 8887 6464 8590 6440
+ 8300 6383 8225 6363 8150 6339 8077 6310 8004 6277 7934 6240
+ 7866 6200
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 5916 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 5783 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 12833 5300 5\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4533 5916 2\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 8916 4600 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 120 7383 5983 3\001
+4 1 0 0 0 0 14 0.0000 2 150 975 10333 5266 '*' / comm\001
+4 1 0 0 0 0 14 0.0000 2 165 120 2900 5916 1\001
+4 1 0 0 0 0 14 0.0000 2 150 150 2116 5783 '/'\001
+4 1 0 0 0 0 14 0.0000 2 90 210 3716 5783 '*'\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 4533 5100 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 975 5850 5766 '*' / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 5850 6116 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 975 7383 5166 '*' / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 120 10333 6383 4\001
+4 1 0 0 0 0 14 0.0000 2 150 915 8916 5883 '/' / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 915 11600 5666 ' ' / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 7383 6650 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 975 8916 6333 '*' / comm\001
diff --git a/doc/comments2.fig b/doc/comments2.fig
new file mode 100644
index 0000000..3417edc
--- /dev/null
+++ b/doc/comments2.fig
@@ -0,0 +1,110 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: comments2
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3716 33 33 33 3716 66 3749
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3716 383 383 1333 3716 1716 4099
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8800 3716 383 383 8800 3716 9183 4099
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8800 3716 450 450 8800 3716 9250 4166
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2900 3716 383 383 2900 3716 3283 4099
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4533 3716 383 383 4533 3716 4916 4099
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7166 3716 383 383 7166 3716 7549 4099
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3650 933 3716 766 3766 766 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2333 3650 2500 3716 2333 3766 2333 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3966 3650 4133 3716 3966 3766 3966 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4300 3266 4266 3433 4200 3266 4300 3266
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6600 3650 6766 3716 6600 3750 6600 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8166 3650 8333 3716 8166 3766 8166 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5000 4033 4866 3916 5050 3933 5000 4033
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6933 3266 6900 3433 6833 3266 6933 3266
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9315 2745 -45 2745 -45 4185 9315 4185 9315 2745
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3716 139 3716 237 3716 354 3716 485 3716 624 3716
+ 766 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3716 1827 3716 1925 3716 2027 3716 2129 3716 2232 3716
+ 2333 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3300 3716 3403 3716 3513 3716 3627 3716 3741 3716 3855 3716
+ 3966 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4800 3433 4820 3334 4816 3240 4785 3158 4728 3092 4644 3049
+ 4533 3033 4449 3041 4382 3064 4329 3100 4290 3146 4264 3203
+ 4250 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 4933 3716 4983 3715 5033 3712 5083 3708 5133 3704 5183 3701
+ 5233 3700 5478 3700 5679 3700 5856 3700 6032 3700 6228 3700
+ 6466 3700 6490 3700 6512 3700 6533 3700 6554 3700 6576 3700
+ 6600 3700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 7566 3716 7660 3716 7759 3716 7860 3716 7962 3716 8065 3716
+ 8166 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 6833 3916 6774 3948 6716 3977 6656 4002 6595 4022 6532 4038
+ 6466 4050 6228 4098 6032 4127 5856 4137 5679 4127 5478 4098
+ 5233 4050 5199 4041 5166 4032 5131 4022 5095 4011 5057 3998
+ 5016 3983
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7433 3433 7454 3334 7449 3240 7418 3158 7361 3092 7277 3049
+ 7166 3033 7083 3041 7015 3064 6962 3100 6923 3146 6897 3203
+ 6883 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3800 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3666 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8800 3800 4\001
+4 1 0 0 0 0 14 0.0000 2 165 120 2900 3800 1\001
+4 1 0 0 0 0 14 0.0000 2 150 150 2116 3666 '/'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4533 3800 2\001
+4 1 0 0 0 0 14 0.0000 2 90 210 3716 3666 '*'\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 4533 2983 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 120 7166 3800 3\001
+4 1 0 0 0 0 14 0.0000 2 150 975 5850 3650 '*' / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 150 7950 3666 '/'\001
+4 1 0 0 0 0 14 0.0000 2 150 1230 5850 3983 DEF / comm\001
+4 1 0 0 0 0 14 0.0000 2 150 975 7166 2983 '*' / comm\001
diff --git a/doc/conds1.fig b/doc/conds1.fig
new file mode 100644
index 0000000..3436e89
--- /dev/null
+++ b/doc/conds1.fig
@@ -0,0 +1,96 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: conds1
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 4650 33 33 33 4650 66 4683
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 4650 383 383 1400 4650 1783 5033
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 4650 450 450 1400 4650 1850 5100
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3233 4650 383 383 3233 4650 3616 5033
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8466 4650 383 383 8466 4650 8849 5033
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8466 4650 450 450 8466 4650 8916 5100
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5500 5683 383 383 5500 5683 5883 6066
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 4583 933 4650 766 4700 766 4583
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2666 4583 2833 4650 2666 4700 2666 4583
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8183 4150 8150 4316 8083 4150 8183 4150
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3783 4683 3616 4633 3783 4566 3783 4683
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5016 5400 5150 5516 4966 5500 5016 5400
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7850 4800 8033 4800 7883 4900 7850 4800
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5266 5233 5233 5400 5166 5233 5266 5233
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9360 3645 -90 3645 -90 6165 9360 6165 9360 3645
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 4650 132 4650 225 4650 341 4650 474 4650 617 4650
+ 766 4650
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1866 4650 1995 4650 2129 4650 2266 4650 2403 4650 2537 4650
+ 2666 4650
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 8783 4316 8808 4210 8801 4112 8762 4027 8693 3959 8594 3915
+ 8466 3900 8372 3908 8291 3931 8225 3968 8175 4018 8144 4079
+ 8133 4150
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 8016 4633 7959 4632 7904 4629 7852 4625 7800 4620 7750 4617
+ 7700 4616 7136 4601 6679 4589 6272 4581 5865 4577 5403 4577
+ 4833 4583 4661 4591 4483 4600 4302 4608 4122 4616 3947 4625
+ 3783 4633
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3600 4816 3800 4908 4029 5014 4275 5127 4525 5241 4771 5351
+ 5000 5450
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5866 5550 6147 5455 6477 5342 6835 5218 7200 5090 7550 4965
+ 7866 4850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5766 5400 5787 5300 5782 5207 5752 5125 5695 5059 5611 5015
+ 5500 5000 5416 5008 5348 5030 5295 5066 5256 5113 5230 5169
+ 5216 5233
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 4733 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 4600 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3233 4733 1\001
+4 1 0 0 0 0 14 0.0000 2 165 360 2350 4600 100\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8466 4733 3\001
+4 1 0 0 0 0 14 0.0000 2 210 1590 8466 3850 97..122(test_len)\001
+4 1 0 0 0 0 14 0.0000 2 210 1305 5500 4533 100(!test_len)\001
+4 1 0 0 0 0 14 0.0000 2 150 120 5500 5766 2\001
+4 1 0 0 0 0 14 0.0000 2 150 600 4233 4966 48..57\001
+4 1 0 0 0 0 14 0.0000 2 180 1245 7083 4900 58 / rec_num\001
+4 1 0 0 0 0 14 0.0000 2 150 600 5500 4950 48..57\001
diff --git a/doc/conds2.fig b/doc/conds2.fig
new file mode 100644
index 0000000..d5a5557
--- /dev/null
+++ b/doc/conds2.fig
@@ -0,0 +1,107 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: conds2
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 4350 33 33 33 4350 66 4383
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 4350 383 383 1333 4350 1716 4733
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 11633 5016 383 383 11633 5016 12016 5399
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 11633 5016 450 450 11633 5016 12083 5466
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9183 4433 383 383 9183 4433 9566 4816
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4766 5383 383 383 4766 5383 5149 5766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 4283 933 4350 766 4400 766 4283
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8616 4316 8783 4383 8616 4416 8616 4316
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4233 5166 4383 5266 4200 5266 4233 5166
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 11033 4816 11183 4916 11000 4916 11033 4816
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8950 3983 8916 4150 8850 3983 8950 3983
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 11016 5050 11183 5083 11016 5150 11016 5050
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8633 4500 8800 4516 8650 4600 8633 4500
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4533 4933 4500 5100 4433 4933 4533 4933
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 12285 3465 -135 3465 -135 5895 12285 5895 12285 3465
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 4350 139 4350 237 4350 354 4350 485 4350 624 4350
+ 766 4350
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 25
+ 1716 4283 1773 4282 1828 4278 1881 4272 1932 4266 1983 4258
+ 2033 4250 2352 4232 2611 4227 2839 4231 3066 4238 3321 4246
+ 3633 4250 4551 4259 5297 4260 5956 4260 6613 4267 7355 4288
+ 8266 4333 8325 4340 8383 4345 8441 4350 8499 4354 8558 4359
+ 8616 4366
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 0.000
+# 0 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1716 4466 2062 4570 2479 4694 2935 4829 3398 4966 3835 5098
+ 4216 5216
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 9566 4516 9774 4564 10009 4622 10260 4685 10518 4750 10773 4811
+ 11016 4866
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 9450 4150 9470 4050 9466 3957 9435 3875 9378 3809 9294 3765
+ 9183 3750 9099 3758 9032 3780 8979 3816 8940 3863 8914 3919
+ 8900 3983
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5166 5383 5685 5380 6364 5370 7158 5352 8024 5324 8919 5284
+ 9800 5233 10010 5215 10222 5195 10433 5172 10638 5149 10833 5124
+ 11016 5100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5150 5300 5623 5200 6208 5075 6854 4937 7508 4796 8118 4663
+ 8633 4550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5033 5100 5054 5000 5049 4907 5018 4825 4961 4759 4877 4715
+ 4766 4700 4683 4708 4615 4730 4562 4766 4523 4813 4497 4869
+ 4483 4933
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 4433 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 4300 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 11633 5100 2\001
+4 1 0 0 0 0 14 0.0000 2 165 120 9183 4516 1\001
+4 1 0 0 0 0 14 0.0000 2 210 1665 4766 4216 97..122(!test_len)\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4766 5466 3\001
+4 1 0 0 0 0 14 0.0000 2 210 1590 2833 4533 97..122(test_len)\001
+4 1 0 0 0 0 14 0.0000 2 165 780 10483 4633 10 / two\001
+4 1 0 0 0 0 14 0.0000 2 195 1440 9183 3700 48..57, 97..122\001
+4 1 0 0 0 0 14 0.0000 2 195 1245 9183 5183 10 / one, two\001
+4 1 0 0 0 0 14 0.0000 2 210 2385 7083 4616 48..57, 97..122(!test_len)\001
+4 1 0 0 0 0 14 0.0000 2 210 1590 4766 4650 97..122(test_len)\001
diff --git a/doc/dropdown.fig b/doc/dropdown.fig
new file mode 100644
index 0000000..29fefec
--- /dev/null
+++ b/doc/dropdown.fig
@@ -0,0 +1,107 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: dropdown
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3950 33 33 33 3950 66 3983
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3950 383 383 1333 3950 1716 4333
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9266 4133 383 383 9266 4133 9649 4516
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9266 4133 450 450 9266 4133 9716 4583
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5383 3550 383 383 5383 3550 5766 3933
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7566 4133 383 383 7566 4133 7949 4516
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3883 933 3950 766 4000 766 3883
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1100 3500 1066 3666 1000 3500 1100 3500
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4816 3433 4983 3500 4816 3533 4816 3433
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1883 4066 1716 4000 1883 3966 1883 4066
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7033 3933 7183 4033 7000 4033 7033 3933
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8633 4066 8800 4133 8633 4183 8633 4066
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1833 4216 1666 4150 1833 4116 1833 4216
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7333 3683 7300 3850 7233 3683 7333 3683
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -90 2970 9765 2970 9765 4680 -90 4680 -90 2970
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3950 139 3950 237 3950 354 3950 485 3950 624 3950
+ 766 3950
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1600 3666 1620 3567 1616 3474 1585 3391 1528 3325 1444 3282
+ 1333 3266 1249 3274 1182 3297 1129 3333 1090 3380 1064 3436
+ 1050 3500
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1666 3750 1726 3725 1787 3700 1850 3677 1912 3654 1973 3634
+ 2033 3616 2528 3528 3036 3474 3537 3450 4013 3447 4446 3460
+ 4816 3483
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5033 3716 4892 3768 4738 3823 4575 3877 4406 3926 4235 3968
+ 4066 4000 3689 4046 3300 4070 2912 4077 2538 4067 2190 4046
+ 1883 4016
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5766 3650 5954 3695 6161 3747 6379 3804 6600 3863 6815 3923
+ 7016 3983
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 7966 4133 8069 4133 8176 4133 8287 4133 8401 4133 8516 4133
+ 8633 4133
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 7183 4233 7062 4258 6935 4282 6804 4304 6669 4323 6534 4339
+ 6400 4350 5539 4415 4838 4443 4216 4433 3595 4384 2893 4295
+ 2033 4166 1999 4166 1966 4166 1933 4166 1899 4166 1866 4166
+ 1833 4166
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7833 3850 7854 3750 7849 3657 7818 3575 7761 3509 7677 3465
+ 7566 3450 7483 3458 7415 3480 7362 3516 7323 3563 7297 3619
+ 7283 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 4033 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3900 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 9266 4216 3\001
+4 1 0 0 0 0 14 0.0000 2 150 1170 1333 3216 DEF / bchar\001
+4 1 0 0 0 0 14 0.0000 2 165 120 5383 3633 1\001
+4 1 0 0 0 0 14 0.0000 2 195 165 3050 3416 ']'\001
+4 1 0 0 0 0 14 0.0000 2 195 2055 3050 3950 DEF / bbrack1, bchar\001
+4 1 0 0 0 0 14 0.0000 2 150 120 7566 4216 2\001
+4 1 0 0 0 0 14 0.0000 2 195 165 6783 3883 ']'\001
+4 1 0 0 0 0 14 0.0000 2 150 225 8383 4083 '>'\001
+4 1 0 0 0 0 14 0.0000 2 195 2055 5383 4300 DEF / bbrack2, bchar\001
+4 1 0 0 0 0 14 0.0000 2 210 1110 7566 3400 ']' / bbrack1\001
diff --git a/doc/entryguard.fig b/doc/entryguard.fig
new file mode 100644
index 0000000..c848716
--- /dev/null
+++ b/doc/entryguard.fig
@@ -0,0 +1,73 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exstpri
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3550 33 33 33 3550 66 3583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3550 383 383 1333 3550 1716 3933
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6266 3550 383 383 6266 3550 6649 3933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6266 3550 450 450 6266 3550 6716 4000
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 3550 383 383 2966 3550 3349 3933
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4533 3550 383 383 4533 3550 4916 3933
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3483 933 3550 766 3600 766 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1100 3100 1066 3266 1000 3100 1100 3100
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2400 3483 2566 3550 2400 3600 2400 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3966 3483 4133 3550 3966 3600 3966 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5633 3483 5800 3550 5633 3600 5633 3483
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -45 2565 6795 2565 6795 4185 -45 4185 -45 2565
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3550 139 3550 237 3550 354 3550 485 3550 624 3550
+ 766 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1600 3266 1620 3167 1616 3074 1585 2991 1528 2925 1444 2882
+ 1333 2866 1249 2874 1182 2897 1129 2933 1090 2980 1064 3036
+ 1050 3100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3550 1837 3550 1946 3550 2060 3550 2175 3550 2289 3550
+ 2400 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3366 3550 3460 3550 3559 3550 3660 3550 3762 3550 3865 3550
+ 3966 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4933 3550 5038 3550 5151 3550 5270 3550 5392 3550 5514 3550
+ 5633 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3633 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3500 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6266 3633 3\001
+4 1 0 0 0 0 14 0.0000 2 150 465 1333 2816 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 120 2966 3633 1\001
+4 1 0 0 0 0 14 0.0000 2 150 225 2150 3500 'F'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4533 3633 2\001
+4 1 0 0 0 0 14 0.0000 2 150 165 3750 3500 'I'\001
+4 1 0 0 0 0 14 0.0000 2 150 270 5366 3500 'N'\001
diff --git a/doc/exaction.fig b/doc/exaction.fig
new file mode 100644
index 0000000..9829f06
--- /dev/null
+++ b/doc/exaction.fig
@@ -0,0 +1,64 @@
+#FIG 3.2
+# Generated by Graphviz version 2.12 (Tue Sep 4 16:56:48 UTC 2007)
+# For: (thurston) Adrian Thurston,,,
+# Title: exaction
+# Pages: 1
+Portrait
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+0 32 #d3d3d3
+2 3 0 1 7 7 2 0 20 0.0 0 0 0 0 0 5
+ 0 2460 0 0 8680 0 8680 2460 0 2460
+# ENTRY
+1 1 0 1 0 0 1 0 20 0.000 0 0.0000 120 720 40 -40 120 720 160 680
+# 1
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 1640 720 420 -430 1640 720 2060 290
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 1640 800 1\001
+# ENTRY->1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 160 720 247 720 364 720 505 720 662 720 829 720 1000 720
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 1000 650 1200 720 1000 790 1000 650
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 680 600 IN\001
+# 3
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 8080 720 422 -430 8080 720 8502 290
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 8080 720 500 -510 8080 720 8580 210
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 8080 800 3\001
+# 1->3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 19
+ 2060 620 2121 610 2185 600 2250 590 2315 580 2379 570 2440 560 3383 488 4150 465 4828 480 5504 521 6265 579 7200 640 7229 641 7255 645 7280 650 7305 655 7331 659 7360 660
+ 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 7368 590 7560 680 7354 730 7368 590
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 4980 360 '\\n' / A, C, N\001
+# 2
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 4980 1960 420 -430 4980 1960 5400 1530
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 4980 2040 2\001
+# 1->2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 2040 860 2376 985 2767 1133 3188 1293 3613 1454 4019 1607 4380 1740
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 4409 1675 4580 1800 4368 1810 4409 1675
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 3160 920 'a'..'z' / A, B\001
+# 2->3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 5380 1800 5669 1681 6002 1547 6363 1405 6731 1259 7090 1116 7420 980
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 7389 917 7600 900 7446 1045 7389 917
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 6640 1000 '\\n' / C, N\001
+# 2->2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 4580 1780 4432 1645 4368 1509 4390 1383 4499 1278 4695 1206 4980 1180 5220 1199 5401 1250 5523 1328 5586 1423 5592 1530 5540 1640
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5577 1701 5380 1780 5484 1596 5577 1701
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 4980 1060 'a'..'z' / B\001
+# end of FIG file
diff --git a/doc/exallact.fig b/doc/exallact.fig
new file mode 100644
index 0000000..593ffd3
--- /dev/null
+++ b/doc/exallact.fig
@@ -0,0 +1,48 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exallact
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 2550 33 33 33 2550 66 2583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 2550 383 383 1333 2550 1716 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 2633 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 2550 139 2550 237 2550 354 2550 485 2550 624 2550 766 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 2483 933 2550 766 2600 766 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 2500 IN\001
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5733 2550 383 383 5733 2550 6116 2933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5733 2550 450 450 5733 2550 6183 3000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5733 2633 2\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3366 2550 383 383 3366 2550 3749 2933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3366 2633 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 2550 1893 2550 2069 2550 2254 2550 2441 2550 2626 2550 2800 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2800 2483 2966 2550 2800 2600 2800 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2350 2500 'm' / A\001
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 3766 2550 3962 2550 4179 2550 4408 2550 4643 2550 4876 2550 5100 2550
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5100 2483 5266 2550 5100 2600 5100 2483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 4516 2500 '1'..'2' / A\001
+# end of FIG file
diff --git a/doc/exconcat.fig b/doc/exconcat.fig
new file mode 100644
index 0000000..e634139
--- /dev/null
+++ b/doc/exconcat.fig
@@ -0,0 +1,217 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exconcat
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 10216 33 33 33 10216 66 10249
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 10216 383 383 1333 10216 1716 10599
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8466 9950 383 383 8466 9950 8849 10333
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8466 9950 450 450 8466 9950 8916 10400
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3000 9283 383 383 3000 9283 3383 9666
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10400 9283 383 383 10400 9283 10783 9666
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4666 8466 383 383 4666 8466 5049 8849
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6533 9000 383 383 6533 9000 6916 9383
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 10150 933 10216 766 10266 766 10150
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1866 10400 1716 10316 1883 10300 1866 10400
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3550 9400 3383 9333 3550 9300 3550 9400
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9850 9416 10033 9416 9883 9516 9850 9416
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1100 9766 1066 9933 1000 9766 1100 9766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2566 9650 2733 9583 2650 9733 2566 9650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 10116 9750 10250 9633 10216 9800 10116 9750
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1750 9833 1583 9916 1666 9750 1750 9833
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 10250 8750 10283 8916 10150 8800 10250 8750
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4150 8666 4316 8633 4200 8766 4150 8666
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1400 10783 1383 10600 1500 10733 1400 10783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 10166 8833 10133 9000 10066 8833 10166 8833
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1500 9716 1366 9833 1400 9666 1500 9716
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9916 8983 10066 9083 9883 9083 9916 8983
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6000 8800 6150 8900 5966 8900 6000 8800
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7916 9650 8050 9766 7866 9750 7916 9650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9850 9183 10016 9250 9850 9283 9850 9183
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 11160 7065 -45 7065 -45 12015 11160 12015 11160 7065
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 10216 139 10216 237 10216 354 10216 485 10216 624 10216
+ 766 10216
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 5 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 8050 10133 7841 10211 7604 10290 7347 10364 7078 10425 6804 10467
+ 6533 10483 5044 10483 4046 10483 3441 10483 3130 10483 3016 10483
+ 3000 10483 2806 10478 2610 10463 2416 10441 2228 10414 2049 10383
+ 1883 10350
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 5 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 8000 9900 7398 9822 6642 9727 5806 9625 4962 9522 4186 9427
+ 3550 9350
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 5 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 8900 9800 9049 9747 9209 9691 9377 9633 9545 9575 9710 9519
+ 9866 9466
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1600 9933 1620 9834 1616 9740 1585 9658 1528 9592 1444 9549
+ 1333 9533 1249 9541 1182 9564 1129 9600 1090 9646 1064 9703
+ 1050 9766
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1716 10150 1810 10122 1908 10089 2008 10052 2108 10010 2205 9965
+ 2300 9916 2356 9889 2411 9856 2462 9820 2511 9782 2556 9741
+ 2600 9700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 1533 10550 1735 10781 1935 10961 2147 11093 2386 11183 2665 11234
+ 3000 11250 3025 11250 3202 11250 3683 11250 4619 11250 6163 11250
+ 8466 11250 8921 11199 9270 11054 9541 10829 9762 10533 9962 10181
+ 10166 9783
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 2 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 2616 9366 2522 9393 2424 9422 2325 9456 2225 9493 2127 9536
+ 2033 9583 1963 9623 1902 9661 1847 9697 1797 9732 1748 9766
+ 1700 9800
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 25
+ 3250 8983 3275 8967 3300 8953 3325 8937 3350 8919 3375 8896
+ 3400 8866 3659 8554 3824 8222 3952 7906 4097 7638 4317 7452
+ 4666 7383 4684 7383 4807 7383 5141 7383 5792 7383 6865 7383
+ 8466 7383 8911 7429 9260 7560 9539 7768 9772 8045 9984 8380
+ 10200 8766
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3350 9116 3472 9055 3606 8990 3745 8922 3888 8853 4029 8784
+ 4166 8716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 31
+ 10366 9666 10365 9691 10362 9715 10358 9737 10354 9756 10351 9772
+ 10350 9783 10276 10083 10211 10331 10137 10545 10038 10746 9898 10952
+ 9700 11183 9509 11404 9339 11583 9170 11722 8982 11821 8754 11880
+ 8466 11900 6163 11900 4619 11900 3683 11900 3202 11900 3025 11900
+ 3000 11900 2609 11865 2294 11764 2037 11600 1822 11374 1631 11089
+ 1450 10750
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 10666 9000 10687 8900 10682 8807 10652 8725 10595 8659 10511 8615
+ 10400 8600 10316 8608 10248 8630 10195 8666 10156 8713 10130 8769
+ 10116 8833
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4266 8466 4030 8471 3764 8488 3477 8520 3180 8572 2884 8647
+ 2600 8750 2326 8880 2098 8999 1906 9122 1740 9267 1591 9448
+ 1450 9683
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 31
+ 5050 8400 5107 8391 5161 8383 5214 8375 5266 8366 5316 8358
+ 5366 8350 5462 8344 5539 8342 5606 8343 5671 8346 5744 8348
+ 5833 8350 6455 8390 6959 8432 7402 8483 7840 8551 8332 8643
+ 8933 8766 9088 8804 9213 8837 9322 8868 9430 8901 9551 8938
+ 9700 8983 9740 8991 9777 9000 9812 9008 9844 9016 9873 9025
+ 9900 9033
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5050 8566 5190 8609 5343 8654 5504 8702 5667 8750 5828 8800
+ 5983 8850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 4 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6866 9200 6926 9233 6987 9266 7050 9297 7112 9328 7173 9357
+ 7233 9383 7342 9434 7454 9487 7566 9541 7679 9595 7790 9648
+ 7900 9700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 4 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 6933 9016 7047 9024 7172 9032 7304 9039 7438 9045 7571 9048
+ 7700 9050 8099 9080 8422 9108 8706 9133 8988 9158 9307 9185
+ 9700 9216 9725 9217 9750 9220 9775 9225 9800 9229 9825 9232
+ 9850 9233
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 10300 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 10166 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8466 10033 5\001
+4 1 0 0 0 0 14 0.0000 2 165 240 4666 10433 10\001
+4 1 0 0 0 0 14 0.0000 2 150 120 3000 9366 2\001
+4 1 0 0 0 0 14 0.0000 2 150 240 5600 9550 'E'\001
+4 1 0 0 0 0 14 0.0000 2 165 120 10400 9366 1\001
+4 1 0 0 0 0 14 0.0000 2 150 465 9466 9500 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 240 1333 9483 10\001
+4 1 0 0 0 0 14 0.0000 2 150 240 2166 9866 'E'\001
+4 1 0 0 0 0 14 0.0000 2 150 465 5600 11200 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 240 2166 9450 10\001
+4 1 0 0 0 0 14 0.0000 2 150 465 6533 7333 DEF\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4666 8550 3\001
+4 1 0 0 0 0 14 0.0000 2 150 270 3833 8800 'O'\001
+4 1 0 0 0 0 14 0.0000 2 165 240 5600 11850 10\001
+4 1 0 0 0 0 14 0.0000 2 150 465 10400 8550 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 240 3000 8516 10\001
+4 1 0 0 0 0 14 0.0000 2 150 465 7466 8433 DEF\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6533 9083 4\001
+4 1 0 0 0 0 14 0.0000 2 150 225 5600 8633 'F'\001
+4 1 0 0 0 0 14 0.0000 2 165 240 7466 9333 10\001
+4 1 0 0 0 0 14 0.0000 2 150 465 8466 9050 DEF\001
diff --git a/doc/exdoneact.fig b/doc/exdoneact.fig
new file mode 100644
index 0000000..3930e5a
--- /dev/null
+++ b/doc/exdoneact.fig
@@ -0,0 +1,51 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exdoneact
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3550 33 33 33 3550 66 3583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3550 383 383 1333 3550 1716 3933
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 3550 383 383 3333 3550 3716 3933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 3550 450 450 3333 3550 3783 4000
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3483 933 3550 766 3600 766 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2700 3483 2866 3550 2700 3600 2700 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1100 3100 1066 3266 1000 3100 1100 3100
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -270 2610 3915 2610 3915 4140 -270 4140 -270 2610
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3550 139 3550 237 3550 354 3550 485 3550 624 3550
+ 766 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3550 1881 3550 2039 3550 2204 3550 2371 3550 2538 3550
+ 2700 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1600 3266 1620 3167 1616 3074 1585 2991 1528 2925 1444 2882
+ 1333 2866 1249 2874 1182 2897 1129 2933 1090 2980 1064 3036
+ 1050 3100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3633 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3500 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3333 3633 1\001
+4 1 0 0 0 0 14 0.0000 2 150 510 2300 3500 ' ' / A\001
+4 1 0 0 0 0 14 0.0000 2 150 510 1333 2816 'a'..'z'\001
diff --git a/doc/exinter.fig b/doc/exinter.fig
new file mode 100644
index 0000000..cc802f6
--- /dev/null
+++ b/doc/exinter.fig
@@ -0,0 +1,75 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exinter
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3816 33 33 33 3816 66 3849
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3816 383 383 1400 3816 1783 4199
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3816 450 450 1400 3816 1850 4266
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1400 3900 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 3816 132 3816 225 3816 341 3816 474 3816 617 3816 766 3816
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 3750 933 3816 766 3866 766 3750
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 3766 IN\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3666 3266 383 383 3666 3266 4049 3649
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3666 3350 1\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1850 3700 2044 3654 2256 3603 2477 3550 2699 3496 2915 3445 3116 3400
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 3116 3350 3283 3366 3133 3450 3116 3350
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2566 3416 ' ', 'a'..'z'\001
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5866 3216 383 383 5866 3216 6249 3599
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5866 3300 2\001
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 4066 3250 4252 3248 4456 3245 4670 3241 4887 3237 5099 3234 5300 3233
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5300 3166 5466 3233 5300 3283 5300 3166
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 4766 3200 ' ', 'a'..'z'\001
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8066 3300 383 383 8066 3300 8449 3683
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 8066 3383 3\001
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 6266 3233 6452 3241 6656 3249 6870 3258 7087 3266 7299 3274 7500 3283
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 7500 3216 7666 3283 7500 3333 7500 3216
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6966 3216 ' ', 'a'..'z'\001
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10266 3816 383 383 10266 3816 10649 4199
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 10266 3900 4\001
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 8450 3383 8637 3428 8845 3479 9064 3533 9288 3587 9508 3637 9716 3683
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 9733 3633 9883 3716 9716 3733 9733 3633
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 9166 3433 ' ', 'a'..'z'\001
+# 4 -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 19
+ 9883 3916 9643 3969 9364 4025 9056 4079 8730 4124 8396 4155 8066 4166 6212 4166 4970 4166 4216 4166 3829 4166 3687 4166 3666 4166 3378 4158 3087 4137 2797 4104 2518 4062 2255 4016 2016 3966
+ 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2000 4016 1850 3933 2016 3916 2000 4016
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5866 4116 10\001
+# end of FIG file
diff --git a/doc/exnegate.fig b/doc/exnegate.fig
new file mode 100644
index 0000000..487fda5
--- /dev/null
+++ b/doc/exnegate.fig
@@ -0,0 +1,52 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exnegate
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3683 33 33 33 3683 66 3716
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3683 383 383 1400 3683 1783 4066
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3683 450 450 1400 3683 1850 4133
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4400 3683 383 383 4400 3683 4783 4066
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4400 3683 450 450 4400 3683 4850 4133
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3616 933 3683 766 3733 766 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3766 3616 3933 3683 3766 3733 3766 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4116 3183 4083 3350 4016 3183 4116 3183
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 2655 -90 2655 -90 4230 4950 4230 4950 2655
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3683 132 3683 225 3683 341 3683 474 3683 617 3683
+ 766 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1866 3683 2147 3683 2462 3683 2797 3683 3137 3683 3465 3683
+ 3766 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4716 3350 4741 3243 4734 3145 4695 3060 4626 2993 4527 2949
+ 4400 2933 4305 2941 4224 2964 4158 3002 4108 3051 4077 3112
+ 4066 3183
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 3766 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3633 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 4400 3766 1\001
+4 1 0 0 0 0 14 0.0000 2 195 1455 2900 3633 -128..'/', ':'..127\001
+4 1 0 0 0 0 14 0.0000 2 150 465 4400 2883 DEF\001
diff --git a/doc/exoption.fig b/doc/exoption.fig
new file mode 100644
index 0000000..fafc107
--- /dev/null
+++ b/doc/exoption.fig
@@ -0,0 +1,84 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exoption
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3683 33 33 33 3683 66 3716
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3683 383 383 1333 3683 1716 4066
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 3683 383 383 3333 3683 3716 4066
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3333 3683 450 450 3333 3683 3783 4133
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4966 3683 383 383 4966 3683 5349 4066
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6966 3683 383 383 6966 3683 7349 4066
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6966 3683 450 450 6966 3683 7416 4133
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3616 933 3683 766 3733 766 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3050 3183 3016 3350 2950 3183 3050 3183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4400 3616 4566 3683 4400 3733 4400 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6683 3183 6650 3350 6583 3183 6683 3183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2700 3616 2866 3683 2700 3733 2700 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6333 3616 6500 3683 6333 3733 6333 3616
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 7515 2655 -45 2655 -45 4230 7515 4230 7515 2655
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3683 139 3683 237 3683 354 3683 485 3683 624 3683
+ 766 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3650 3350 3675 3243 3667 3145 3629 3060 3559 2993 3460 2949
+ 3333 2933 3239 2941 3158 2964 3091 3002 3041 3051 3010 3112
+ 3000 3183
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3800 3683 3894 3683 3992 3683 4093 3683 4196 3683 4298 3683
+ 4400 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7283 3350 7308 3243 7301 3145 7262 3060 7193 2993 7094 2949
+ 6966 2933 6872 2941 6791 2964 6725 3002 6675 3051 6644 3112
+ 6633 3183
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3683 1881 3683 2039 3683 2204 3683 2371 3683 2538 3683
+ 2700 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5366 3683 5514 3683 5672 3683 5837 3683 6004 3683 6171 3683
+ 6333 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3766 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3633 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3333 3766 1\001
+4 1 0 0 0 0 14 0.0000 2 150 540 3333 2883 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4966 3766 2\001
+4 1 0 0 0 0 14 0.0000 2 150 150 4183 3633 '.'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6966 3766 3\001
+4 1 0 0 0 0 14 0.0000 2 150 540 6966 2883 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 540 2300 3633 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 540 5933 3633 '0'..'9'\001
diff --git a/doc/exor.fig b/doc/exor.fig
new file mode 100644
index 0000000..62e0184
--- /dev/null
+++ b/doc/exor.fig
@@ -0,0 +1,128 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exor
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 8700 33 33 33 8700 66 8733
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 8700 383 383 1333 8700 1716 9083
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4066 7683 383 383 4066 7683 4449 8066
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4066 7683 450 450 4066 7683 4516 8133
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6133 8700 383 383 6133 8700 6516 9083
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6133 8700 450 450 6133 8700 6583 9150
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6133 7000 383 383 6133 7000 6516 7383
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9533 7000 383 383 9533 7000 9916 7383
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 9533 7000 450 450 9533 7000 9983 7450
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4066 10316 383 383 4066 10316 4449 10699
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4066 10316 450 450 4066 10316 4516 10766
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 8633 933 8700 766 8750 766 8633
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5600 8366 5716 8500 5550 8466 5600 8366
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5583 7116 5766 7116 5616 7216 5583 7116
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5850 8200 5816 8366 5750 8200 5850 8200
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9250 6500 9216 6666 9150 6500 9250 6500
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3783 9816 3750 9983 3683 9816 3783 9816
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3450 7850 3633 7850 3483 7950 3450 7850
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5500 8633 5666 8700 5500 8750 5500 8633
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3533 9966 3650 10100 3483 10066 3533 9966
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8900 6933 9066 7000 8900 7050 8900 6933
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 10530 5985 -90 5985 -90 10845 10530 10845 10530 5985
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 8700 139 8700 237 8700 354 8700 485 8700 624 8700
+ 766 8700
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4483 7883 4650 7963 4830 8051 5018 8143 5208 8237 5392 8329
+ 5566 8416
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4500 7533 4672 7479 4855 7419 5043 7356 5233 7291 5420 7227
+ 5600 7166
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6450 8366 6475 8260 6467 8162 6429 8077 6359 8009 6260 7965
+ 6133 7950 6039 7958 5958 7981 5891 8018 5841 8068 5810 8129
+ 5800 8200
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 4 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 9850 6666 9875 6560 9867 6462 9829 6377 9759 6309 9660 6265
+ 9533 6250 9439 6258 9358 6281 9291 6318 9241 6368 9210 6429
+ 9200 6500
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 5 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4383 9983 4408 9877 4401 9779 4362 9693 4293 9626 4194 9582
+ 4066 9566 3972 9574 3891 9598 3825 9635 3775 9685 3744 9746
+ 3733 9816
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1700 8566 1950 8473 2239 8364 2552 8245 2871 8124 3181 8007
+ 3466 7900
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 8700 2226 8700 2850 8700 3547 8700 4260 8700 4930 8700
+ 5500 8700
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1650 8933 1709 8976 1771 9020 1835 9066 1900 9112 1966 9157
+ 2033 9200 2280 9349 2535 9496 2791 9639 3041 9775 3280 9901
+ 3500 10016
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 6533 7000 6862 7000 7250 7000 7672 7000 8104 7000 8522 7000
+ 8900 7000
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 8783 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 8650 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 4066 7766 1\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6133 8783 2\001
+4 1 0 0 0 0 14 0.0000 2 150 540 5100 7966 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6133 7083 3\001
+4 1 0 0 0 0 14 0.0000 2 150 210 5100 7200 'x'\001
+4 1 0 0 0 0 14 0.0000 2 150 540 6133 7900 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 9533 7083 4\001
+4 1 0 0 0 0 14 0.0000 2 180 1875 9533 6200 '0'..'9', 'A'..'F', 'a'..'f'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4066 10400 5\001
+4 1 0 0 0 0 14 0.0000 2 180 1920 4066 9516 '0'..'9', 'A'..'Z', 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 150 210 2666 7916 '0'\001
+4 1 0 0 0 0 14 0.0000 2 165 540 4066 8650 '1'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 180 1260 2666 9100 'A'..'Z', 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 180 1875 7833 6950 '0'..'9', 'A'..'F', 'a'..'f'\001
diff --git a/doc/exoutact1.fig b/doc/exoutact1.fig
new file mode 100644
index 0000000..5ebc332
--- /dev/null
+++ b/doc/exoutact1.fig
@@ -0,0 +1,62 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exoutact1
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3550 33 33 33 3550 66 3583
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3550 383 383 1333 3550 1716 3933
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5333 3550 383 383 5333 3550 5716 3933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5333 3550 450 450 5333 3550 5783 4000
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3266 3550 383 383 3266 3550 3649 3933
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3483 933 3550 766 3600 766 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2700 3483 2866 3550 2700 3600 2700 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4700 3483 4866 3550 4700 3600 4700 3483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3033 3100 3000 3266 2933 3100 3033 3100
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -135 2610 5895 2610 5895 4140 -135 4140 -135 2610
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3550 139 3550 237 3550 354 3550 485 3550 624 3550
+ 766 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3550 1881 3550 2039 3550 2204 3550 2371 3550 2538 3550
+ 2700 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3666 3550 3824 3550 3993 3550 4170 3550 4350 3550 4528 3550
+ 4700 3550
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3533 3266 3554 3167 3549 3074 3518 2991 3461 2925 3377 2882
+ 3266 2866 3183 2874 3115 2897 3062 2933 3023 2980 2997 3036
+ 2983 3100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3633 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3500 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 5333 3633 2\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3266 3633 1\001
+4 1 0 0 0 0 14 0.0000 2 150 510 2300 3500 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 165 600 4266 3500 10 / A\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3266 2816 'a'..'z'\001
diff --git a/doc/exoutact2.fig b/doc/exoutact2.fig
new file mode 100644
index 0000000..7e01a18
--- /dev/null
+++ b/doc/exoutact2.fig
@@ -0,0 +1,78 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exoutact2
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3716 33 33 33 3716 66 3749
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3716 383 383 1333 3716 1716 4099
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8500 3716 383 383 8500 3716 8883 4099
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8500 3716 450 450 8500 3716 8950 4166
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4733 3716 383 383 4733 3716 5116 4099
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3650 933 3716 766 3766 766 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4166 3650 4333 3716 4166 3750 4166 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7866 3650 8033 3716 7866 3766 7866 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1800 4033 1666 3916 1850 3933 1800 4033
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4500 3266 4466 3433 4400 3266 4500 3266
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -135 2745 9090 2745 9090 4320 -135 4320 -135 2745
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3716 139 3716 237 3716 354 3716 485 3716 624 3716
+ 766 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 1733 3716 1783 3715 1833 3712 1883 3708 1933 3704 1983 3701
+ 2033 3700 2432 3700 2755 3700 3039 3700 3322 3700 3640 3700
+ 4033 3700 4057 3700 4079 3700 4100 3700 4120 3700 4142 3700
+ 4166 3700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5133 3716 5508 3716 5960 3716 6456 3716 6961 3716 7443 3716
+ 7866 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 4400 3916 4341 3948 4282 3977 4222 4002 4161 4022 4098 4038
+ 4033 4050 3645 4126 3325 4172 3039 4187 2751 4172 2428 4126
+ 2033 4050 1999 4041 1966 4032 1931 4022 1895 4011 1857 3998
+ 1816 3983
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5000 3433 5020 3334 5016 3240 4985 3158 4928 3092 4844 3049
+ 4733 3033 4649 3041 4582 3064 4529 3100 4490 3146 4464 3203
+ 4450 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3800 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3666 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8500 3800 2\001
+4 1 0 0 0 0 14 0.0000 2 165 120 4733 3800 1\001
+4 1 0 0 0 0 14 0.0000 2 165 1230 3033 3650 'a'..'z' / lower\001
+4 1 0 0 0 0 14 0.0000 2 195 2325 6583 3666 10 / term_word, newline\001
+4 1 0 0 0 0 14 0.0000 2 210 2010 3033 3983 ' ' / term_word, space\001
+4 1 0 0 0 0 14 0.0000 2 165 1230 4733 2983 'a'..'z' / lower\001
diff --git a/doc/explus.fig b/doc/explus.fig
new file mode 100644
index 0000000..81636f0
--- /dev/null
+++ b/doc/explus.fig
@@ -0,0 +1,51 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: explus
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3683 33 33 33 3683 66 3716
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3683 383 383 1333 3683 1716 4066
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4700 3683 383 383 4700 3683 5083 4066
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4700 3683 450 450 4700 3683 5150 4133
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3616 933 3683 766 3733 766 3616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4416 3183 4383 3350 4316 3183 4416 3183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4066 3616 4233 3683 4066 3733 4066 3616
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5850 2655 -90 2655 -90 4230 5850 4230 5850 2655
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3683 139 3683 237 3683 354 3683 485 3683 624 3683
+ 766 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5016 3350 5041 3243 5034 3145 4995 3060 4926 2993 4827 2949
+ 4700 2933 4605 2941 4524 2964 4458 3002 4408 3051 4377 3112
+ 4366 3183
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3683 2055 3683 2438 3683 2856 3683 3283 3683 3695 3683
+ 4066 3683
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3766 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3633 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 4700 3766 1\001
+4 1 0 0 0 0 14 0.0000 2 180 1920 4700 2883 '0'..'9', 'A'..'Z', 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 180 1920 2983 3633 '0'..'9', 'A'..'Z', 'a'..'z'\001
diff --git a/doc/exstact.fig b/doc/exstact.fig
new file mode 100644
index 0000000..849f8ed
--- /dev/null
+++ b/doc/exstact.fig
@@ -0,0 +1,64 @@
+#FIG 3.2
+# Generated by Graphviz version 2.12 (Tue Sep 4 16:56:48 UTC 2007)
+# For: (thurston) Adrian Thurston,,,
+# Title: exstact
+# Pages: 1
+Portrait
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+0 32 #d3d3d3
+2 3 0 1 7 7 2 0 20 0.0 0 0 0 0 0 5
+ 0 2340 0 0 6920 0 6920 2340 0 2340
+# ENTRY
+1 1 0 1 0 0 1 0 20 0.000 0 0.0000 120 600 40 -40 120 600 160 560
+# 1
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 1640 600 420 -430 1640 600 2060 170
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 1640 680 1\001
+# ENTRY->1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 160 600 247 600 364 600 505 600 662 600 829 600 1000 600
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 1000 530 1200 600 1000 670 1000 530
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 680 480 IN\001
+# 3
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 6320 600 422 -430 6320 600 6742 170
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 6320 600 500 -510 6320 600 6820 90
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 6320 680 3\001
+# 1->3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 19
+ 2080 560 2140 551 2200 545 2260 540 2320 535 2380 529 2440 520 2902 495 3277 479 3608 470 3936 468 4306 472 4760 480 4901 490 5044 500 5188 510 5329 520 5467 530 5600 540
+ 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5608 470 5800 560 5594 610 5608 470
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 4320 360 SP / A\001
+# 2
+1 1 0 1 0 7 1 0 -1 0.000 0 0.0000 4320 1840 420 -430 4320 1840 4740 1410
+4 1 0 1 0 0 14.0 0.0000 4 0.0 0.0 4320 1920 2\001
+# 1->2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 2020 780 2273 899 2560 1032 2868 1173 3180 1315 3483 1453 3760 1580
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 3786 1515 3940 1660 3729 1643 3786 1515
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 2980 880 'a'..'z' / A\001
+# 2->3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 4680 1620 4829 1525 4993 1423 5168 1315 5347 1204 5526 1091 5700 980
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 5671 916 5880 880 5739 1038 5671 916
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 5280 1080 SP\001
+# 2->2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 4020 1540 3970 1421 3960 1309 3990 1210 4060 1131 4170 1079 4320 1060 4430 1070 4520 1097 4590 1140 4640 1196 4670 1264 4680 1340
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 4745 1369 4620 1540 4610 1328 4745 1369
+4 1 0 0 0 0 14.0 0.0000 4 0.0 0.0 4320 940 'a'..'z'\001
+# end of FIG file
diff --git a/doc/exstar.fig b/doc/exstar.fig
new file mode 100644
index 0000000..3d82215
--- /dev/null
+++ b/doc/exstar.fig
@@ -0,0 +1,77 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exstar
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3850 33 33 33 3850 66 3883
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3850 383 383 1400 3850 1783 4233
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3850 450 450 1400 3850 1850 4300
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3400 3850 383 383 3400 3850 3783 4233
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3783 933 3850 766 3900 766 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1116 3350 1083 3516 1016 3350 1116 3350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2833 3783 3000 3850 2833 3883 2833 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1950 4183 1816 4066 2000 4083 1950 4183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3166 3400 3133 3566 3066 3400 3166 3400
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3915 2835 -90 2835 -90 4410 3915 4410 3915 2835
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3850 132 3850 225 3850 341 3850 474 3850 617 3850
+ 766 3850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1716 3516 1741 3410 1734 3312 1695 3227 1626 3159 1527 3115
+ 1400 3100 1305 3108 1224 3131 1158 3168 1108 3218 1077 3279
+ 1066 3350
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 1866 3850 1916 3842 1966 3838 2016 3835 2066 3833 2116 3833
+ 2166 3833 2276 3833 2364 3833 2439 3833 2513 3833 2596 3833
+ 2700 3833 2723 3833 2745 3833 2766 3833 2787 3833 2809 3833
+ 2833 3833
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 3066 4050 3008 4081 2949 4110 2889 4135 2828 4156 2765 4172
+ 2700 4183 2601 4203 2517 4212 2439 4214 2360 4209 2272 4198
+ 2166 4183 2133 4175 2100 4166 2066 4158 2033 4150 2000 4141
+ 1966 4133
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3666 3566 3687 3467 3682 3374 3652 3291 3595 3225 3511 3182
+ 3400 3166 3316 3174 3248 3197 3195 3233 3156 3280 3130 3336
+ 3116 3400
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 3933 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3800 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 240 1400 3050 10\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3400 3933 1\001
+4 1 0 0 0 0 14 0.0000 2 150 510 2433 3783 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 165 240 2433 4116 10\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3400 3116 'a'..'z'\001
diff --git a/doc/exstrongsubtr.fig b/doc/exstrongsubtr.fig
new file mode 100644
index 0000000..2f25699
--- /dev/null
+++ b/doc/exstrongsubtr.fig
@@ -0,0 +1,120 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exstrongsubtr
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3716 33 33 33 3716 66 3749
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 3716 383 383 1333 3716 1716 4099
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8433 3716 383 383 8433 3716 8816 4099
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8433 3716 450 450 8433 3716 8883 4166
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3266 3716 383 383 3266 3716 3649 4099
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4833 3716 383 383 4833 3716 5216 4099
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6700 3716 383 383 6700 3716 7083 4099
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3650 933 3716 766 3766 766 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2700 3650 2866 3716 2700 3766 2700 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3033 3266 3000 3433 2933 3266 3033 3266
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4266 3650 4433 3716 4266 3766 4266 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4600 3266 4566 3433 4500 3266 4600 3266
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6133 3650 6300 3716 6133 3750 6133 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7800 3650 7966 3716 7800 3766 7800 3650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5300 4033 5166 3916 5350 3933 5300 4033
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6466 3266 6433 3433 6366 3266 6466 3266
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9135 2745 -180 2745 -180 4365 9135 4365 9135 2745
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3716 139 3716 237 3716 354 3716 485 3716 624 3716
+ 766 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1733 3716 1881 3716 2039 3716 2204 3716 2371 3716 2538 3716
+ 2700 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3533 3433 3554 3334 3549 3240 3518 3158 3461 3092 3377 3049
+ 3266 3033 3183 3041 3115 3064 3062 3100 3023 3146 2997 3203
+ 2983 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3666 3716 3760 3716 3859 3716 3960 3716 4062 3716 4165 3716
+ 4266 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5100 3433 5120 3334 5116 3240 5085 3158 5028 3092 4944 3049
+ 4833 3033 4749 3041 4682 3064 4629 3100 4590 3146 4564 3203
+ 4550 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 5233 3716 5283 3715 5333 3712 5383 3708 5433 3704 5483 3701
+ 5533 3700 5629 3700 5706 3700 5772 3700 5838 3700 5911 3700
+ 6000 3700 6023 3700 6045 3700 6066 3700 6087 3700 6109 3700
+ 6133 3700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 7100 3716 7205 3716 7318 3716 7437 3716 7559 3716 7681 3716
+ 7800 3716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 6366 3916 6308 3948 6249 3977 6189 4002 6128 4022 6065 4038
+ 6000 4050 5911 4063 5838 4072 5772 4075 5706 4072 5629 4063
+ 5533 4050 5499 4041 5466 4032 5431 4022 5395 4011 5357 3998
+ 5316 3983
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6966 3433 6987 3334 6982 3240 6952 3158 6895 3092 6811 3049
+ 6700 3033 6616 3041 6548 3064 6495 3100 6456 3146 6430 3203
+ 6416 3266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 3800 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3666 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8433 3800 4\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3266 3800 1\001
+4 1 0 0 0 0 14 0.0000 2 150 510 2300 3666 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3266 2983 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4833 3800 2\001
+4 1 0 0 0 0 14 0.0000 2 150 150 4050 3666 ':'\001
+4 1 0 0 0 0 14 0.0000 2 150 465 4833 2983 DEF\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6700 3800 3\001
+4 1 0 0 0 0 14 0.0000 2 165 240 5766 3650 13\001
+4 1 0 0 0 0 14 0.0000 2 165 240 7533 3666 10\001
+4 1 0 0 0 0 14 0.0000 2 150 465 5766 3983 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 240 6700 2983 13\001
diff --git a/doc/exsubtr.fig b/doc/exsubtr.fig
new file mode 100644
index 0000000..4a2ead2
--- /dev/null
+++ b/doc/exsubtr.fig
@@ -0,0 +1,141 @@
+#FIG 3.2
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exsubtr
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 9100 33 33 33 9100 66 9133
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 9100 383 383 1333 9100 1716 9483
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 1333 9183 0\001
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 66 9100 139 9100 237 9100 354 9100 485 9100 624 9100 766 9100
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 766 9033 933 9100 766 9150 766 9033
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 500 9050 IN\001
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10600 8400 383 383 10600 8400 10983 8783
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10600 8400 450 450 10600 8400 11050 8850
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 10600 8483 1\001
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 10916 8066 10941 7960 10934 7862 10895 7777 10826 7709 10727 7665 10600 7650 10505 7658 10424 7681 10358 7718 10308 7768 10277 7829 10266 7900
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10316 7900 10283 8066 10216 7900 10316 7900
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 10600 7600 'a'..'z'\001
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 7633 383 383 2966 7633 3349 8016
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 7633 450 450 2966 7633 3416 8083
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2966 7716 2\001
+# 2 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 3433 7650 3917 7670 4530 7701 5237 7741 6002 7793 6790 7856 7566 7933 7997 7981 8433 8038 8862 8102 9271 8166 9649 8228 9983 8283
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10000 8233 10150 8316 9983 8333 10000 8233
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6950 7783 'a'..'n', 'p'..'z'\001
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5150 6716 383 383 5150 6716 5533 7099
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5150 6716 450 450 5150 6716 5600 7166
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5150 6800 3\001
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 3400 7450 3576 7372 3769 7291 3972 7208 4180 7125 4385 7044 4583 6966
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 4550 6916 4733 6900 4600 7016 4550 6916
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3850 7200 'o'\001
+# 3 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 5600 6616 6025 6539 6548 6468 7137 6422 7762 6420 8393 6478 9000 6616 9362 6750 9657 6893 9900 7058 10103 7256 10282 7499 10450 7800
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10500 7766 10516 7950 10400 7816 10500 7766
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 8433 6383 'a'..'q', 's'..'z'\001
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8433 7150 383 383 8433 7150 8816 7533
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 8433 7233 4\001
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 5600 6783 5938 6827 6321 6875 6729 6927 7139 6979 7531 7032 7883 7083
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 7883 7033 8050 7100 7883 7133 7883 7033
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6950 6850 'r'\001
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 9100 383 383 2966 9100 3349 9483
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 2966 9100 450 450 2966 9100 3416 9550
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2966 9183 5\001
+# 5 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 19
+ 3416 9166 3546 9177 3685 9191 3829 9208 3975 9224 4122 9239 4266 9250 5378 9281 6280 9248 7075 9158 7864 9017 8749 8834 9833 8616 9866 8615 9899 8612 9931 8608 9961 8604 9990 8601 10016 8600
+ 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10016 8550 10183 8583 10016 8650 10016 8550
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6950 9033 'a'..'m', 'o'..'z'\001
+# 6
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5150 8650 383 383 5150 8650 5533 9033
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5150 8650 450 450 5150 8650 5600 9100
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5150 8733 6\001
+# 5 -> 6
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 3416 9000 3590 8965 3776 8928 3968 8889 4162 8849 4352 8808 4533 8766
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 4533 8716 4700 8733 4550 8816 4533 8716
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 3850 8883 'n'\001
+# 6 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 5616 8650 5881 8656 6185 8660 6516 8660 6864 8656 7218 8647 7566 8633 7992 8612 8425 8586 8854 8556 9262 8524 9638 8494 9966 8466
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 9966 8416 10133 8450 9966 8516 9966 8416
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 8433 8516 'a'..'s', 'u'..'z'\001
+# 6 -> 4
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 5616 8616 5947 8587 6318 8548 6697 8497 7053 8435 7353 8358 7566 8266 7694 8183 7811 8087 7918 7981 8016 7867 8104 7750 8183 7633
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 8133 7616 8266 7500 8233 7666 8133 7616
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 6950 8216 't'\001
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 19
+ 1566 9416 1727 9603 1922 9801 2147 9989 2400 10148 2674 10258 2966 10300 2991 10300 3169 10300 3650 10300 4586 10300 6130 10300 8433 10300 8906 10255 9276 10127 9572 9925 9823 9655 10056 9327 10300 8950
+ 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10266 8900 10400 8800 10350 8966 10266 8900
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 5150 10250 'a'..'e', 'g'..'h', 'j'..'z'\001
+# 0 -> 2
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1633 8833 1765 8717 1909 8589 2060 8454 2212 8316 2360 8179 2500 8050
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2466 8000 2633 7933 2550 8083 2466 8000
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2116 8316 'f'\001
+# 0 -> 5
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 7
+ 1733 9100 1827 9100 1925 9100 2027 9100 2129 9100 2232 9100 2333 9100
+ 0 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 2333 9033 2500 9100 2333 9150 2333 9033
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 2116 9050 'i'\001
+# 4 -> 1
+3 4 0 1 0 0 0 0 -1 0.0 0 0 0 13
+ 8800 7283 8957 7345 9127 7416 9304 7493 9483 7578 9661 7669 9833 7766 9883 7801 9933 7837 9983 7875 10033 7912 10083 7948 10133 7983
+ 0 1 1 1 1 1 1 1 1 1 1 1 0
+2 3 0 1 0 0 0 0 20 0.0 0 0 0 0 0 4
+ 10166 7933 10266 8083 10100 8033 10166 7933
+4 1 0 0 0 0 14.0 0.0000 2 0.0 0.0 9566 7450 'a'..'z'\001
+# end of FIG file
diff --git a/doc/finguard.fig b/doc/finguard.fig
new file mode 100644
index 0000000..325eeb7
--- /dev/null
+++ b/doc/finguard.fig
@@ -0,0 +1,119 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exdonepri
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 4983 33 33 33 4983 66 5016
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1333 4983 383 383 1333 4983 1716 5366
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6566 4983 383 383 6566 4983 6949 5366
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 6566 4983 450 450 6566 4983 7016 5433
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3200 4466 383 383 3200 4466 3583 4849
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4833 4983 383 383 4833 4983 5216 5366
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 4916 933 4983 766 5033 766 4916
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1100 4533 1066 4700 1000 4533 1100 4533
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2633 4483 2800 4500 2650 4583 2633 4483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1866 5150 1716 5066 1883 5050 1866 5150
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2966 4016 2933 4183 2866 4016 2966 4016
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4350 4683 4483 4800 4300 4783 4350 4683
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5933 4916 6100 4983 5933 5033 5933 4916
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1816 5250 1650 5216 1816 5150 1816 5250
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3550 4900 3450 4766 3616 4816 3550 4900
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -90 3510 7155 3510 7155 5535 -90 5535 -90 3510
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 4983 139 4983 237 4983 354 4983 485 4983 624 4983
+ 766 4983
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1600 4700 1620 4600 1616 4507 1585 4425 1528 4359 1444 4315
+ 1333 4300 1249 4308 1182 4330 1129 4366 1090 4413 1064 4469
+ 1050 4533
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1683 4800 1741 4775 1799 4750 1858 4725 1916 4700 1974 4675
+ 2033 4650 2127 4626 2225 4604 2327 4585 2429 4567 2532 4550
+ 2633 4533
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 2950 4766 2892 4821 2833 4869 2768 4912 2694 4953 2606 4992
+ 2500 5033 2398 5068 2295 5091 2191 5104 2087 5108 1984 5106
+ 1883 5100
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3466 4183 3487 4084 3482 3990 3452 3908 3395 3842 3311 3799
+ 3200 3783 3116 3791 3048 3814 2995 3850 2956 3896 2930 3953
+ 2916 4016
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3583 4533 3669 4544 3759 4559 3852 4579 3946 4601 4040 4625
+ 4133 4650 4166 4665 4200 4679 4233 4691 4266 4704 4300 4717
+ 4333 4733
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 5233 4983 5338 4983 5451 4983 5570 4983 5692 4983 5814 4983
+ 5933 4983
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 4483 5166 4354 5206 4228 5229 4097 5241 3954 5248 3791 5254
+ 3600 5266 3295 5296 3045 5304 2822 5295 2598 5272 2344 5239
+ 2033 5200 1992 5194 1954 5192 1918 5193 1883 5196 1850 5198
+ 1816 5200
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 2 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4450 5033 4362 5038 4270 5038 4175 5033 4079 5022 3987 5005
+ 3900 4983 3836 4965 3777 4945 3725 4925 3677 4904 3636 4884
+ 3600 4866
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1333 5066 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 4933 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 120 6566 5066 3\001
+4 1 0 0 0 0 14 0.0000 2 150 465 1333 4250 DEF\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3200 4550 1\001
+4 1 0 0 0 0 14 0.0000 2 150 225 2266 4533 'F'\001
+4 1 0 0 0 0 14 0.0000 2 150 465 2266 4983 DEF\001
+4 1 0 0 0 0 14 0.0000 2 150 225 3200 3733 'F'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 4833 5066 2\001
+4 1 0 0 0 0 14 0.0000 2 150 165 4016 4550 'I'\001
+4 1 0 0 0 0 14 0.0000 2 150 270 5666 4933 'N'\001
+4 1 0 0 0 0 14 0.0000 2 150 465 3200 5216 DEF\001
+4 1 0 0 0 0 14 0.0000 2 150 225 4016 4933 'F'\001
diff --git a/doc/leftguard.fig b/doc/leftguard.fig
new file mode 100644
index 0000000..0fdb7f7
--- /dev/null
+++ b/doc/leftguard.fig
@@ -0,0 +1,94 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: leftguard
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 5183 33 33 33 5183 66 5216
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 5183 383 383 1400 5183 1783 5566
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 5183 450 450 1400 5183 1850 5633
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4033 4550 383 383 4033 4550 4416 4933
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 4033 4550 450 450 4033 4550 4483 5000
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7500 5183 383 383 7500 5183 7883 5566
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 7500 5183 450 450 7500 5183 7950 5633
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 5116 933 5183 766 5233 766 5116
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3416 4650 3583 4666 3433 4750 3416 4650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6883 5216 7050 5250 6883 5316 6883 5216
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3750 4050 3716 4216 3650 4050 3750 4050
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6900 5016 7050 5100 6883 5116 6900 5016
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7400 4600 7333 4766 7300 4600 7400 4600
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7033 4766 7116 4933 6950 4850 7033 4766
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8190 3510 -45 3510 -45 5715 8190 5715 8190 3510
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 5183 132 5183 225 5183 341 5183 474 5183 617 5183
+ 766 5183
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1850 5083 2082 5028 2341 4965 2614 4897 2891 4829 3162 4761
+ 3416 4700
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1866 5266 2062 5292 2280 5320 2512 5347 2753 5374 2995 5397
+ 3233 5416 3891 5447 4564 5444 5227 5416 5851 5372 6412 5319
+ 6883 5266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4350 4216 4375 4110 4367 4012 4329 3927 4259 3859 4160 3815
+ 4033 3800 3939 3808 3858 3831 3791 3868 3741 3918 3710 3979
+ 3700 4050
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4483 4633 4827 4692 5227 4764 5658 4843 6094 4924 6511 5001
+ 6883 5066
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7666 4766 7662 4678 7649 4598 7627 4531 7595 4479 7552 4445
+ 7500 4433 7462 4438 7431 4454 7406 4479 7385 4512 7366 4552
+ 7350 4600
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7883 4933 8038 4752 8106 4570 8085 4402 7977 4262 7781 4168
+ 7500 4133 7243 4160 7055 4236 6937 4350 6888 4491 6909 4650
+ 7000 4816
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 5266 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 5133 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 4033 4633 1\001
+4 1 0 0 0 0 14 0.0000 2 150 720 2550 4800 ' ' / start\001
+4 1 0 0 0 0 14 0.0000 2 150 120 7500 5266 2\001
+4 1 0 0 0 0 14 0.0000 2 225 1575 4033 5366 'a'..'z' / fin, alpha\001
+4 1 0 0 0 0 14 0.0000 2 150 150 4033 3750 ' '\001
+4 1 0 0 0 0 14 0.0000 2 225 1575 5933 4716 'a'..'z' / fin, alpha\001
+4 1 0 0 0 0 14 0.0000 2 150 600 7500 4383 ' ' / ws\001
+4 1 0 0 0 0 14 0.0000 2 225 1200 7500 4083 'a'..'z' / alpha\001
diff --git a/doc/lines1.fig b/doc/lines1.fig
new file mode 100644
index 0000000..dfaf219
--- /dev/null
+++ b/doc/lines1.fig
@@ -0,0 +1,164 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: lines1
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 6150 33 33 33 6150 66 6183
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 6150 383 383 1400 6150 1783 6533
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 6150 450 450 1400 6150 1850 6600
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3933 6150 383 383 3933 6150 4316 6533
+# 4
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5666 5416 383 383 5666 5416 6049 5799
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5666 5416 450 450 5666 5416 6116 5866
+# 5
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8633 5716 383 383 8633 5716 9016 6099
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 10433 5716 383 383 10433 5716 10816 6099
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 12833 5066 383 383 12833 5066 13216 5449
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 6083 933 6150 766 6200 766 6083
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3366 6083 3533 6150 3366 6200 3366 6083
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8116 5466 8266 5566 8083 5566 8116 5466
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5050 5616 5233 5600 5100 5716 5050 5616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3700 5700 3666 5866 3600 5700 3700 5700
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9900 5916 10083 5900 9950 6016 9900 5916
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 12283 5083 12450 5116 12283 5183 12283 5083
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6266 5216 6083 5216 6216 5100 6266 5216
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 10966 5900 10816 5816 10983 5800 10966 5900
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 12600 4616 12566 4783 12500 4616 12600 4616
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6166 5800 6050 5666 6216 5700 6166 5800
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 9866 5650 10033 5716 9866 5766 9866 5650
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 8400 5266 8366 5433 8300 5266 8400 5266
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 13455 4095 -45 4095 -45 6660 13455 6660 13455 4095
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 6150 132 6150 225 6150 341 6150 474 6150 617 6150
+ 766 6150
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 1866 6150 2091 6150 2340 6150 2604 6150 2870 6150 3128 6150
+ 3366 6150
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 4 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6116 5400 6370 5393 6658 5391 6968 5397 7291 5413 7617 5441
+ 7933 5483 7959 5484 7987 5488 8016 5493 8045 5500 8073 5508
+ 8100 5516
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4300 6000 4414 5947 4540 5891 4672 5833 4809 5775 4947 5719
+ 5083 5666
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4200 5866 4220 5767 4216 5674 4185 5591 4128 5525 4044 5482
+ 3933 5466 3849 5474 3782 5497 3729 5533 3690 5580 3664 5636
+ 3650 5700
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4316 6216 4847 6281 5543 6347 6356 6395 7240 6408 8148 6365
+ 9033 6250 9191 6218 9348 6176 9502 6127 9651 6073 9796 6018
+ 9933 5966
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 10783 5533 10841 5508 10900 5483 10958 5458 11016 5433 11075 5408
+ 11133 5383 11322 5327 11520 5277 11720 5233 11918 5194 12107 5161
+ 12283 5133
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 25
+ 12450 4933 12399 4916 12349 4900 12297 4885 12245 4871 12190 4859
+ 12133 4850 11611 4766 10966 4689 10252 4627 9522 4588 8831 4581
+ 8233 4616 7870 4671 7577 4725 7320 4785 7066 4857 6781 4948
+ 6433 5066 6400 5082 6367 5095 6335 5108 6304 5120 6276 5134
+ 6250 5150
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 12616 5383 12554 5459 12483 5534 12406 5606 12321 5670 12230 5725
+ 12133 5766 11943 5828 11746 5866 11545 5883 11348 5883 11158 5871
+ 10983 5850
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 13100 4783 13120 4684 13116 4590 13085 4508 13028 4442 12944 4399
+ 12833 4383 12749 4391 12682 4414 12629 4450 12590 4496 12564 4553
+ 12550 4616
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 5 -> 4
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 8250 5800 8003 5840 7719 5874 7410 5895 7085 5897 6756 5873
+ 6433 5816 6392 5807 6354 5795 6316 5783 6279 5770 6240 5759
+ 6200 5750
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 5 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 9033 5716 9163 5716 9301 5716 9443 5716 9587 5716 9729 5716
+ 9866 5716
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 5 -> 5
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 8900 5433 8920 5334 8916 5240 8885 5158 8828 5092 8744 5049
+ 8633 5033 8549 5041 8482 5064 8429 5100 8390 5146 8364 5203
+ 8350 5266
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 6233 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 6100 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3933 6233 1\001
+4 1 0 0 0 0 14 0.0000 2 150 1050 2700 6100 'a'..'z' / first\001
+4 1 0 0 0 0 14 0.0000 2 150 120 5666 5500 4\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8633 5800 5\001
+4 1 0 0 0 0 14 0.0000 2 195 1455 7183 5350 'a'..'z' / tail, first\001
+4 1 0 0 0 0 14 0.0000 2 165 240 4766 5733 10\001
+4 1 0 0 0 0 14 0.0000 2 150 1050 3933 5416 'a'..'z' / first\001
+4 1 0 0 0 0 14 0.0000 2 150 120 10433 5800 2\001
+4 1 0 0 0 0 14 0.0000 2 180 390 7183 6350 9, ' '\001
+4 1 0 0 0 0 14 0.0000 2 150 120 12833 5150 3\001
+4 1 0 0 0 0 14 0.0000 2 165 975 11633 5133 'a'..'z' / tail\001
+4 1 0 0 0 0 14 0.0000 2 165 240 9533 4550 10\001
+4 1 0 0 0 0 14 0.0000 2 180 390 11633 5716 9, ' '\001
+4 1 0 0 0 0 14 0.0000 2 165 975 12833 4333 'a'..'z' / tail\001
+4 1 0 0 0 0 14 0.0000 2 165 240 7183 5766 10\001
+4 1 0 0 0 0 14 0.0000 2 180 390 9533 5666 9, ' '\001
+4 1 0 0 0 0 14 0.0000 2 195 1455 8633 4983 'a'..'z' / first, tail\001
diff --git a/doc/lines2.fig b/doc/lines2.fig
new file mode 100644
index 0000000..9d9d713
--- /dev/null
+++ b/doc/lines2.fig
@@ -0,0 +1,121 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: lines2
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 4883 33 33 33 4883 66 4916
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 4883 383 383 1400 4883 1783 5266
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 4883 450 450 1400 4883 1850 5333
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3933 4416 383 383 3933 4416 4316 4799
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5733 4416 383 383 5733 4416 6116 4799
+# 3
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 8133 4883 383 383 8133 4883 8516 5266
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 4816 933 4883 766 4933 766 4816
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3366 4350 3533 4416 3366 4466 3366 4350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2000 5066 1850 4983 2016 4966 2000 5066
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3700 3966 3666 4133 3600 3966 3700 3966
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5166 4350 5333 4416 5166 4466 5166 4350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7666 4566 7783 4700 7616 4666 7666 4566
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1933 5183 1766 5150 1933 5083 1933 5183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 6133 4816 6033 4666 6200 4716 6133 4816
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 7900 4433 7866 4600 7800 4433 7900 4433
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8775 3465 -45 3465 -45 5400 8775 5400 8775 3465
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 4883 132 4883 225 4883 341 4883 474 4883 617 4883
+ 766 4883
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1816 4683 1875 4658 1933 4633 1991 4610 2050 4588 2108 4567
+ 2166 4550 2370 4505 2577 4470 2785 4445 2988 4429 3184 4419
+ 3366 4416
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3650 4683 3590 4733 3527 4781 3460 4827 3389 4868 3313 4904
+ 3233 4933 3035 4988 2829 5021 2618 5037 2409 5039 2207 5031
+ 2016 5016
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 4200 4133 4220 4034 4216 3940 4185 3858 4128 3792 4044 3749
+ 3933 3733 3849 3741 3782 3764 3729 3800 3690 3846 3664 3903
+ 3650 3966
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 4333 4416 4463 4416 4601 4416 4743 4416 4887 4416 5029 4416
+ 5166 4416
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6133 4416 6321 4418 6529 4425 6752 4439 6981 4463 7210 4499
+ 7433 4550 7466 4558 7499 4567 7533 4577 7566 4588 7599 4601
+ 7633 4616
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 25
+ 7800 5066 7748 5072 7693 5074 7635 5075 7572 5075 7505 5077
+ 7433 5083 6610 5156 5940 5185 5345 5183 4748 5164 4069 5143
+ 3233 5133 3025 5142 2856 5151 2706 5158 2554 5159 2381 5151
+ 2166 5133 2125 5127 2083 5125 2043 5127 2004 5129 1967 5132
+ 1933 5133
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 0.000
+# 3 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 7750 4950 7561 4971 7349 4984 7122 4985 6889 4970 6657 4938
+ 6433 4883 6384 4872 6338 4856 6293 4837 6250 4815 6208 4791
+ 6166 4766
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 3 -> 3
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 8400 4600 8420 4500 8416 4407 8385 4325 8328 4259 8244 4215
+ 8133 4200 8049 4208 7982 4230 7929 4266 7890 4313 7864 4369
+ 7850 4433
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 4966 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 4833 IN\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3933 4500 1\001
+4 1 0 0 0 0 14 0.0000 2 150 1050 2700 4400 'a'..'z' / first\001
+4 1 0 0 0 0 14 0.0000 2 165 240 2700 4883 10\001
+4 1 0 0 0 0 14 0.0000 2 150 1050 3933 3683 'a'..'z' / first\001
+4 1 0 0 0 0 14 0.0000 2 150 120 5733 4500 2\001
+4 1 0 0 0 0 14 0.0000 2 180 390 4833 4366 9, ' '\001
+4 1 0 0 0 0 14 0.0000 2 150 120 8133 4966 3\001
+4 1 0 0 0 0 14 0.0000 2 165 975 6933 4400 'a'..'z' / tail\001
+4 1 0 0 0 0 14 0.0000 2 165 240 4833 5116 10\001
+4 1 0 0 0 0 14 0.0000 2 180 390 6933 4833 9, ' '\001
+4 1 0 0 0 0 14 0.0000 2 165 975 8133 4150 'a'..'z' / tail\001
diff --git a/doc/lmkleene.fig b/doc/lmkleene.fig
new file mode 100644
index 0000000..b0207af
--- /dev/null
+++ b/doc/lmkleene.fig
@@ -0,0 +1,116 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: exfinpri
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 6166 33 33 33 6166 66 6199
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 6166 383 383 1400 6166 1783 6549
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 6166 450 450 1400 6166 1850 6616
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3466 5416 383 383 3466 5416 3849 5799
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 3466 5416 450 450 3466 5416 3916 5866
+# 2
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5866 6433 383 383 5866 6433 6249 6816
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5866 6433 450 450 5866 6433 6316 6883
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 6100 933 6166 766 6216 766 6100
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1116 5666 1083 5833 1016 5666 1116 5666
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2833 5366 3000 5400 2833 5466 2833 5366
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5233 6350 5400 6416 5233 6450 5233 6350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 2033 6166 1866 6133 2033 6066 2033 6166
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 3183 4916 3150 5083 3083 4916 3183 4916
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5300 6133 5433 6250 5250 6233 5300 6133
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1950 6483 1816 6366 2000 6383 1950 6483
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 5583 5933 5550 6100 5483 5933 5583 5933
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ -45 4365 6615 4365 6615 7020 -45 7020 -45 4365
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 6166 132 6166 225 6166 341 6166 474 6166 617 6166
+ 766 6166
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1716 5833 1741 5727 1734 5629 1695 5543 1626 5476 1527 5432
+ 1400 5416 1305 5424 1224 5448 1158 5485 1108 5535 1077 5596
+ 1066 5666
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1733 5833 1794 5782 1860 5730 1931 5679 2006 5630 2084 5587
+ 2166 5550 2270 5512 2380 5482 2493 5458 2608 5440 2722 5426
+ 2833 5416
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1866 6200 2033 6216 2216 6232 2408 6247 2606 6261 2804 6273
+ 3000 6283 3391 6307 3790 6328 4185 6347 4565 6366 4918 6383
+ 5233 6400
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3116 5700 3049 5742 2982 5786 2914 5829 2845 5869 2773 5904
+ 2700 5933 2590 5979 2479 6017 2366 6050 2254 6076 2142 6098
+ 2033 6116
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 3783 5083 3808 4977 3801 4879 3762 4793 3693 4726 3594 4682
+ 3466 4666 3372 4674 3291 4698 3225 4735 3175 4785 3144 4846
+ 3133 4916
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 1 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 3883 5600 4095 5688 4327 5784 4570 5885 4816 5987 5056 6088
+ 5283 6183
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 2 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5416 6533 5099 6593 4727 6650 4314 6695 3878 6722 3434 6720
+ 3000 6683 2783 6650 2595 6618 2427 6583 2271 6542 2120 6493
+ 1966 6433
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 2 -> 2
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 6183 6100 6208 5993 6201 5895 6162 5810 6093 5743 5994 5699
+ 5866 5683 5772 5691 5691 5714 5625 5752 5575 5801 5544 5862
+ 5533 5933
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 6250 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 6116 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 150 1400 5366 ' '\001
+4 1 0 0 0 0 14 0.0000 2 165 120 3466 5500 1\001
+4 1 0 0 0 0 14 0.0000 2 150 540 2433 5400 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 120 5866 6516 2\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3466 6233 'a'..'z'\001
+4 1 0 0 0 0 14 0.0000 2 150 495 2433 5883 ' ' / B\001
+4 1 0 0 0 0 14 0.0000 2 150 540 3466 4616 '0'..'9'\001
+4 1 0 0 0 0 14 0.0000 2 150 855 4666 5733 'a'..'z' / B\001
+4 1 0 0 0 0 14 0.0000 2 150 510 3466 6633 ' ' / A\001
+4 1 0 0 0 0 14 0.0000 2 180 1170 5866 5633 '0'..'9', 'a'..'z'\001
diff --git a/doc/opconcat.fig b/doc/opconcat.fig
new file mode 100644
index 0000000..d46084e
--- /dev/null
+++ b/doc/opconcat.fig
@@ -0,0 +1,39 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 585 630 135 135 585 630 720 630
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 810 90 90 1215 810 1305 810
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 810 135 135 1215 810 1350 810
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 450 135 135 1215 450 1350 450
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 450 90 90 1215 450 1305 450
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2340 630 135 135 2340 630 2475 630
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2970 450 90 90 2970 450 3060 450
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2970 450 135 135 2970 450 3105 450
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2970 810 135 135 2970 810 3105 810
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2970 810 90 90 2970 810 3060 810
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 1350 450 2205 585
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 1350 810 2205 675
+3 1 0 1 0 7 50 0 -1 0.000 0 0 0 8
+ 225 630 495 270 1125 180 1485 270 1530 630 1485 990
+ 1125 1080 495 990
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 1 0 1 0 7 50 0 -1 0.000 0 0 0 8
+ 1980 630 2250 270 2880 180 3240 270 3285 630 3240 990
+ 2880 1080 2250 990
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 0 0 1 0 7 50 0 -1 0.000 0 1 0 6
+ 1 1 1.00 45.00 60.00
+ 45 675 135 540 225 810 315 630 360 630 450 630
+ 0.000 1.000 1.000 1.000 1.000 0.000
+4 0 0 50 0 32 10 0.0000 4 90 75 1710 450 e\001
+4 0 0 50 0 32 10 0.0000 4 90 75 1710 900 e\001
diff --git a/doc/opor.fig b/doc/opor.fig
new file mode 100644
index 0000000..edeefb4
--- /dev/null
+++ b/doc/opor.fig
@@ -0,0 +1,40 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 585 945 135 135 585 945 720 945
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 450 135 135 1215 450 1350 450
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 630 135 135 1845 630 1980 630
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 630 90 90 1845 630 1935 630
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 270 135 135 1845 270 1980 270
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 270 90 90 1845 270 1935 270
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 1260 90 90 1845 1260 1935 1260
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 1260 135 135 1845 1260 1980 1260
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 1440 135 135 1215 1440 1350 1440
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 1620 90 90 1845 1620 1935 1620
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1845 1620 135 135 1845 1620 1980 1620
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 675 1035 1125 1350
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 675 855 1125 540
+3 1 0 1 0 7 50 0 -1 0.000 0 0 0 8
+ 855 1440 1125 1080 1755 990 2115 1080 2160 1440 2115 1800
+ 1755 1890 1125 1800
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 1 0 1 0 7 50 0 -1 0.000 0 0 0 8
+ 855 450 1125 90 1755 0 2115 90 2160 450 2115 810
+ 1755 900 1125 810
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 0 0 1 0 7 50 0 -1 0.000 0 1 0 6
+ 1 1 1.00 45.00 60.00
+ 45 990 135 855 225 1125 315 945 360 945 450 945
+ 0.000 1.000 1.000 1.000 1.000 0.000
+4 0 0 50 0 32 10 0.0000 4 90 75 720 1260 e\001
+4 0 0 50 0 32 10 0.0000 4 90 75 720 720 e\001
diff --git a/doc/opstar.fig b/doc/opstar.fig
new file mode 100644
index 0000000..cb2cac6
--- /dev/null
+++ b/doc/opstar.fig
@@ -0,0 +1,43 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 945 675 135 135 945 675 1080 675
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1149 58 90 90 1149 58 1239 58
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1149 58 135 135 1149 58 1284 58
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 1620 495 135 135 1620 495 1755 495
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2250 315 90 90 2250 315 2340 315
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2250 315 135 135 2250 315 2385 315
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2250 675 135 135 2250 675 2385 675
+1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 2250 675 90 90 2250 675 2340 675
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 1080 630 1485 540
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 45.00 60.00
+ 973 543 1103 203
+3 1 0 1 0 7 50 0 -1 0.000 0 0 0 8
+ 1260 495 1530 135 2160 45 2520 135 2565 495 2520 855
+ 2160 945 1530 855
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 0 0 1 0 7 50 0 -1 0.000 0 1 0 6
+ 1 1 1.00 45.00 60.00
+ 2385 360 2700 630 2700 1215 1980 1395 1260 1125 978 801
+ 0.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 1 0 7 50 0 -1 0.000 0 1 0 6
+ 1 1 1.00 45.00 60.00
+ 405 720 495 585 585 855 675 675 720 675 810 675
+ 0.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 1 0 7 50 0 -1 0.000 0 1 0 6
+ 1 1 1.00 45.00 60.00
+ 2385 720 2520 855 2475 1125 1935 1215 1395 1035 1067 730
+ 0.000 1.000 1.000 1.000 1.000 0.000
+4 0 0 50 0 32 10 0.0000 4 90 75 1845 1125 e\001
+4 0 0 50 0 32 10 0.0000 4 90 75 1845 1440 e\001
+4 0 0 50 0 32 10 0.0000 4 90 75 1156 549 e\001
+4 0 0 50 0 32 10 0.0000 4 90 75 896 442 e\001
diff --git a/doc/ragel-guide.pdf b/doc/ragel-guide.pdf
new file mode 100644
index 0000000..38dae46
--- /dev/null
+++ b/doc/ragel-guide.pdf
Binary files differ
diff --git a/doc/ragel-guide.tex b/doc/ragel-guide.tex
new file mode 100644
index 0000000..fab8a51
--- /dev/null
+++ b/doc/ragel-guide.tex
@@ -0,0 +1,3709 @@
+%
+% Copyright 2001-2009 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
+
+% TODO: Need a section on the different strategies for handline recursion.
+
+\documentclass[letterpaper,11pt,oneside]{book}
+\usepackage{graphicx}
+\usepackage{comment}
+\usepackage{multicol}
+\usepackage[
+ colorlinks=true,
+ linkcolor=black,
+ citecolor=green,
+ filecolor=black,
+ urlcolor=black]{hyperref}
+
+\topmargin -0.20in
+\oddsidemargin 0in
+\textwidth 6.5in
+\textheight 9in
+
+\setlength{\parskip}{0pt}
+\setlength{\topsep}{0pt}
+\setlength{\partopsep}{0pt}
+\setlength{\itemsep}{0pt}
+
+\input{version}
+
+\newcommand{\verbspace}{\vspace{10pt}}
+\newcommand{\graphspace}{\vspace{10pt}}
+
+\renewcommand\floatpagefraction{.99}
+\renewcommand\topfraction{.99}
+\renewcommand\bottomfraction{.99}
+\renewcommand\textfraction{.01}
+\setcounter{totalnumber}{50}
+\setcounter{topnumber}{50}
+\setcounter{bottomnumber}{50}
+
+\newenvironment{inline_code}{\def\baselinestretch{1}\vspace{12pt}\small}{}
+
+\begin{document}
+
+%
+% Title page
+%
+\thispagestyle{empty}
+\begin{center}
+\vspace*{3in}
+{\huge Ragel State Machine Compiler}\\
+\vspace*{12pt}
+{\Large User Guide}\\
+\vspace{1in}
+by\\
+\vspace{12pt}
+{\large Adrian Thurston}\\
+\end{center}
+\clearpage
+
+\pagenumbering{roman}
+
+%
+% License page
+%
+\chapter*{License}
+Ragel version \version, \pubdate\\
+Copyright \copyright\ 2003-2007 Adrian Thurston
+\vspace{6mm}
+
+{\bf\it\noindent This document is part of Ragel, and as such, this document is
+released 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.}
+
+\vspace{5pt}
+
+{\bf\it\noindent 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.}
+
+\vspace{5pt}
+
+{\bf\it\noindent 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}
+
+%
+% Table of contents
+%
+\clearpage
+\tableofcontents
+\clearpage
+
+%
+% Chapter 1
+%
+
+\pagenumbering{arabic}
+
+\chapter{Introduction}
+
+\section{Abstract}
+
+Regular expressions are used heavily in practice for the purpose of specifying
+parsers. They are normally used as black boxes linked together with program
+logic. User actions are executed in between invocations of the regular
+expression engine. Adding actions before a pattern terminates requires patterns
+to be broken and pasted back together with program logic. The more user actions
+are needed, the less the advantages of regular expressions are seen.
+
+Ragel is a software development tool that allows user actions to be
+embedded into the transitions of a regular expression's corresponding state
+machine, eliminating the need to switch from the regular expression engine and
+user code execution environment and back again. As a result, expressions can be
+maximally continuous. One is free to specify an entire parser using a single
+regular expression. The single-expression model affords concise and elegant
+descriptions of languages and the generation of very simple, fast and robust
+code. Ragel compiles executable finite state machines from a high level regular language
+notation. Ragel targets C, C++, Objective-C, D, Go, Java and Ruby.
+
+In addition to building state machines from regular expressions, Ragel allows
+the programmer to directly specify state machines with state charts. These two
+notations may be freely combined. There are also facilities for controlling
+nondeterminism in the resulting machines and building scanners using patterns
+that themselves have embedded actions. Ragel can produce code that is small and
+runs very fast. Ragel can handle integer-sized alphabets and can compile very
+large state machines.
+
+\section{Motivation}
+
+When a programmer is faced with the task of producing a parser for a
+context-free language there are many tools to choose from. It is quite common
+to generate useful and efficient parsers for programming languages from a
+formal grammar. It is also quite common for programmers to avoid such tools
+when making parsers for simple computer languages, such as file formats and
+communication protocols. Such languages are often regular and tools for
+processing the context-free languages are viewed as too heavyweight for the
+purpose of parsing regular languages. The extra run-time effort required for
+supporting the recursive nature of context-free languages is wasted.
+
+When we turn to the regular expression-based parsing tools, such as Lex, Re2C,
+and scripting languages such as Sed, Awk and Perl we find that they are split
+into two levels: a regular expression matching engine and some kind of program
+logic for linking patterns together. For example, a Lex program is composed of
+sets of regular expressions. The implied program logic repeatedly attempts to
+match a pattern in the current set. When a match is found the associated user
+code executed. It requires the user to consider a language as a sequence of
+independent tokens. Scripting languages and regular expression libraries allow
+one to link patterns together using arbitrary program code. This is very
+flexible and powerful, however we can be more concise and clear if we avoid
+gluing together regular expressions with if statements and while loops.
+
+This model of execution, where the runtime alternates between regular
+expression matching and user code exectution places restrictions on when
+action code may be executed. Since action code can only be associated with
+complete patterns, any action code that must be executed before an entire
+pattern is matched requires that the pattern be broken into smaller units.
+Instead of being forced to disrupt the regular expression syntax and write
+smaller expressions, it is desirable to retain a single expression and embed
+code for performing actions directly into the transitions that move over the
+characters. After all, capable programmers are astutely aware of the machinery
+underlying their programs, so why not provide them with access to that
+machinery? To achieve this we require an action execution model for associating
+code with the sub-expressions of a regular expression in a way that does not
+disrupt its syntax.
+
+The primary goal of Ragel is to provide developers with an ability to embed
+actions into the transitions and states of a regular expression's state machine
+in support of the definition of entire parsers or large sections of parsers
+using a single regular expression. From the regular expression we gain a clear
+and concise statement of our language. From the state machine we obtain a very
+fast and robust executable that lends itself to many kinds of analysis and
+visualization.
+
+\section{Overview}
+
+Ragel is a language for specifying state machines. The Ragel program is a
+compiler that assembles a state machine definition to executable code. Ragel
+is based on the principle that any regular language can be converted to a
+deterministic finite state automaton. Since every regular language has a state
+machine representation and vice versa, the terms regular language and state
+machine (or just machine) will be used interchangeably in this document.
+
+Ragel outputs machines to C, C++, Objective-C, D, Go, Java or Ruby code. The output is
+designed to be generic and is not bound to any particular input or processing
+method. A Ragel machine expects to have data passed to it in buffer blocks.
+When there is no more input, the machine can be queried for acceptance. In
+this way, a Ragel machine can be used to simply recognize a regular language
+like a regular expression library. By embedding code into the regular language,
+a Ragel machine can also be used to parse input.
+
+The Ragel language has many operators for constructing and manipulating
+machines. Machines are built up from smaller machines, to bigger ones, to the
+final machine representing the language that needs to be recognized or parsed.
+
+The core state machine construction operators are those found in most theory
+of computation textbooks. They date back to the 1950s and are widely studied.
+They are based on set operations and permit one to think of languages as a set
+of strings. They are Union, Intersection, Difference, Concatenation and Kleene
+Star. Put together, these operators make up what most people know as regular
+expressions. Ragel also provides a scanner construction operator
+and provides operators for explicitly constructing machines
+using a state chart method. In the state chart method, one joins machines
+together without any implied transitions and then explicitly specifies where
+epsilon transitions should be drawn.
+
+The state machine manipulation operators are specific to Ragel. They allow the
+programmer to access the states and transitions of regular language's
+corresponding machine. There are two uses of the manipulation operators. The
+first and primary use is to embed code into transitions and states, allowing
+the programmer to specify the actions of the state machine.
+
+Ragel attempts to make the action embedding facility as intuitive as possible.
+To do so, a number of issues need to be addressed. For example, when making a
+nondeterministic specification into a DFA using machines that have embedded
+actions, new transitions are often made that have the combined actions of
+several source transitions. Ragel ensures that multiple actions associated with
+a single transition are ordered consistently with respect to the order of
+reference and the natural ordering implied by the construction operators.
+
+The second use of the manipulation operators is to assign priorities to
+transitions. Priorities provide a convenient way of controlling any
+nondeterminism introduced by the construction operators. Suppose two
+transitions leave from the same state and go to distinct target states on the
+same character. If these transitions are assigned conflicting priorities, then
+during the determinization process the transition with the higher priority will
+take precedence over the transition with the lower priority. The lower priority
+transition gets abandoned. The transitions would otherwise be combined into a new
+transition that goes to a new state that is a combination of the original
+target states. Priorities are often required for segmenting machines. The most
+common uses of priorities have been encoded into a set of simple operators
+that should be used instead of priority embeddings whenever possible.
+
+For the purposes of embedding, Ragel divides transitions and states into
+different classes. There are four operators for embedding actions and
+priorities into the transitions of a state machine. It is possible to embed
+into entering transitions, finishing transitions, all transitions and leaving
+transitions. The embedding into leaving transitions is a special case.
+These transition embeddings get stored in the final states of a machine. They
+are transferred to any transitions that are made going out of the machine by
+future concatenation or kleene star operations.
+
+There are several more operators for embedding actions into states. Like the
+transition embeddings, there are various different classes of states that the
+embedding operators access. For example, one can access start states, final
+states or all states, among others. Unlike the transition embeddings, there are
+several different types of state action embeddings. These are executed at
+various different times during the processing of input. It is possible to embed
+actions that are exectued on transitions into a state, on transitions out of a
+state, on transitions taken on the error event, or on transitions taken on the
+EOF event.
+
+Within actions, it is possible to influence the behaviour of the state machine.
+The user can write action code that jumps or calls to another portion of the
+machine, changes the current character being processed, or breaks out of the
+processing loop. With the state machine calling feature Ragel can be used to
+parse languages that are not regular. For example, one can parse balanced
+parentheses by calling into a parser when an open parenthesis character is seen
+and returning to the state on the top of the stack when the corresponding
+closing parenthesis character is seen. More complicated context-free languages
+such as expressions in C are out of the scope of Ragel.
+
+Ragel also provides a scanner construction operator that can be used to build
+scanners much the same way that Lex is used. The Ragel generated code, which
+relies on user-defined variables for backtracking, repeatedly tries to match
+patterns to the input, favouring longer patterns over shorter ones and patterns
+that appear ahead of others when the lengths of the possible matches are
+identical. When a pattern is matched the associated action is executed.
+
+The key distinguishing feature between scanners in Ragel and scanners in Lex is
+that Ragel patterns may be arbitrary Ragel expressions and can therefore
+contain embedded code. With a Ragel-based scanner the user need not wait until
+the end of a pattern before user code can be executed.
+
+Scanners do take Ragel out of the domain of pure state machines and require the
+user to maintain the backtracking related variables. However, scanners
+integrate well with regular state machine instantiations. They can be called to
+or jumped to only when needed, or they can be called out of or jumped out of
+when a simpler, pure state machine model is appropriate.
+
+Two types of output code style are available. Ragel can produce a table-driven
+machine or a directly executable machine. The directly executable machine is
+much faster than the table-driven. On the other hand, the table-driven machine
+is more compact and less demanding on the host language compiler. It is better
+suited to compiling large state machines.
+
+\section{Related Work}
+
+Lex is perhaps the best-known tool for constructing parsers from regular
+expressions. In the Lex processing model, generated code attempts to match one
+of the user's regular expression patterns, favouring longer matches over
+shorter ones. Once a match is made it then executes the code associated with
+the pattern and consumes the matching string. This process is repeated until
+the input is fully consumed.
+
+Through the use of start conditions, related sets of patterns may be defined.
+The active set may be changed at any time. This allows the user to define
+different lexical regions. It also allows the user to link patterns together by
+requiring that some patterns come before others. This is quite like a
+concatenation operation. However, use of Lex for languages that require a
+considerable amount of pattern concatenation is inappropriate. In such cases a
+Lex program deteriorates into a manually specified state machine, where start
+conditions define the states and pattern actions define the transitions. Lex
+is therefore best suited to parsing tasks where the language to be parsed can
+be described in terms of regions of tokens.
+
+Lex is useful in many scenarios and has undoubtedly stood the test of time.
+There are, however, several drawbacks to using Lex. Lex can impose too much
+overhead for parsing applications where buffering is not required because all
+the characters are available in a single string. In these cases there is
+structure to the language to be parsed and a parser specification tool can
+help, but employing a heavyweight processing loop that imposes a stream
+``pull'' model and dynamic input buffer allocation is inappropriate. An
+example of this kind of scenario is the conversion of floating point numbers
+contained in a string to their corresponding numerical values.
+
+Another drawback is the very issue that Ragel attempts to solve.
+It is not possible to execute a user action while
+matching a character contained inside a pattern. For example, if scanning a
+programming language and string literals can contain newlines which must be
+counted, a Lex user must break up a string literal pattern so as to associate
+an action with newlines. This forces the definition of a new start condition.
+Alternatively the user can reprocess the text of the matched string literal to
+count newlines.
+
+\begin{comment}
+How ragel is different from Lex.
+
+%Like Re2c, Ragel provides a simple execution model that does not make any
+%assumptions as to how the input is collected. Also, Ragel does not do any
+%buffering in the generated code. Consequently there are no dependencies on
+%external functions such as \verb|malloc|.
+
+%If buffering is required it can be manually implemented by embedding actions
+%that copy the current character to a buffer, or data can be passed to the
+%parser using known block boundaries. If the longest-match operator is used,
+%Ragel requires the user to ensure that the ending portion of the input buffer
+%is preserved when the buffer is exhaused before a token is fully matched. The
+%user should move the token prefix to a new memory location, such as back to the
+%beginning of the input buffer, then place the subsequently read input
+%immediately after the prefix.
+
+%These properties of Ragel make it more work to write a program that requires
+%the longest-match operator or buffering of input, however they make Ragel a
+%more flexible tool that can produce very simple and fast-running programs under
+%a variety of input acquisition arrangements.
+
+%In Ragel, it is not necessary
+%to introduce start conditions to concatenate tokens and retain action
+%execution. Ragel allows one to structure a parser as a series of tokens, but
+%does not require it.
+
+%Like Lex and Re2C, Ragel is able to process input using a longest-match
+%execution model, however the core of the Ragel language specifies parsers at a
+%much lower level. This core is built around a pure state machine model. When
+%building basic machines there is no implied algorithm for processing input
+%other than to move from state to state on the transitions of the machine. This
+%core of pure state machine operations makes Ragel well suited to handling
+%parsing problems not based on token scanning. Should one need to use a
+%longest-match model, the functionality is available and the lower level state
+%machine construction facilities can be used to specify the patterns of a
+%longest-match machine.
+
+%This is not possible in Ragel. One can only program
+%a longest-match instantiation with a fixed set of rules. One can jump to
+%another longest-match machine that employs the same machine definitions in the
+%construction of its rules, however no states will be shared.
+
+%In Ragel, input may be re-parsed using a
+%different machine, but since the action to be executed is associated with
+%transitions of the compiled state machine, the longest-match construction does
+%not permit a single rule to be excluded from the active set. It cannot be done
+%ahead of time nor in the excluded rule's action.
+\end{comment}
+
+The Re2C program defines an input processing model similar to that of Lex.
+Re2C focuses on making generated state machines run very fast and
+integrate easily into any program, free of dependencies. Re2C generates
+directly executable code and is able to claim that generated parsers run nearly
+as fast as their hand-coded equivalents. This is very important for user
+adoption, as programmers are reluctant to use a tool when a faster alternative
+exists. A consideration to ease of use is also important because developers
+need the freedom to integrate the generated code as they see fit.
+
+Many scripting languages provide ways of composing parsers by linking regular
+expressions using program logic. For example, Sed and Awk are two established
+Unix scripting tools that allow the programmer to exploit regular expressions
+for the purpose of locating and extracting text of interest. High-level
+programming languages such as Perl, Python, PHP and Ruby all provide regular
+expression libraries that allow the user to combine regular expressions with
+arbitrary code.
+
+In addition to supporting the linking of regular expressions with arbitrary
+program logic, the Perl programming language permits the embedding of code into
+regular expressions. Perl embeddings do not translate into the embedding of
+code into deterministic state machines. Perl regular expressions are in fact
+not fully compiled to deterministic machines when embedded code is involved.
+They are instead interpreted and involve backtracking. This is shown by the
+following Perl program. When it is fed the input \verb|abcd| the interpretor
+attempts to match the first alternative, printing \verb|a1 b1|. When this
+possibility fails it backtracks and tries the second possibility, printing
+\verb|a2 b2|, at which point it succeeds.
+
+\begin{inline_code}
+\begin{verbatim}
+print "YES\n" if ( <STDIN> =~
+ /( a (?{ print "a1 "; }) b (?{ print "b1 "; }) cX ) |
+ ( a (?{ print "a2 "; }) b (?{ print "b2 "; }) cd )/x )
+\end{verbatim}
+\end{inline_code}
+\verbspace
+
+In Ragel there is no regular expression interpretor. Aside from the scanner
+operator, all Ragel expressions are made into deterministic machines and the
+run time simply moves from state to state as it consumes input. An equivalent
+parser expressed in Ragel would attempt both of the alternatives concurrently,
+printing \verb|a1 a2 b1 b2|.
+
+\section{Development Status}
+
+Ragel is a relatively new tool and is under continuous development. As a rough
+release guide, minor revision number changes are for implementation
+improvements and feature additions. Major revision number changes are for
+implementation and language changes that do not preserve backwards
+compatibility. Though in the past this has not always held true: changes that
+break code have crept into minor version number changes. Typically, the
+documentation lags behind the development in the interest of documenting only
+the lasting features. The latest changes are always documented in the ChangeLog
+file.
+
+\chapter{Constructing State Machines}
+
+\section{Ragel State Machine Specifications}
+
+A Ragel input file consists of a program in the host language that contains embedded machine
+specifications. Ragel normally passes input straight to output. When it sees
+a machine specification it stops to read the Ragel statements and possibly generate
+code in place of the specification.
+Afterwards it continues to pass input through. There
+can be any number of FSM specifications in an input file. A multi-line FSM spec
+starts with \verb|%%{| and ends with \verb|}%%|. A single-line FSM spec starts
+with \verb|%%| and ends at the first newline.
+
+While Ragel is looking for FSM specifications it does basic lexical analysis on
+the surrounding input. It interprets literal strings and comments so a
+\verb|%%| sequence in either of those will not trigger the parsing of an FSM
+specification. Ragel does not pass the input through any preprocessor nor does it
+interpret preprocessor directives itself so includes, defines and ifdef logic
+cannot be used to alter the parse of a Ragel input file. It is therefore not
+possible to use an \verb|#if 0| directive to comment out a machine as is
+commonly done in C code. As an alternative, a machine can be prevented from
+causing any generated output by commenting out write statements.
+
+In Figure \ref{cmd-line-parsing}, a multi-line specification is used to define the
+machine and single line specifications are used to trigger the writing of the machine
+data and execution code.
+
+\begin{figure}
+\begin{multicols}{2}
+\small
+\begin{verbatim}
+#include <string.h>
+#include <stdio.h>
+
+%%{
+ machine foo;
+ main :=
+ ( 'foo' | 'bar' )
+ 0 @{ res = 1; };
+}%%
+
+%% write data;
+\end{verbatim}
+\columnbreak
+\begin{verbatim}
+int main( int argc, char **argv )
+{
+ int cs, res = 0;
+ if ( argc > 1 ) {
+ char *p = argv[1];
+ char *pe = p + strlen(p) + 1;
+ %% write init;
+ %% write exec;
+ }
+ printf("result = %i\n", res );
+ return 0;
+}
+\end{verbatim}
+\end{multicols}
+\caption{Parsing a command line argument.}
+\label{cmd-line-parsing}
+\end{figure}
+
+\subsection{Naming Ragel Blocks}
+
+\begin{verbatim}
+machine fsm_name;
+\end{verbatim}
+\verbspace
+
+The \verb|machine| statement gives the name of the FSM. If present in a
+specification, this statement must appear first. If a machine specification
+does not have a name then Ragel uses the previous specification name. If no
+previous specification name exists then this is an error. Because FSM
+specifications persist in memory, a machine's statements can be spread across
+multiple machine specifications. This allows one to break up a machine across
+several files or draw in statements that are common to multiple machines using
+the \verb|include| statement.
+
+\subsection{Machine Definition}
+\label{definition}
+
+\begin{verbatim}
+<name> = <expression>;
+\end{verbatim}
+\verbspace
+
+The machine definition statement associates an FSM expression with a name. Machine
+expressions assigned to names can later be referenced in other expressions. A
+definition statement on its own does not cause any states to be generated. It is simply a
+description of a machine to be used later. States are generated only when a definition is
+instantiated, which happens when a definition is referenced in an instantiated
+expression.
+
+\subsection{Machine Instantiation}
+\label{instantiation}
+
+\begin{verbatim}
+<name> := <expression>;
+\end{verbatim}
+\verbspace
+
+The machine instantiation statement generates a set of states representing an
+expression. Each instantiation generates a distinct set of states. The starting
+state of the instantiation is written in the data section of the generated code
+using the instantiation name. If a machine named
+\verb|main| is instantiated, its start state is used as the
+specification's start state and is assigned to the \verb|cs| variable by the
+\verb|write init| command. If no \verb|main| machine is given, the start state
+of the last machine instantiation to appear is used as the specification's
+start state.
+
+From outside the execution loop, control may be passed to any machine by
+assigning the entry point to the \verb|cs| variable. From inside the execution
+loop, control may be passed to any machine instantiation using \verb|fcall|,
+\verb|fgoto| or \verb|fnext| statements.
+
+\subsection{Including Ragel Code}
+
+\begin{verbatim}
+include FsmName "inputfile.rl";
+\end{verbatim}
+\verbspace
+
+The \verb|include| statement can be used to draw in the statements of another FSM
+specification. Both the name and input file are optional, however at least one
+must be given. Without an FSM name, the given input file is searched for an FSM
+of the same name as the current specification. Without an input file the
+current file is searched for a machine of the given name. If both are present,
+the given input file is searched for a machine of the given name.
+
+Ragel searches for included files from the location of the current file.
+Additional directories can be added to the search path using the \verb|-I|
+option.
+
+\subsection{Importing Definitions}
+\label{import}
+
+\begin{verbatim}
+import "inputfile.h";
+\end{verbatim}
+\verbspace
+
+The \verb|import| statement scrapes a file for sequences of tokens that match
+the following forms. Ragel treats these forms as state machine definitions.
+
+\begin{itemize}
+ \setlength{\itemsep}{-2mm}
+ \item \verb|name '=' number|
+ \item \verb|name '=' lit_string|
+ \item \verb|'define' name number|
+ \item \verb|'define' name lit_string|
+\end{itemize}
+
+If the input file is a Ragel program then tokens inside any Ragel
+specifications are ignored. See Section \ref{export} for a description of
+exporting machine definitions.
+
+Ragel searches for imported files from the location of the current file.
+Additional directories can be added to the search path using the \verb|-I|
+option.
+
+\section{Lexical Analysis of a Ragel Block}
+\label{lexing}
+
+Within a machine specification the following lexical rules apply to the input.
+
+\begin{itemize}
+
+\item The \verb|#| symbol begins a comment that terminates at the next newline.
+
+\item The symbols \verb|""|, \verb|''|, \verb|//|, \verb|[]| behave as the
+delimiters of literal strings. Within them, the following escape sequences
+are interpreted:
+
+\verb| \0 \a \b \t \n \v \f \r|
+
+A backslash at the end of a line joins the following line onto the current. A
+backslash preceding any other character removes special meaning. This applies
+to terminating characters and to special characters in regular expression
+literals. As an exception, regular expression literals do not support escape
+sequences as the operands of a range within a list. See the bullet on regular
+expressions in Section \ref{basic}.
+
+\item The symbols \verb|{}| delimit a block of host language code that will be
+embedded into the machine as an action. Within the block of host language
+code, basic lexical analysis of comments and strings is done in order to
+correctly find the closing brace of the block. With the exception of FSM
+commands embedded in code blocks, the entire block is preserved as is for
+identical reproduction in the output code.
+
+\item The pattern \verb|[+-]?[0-9]+| denotes an integer in decimal format.
+Integers used for specifying machines may be negative only if the alphabet type
+is signed. Integers used for specifying priorities may be positive or negative.
+
+\item The pattern \verb|0x[0-9A-Fa-f]+| denotes an integer in hexadecimal
+format.
+
+\item The keywords are \verb|access|, \verb|action|, \verb|alphtype|,
+\verb|getkey|, \verb|write|, \verb|machine| and \verb|include|.
+
+\item The pattern \verb|[a-zA-Z_][a-zA-Z_0-9]*| denotes an identifier.
+
+%\item The allowable symbols are:
+%
+%\verb/ ( ) ! ^ * ? + : -> - | & . , := = ; > @ $ % /\\
+%\verb| >/ $/ %/ </ @/ <>/ >! $! %! <! @! <>!|\\
+%\verb| >^ $^ %^ <^ @^ <>^ >~ $~ %~ <~ @~ <>~|\\
+%\verb| >* $* %* <* @* <>*|
+
+\item Any amount of whitespace may separate tokens.
+
+\end{itemize}
+
+%\section{Parse of an FSM Specification}
+
+%The following statements are possible within an FSM specification. The
+%requirements for trailing semicolons loosely follow that of C.
+%A block
+%specifying code does not require a trailing semicolon. An expression
+%statement does require a trailing semicolon.
+
+
+\section{Basic Machines}
+\label{basic}
+
+The basic machines are the base operands of regular language expressions. They
+are the smallest unit to which machine construction and manipulation operators
+can be applied.
+
+\begin{itemize}
+
+\item \verb|'hello'| -- Concatenation Literal. Produces a machine that matches
+the sequence of characters in the quoted string. If there are 5 characters
+there will be 6 states chained together with the characters in the string. See
+Section \ref{lexing} for information on valid escape sequences.
+
+% GENERATE: bmconcat
+% OPT: -p
+% %%{
+% machine bmconcat;
+\begin{comment}
+\begin{verbatim}
+main := 'hello';
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmconcat}
+\end{center}
+
+It is possible
+to make a concatenation literal case-insensitive by appending an \verb|i| to
+the string, for example \verb|'cmd'i|.
+
+\item \verb|"hello"| -- Identical to the single quoted version.
+
+\item \verb|[hello]| -- Or Expression. Produces a union of characters. There
+will be two states with a transition for each unique character between the two states.
+The \verb|[]| delimiters behave like the quotes of a literal string. For example,
+\verb|[ \t]| means tab or space. The \verb|or| expression supports character ranges
+with the \verb|-| symbol as a separator. The meaning of the union can be negated
+using an initial \verb|^| character as in standard regular expressions.
+See Section \ref{lexing} for information on valid escape sequences
+in \verb|or| expressions.
+
+% GENERATE: bmor
+% OPT: -p
+% %%{
+% machine bmor;
+\begin{comment}
+\begin{verbatim}
+main := [hello];
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmor}
+\end{center}
+
+\item \verb|''|, \verb|""|, and \verb|[]| -- Zero Length Machine. Produces a machine
+that matches the zero length string. Zero length machines have one state that is both
+a start state and a final state.
+
+% GENERATE: bmnull
+% OPT: -p
+% %%{
+% machine bmnull;
+\begin{comment}
+\begin{verbatim}
+main := '';
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmnull}
+\end{center}
+
+% FIXME: More on the range of values here.
+\item \verb|42| -- Numerical Literal. Produces a two state machine with one
+transition on the given number. The number may be in decimal or hexadecimal
+format and should be in the range allowed by the alphabet type. The minimum and
+maximum values permitted are defined by the host machine that Ragel is compiled
+on. For example, numbers in a \verb|short| alphabet on an i386 machine should
+be in the range \verb|-32768| to \verb|32767|.
+
+% GENERATE: bmnum
+% %%{
+% machine bmnum;
+\begin{comment}
+\begin{verbatim}
+main := 42;
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmnum}
+\end{center}
+
+\item \verb|/simple_regex/| -- Regular Expression. Regular expressions are
+parsed as a series of expressions that are concatenated together. Each
+concatenated expression
+may be a literal character, the ``any'' character specified by the \verb|.|
+symbol, or a union of characters specified by the \verb|[]| delimiters. If the
+first character of a union is \verb|^| then it matches any character not in the
+list. Within a union, a range of characters can be given by separating the first
+and last characters of the range with the \verb|-| symbol. Each
+concatenated machine may have repetition specified by following it with the
+\verb|*| symbol. The standard escape sequences described in Section
+\ref{lexing} are supported everywhere in regular expressions except as the
+operands of a range within in a list. This notation also supports the \verb|i|
+trailing option. Use it to produce case-insensitive machines, as in \verb|/GET/i|.
+
+Ragel does not support very complex regular expressions because the desired
+results can always be achieved using the more general machine construction
+operators listed in Section \ref{machconst}. The following diagram shows the
+result of compiling \verb|/ab*[c-z].*[123]/|. \verb|DEF| represents the default
+transition, which is taken if no other transition can be taken.
+
+
+% GENERATE: bmregex
+% OPT: -p
+% %%{
+% machine bmregex;
+\begin{comment}
+\begin{verbatim}
+main := /ab*[c-z].*[123]/;
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmregex}
+\end{center}
+
+\item \verb|'a' .. 'z'| -- Range. Produces a machine that matches any
+characters in the specified range. Allowable upper and lower bounds of the
+range are concatenation literals of length one and numerical literals. For
+example, \verb|0x10..0x20|, \verb|0..63|, and \verb|'a'..'z'| are valid ranges.
+The bounds should be in the range allowed by the alphabet type.
+
+% GENERATE: bmrange
+% OPT: -p
+% %%{
+% machine bmrange;
+\begin{comment}
+\begin{verbatim}
+main := 'a' .. 'z';
+\end{verbatim}
+\end{comment}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{bmrange}
+\end{center}
+
+
+\item \verb|variable_name| -- Lookup the machine definition assigned to the
+variable name given and use an instance of it. See Section \ref{definition} for
+an important note on what it means to reference a variable name.
+
+\item \verb|builtin_machine| -- There are several built-in machines available
+for use. They are all two state machines for the purpose of matching common
+classes of characters. They are:
+
+\begin{itemize}
+
+\item \verb|any | -- Any character in the alphabet.
+
+\item \verb|ascii | -- Ascii characters. \verb|0..127|
+
+\item \verb|extend| -- Ascii extended characters. This is the range
+\verb|-128..127| for signed alphabets and the range \verb|0..255| for unsigned
+alphabets.
+
+\item \verb|alpha | -- Alphabetic characters. \verb|[A-Za-z]|
+
+\item \verb|digit | -- Digits. \verb|[0-9]|
+
+\item \verb|alnum | -- Alpha numerics. \verb|[0-9A-Za-z]|
+
+\item \verb|lower | -- Lowercase characters. \verb|[a-z]|
+
+\item \verb|upper | -- Uppercase characters. \verb|[A-Z]|
+
+\item \verb|xdigit| -- Hexadecimal digits. \verb|[0-9A-Fa-f]|
+
+\item \verb|cntrl | -- Control characters. \verb|0..31|
+
+\item \verb|graph | -- Graphical characters. \verb|[!-~]|
+
+\item \verb|print | -- Printable characters. \verb|[ -~]|
+
+\item \verb|punct | -- Punctuation. Graphical characters that are not alphanumerics.
+\verb|[!-/:-@[-`{-~]|
+
+\item \verb|space | -- Whitespace. \verb|[\t\v\f\n\r ]|
+
+\item \verb|zlen | -- Zero length string. \verb|""|
+
+\item \verb|empty | -- Empty set. Matches nothing. \verb|^any|
+
+\end{itemize}
+\end{itemize}
+
+\section{Operator Precedence}
+The following table shows operator precedence from lowest to highest. Operators
+in the same precedence group are evaluated from left to right.
+
+\verbspace
+\begin{tabular}{|c|c|c|}
+\hline
+1&\verb| , |&Join\\
+\hline
+2&\verb/ | & - --/&Union, Intersection and Subtraction\\
+\hline
+3&\verb| . <: :> :>> |&Concatenation\\
+\hline
+4&\verb| : |&Label\\
+\hline
+5&\verb| -> |&Epsilon Transition\\
+\hline
+&\verb| > @ $ % |&Transitions Actions and Priorities\\
+\cline{2-3}
+&\verb| >/ $/ %/ </ @/ <>/ |&EOF Actions\\
+\cline{2-3}
+6&\verb| >! $! %! <! @! <>! |&Global Error Actions\\
+\cline{2-3}
+&\verb| >^ $^ %^ <^ @^ <>^ |&Local Error Actions\\
+\cline{2-3}
+&\verb| >~ $~ %~ <~ @~ <>~ |&To-State Actions\\
+\cline{2-3}
+&\verb| >* $* %* <* @* <>* |&From-State Action\\
+\hline
+7&\verb| * ** ? + {n} {,n} {n,} {n,m} |&Repetition\\
+\hline
+8&\verb| ! ^ |&Negation and Character-Level Negation\\
+\hline
+9&\verb| ( <expr> ) |&Grouping\\
+\hline
+\end{tabular}
+
+\section{Regular Language Operators}
+\label{machconst}
+
+When using Ragel it is helpful to have a sense of how it constructs machines.
+The determinization process can produce results that seem unusual to someone
+not familiar with the NFA to DFA conversion algorithm. In this section we
+describe Ragel's state machine operators. Though the operators are defined
+using epsilon transitions, it should be noted that this is for discussion only.
+The epsilon transitions described in this section do not persist, but are
+immediately removed by the determinization process which is executed at every
+operation. Ragel does not make use of any nondeterministic intermediate state
+machines.
+
+To create an epsilon transition between two states \verb|x| and \verb|y| is to
+copy all of the properties of \verb|y| into \verb|x|. This involves drawing in
+all of \verb|y|'s to-state actions, EOF actions, etc., in addition to its
+transitions. If \verb|x| and \verb|y| both have a transition out on the same
+character, then the transitions must be combined. During transition
+combination a new transition is made that goes to a new state that is the
+combination of both target states. The new combination state is created using
+the same epsilon transition method. The new state has an epsilon transition
+drawn to all the states that compose it. Since the creation of new epsilon
+transitions may be triggered every time an epsilon transition is drawn, the
+process of drawing epsilon transitions is repeated until there are no more
+epsilon transitions to be made.
+
+A very common error that is made when using Ragel is to make machines that do
+too much. That is, to create machines that have unintentional
+nondetermistic properties. This usually results from being unaware of the common strings
+between machines that are combined together using the regular language
+operators. This can involve never leaving a machine, causing its actions to be
+propagated through all the following states. Or it can involve an alternation
+where both branches are unintentionally taken simultaneously.
+
+This problem forces one to think hard about the language that needs to be
+matched. To guard against this kind of problem one must ensure that the machine
+specification is divided up using boundaries that do not allow ambiguities from
+one portion of the machine to the next. See Chapter
+\ref{controlling-nondeterminism} for more on this problem and how to solve it.
+
+The Graphviz tool is an immense help when debugging improperly compiled
+machines or otherwise learning how to use Ragel. Graphviz Dot files can be
+generated from Ragel programs using the \verb|-V| option. See Section
+\ref{visualization} for more information.
+
+
+\subsection{Union}
+
+\verb/expr | expr/
+\verbspace
+
+The union operation produces a machine that matches any string in machine one
+or machine two. The operation first creates a new start state. Epsilon
+transitions are drawn from the new start state to the start states of both
+input machines. The resulting machine has a final state set equivalent to the
+union of the final state sets of both input machines. In this operation, there
+is the opportunity for nondeterminism among both branches. If there are
+strings, or prefixes of strings that are matched by both machines then the new
+machine will follow both parts of the alternation at once. The union operation is
+shown below.
+
+\graphspace
+\begin{center}
+\includegraphics{opor}
+\end{center}
+\graphspace
+
+The following example demonstrates the union of three machines representing
+common tokens.
+
+% GENERATE: exor
+% OPT: -p
+% %%{
+% machine exor;
+\begin{inline_code}
+\begin{verbatim}
+# Hex digits, decimal digits, or identifiers
+main := '0x' xdigit+ | digit+ | alpha alnum*;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exor}
+\end{center}
+
+\subsection{Intersection}
+
+\verb|expr & expr|
+\verbspace
+
+Intersection produces a machine that matches any
+string that is in both machine one and machine two. To achieve intersection, a
+union is performed on the two machines. After the result has been made
+deterministic, any final state that is not a combination of final states from
+both machines has its final state status revoked. To complete the operation,
+paths that do not lead to a final state are pruned from the machine. Therefore,
+if there are any such paths in either of the expressions they will be removed
+by the intersection operator. Intersection can be used to require that two
+independent patterns be simultaneously satisfied as in the following example.
+
+% GENERATE: exinter
+% OPT: -p
+% %%{
+% machine exinter;
+\begin{inline_code}
+\begin{verbatim}
+# Match lines four characters wide that contain
+# words separated by whitespace.
+main :=
+ /[^\n][^\n][^\n][^\n]\n/* &
+ (/[a-z][a-z]*/ | [ \n])**;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exinter}
+\end{center}
+
+\subsection{Difference}
+
+\verb|expr - expr|
+\verbspace
+
+The difference operation produces a machine that matches
+strings that are in machine one but are not in machine two. To achieve subtraction,
+a union is performed on the two machines. After the result has been made
+deterministic, any final state that came from machine two or is a combination
+of states involving a final state from machine two has its final state status
+revoked. As with intersection, the operation is completed by pruning any path
+that does not lead to a final state. The following example demonstrates the
+use of subtraction to exclude specific cases from a set.
+
+\verbspace
+
+% GENERATE: exsubtr
+% OPT: -p
+% %%{
+% machine exsubtr;
+\begin{inline_code}
+\begin{verbatim}
+# Subtract keywords from identifiers.
+main := /[a-z][a-z]*/ - ( 'for' | 'int' );
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exsubtr}
+\end{center}
+\graphspace
+
+
+\subsection{Strong Difference}
+\label{strong_difference}
+
+\verb|expr -- expr|
+\verbspace
+
+Strong difference produces a machine that matches any string of the first
+machine that does not have any string of the second machine as a substring. In
+the following example, strong subtraction is used to excluded \verb|CRLF| from
+a sequence. In the corresponding visualization, the label \verb|DEF| is short
+for default. The default transition is taken if no other transition can be
+taken.
+
+% GENERATE: exstrongsubtr
+% OPT: -p
+% %%{
+% machine exstrongsubtr;
+\begin{inline_code}
+\begin{verbatim}
+crlf = '\r\n';
+main := [a-z]+ ':' ( any* -- crlf ) crlf;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exstrongsubtr}
+\end{center}
+\graphspace
+
+This operator is equivalent to the following.
+
+\verbspace
+\begin{verbatim}
+expr - ( any* expr any* )
+\end{verbatim}
+
+\subsection{Concatenation}
+
+\verb|expr . expr|
+\verbspace
+
+Concatenation produces a machine that matches all the strings in machine one followed by all
+the strings in machine two. Concatenation draws epsilon transitions from the
+final states of the first machine to the start state of the second machine. The
+final states of the first machine lose their final state status, unless the
+start state of the second machine is final as well.
+Concatenation is the default operator. Two machines next to each other with no
+operator between them results in concatenation.
+
+\graphspace
+\begin{center}
+\includegraphics{opconcat}
+\end{center}
+\graphspace
+
+The opportunity for nondeterministic behaviour results from the possibility of
+the final states of the first machine accepting a string that is also accepted
+by the start state of the second machine.
+The most common scenario in which this happens is the
+concatenation of a machine that repeats some pattern with a machine that gives
+a terminating string, but the repetition machine does not exclude the
+terminating string. The example in Section \ref{strong_difference}
+guards against this. Another example is the expression \verb|("'" any* "'")|.
+When executed the thread of control will
+never leave the \verb|any*| machine. This is a problem especially if actions
+are embedded to process the characters of the \verb|any*| component.
+
+In the following example, the first machine is always active due to the
+nondeterministic nature of concatenation. This particular nondeterminism is intended
+however because we wish to permit EOF strings before the end of the input.
+
+% GENERATE: exconcat
+% OPT: -p
+% %%{
+% machine exconcat;
+\begin{inline_code}
+\begin{verbatim}
+# Require an eof marker on the last line.
+main := /[^\n]*\n/* . 'EOF\n';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exconcat}
+\end{center}
+\graphspace
+
+\noindent {\bf Note:} There is a language
+ambiguity involving concatenation and subtraction. Because concatenation is the
+default operator for two
+adjacent machines there is an ambiguity between subtraction of
+a positive numerical literal and concatenation of a negative numerical literal.
+For example, \verb|(x-7)| could be interpreted as \verb|(x . -7)| or
+\verb|(x - 7)|. In the Ragel language, the subtraction operator always takes precedence
+over concatenation of a negative literal. We adhere to the rule that the default
+concatenation operator takes effect only when there are no other operators between
+two machines. Beware of writing machines such as \verb|(any -1)| when what is
+desired is a concatenation of \verb|any| and \verb|-1|. Instead write
+\verb|(any . -1)| or \verb|(any (-1))|. If in doubt of the meaning of your program do not
+rely on the default concatenation operator; always use the \verb|.| symbol.
+
+
+\subsection{Kleene Star}
+
+\verb|expr*|
+\verbspace
+
+The machine resulting from the Kleene Star operator will match zero or more
+repetitions of the machine it is applied to.
+It creates a new start state and an additional final
+state. Epsilon transitions are drawn between the new start state and the old start
+state, between the new start state and the new final state, and
+between the final states of the machine and the new start state. After the
+machine is made deterministic the effect is of the final states getting all the
+transitions of the start state.
+
+\graphspace
+\begin{center}
+\includegraphics{opstar}
+\end{center}
+\graphspace
+
+The possibility for nondeterministic behaviour arises if the final states have
+transitions on any of the same characters as the start state. This is common
+when applying kleene star to an alternation of tokens. Like the other problems
+arising from nondeterministic behavior, this is discussed in more detail in Chapter
+\ref{controlling-nondeterminism}. This particular problem can also be solved
+by using the longest-match construction discussed in Section
+\ref{generating-scanners} on scanners.
+
+In this
+example, there is no nondeterminism introduced by the exterior kleene star due to
+the newline at the end of the regular expression. Without the newline the
+exterior kleene star would be redundant and there would be ambiguity between
+repeating the inner range of the regular expression and the entire regular
+expression. Though it would not cause a problem in this case, unnecessary
+nondeterminism in the kleene star operator often causes undesired results for
+new Ragel users and must be guarded against.
+
+% GENERATE: exstar
+% OPT: -p
+% %%{
+% machine exstar;
+\begin{inline_code}
+\begin{verbatim}
+# Match any number of lines with only lowercase letters.
+main := /[a-z]*\n/*;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exstar}
+\end{center}
+\graphspace
+
+\subsection{One Or More Repetition}
+
+\verb|expr+|
+\verbspace
+
+This operator produces the concatenation of the machine with the kleene star of
+itself. The result will match one or more repetitions of the machine. The plus
+operator is equivalent to \verb|(expr . expr*)|.
+
+% GENERATE: explus
+% OPT: -p
+% %%{
+% machine explus;
+\begin{inline_code}
+\begin{verbatim}
+# Match alpha-numeric words.
+main := alnum+;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{explus}
+\end{center}
+\graphspace
+
+\subsection{Optional}
+
+\verb|expr?|
+\verbspace
+
+The {\em optional} operator produces a machine that accepts the machine
+given or the zero length string. The optional operator is equivalent to
+\verb/(expr | '' )/. In the following example the optional operator is used to
+possibly extend a token.
+
+% GENERATE: exoption
+% OPT: -p
+% %%{
+% machine exoption;
+\begin{inline_code}
+\begin{verbatim}
+# Match integers or floats.
+main := digit+ ('.' digit+)?;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exoption}
+\end{center}
+\graphspace
+
+
+\subsection{Repetition}
+
+\begin{tabbing}
+\noindent \verb|expr {n}| \hspace{16pt}\=-- Exactly N copies of expr.\\
+
+\noindent \verb|expr {,n}| \>-- Zero to N copies of expr.\\
+
+\noindent \verb|expr {n,}| \>-- N or more copies of expr.\\
+
+\noindent \verb|expr {n,m}| \>-- N to M copies of expr.
+\end{tabbing}
+
+\subsection{Negation}
+
+\verb|!expr|
+\verbspace
+
+Negation produces a machine that matches any string not matched by the given
+machine. Negation is equivalent to \verb|(any* - expr)|.
+
+% GENERATE: exnegate
+% OPT: -p
+% %%{
+% machine exnegate;
+\begin{inline_code}
+\begin{verbatim}
+# Accept anything but a string beginning with a digit.
+main := ! ( digit any* );
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exnegate}
+\end{center}
+\graphspace
+
+
+\subsection{Character-Level Negation}
+
+\verb|^expr|
+\verbspace
+
+Character-level negation produces a machine that matches any single character
+not matched by the given machine. Character-Level Negation is equivalent to
+\verb|(any - expr)|. It must be applied only to machines that match strings of
+length one.
+
+\section{State Machine Minimization}
+
+State machine minimization is the process of finding the minimal equivalent FSM accepting
+the language. Minimization reduces the number of states in machines
+by merging equivalent states. It does not change the behaviour of the machine
+in any way. It will cause some states to be merged into one because they are
+functionally equivalent. State minimization is on by default. It can be turned
+off with the \verb|-n| option.
+
+The algorithm implemented is similar to Hopcroft's state minimization
+algorithm. Hopcroft's algorithm assumes a finite alphabet that can be listed in
+memory, whereas Ragel supports arbitrary integer alphabets that cannot be
+listed in memory. Though exact analysis is very difficult, Ragel minimization
+runs close to $O(n \times log(n))$ and requires $O(n)$ temporary storage where
+$n$ is the number of states.
+
+\section{Visualization}
+\label{visualization}
+
+%In many cases, practical
+%parsing programs will be too large to completely visualize with Graphviz. The
+%proper approach is to reduce the language to the smallest subset possible that
+%still exhibits the characteristics that one wishes to learn about or to fix.
+%This can be done without modifying the source code using the \verb|-M| and
+%\verb|-S| options. If a machine cannot be easily reduced,
+%embeddings of unique actions can be very useful for tracing a
+%particular component of a larger machine specification, since action names are
+%written out on transition labels.
+
+Ragel is able to emit compiled state machines in Graphviz's Dot file format.
+This is done using the \verb|-V| option.
+Graphviz support allows users to perform
+incremental visualization of their parsers. User actions are displayed on
+transition labels of the graph.
+
+If the final graph is too large to be
+meaningful, or even drawn, the user is able to inspect portions of the parser
+by naming particular regular expression definitions with the \verb|-S| and
+\verb|-M| options to the \verb|ragel| program. Use of Graphviz greatly
+improves the Ragel programming experience. It allows users to learn Ragel by
+experimentation and also to track down bugs caused by unintended
+nondeterminism.
+
+Ragel has another option to help debugging. The \verb|-x| option causes Ragel
+to emit the compiled machine in an XML format.
+
+\chapter{User Actions}
+
+Ragel permits the user to embed actions into the transitions of a regular
+expression's corresponding state machine. These actions are executed when the
+generated code moves over a transition. Like the regular expression operators,
+the action embedding operators are fully compositional. They take a state
+machine and an action as input, embed the action and yield a new state machine
+that can be used in the construction of other machines. Due to the
+compositional nature of embeddings, the user has complete freedom in the
+placement of actions.
+
+A machine's transitions are categorized into four classes. The action embedding
+operators access the transitions defined by these classes. The {\em entering
+transition} operator \verb|>| isolates the start state, then embeds an action
+into all transitions leaving it. The {\em finishing transition} operator
+\verb|@| embeds an action into all transitions going into a final state. The
+{\em all transition} operator \verb|$| embeds an action into all transitions of
+an expression. The {\em leaving transition} operator \verb|%| provides access
+to the yet-unmade transitions moving out of the machine via the final states.
+
+\section{Embedding Actions}
+
+\begin{verbatim}
+action ActionName {
+ /* Code an action here. */
+ count += 1;
+}
+\end{verbatim}
+\verbspace
+
+The action statement defines a block of code that can be embedded into an FSM.
+Action names can be referenced by the action embedding operators in
+expressions. Though actions need not be named in this way (literal blocks
+of code can be embedded directly when building machines), defining reusable
+blocks of code whenever possible is good practice because it potentially increases the
+degree to which the machine can be minimized.
+
+Within an action some Ragel expressions and statements are parsed and
+translated. These allow the user to interact with the machine from action code.
+See Section \ref{vals} for a complete list of statements and values available
+in code blocks.
+
+\subsection{Entering Action}
+
+\verb|expr > action|
+\verbspace
+
+The entering action operator embeds an action into all transitions
+that enter into the machine from the start state. If the start state is final,
+then the action is also embedded into the start state as a leaving action. This
+means that if a machine accepts the zero-length string and control passes
+through the start state then the entering action is executed. Note
+that this can happen on both a following character and on the EOF event.
+
+In some machines the start state has transtions coming in from within the
+machine. In these cases the start state is first isolated from the rest of the
+machine ensuring that the entering actions are exected once only.
+
+\verbspace
+
+% GENERATE: exstact
+% OPT: -p
+% %%{
+% machine exstact;
+\begin{inline_code}
+\begin{verbatim}
+# Execute A at the beginning of a string of alpha.
+action A {}
+main := ( lower* >A ) . ' ';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exstact}
+\end{center}
+\graphspace
+
+\subsection{Finishing Action}
+
+\verb|expr @ action|
+\verbspace
+
+The finishing action operator embeds an action into any transitions that move
+the machine into a final state. Further input may move the machine out of the
+final state, but keep it in the machine. Therefore finishing actions may be
+executed more than once if a machine has any internal transitions out of a
+final state. In the following example the final state has no transitions out
+and the finishing action is executed only once.
+
+% GENERATE: exdoneact
+% OPT: -p
+% %%{
+% machine exdoneact;
+% action A {}
+\begin{inline_code}
+\begin{verbatim}
+# Execute A when the trailing space is seen.
+main := ( lower* ' ' ) @A;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exdoneact}
+\end{center}
+\graphspace
+
+
+\subsection{All Transition Action}
+
+\verb|expr $ action|
+\verbspace
+
+The all transition operator embeds an action into all transitions of a machine.
+The action is executed whenever a transition of the machine is taken. In the
+following example, A is executed on every character matched.
+
+% GENERATE: exallact
+% OPT: -p
+% %%{
+% machine exallact;
+% action A {}
+\begin{inline_code}
+\begin{verbatim}
+# Execute A on any characters of the machine.
+main := ( 'm1' | 'm2' ) $A;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exallact}
+\end{center}
+\graphspace
+
+
+\subsection{Leaving Actions}
+\label{out-actions}
+
+\verb|expr % action|
+\verbspace
+
+The leaving action operator queues an action for embedding into the transitions
+that go out of a machine via a final state. The action is first stored in
+the machine's final states and is later transferred to any transitions that are
+made going out of the machine by a kleene star or concatenation operation.
+
+If a final state of the machine is still final when compilation is complete
+then the leaving action is also embedded as an EOF action. Therefore, leaving
+the machine is defined as either leaving on a character or as state machine
+acceptance.
+
+This operator allows one to associate an action with the termination of a
+sequence, without being concerned about what particular character terminates
+the sequence. In the following example, A is executed when leaving the alpha
+machine on the newline character.
+
+% GENERATE: exoutact1
+% OPT: -p
+% %%{
+% machine exoutact1;
+% action A {}
+\begin{inline_code}
+\begin{verbatim}
+# Match a word followed by a newline. Execute A when
+# finishing the word.
+main := ( lower+ %A ) . '\n';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exoutact1}
+\end{center}
+\graphspace
+
+In the following example, the \verb|term_word| action could be used to register
+the appearance of a word and to clear the buffer that the \verb|lower| action used
+to store the text of it.
+
+% GENERATE: exoutact2
+% OPT: -p
+% %%{
+% machine exoutact2;
+% action lower {}
+% action space {}
+% action term_word {}
+% action newline {}
+\begin{inline_code}
+\begin{verbatim}
+word = ( [a-z] @lower )+ %term_word;
+main := word ( ' ' @space word )* '\n' @newline;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exoutact2}
+\end{center}
+\graphspace
+
+In this final example of the action embedding operators, A is executed upon entering
+the alpha machine, B is executed on all transitions of the
+alpha machine, C is executed when the alpha machine is exited by moving into the
+newline machine and N is executed when the newline machine moves into a final
+state.
+
+% GENERATE: exaction
+% OPT: -p
+% %%{
+% machine exaction;
+% action A {}
+% action B {}
+% action C {}
+% action N {}
+\begin{inline_code}
+\begin{verbatim}
+# Execute A on starting the alpha machine, B on every transition
+# moving through it and C upon finishing. Execute N on the newline.
+main := ( lower* >A $B %C ) . '\n' @N;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{exaction}
+\end{center}
+\graphspace
+
+
+\section{State Action Embedding Operators}
+
+The state embedding operators allow one to embed actions into states. Like the
+transition embedding operators, there are several different classes of states
+that the operators access. The meanings of the symbols are similar to the
+meanings of the symbols used for the transition embedding operators. The design
+of the state selections was driven by a need to cover the states of an
+expression with exactly one error action.
+
+Unlike the transition embedding operators, the state embedding operators are
+also distinguished by the different kinds of events that embedded actions can
+be associated with. Therefore the state embedding operators have two
+components. The first, which is the first one or two characters, specifies the
+class of states that the action will be embedded into. The second component
+specifies the type of event the action will be executed on. The symbols of the
+second component also have equivalent kewords.
+
+\vspace{10pt}
+
+\def\fakeitem{\hspace*{12pt}$\bullet$\hspace*{10pt}}
+
+\begin{minipage}{\textwidth}
+\begin{multicols}{2}
+\raggedcolumns
+\noindent The different classes of states are:\\
+\fakeitem \verb|> | -- the start state\\
+\fakeitem \verb|< | -- any state except the start state\\
+\fakeitem \verb|$ | -- all states\\
+\fakeitem \verb|% | -- final states\\
+\fakeitem \verb|@ | -- any state except final states\\
+\fakeitem \verb|<>| -- any except start and final (middle)
+
+\columnbreak
+
+\noindent The different kinds of embeddings are:\\
+\fakeitem \verb|~| -- to-state actions (\verb|to|)\\
+\fakeitem \verb|*| -- from-state actions (\verb|from|)\\
+\fakeitem \verb|/| -- EOF actions (\verb|eof|)\\
+\fakeitem \verb|!| -- error actions (\verb|err|)\\
+\fakeitem \verb|^| -- local error actions (\verb|lerr|)\\
+\end{multicols}
+\end{minipage}
+
+\subsection{To-State and From-State Actions}
+
+\subsubsection{To-State Actions}
+
+\def\sasp{\hspace*{40pt}}
+
+\sasp\verb|>~action >to(name) >to{...} | -- the start state\\
+\sasp\verb|<~action <to(name) <to{...} | -- any state except the start state\\
+\sasp\verb|$~action $to(name) $to{...} | -- all states\\
+\sasp\verb|%~action %to(name) %to{...} | -- final states\\
+\sasp\verb|@~action @to(name) @to{...} | -- any state except final states\\
+\sasp\verb|<>~action <>to(name) <>to{...}| -- any except start and final (middle)
+\vspace{12pt}
+
+
+To-state actions are executed whenever the state machine moves into the
+specified state, either by a natural movement over a transition or by an
+action-based transfer of control such as \verb|fgoto|. They are executed after the
+in-transition's actions but before the current character is advanced and
+tested against the end of the input block. To-state embeddings stay with the
+state. They are irrespective of the state's current set of transitions and any
+future transitions that may be added in or out of the state.
+
+Note that the setting of the current state variable \verb|cs| outside of the
+execute code is not considered by Ragel as moving into a state and consequently
+the to-state actions of the new current state are not executed. This includes
+the initialization of the current state when the machine begins. This is
+because the entry point into the machine execution code is after the execution
+of to-state actions.
+
+\subsubsection{From-State Actions}
+
+\sasp\verb|>*action >from(name) >from{...} | -- the start state\\
+\sasp\verb|<*action <from(name) <from{...} | -- any state except the start state\\
+\sasp\verb|$*action $from(name) $from{...} | -- all states\\
+\sasp\verb|%*action %from(name) %from{...} | -- final states\\
+\sasp\verb|@*action @from(name) @from{...} | -- any state except final states\\
+\sasp\verb|<>*action <>from(name) <>from{...}| -- any except start and final (middle)
+\vspace{12pt}
+
+From-state actions are executed whenever the state machine takes a transition from a
+state, either to itself or to some other state. These actions are executed
+immediately after the current character is tested against the input block end
+marker and before the transition to take is sought based on the current
+character. From-state actions are therefore executed even if a transition
+cannot be found and the machine moves into the error state. Like to-state
+embeddings, from-state embeddings stay with the state.
+
+\subsection{EOF Actions}
+
+\sasp\verb|>/action >eof(name) >eof{...} | -- the start state\\
+\sasp\verb|</action <eof(name) <eof{...} | -- any state except the start state\\
+\sasp\verb|$/action $eof(name) $eof{...} | -- all states\\
+\sasp\verb|%/action %eof(name) %eof{...} | -- final states\\
+\sasp\verb|@/action @eof(name) @eof{...} | -- any state except final states\\
+\sasp\verb|<>/action <>eof(name) <>eof{...}| -- any except start and final (middle)
+\vspace{12pt}
+
+The EOF action embedding operators enable the user to embed actions that are
+executed at the end of the input stream. EOF actions are stored in states and
+generated in the \verb|write exec| block. They are run when \verb|p == pe == eof|
+as the execute block is finishing. EOF actions are free to adjust \verb|p| and
+jump to another part of the machine to restart execution.
+
+\subsection{Handling Errors}
+
+In many applications it is useful to be able to react to parsing errors. The
+user may wish to print an error message that depends on the context. It
+may also be desirable to consume input in an attempt to return the input stream
+to some known state and resume parsing. To support error handling and recovery,
+Ragel provides error action embedding operators. There are two kinds of error
+actions: global error actions and local error actions.
+Error actions can be used to simply report errors, or by jumping to a machine
+instantiation that consumes input, can attempt to recover from errors.
+
+\subsubsection{Global Error Actions}
+
+\sasp\verb|>!action >err(name) >err{...} | -- the start state\\
+\sasp\verb|<!action <err(name) <err{...} | -- any state except the start state\\
+\sasp\verb|$!action $err(name) $err{...} | -- all states\\
+\sasp\verb|%!action %err(name) %err{...} | -- final states\\
+\sasp\verb|@!action @err(name) @err{...} | -- any state except final states\\
+\sasp\verb|<>!action <>err(name) <>err{...}| -- any except start and final (middle)
+\vspace{12pt}
+
+Global error actions are stored in the states they are embedded into until
+compilation is complete. They are then transferred to the transitions that move
+into the error state. These transitions are taken on all input characters that
+are not already covered by the state's transitions. If a state with an error
+action is not final when compilation is complete, then the action is also
+embedded as an EOF action.
+
+Error actions can be used to recover from errors by jumping back into the
+machine with \verb|fgoto| and optionally altering \verb|p|.
+
+\subsubsection{Local Error Actions}
+
+\sasp\verb|>^action >lerr(name) >lerr{...} | -- the start state\\
+\sasp\verb|<^action <lerr(name) <lerr{...} | -- any state except the start state\\
+\sasp\verb|$^action $lerr(name) $lerr{...} | -- all states\\
+\sasp\verb|%^action %lerr(name) %lerr{...} | -- final states\\
+\sasp\verb|@^action @lerr(name) @lerr{...} | -- any state except final states\\
+\sasp\verb|<>^action <>lerr(name) <>lerr{...}| -- any except start and final (middle)
+\vspace{12pt}
+
+Like global error actions, local error actions are also stored in the states
+they are embedded into until a transfer point. The transfer point is different
+however. Each local error action embedding is associated with a name. When a
+machine definition has been fully constructed, all local error action
+embeddings associated with the same name as the machine definition are
+transferred to the error transitions. At this time they are also embedded as
+EOF actions in the case of non-final states.
+
+Local error actions can be used to specify an action to take when a particular
+section of a larger state machine fails to match. A particular machine
+definition's ``thread'' may die and the local error actions executed, however
+the machine as a whole may continue to match input.
+
+There are two forms of local error action embeddings. In the first form the
+name defaults to the current machine. In the second form the machine name can
+be specified. This is useful when it is more convenient to specify the local
+error action in a sub-definition that is used to construct the machine
+definition that the local error action is associated with. To embed local
+error actions and
+explicitly state the machine definition on which the transfer is to happen use
+\verb|(name, action)| as the action.
+
+\subsubsection{Example}
+
+The following example uses error actions to report an error and jump to a
+machine that consumes the remainder of the line when parsing fails. After
+consuming the line, the error recovery machine returns to the main loop.
+
+% GENERATE: erract
+% %%{
+% machine erract;
+% ws = ' ';
+% address = 'foo@bar.com';
+% date = 'Monday May 12';
+\begin{inline_code}
+\begin{verbatim}
+action cmd_err {
+ printf( "command error\n" );
+ fhold; fgoto line;
+}
+action from_err {
+ printf( "from error\n" );
+ fhold; fgoto line;
+}
+action to_err {
+ printf( "to error\n" );
+ fhold; fgoto line;
+}
+
+line := [^\n]* '\n' @{ fgoto main; };
+
+main := (
+ (
+ 'from' @err(cmd_err)
+ ( ws+ address ws+ date '\n' ) $err(from_err) |
+ 'to' @err(cmd_err)
+ ( ws+ address '\n' ) $err(to_err)
+ )
+)*;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% %% write data;
+% void f()
+% {
+% %% write init;
+% %% write exec;
+% }
+% END GENERATE
+
+
+
+\section{Action Ordering and Duplicates}
+
+When combining expressions that have embedded actions it is often the case that
+a number of actions must be executed on a single input character. For example,
+following a concatenation the leaving action of the left expression and the
+entering action of the right expression will be embedded into one transition.
+This requires a method of ordering actions that is intuitive and
+predictable for the user, and repeatable for the compiler.
+
+We associate with the embedding of each action a unique timestamp that is
+used to order actions that appear together on a single transition in the final
+state machine. To accomplish this we recursively traverse the parse tree of
+regular expressions and assign timestamps to action embeddings. References to
+machine definitions are followed in the traversal. When we visit a
+parse tree node we assign timestamps to all {\em entering} action embeddings,
+recurse on the parse tree, then assign timestamps to the remaining {\em all},
+{\em finishing}, and {\em leaving} embeddings in the order in which they
+appear.
+
+By default Ragel does not permit a single action to appear multiple times in an action
+list. When the final machine has been created, actions that appear more than
+once in a single transition, to-state, from-state or EOF action list have their
+duplicates removed.
+The first appearance of the action is preserved. This is useful in a number of
+scenarios. First, it allows us to union machines with common prefixes without
+worrying about the action embeddings in the prefix being duplicated. Second, it
+prevents leaving actions from being transferred multiple times. This can
+happen when a machine is repeated, then followed with another machine that
+begins with a common character. For example:
+
+\verbspace
+\begin{verbatim}
+word = [a-z]+ %act;
+main := word ( '\n' word )* '\n\n';
+\end{verbatim}
+\verbspace
+
+Note that Ragel does not compare action bodies to determine if they have
+identical program text. It simply checks for duplicates using each action
+block's unique location in the program.
+
+The removal of duplicates can be turned off using the \verb|-d| option.
+
+\section{Values and Statements Available in Code Blocks}
+\label{vals}
+
+\noindent The following values are available in code blocks:
+
+\begin{itemize}
+\item \verb|fpc| -- A pointer to the current character. This is equivalent to
+accessing the \verb|p| variable.
+
+\item \verb|fc| -- The current character. This is equivalent to the expression \verb|(*p)|.
+
+\item \verb|fcurs| -- An integer value representing the current state. This
+value should only be read from. To move to a different place in the machine
+from action code use the \verb|fgoto|, \verb|fnext| or \verb|fcall| statements.
+Outside of the machine execution code the \verb|cs| variable may be modified.
+
+\item \verb|ftargs| -- An integer value representing the target state. This
+value should only be read from. Again, \verb|fgoto|, \verb|fnext| and
+\verb|fcall| can be used to move to a specific entry point.
+
+\item \verb|fentry(<label>)| -- Retrieve an integer value representing the
+entry point \verb|label|. The integer value returned will be a compile time
+constant. This number is suitable for later use in control flow transfer
+statements that take an expression. This value should not be compared against
+the current state because any given label can have multiple states representing
+it. The value returned by \verb|fentry| can be any one of the multiple states that
+it represents.
+\end{itemize}
+
+\noindent The following statements are available in code blocks:
+
+\begin{itemize}
+
+\item \verb|fhold;| -- Do not advance over the current character. If processing
+data in multiple buffer blocks, the \verb|fhold| statement should only be used
+once in the set of actions executed on a character. Multiple calls may result
+in backing up over the beginning of the buffer block. The \verb|fhold|
+statement does not imply any transfer of control. It is equivalent to the
+\verb|p--;| statement.
+
+\item \verb|fexec <expr>;| -- Set the next character to process. This can be
+used to backtrack to previous input or advance ahead.
+Unlike \verb|fhold|, which can be used
+anywhere, \verb|fexec| requires the user to ensure that the target of the
+backtrack is in the current buffer block or is known to be somewhere ahead of
+it. The machine will continue iterating forward until \verb|pe| is arrived at,
+\verb|fbreak| is called or the machine moves into the error state. In actions
+embedded into transitions, the \verb|fexec| statement is equivalent to setting
+\verb|p| to one position ahead of the next character to process. If the user
+also modifies \verb|pe|, it is possible to change the buffer block entirely.
+
+\item \verb|fgoto <label>;| -- Jump to an entry point defined by
+\verb|<label>|. The \verb|fgoto| statement immediately transfers control to
+the destination state.
+
+\item \verb|fgoto *<expr>;| -- Jump to an entry point given by \verb|<expr>|.
+The expression must evaluate to an integer value representing a state.
+
+\item \verb|fnext <label>;| -- Set the next state to be the entry point defined
+by \verb|label|. The \verb|fnext| statement does not immediately jump to the
+specified state. Any action code following the statement is executed.
+
+\item \verb|fnext *<expr>;| -- Set the next state to be the entry point given
+by \verb|<expr>|. The expression must evaluate to an integer value representing
+a state.
+
+\item \verb|fcall <label>;| -- Push the target state and jump to the entry
+point defined by \verb|<label>|. The next \verb|fret| will jump to the target
+of the transition on which the call was made. Use of \verb|fcall| requires
+the declaration of a call stack. An array of integers named \verb|stack| and a
+single integer named \verb|top| must be declared. With the \verb|fcall|
+construct, control is immediately transferred to the destination state.
+See section \ref{modularization} for more information.
+
+\item \verb|fcall *<expr>;| -- Push the current state and jump to the entry
+point given by \verb|<expr>|. The expression must evaluate to an integer value
+representing a state.
+
+\item \verb|fret;| -- Return to the target state of the transition on which the
+last \verb|fcall| was made. Use of \verb|fret| requires the declaration of a
+call stack. Control is immediately transferred to the destination state.
+
+\item \verb|fbreak;| -- Advance \verb|p|, save the target state to \verb|cs|
+and immediately break out of the execute loop. This statement is useful
+in conjunction with the \verb|noend| write option. Rather than process input
+until \verb|pe| is arrived at, the fbreak statement
+can be used to stop processing from an action. After an \verb|fbreak|
+statement the \verb|p| variable will point to the next character in the input. The
+current state will be the target of the current transition. Note that \verb|fbreak|
+causes the target state's to-state actions to be skipped.
+
+\end{itemize}
+
+\noindent {\bf Note:} Once actions with control-flow commands are embedded into a
+machine, the user must exercise caution when using the machine as the operand
+to other machine construction operators. If an action jumps to another state
+then unioning any transition that executes that action with another transition
+that follows some other path will cause that other path to be lost. Using
+commands that manually jump around a machine takes us out of the domain of
+regular languages because transitions that the
+machine construction operators are not aware of are introduced. These
+commands should therefore be used with caution.
+
+
+\chapter{Controlling Nondeterminism}
+\label{controlling-nondeterminism}
+
+Along with the flexibility of arbitrary action embeddings comes a need to
+control nondeterminism in regular expressions. If a regular expression is
+ambiguous, then sub-components of a parser other than the intended parts may become
+active. This means that actions that are irrelevant to the
+current subset of the parser may be executed, causing problems for the
+programmer.
+
+Tools that are based on regular expression engines and that are used for
+recognition tasks will usually function as intended regardless of the presence
+of ambiguities. It is quite common for users of scripting languages to write
+regular expressions that are heavily ambiguous and it generally does not
+matter. As long as one of the potential matches is recognized, there can be any
+number of other matches present. In some parsing systems the run-time engine
+can employ a strategy for resolving ambiguities, for example always pursuing
+the longest possible match and discarding others.
+
+In Ragel, there is no regular expression run-time engine, just a simple state
+machine execution model. When we begin to embed actions and face the
+possibility of spurious action execution, it becomes clear that controlling
+nondeterminism at the machine construction level is very important. Consider
+the following example.
+
+% GENERATE: lines1
+% OPT: -p
+% %%{
+% machine lines1;
+% action first {}
+% action tail {}
+% word = [a-z]+;
+\begin{inline_code}
+\begin{verbatim}
+ws = [\n\t ];
+line = word $first ( ws word $tail )* '\n';
+lines = line*;
+\end{verbatim}
+\end{inline_code}
+% main := lines;
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.53]{lines1}
+\end{center}
+\graphspace
+
+Since the \verb|ws| expression includes the newline character, we will
+not finish the \verb|line| expression when a newline character is seen. We will
+simultaneously pursue the possibility of matching further words on the same
+line and the possibility of matching a second line. Evidence of this fact is
+in the state tables. On several transitions both the \verb|first| and
+\verb|tail| actions are executed. The solution here is simple: exclude
+the newline character from the \verb|ws| expression.
+
+% GENERATE: lines2
+% OPT: -p
+% %%{
+% machine lines2;
+% action first {}
+% action tail {}
+% word = [a-z]+;
+\begin{inline_code}
+\begin{verbatim}
+ws = [\t ];
+line = word $first ( ws word $tail )* '\n';
+lines = line*;
+\end{verbatim}
+\end{inline_code}
+% main := lines;
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{lines2}
+\end{center}
+\graphspace
+
+Solving this kind of problem is straightforward when the ambiguity is created
+by strings that are a single character long. When the ambiguity is created by
+strings that are multiple characters long we have a more difficult problem.
+The following example is an incorrect attempt at a regular expression for C
+language comments.
+
+% GENERATE: comments1
+% OPT: -p
+% %%{
+% machine comments1;
+% action comm {}
+\begin{inline_code}
+\begin{verbatim}
+comment = '/*' ( any @comm )* '*/';
+main := comment ' ';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{comments1}
+\end{center}
+\graphspace
+
+Using standard concatenation, we will never leave the \verb|any*| expression.
+We will forever entertain the possibility that a \verb|'*/'| string that we see
+is contained in a longer comment and that, simultaneously, the comment has
+ended. The concatenation of the \verb|comment| machine with \verb|SP| is done
+to show this. When we match space, we are also still matching the comment body.
+
+One way to approach the problem is to exclude the terminating string
+from the \verb|any*| expression using set difference. We must be careful to
+exclude not just the terminating string, but any string that contains it as a
+substring. A verbose, but proper specification of a C comment parser is given
+by the following regular expression.
+
+% GENERATE: comments2
+% OPT: -p
+% %%{
+% machine comments2;
+% action comm {}
+\begin{inline_code}
+\begin{verbatim}
+comment = '/*' ( ( any @comm )* - ( any* '*/' any* ) ) '*/';
+\end{verbatim}
+\end{inline_code}
+% main := comment;
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{comments2}
+\end{center}
+\graphspace
+
+Note that Ragel's strong subtraction operator \verb|--| can also be used here.
+In doing this subtraction we have phrased the problem of controlling non-determinism in
+terms of excluding strings common to two expressions that interact when
+combined.
+We can also phrase the problem in terms of the transitions of the state
+machines that implement these expressions. During the concatenation of
+\verb|any*| and \verb|'*/'| we will be making transitions that are composed of
+both the loop of the first expression and the final character of the second.
+At this time we want the transition on the \verb|'/'| character to take precedence
+over and disallow the transition that originated in the \verb|any*| loop.
+
+In another parsing problem, we wish to implement a lightweight tokenizer that we can
+utilize in the composition of a larger machine. For example, some HTTP headers
+have a token stream as a sub-language. The following example is an attempt
+at a regular expression-based tokenizer that does not function correctly due to
+unintended nondeterminism.
+
+\newpage
+
+% GENERATE: smallscanner
+% OPT: -p
+% %%{
+% machine smallscanner;
+% action start_str {}
+% action on_char {}
+% action finish_str {}
+\begin{inline_code}
+\begin{verbatim}
+header_contents = (
+ lower+ >start_str $on_char %finish_str |
+ ' '
+)*;
+\end{verbatim}
+\end{inline_code}
+% main := header_contents;
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{smallscanner}
+\end{center}
+\graphspace
+
+In this case, the problem with using a standard kleene star operation is that
+there is an ambiguity between extending a token and wrapping around the machine
+to begin a new token. Using the standard operator, we get an undesirable
+nondeterministic behaviour. Evidence of this can be seen on the transition out
+of state one to itself. The transition extends the string, and simultaneously,
+finishes the string only to immediately begin a new one. What is required is
+for the
+transitions that represent an extension of a token to take precedence over the
+transitions that represent the beginning of a new token. For this problem
+there is no simple solution that uses standard regular expression operators.
+
+\section{Priorities}
+
+A priority mechanism was devised and built into the determinization
+process, specifically for the purpose of allowing the user to control
+nondeterminism. Priorities are integer values embedded into transitions. When
+the determinization process is combining transitions that have different
+priorities, the transition with the higher priority is preserved and the
+transition with the lower priority is dropped.
+
+Unfortunately, priorities can have unintended side effects because their
+operation requires that they linger in transitions indefinitely. They must linger
+because the Ragel program cannot know when the user is finished with a priority
+embedding. A solution whereby they are explicitly deleted after use is
+conceivable; however this is not very user-friendly. Priorities were therefore
+made into named entities. Only priorities with the same name are allowed to
+interact. This allows any number of priorities to coexist in one machine for
+the purpose of controlling various different regular expression operations and
+eliminates the need to ever delete them. Such a scheme allows the user to
+choose a unique name, embed two different priority values using that name
+and be confident that the priority embedding will be free of any side effects.
+
+In the first form of priority embedding the name defaults to the name of the machine
+definition that the priority is assigned in. In this sense priorities are by
+default local to the current machine definition or instantiation. Beware of
+using this form in a longest-match machine, since there is only one name for
+the entire set of longest match patterns. In the second form the priority's
+name can be specified, allowing priority interaction across machine definition
+boundaries.
+
+\begin{itemize}
+\setlength{\parskip}{0in}
+\item \verb|expr > int| -- Sets starting transitions to have priority int.
+\item \verb|expr @ int| -- Sets transitions that go into a final state to have priority int.
+\item \verb|expr $ int| -- Sets all transitions to have priority int.
+\item \verb|expr % int| -- Sets leaving transitions to
+have priority int. When a transition is made going out of the machine (either
+by concatenation or kleene star) its priority is immediately set to the
+leaving priority.
+\end{itemize}
+
+The second form of priority assignment allows the programmer to specify the name
+to which the priority is assigned.
+
+\begin{itemize}
+\setlength{\parskip}{0in}
+\item \verb|expr > (name, int)| -- Starting transitions.
+\item \verb|expr @ (name, int)| -- Finishing transitions (into a final state).
+\item \verb|expr $ (name, int)| -- All transitions.
+\item \verb|expr % (name, int)| -- Leaving transitions.
+\end{itemize}
+
+\section{Guarded Operators that Encapsulate Priorities}
+
+Priority embeddings are a very expressive mechanism. At the same time they
+can be very confusing for the user. They force the user to imagine
+the transitions inside two interacting expressions and work out the precise
+effects of the operations between them. When we consider
+that this problem is worsened by the
+potential for side effects caused by unintended priority name collisions, we
+see that exposing the user to priorities is undesirable.
+
+Fortunately, in practice the use of priorities has been necessary only in a
+small number of scenarios. This allows us to encapsulate their functionality
+into a small set of operators and fully hide them from the user. This is
+advantageous from a language design point of view because it greatly simplifies
+the design.
+
+Going back to the C comment example, we can now properly specify
+it using a guarded concatenation operator which we call {\em finish-guarded
+concatenation}. From the user's point of view, this operator terminates the
+first machine when the second machine moves into a final state. It chooses a
+unique name and uses it to embed a low priority into all
+transitions of the first machine. A higher priority is then embedded into the
+transitions of the second machine that enter into a final state. The following
+example yields a machine identical to the example in Section
+\ref{controlling-nondeterminism}.
+
+\begin{inline_code}
+\begin{verbatim}
+comment = '/*' ( any @comm )* :>> '*/';
+\end{verbatim}
+\end{inline_code}
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{comments2}
+\end{center}
+\graphspace
+
+Another guarded operator is {\em left-guarded concatenation}, given by the
+\verb|<:| compound symbol. This operator places a higher priority on all
+transitions of the first machine. This is useful if one must forcibly separate
+two lists that contain common elements. For example, one may need to tokenize a
+stream, but first consume leading whitespace.
+
+Ragel also includes a {\em longest-match kleene star} operator, given by the
+\verb|**| compound symbol. This
+guarded operator embeds a high
+priority into all transitions of the machine.
+A lower priority is then embedded into the leaving transitions. When the
+kleene star operator makes the epsilon transitions from
+the final states into the new start state, the lower priority will be transferred
+to the epsilon transitions. In cases where following an epsilon transition
+out of a final state conflicts with an existing transition out of a final
+state, the epsilon transition will be dropped.
+
+Other guarded operators are conceivable, such as guards on union that cause one
+alternative to take precedence over another. These may be implemented when it
+is clear they constitute a frequently used operation.
+In the next section we discuss the explicit specification of state machines
+using state charts.
+
+\subsection{Entry-Guarded Concatenation}
+
+\verb|expr :> expr|
+\verbspace
+
+This operator concatenates two machines, but first assigns a low
+priority to all transitions
+of the first machine and a high priority to the starting transitions of the
+second machine. This operator is useful if from the final states of the first
+machine it is possible to accept the characters in the entering transitions of
+the second machine. This operator effectively terminates the first machine
+immediately upon starting the second machine, where otherwise they would be
+pursued concurrently. In the following example, entry-guarded concatenation is
+used to move out of a machine that matches everything at the first sign of an
+end-of-input marker.
+
+% GENERATE: entryguard
+% OPT: -p
+% %%{
+% machine entryguard;
+\begin{inline_code}
+\begin{verbatim}
+# Leave the catch-all machine on the first character of FIN.
+main := any* :> 'FIN';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{entryguard}
+\end{center}
+\graphspace
+
+Entry-guarded concatenation is equivalent to the following:
+
+\verbspace
+\begin{verbatim}
+expr $(unique_name,0) . expr >(unique_name,1)
+\end{verbatim}
+
+\subsection{Finish-Guarded Concatenation}
+
+\verb|expr :>> expr|
+\verbspace
+
+This operator is
+like the previous operator, except the higher priority is placed on the final
+transitions of the second machine. This is useful if one wishes to entertain
+the possibility of continuing to match the first machine right up until the
+second machine enters a final state. In other words it terminates the first
+machine only when the second accepts. In the following example, finish-guarded
+concatenation causes the move out of the machine that matches everything to be
+delayed until the full end-of-input marker has been matched.
+
+% GENERATE: finguard
+% OPT: -p
+% %%{
+% machine finguard;
+\begin{inline_code}
+\begin{verbatim}
+# Leave the catch-all machine on the last character of FIN.
+main := any* :>> 'FIN';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{finguard}
+\end{center}
+\graphspace
+
+Finish-guarded concatenation is equivalent to the following, with one
+exception. If the right machine's start state is final, the higher priority is
+also embedded into it as a leaving priority. This prevents the left machine
+from persisting via the zero-length string.
+
+\verbspace
+\begin{verbatim}
+expr $(unique_name,0) . expr @(unique_name,1)
+\end{verbatim}
+
+\subsection{Left-Guarded Concatenation}
+
+\verb|expr <: expr|
+\verbspace
+
+This operator places
+a higher priority on the left expression. It is useful if you want to prefix a
+sequence with another sequence composed of some of the same characters. For
+example, one can consume leading whitespace before tokenizing a sequence of
+whitespace-separated words as in:
+
+% GENERATE: leftguard
+% OPT: -p
+% %%{
+% machine leftguard;
+% action alpha {}
+% action ws {}
+% action start {}
+% action fin {}
+\begin{inline_code}
+\begin{verbatim}
+main := ( ' '* >start %fin ) <: ( ' ' $ws | [a-z] $alpha )*;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{leftguard}
+\end{center}
+\graphspace
+
+Left-guarded concatenation is equivalent to the following:
+
+\verbspace
+\begin{verbatim}
+expr $(unique_name,1) . expr >(unique_name,0)
+\end{verbatim}
+\verbspace
+
+\subsection{Longest-Match Kleene Star}
+\label{longest_match_kleene_star}
+
+\verb|expr**|
+\verbspace
+
+This version of kleene star puts a higher priority on staying in the
+machine versus wrapping around and starting over. The LM kleene star is useful
+when writing simple tokenizers. These machines are built by applying the
+longest-match kleene star to an alternation of token patterns, as in the
+following.
+
+\verbspace
+
+% GENERATE: lmkleene
+% OPT: -p
+% %%{
+% machine exfinpri;
+% action A {}
+% action B {}
+\begin{inline_code}
+\begin{verbatim}
+# Repeat tokens, but make sure to get the longest match.
+main := (
+ lower ( lower | digit )* %A |
+ digit+ %B |
+ ' '
+)**;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{lmkleene}
+\end{center}
+\graphspace
+
+If a regular kleene star were used the machine above would not be able to
+distinguish between extending a word and beginning a new one. This operator is
+equivalent to:
+
+\verbspace
+\begin{verbatim}
+( expr $(unique_name,1) %(unique_name,0) )*
+\end{verbatim}
+\verbspace
+
+When the kleene star is applied, transitions that go out of the machine and
+back into it are made. These are assigned a priority of zero by the leaving
+transition mechanism. This is less than the priority of one assigned to the
+transitions leaving the final states but not leaving the machine. When
+these transitions clash on the same character, the
+transition that stays in the machine takes precedence. The transition
+that wraps around is dropped.
+
+Note that this operator does not build a scanner in the traditional sense
+because there is never any backtracking. To build a scanner with backtracking
+use the Longest-Match machine construction described in Section
+\ref{generating-scanners}.
+
+\chapter{Interface to Host Program}
+
+The Ragel code generator is very flexible. The generated code has no
+dependencies and can be inserted in any function, perhaps inside a loop if
+desired. The user is responsible for declaring and initializing a number of
+required variables, including the current state and the pointer to the input
+stream. These can live in any scope. Control of the input processing loop is
+also possible: the user may break out of the processing loop and return to it
+at any time.
+
+In the case of the C, D, and Go host languages, Ragel is able to generate very
+fast-running code that implements state machines as directly executable code.
+Since very large files strain the host language compiler, table-based code
+generation is also supported. In the future we hope to provide a partitioned,
+directly executable format that is able to reduce the burden on the host
+compiler by splitting large machines across multiple functions.
+
+In the case of Java and Ruby, table-based code generation is the only code
+style supported. In the future this may be expanded to include other code
+styles.
+
+Ragel can be used to parse input in one block, or it can be used to parse input
+in a sequence of blocks as it arrives from a file or socket. Parsing the input
+in a sequence of blocks brings with it a few responsibilities. If the parser
+utilizes a scanner, care must be taken to not break the input stream anywhere
+but token boundaries. If pointers to the input stream are taken during
+parsing, care must be taken to not use a pointer that has been invalidated by
+movement to a subsequent block. If the current input data pointer is moved
+backwards it must not be moved past the beginning of the current block.
+
+Figure \ref{basic-example} shows a simple Ragel program that does not have any
+actions. The example tests the first argument of the program against a number
+pattern and then prints the machine's acceptance status.
+
+\begin{figure}
+\small
+\begin{verbatim}
+#include <stdio.h>
+#include <string.h>
+%%{
+ machine foo;
+ write data;
+}%%
+int main( int argc, char **argv )
+{
+ int cs;
+ if ( argc > 1 ) {
+ char *p = argv[1];
+ char *pe = p + strlen( p );
+ %%{
+ main := [0-9]+ ( '.' [0-9]+ )?;
+
+ write init;
+ write exec;
+ }%%
+ }
+ printf("result = %i\n", cs >= foo_first_final );
+ return 0;
+}
+\end{verbatim}
+\caption{A basic Ragel example without any actions.}
+\label{basic-example}
+\end{figure}
+
+\section{Variables Used by Ragel}
+
+There are a number of variables that Ragel expects the user to declare. At a
+very minimum the \verb|cs|, \verb|p| and \verb|pe| variables must be declared.
+In Go, Java and Ruby code the \verb|data| variable must also be declared. If
+EOF actions are used then the \verb|eof| variable is required. If
+stack-based state machine control flow statements are used then the
+\verb|stack| and \verb|top| variables are required. If a scanner is declared
+then the \verb|act|, \verb|ts| and \verb|te| variables must be
+declared.
+
+\begin{itemize}
+
+\item \verb|cs| - Current state. This must be an integer and it should persist
+across invocations of the machine when the data is broken into blocks that are
+processed independently. This variable may be modified from outside the
+execution loop, but not from within.
+
+\item \verb|p| - Data pointer. In C/D code this variable is expected to be a
+pointer to the character data to process. It should be initialized to the
+beginning of the data block on every run of the machine. In Go, Java and Ruby it is
+used as an offset to \verb|data| and must be an integer. In this case it should
+be initialized to zero on every run of the machine.
+
+\item \verb|pe| - Data end pointer. This should be initialized to \verb|p| plus
+the data length on every run of the machine. In Go, Java and Ruby code this should
+be initialized to the data length.
+
+\item \verb|eof| - End of file pointer. This should be set to \verb|pe| when
+the buffer block being processed is the last one, otherwise it should be set to
+null. In Go, Java and Ruby code \verb|-1| must be used instead of null. If the EOF
+event can be known only after the final buffer block has been processed, then
+it is possible to set \verb|p = pe = eof| and run the execute block.
+
+\item \verb|data| - This variable is only required in Go, Java and Ruby code. It
+must be an array containting the data to process.
+
+\item \verb|stack| - This must be an array of integers. It is used to store
+integer values representing states. If the stack must resize dynamically the
+Pre-push and Post-Pop statements can be used to do this (Sections
+\ref{prepush} and \ref{postpop}).
+
+\item \verb|top| - This must be an integer value and will be used as an offset
+to \verb|stack|, giving the next available spot on the top of the stack.
+
+\item \verb|act| - This must be an integer value. It is a variable sometimes
+used by scanner code to keep track of the most recent successful pattern match.
+
+\item \verb|ts| - This must be a pointer to character data. In Go, Java and
+Ruby code this must be an integer. See Section \ref{generating-scanners} for
+more information.
+
+\item \verb|te| - Also a pointer to character data.
+
+\end{itemize}
+
+\section{Alphtype Statement}
+
+\begin{verbatim}
+alphtype unsigned int;
+\end{verbatim}
+\verbspace
+
+The alphtype statement specifies the alphabet data type that the machine
+operates on. During the compilation of the machine, integer literals are
+expected to be in the range of possible values of the alphtype. The default
+is \verb|char| for all languages except Go where the default is \verb|byte|.
+
+\begin{multicols}{2}
+\setlength{\columnseprule}{1pt}
+C/C++/Objective-C:
+\begin{verbatim}
+ char unsigned char
+ short unsigned short
+ int unsigned int
+ long unsigned long
+\end{verbatim}
+
+Go:
+\begin{verbatim}
+ byte
+ int8 uint8
+ int16 uint16
+ int32 uint32
+ int64 uint64
+ rune
+\end{verbatim}
+
+Ruby:
+\begin{verbatim}
+ char
+ int
+\end{verbatim}
+
+\columnbreak
+
+Java:
+\begin{verbatim}
+ char
+ byte
+ short
+ int
+\end{verbatim}
+
+D:
+\begin{verbatim}
+ char
+ byte ubyte
+ short ushort
+ wchar
+ int uint
+ dchar
+\end{verbatim}
+
+\end{multicols}
+
+\section{Getkey Statement}
+
+\begin{verbatim}
+getkey fpc->id;
+\end{verbatim}
+\verbspace
+
+This statement specifies to Ragel how to retrieve the current character from
+from the pointer to the current element (\verb|p|). Any expression that returns
+a value of the alphabet type
+may be used. The getkey statement may be used for looking into element
+structures or for translating the character to process. The getkey expression
+defaults to \verb|(*p)|. In goto-driven machines the getkey expression may be
+evaluated more than once per element processed, therefore it should not incur a
+large cost nor preclude optimization.
+
+\section{Access Statement}
+
+\begin{verbatim}
+access fsm->;
+\end{verbatim}
+\verbspace
+
+The access statement specifies how the generated code should
+access the machine data that is persistent across processing buffer blocks.
+This applies to all variables except \verb|p|, \verb|pe| and \verb|eof|. This includes
+\verb|cs|, \verb|top|, \verb|stack|, \verb|ts|, \verb|te| and \verb|act|.
+The access statement is useful if a machine is to be encapsulated inside a
+structure in C code. It can be used to give the name of
+a pointer to the structure.
+
+\section{Variable Statement}
+
+\begin{verbatim}
+variable p fsm->p;
+\end{verbatim}
+\verbspace
+
+The variable statement specifies how to access a specific
+variable. All of the variables that are declared by the user and
+used by Ragel can be changed. This includes \verb|p|, \verb|pe|, \verb|eof|, \verb|cs|,
+\verb|top|, \verb|stack|, \verb|ts|, \verb|te| and \verb|act|.
+In Go, Ruby and Java code generation the \verb|data| variable can also be changed.
+
+\section{Pre-Push Statement}
+\label{prepush}
+
+\begin{verbatim}
+prepush {
+ /* stack growing code */
+}
+\end{verbatim}
+\verbspace
+
+The prepush statement allows the user to supply stack management code that is
+written out during the generation of fcall, immediately before the current
+state is pushed to the stack. This statement can be used to test the number of
+available spaces and dynamically grow the stack if necessary.
+
+\section{Post-Pop Statement}
+\label{postpop}
+
+\begin{verbatim}
+postpop {
+ /* stack shrinking code */
+}
+\end{verbatim}
+\verbspace
+
+The postpop statement allows the user to supply stack management code that is
+written out during the generation of fret, immediately after the next state is
+popped from the stack. This statement can be used to dynamically shrink the
+stack.
+
+\section{Write Statement}
+\label{write-statement}
+
+\begin{verbatim}
+write <component> [options];
+\end{verbatim}
+\verbspace
+
+The write statement is used to generate parts of the machine.
+There are seven
+components that can be generated by a write statement. These components make up the
+state machine's data, initialization code, execution code, and export definitions.
+A write statement may appear before a machine is fully defined.
+This allows one to write out the data first then later define the machine where
+it is used. An example of this is shown in Figure \ref{fbreak-example}.
+
+\subsection{Write Data}
+\begin{verbatim}
+write data [options];
+\end{verbatim}
+\verbspace
+
+The write data statement causes Ragel to emit the constant static data needed
+by the machine. In table-driven output styles (see Section \ref{genout}) this
+is a collection of arrays that represent the states and transitions of the
+machine. In goto-driven machines much less data is emitted. At the very
+minimum a start state \verb|name_start| is generated. All variables written
+out in machine data have both the \verb|static| and \verb|const| properties and
+are prefixed with the name of the machine and an
+underscore. The data can be placed inside a class, inside a function, or it can
+be defined as global data.
+
+Two variables are written that may be used to test the state of the machine
+after a buffer block has been processed. The \verb|name_error| variable gives
+the id of the state that the machine moves into when it cannot find a valid
+transition to take. The machine immediately breaks out of the processing loop when
+it finds itself in the error state. The error variable can be compared to the
+current state to determine if the machine has failed to parse the input. If the
+machine is complete, that is from every state there is a transition to a proper
+state on every possible character of the alphabet, then no error state is required
+and this variable will be set to -1.
+
+The \verb|name_first_final| variable stores the id of the first final state. All of the
+machine's states are sorted by their final state status before having their ids
+assigned. Checking if the machine has accepted its input can then be done by
+checking if the current state is greater-than or equal to the first final
+state.
+
+Data generation has several options:
+
+\begin{itemize}
+\setlength{\itemsep}{-2mm}
+\item \verb|noerror | - Do not generate the integer variable that gives the
+id of the error state.
+\item \verb|nofinal | - Do not generate the integer variable that gives the
+id of the first final state.
+\item \verb|noprefix | - Do not prefix the variable names with the name of the
+machine.
+\end{itemize}
+
+\begin{figure}
+\small
+\begin{verbatim}
+#include <stdio.h>
+%% machine foo;
+%% write data;
+int main( int argc, char **argv )
+{
+ int cs, res = 0;
+ if ( argc > 1 ) {
+ char *p = argv[1];
+ %%{
+ main :=
+ [a-z]+
+ 0 @{ res = 1; fbreak; };
+ write init;
+ write exec noend;
+ }%%
+ }
+ printf("execute = %i\n", res );
+ return 0;
+}
+\end{verbatim}
+\caption{Use of {\tt noend} write option and the {\tt fbreak} statement for
+processing a string.}
+\label{fbreak-example}
+\end{figure}
+
+\subsection{Write Start, First Final and Error}
+
+\begin{verbatim}
+write start;
+write first_final;
+write error;
+\end{verbatim}
+\verbspace
+
+These three write statements provide an alternative means of accessing the
+\verb|start|, \verb|first_final| and \verb|error| states. If there are many
+different machine specifications in one file it is easy to get the prefix for
+these wrong. This is especially true if the state machine boilerplate is
+frequently made by a copy-paste-edit process. These write statements allow the
+problem to be avoided. They can be used as follows:
+
+\verbspace
+
+{
+\small
+\begin{verbatim}
+/* Did parsing succeed? */
+if ( cs < %%{ write first_final; }%% ) {
+ result = ERR_PARSE_ERROR;
+ goto fail;
+}
+\end{verbatim}
+}
+
+
+\subsection{Write Init}
+\begin{verbatim}
+write init [options];
+\end{verbatim}
+\verbspace
+
+The write init statement causes Ragel to emit initialization code. This should
+be executed once before the machine is started. At a very minimum this sets the
+current state to the start state. If other variables are needed by the
+generated code, such as call stack variables or scanner management
+variables, they are also initialized here.
+
+The \verb|nocs| option to the write init statement will cause ragel to skip
+intialization of the cs variable. This is useful if the user wishes to use
+custom logic to decide which state the specification should start in.
+
+\subsection{Write Exec}
+\begin{verbatim}
+write exec [options];
+\end{verbatim}
+\verbspace
+
+The write exec statement causes Ragel to emit the state machine's execution code.
+Ragel expects several variables to be available to this code. At a very minimum, the
+generated code needs access to the current character position \verb|p|, the ending
+position \verb|pe| and the current state \verb|cs| (though \verb|pe|
+can be omitted using the \verb|noend| write option).
+The \verb|p| variable is the cursor that the execute code will
+used to traverse the input. The \verb|pe| variable should be set up to point to one
+position past the last valid character in the buffer.
+
+Other variables are needed when certain features are used. For example using
+the \verb|fcall| or \verb|fret| statements requires \verb|stack| and
+\verb|top| variables to be defined. If a longest-match construction is used,
+variables for managing backtracking are required.
+
+The write exec statement has one option. The \verb|noend| option tells Ragel
+to generate code that ignores the end position \verb|pe|. In this
+case the user must explicitly break out of the processing loop using
+\verb|fbreak|, otherwise the machine will continue to process characters until
+it moves into the error state. This option is useful if one wishes to process a
+null terminated string. Rather than traverse the string to discover then length
+before processing the input, the user can break out when the null character is
+seen. The example in Figure \ref{fbreak-example} shows the use of the
+\verb|noend| write option and the \verb|fbreak| statement for processing a string.
+
+\subsection{Write Exports}
+\label{export}
+
+\begin{verbatim}
+write exports;
+\end{verbatim}
+\verbspace
+
+The export feature can be used to export simple machine definitions. Machine definitions
+are marked for export using the \verb|export| keyword.
+
+\verbspace
+\begin{verbatim}
+export machine_to_export = 0x44;
+\end{verbatim}
+\verbspace
+
+When the write exports statement is used these machines are
+written out in the generated code. Defines are used for C and constant integers
+are used for D, Java and Ruby. See Section \ref{import} for a description of the
+import statement.
+
+\section{Maintaining Pointers to Input Data}
+
+In the creation of any parser it is not uncommon to require the collection of
+the data being parsed. It is always possible to collect data into a growable
+buffer as the machine moves over it, however the copying of data is a somewhat
+wasteful use of processor cycles. The most efficient way to collect data from
+the parser is to set pointers into the input then later reference them. This
+poses a problem for uses of Ragel where the input data arrives in blocks, such
+as over a socket or from a file. If a pointer is set in one buffer block but
+must be used while parsing a following buffer block, some extra consideration
+to correctness must be made.
+
+The scanner constructions exhibit this problem, requiring the maintenance
+code described in Section \ref{generating-scanners}. If a longest-match
+construction has been used somewhere in the machine then it is possible to
+take advantage of the required prefix maintenance code in the driver program to
+ensure pointers to the input are always valid. If laying down a pointer one can
+set \verb|ts| at the same spot or ahead of it. When data is shifted in
+between loops the user must also shift the pointer. In this way it is possible
+to maintain pointers to the input that will always be consistent.
+
+\begin{figure}
+\small
+\begin{verbatim}
+ int have = 0;
+ while ( 1 ) {
+ char *p, *pe, *data = buf + have;
+ int len, space = BUFSIZE - have;
+
+ if ( space == 0 ) {
+ fprintf(stderr, "BUFFER OUT OF SPACE\n");
+ exit(1);
+ }
+
+ len = fread( data, 1, space, stdin );
+ if ( len == 0 )
+ break;
+
+ /* Find the last newline by searching backwards. */
+ p = buf;
+ pe = data + len - 1;
+ while ( *pe != '\n' && pe >= buf )
+ pe--;
+ pe += 1;
+
+ %% write exec;
+
+ /* How much is still in the buffer? */
+ have = data + len - pe;
+ if ( have > 0 )
+ memmove( buf, pe, have );
+
+ if ( len < space )
+ break;
+ }
+\end{verbatim}
+\caption{An example of line-oriented processing.}
+\label{line-oriented}
+\end{figure}
+
+In general, there are two approaches for guaranteeing the consistency of
+pointers to input data. The first approach is the one just described;
+lay down a marker from an action,
+then later ensure that the data the marker points to is preserved ahead of
+the buffer on the next execute invocation. This approach is good because it
+allows the parser to decide on the pointer-use boundaries, which can be
+arbitrarily complex parsing conditions. A downside is that it requires any
+pointers that are set to be corrected in between execute invocations.
+
+The alternative is to find the pointer-use boundaries before invoking the execute
+routine, then pass in the data using these boundaries. For example, if the
+program must perform line-oriented processing, the user can scan backwards from
+the end of an input block that has just been read in and process only up to the
+first found newline. On the next input read, the new data is placed after the
+partially read line and processing continues from the beginning of the line.
+An example of line-oriented processing is given in Figure \ref{line-oriented}.
+
+\section{Specifying the Host Language}
+
+The \verb|ragel| program has a number of options for specifying the host
+language. The host-language options are:
+
+\begin{itemize}
+\item \verb|-C | for C/C++/Objective-C code (default)
+\item \verb|-D | for D code.
+\item \verb|-Z | for Go code.
+\item \verb|-J | for Java code.
+\item \verb|-R | for Ruby code.
+\item \verb|-A | for C\# code.
+\end{itemize}
+
+\section{Choosing a Generated Code Style}
+\label{genout}
+
+There are three styles of code output to choose from. Code style affects the
+size and speed of the compiled binary. Changing code style does not require any
+change to the Ragel program. There are two table-driven formats and a goto
+driven format.
+
+In addition to choosing a style to emit, there are various levels of action
+code reuse to choose from. The maximum reuse levels (\verb|-T0|, \verb|-F0|
+and \verb|-G0|) ensure that no FSM action code is ever duplicated by encoding
+each transition's action list as static data and iterating
+through the lists on every transition. This will normally result in a smaller
+binary. The less action reuse options (\verb|-T1|, \verb|-F1| and \verb|-G1|)
+will usually produce faster running code by expanding each transition's action
+list into a single block of code, eliminating the need to iterate through the
+lists. This duplicates action code instead of generating the logic necessary
+for reuse. Consequently the binary will be larger. However, this tradeoff applies to
+machines with moderate to dense action lists only. If a machine's transitions
+frequently have less than two actions then the less reuse options will actually
+produce both a smaller and a faster running binary due to less action sharing
+overhead. The best way to choose the appropriate code style for your
+application is to perform your own tests.
+
+The table-driven FSM represents the state machine as constant static data. There are
+tables of states, transitions, indices and actions. The current state is
+stored in a variable. The execution is simply a loop that looks up the current
+state, looks up the transition to take, executes any actions and moves to the
+target state. In general, the table-driven FSM can handle any machine, produces
+a smaller binary and requires a less expensive host language compile, but
+results in slower running code. Since the table-driven format is the most
+flexible it is the default code style.
+
+The flat table-driven machine is a table-based machine that is optimized for
+small alphabets. Where the regular table machine uses the current character as
+the key in a binary search for the transition to take, the flat table machine
+uses the current character as an index into an array of transitions. This is
+faster in general, however is only suitable if the span of possible characters
+is small.
+
+The goto-driven FSM represents the state machine using goto and switch
+statements. The execution is a flat code block where the transition to take is
+computed using switch statements and directly executable binary searches. In
+general, the goto FSM produces faster code but results in a larger binary and a
+more expensive host language compile.
+
+The goto-driven format has an additional action reuse level (\verb|-G2|) that
+writes actions directly into the state transitioning logic rather than putting
+all the actions together into a single switch. Generally this produces faster
+running code because it allows the machine to encode the current state using
+the processor's instruction pointer. Again, sparse machines may actually
+compile to smaller binaries when \verb|-G2| is used due to less state and
+action management overhead. For many parsing applications \verb|-G2| is the
+preferred output format.
+
+\verbspace
+\begin{center}
+\begin{tabular}{|c|c|c|}
+\hline
+\multicolumn{3}{|c|}{\bf Code Output Style Options} \\
+\hline
+\verb|-T0|&binary search table-driven&C/D/Java/Ruby/C\#/Go\\
+\hline
+\verb|-T1|&binary search, expanded actions&C/D/Ruby/C\#/Go\\
+\hline
+\verb|-F0|&flat table-driven&C/D/Ruby/C\#/Go\\
+\hline
+\verb|-F1|&flat table, expanded actions&C/D/Ruby/C\#/Go\\
+\hline
+\verb|-G0|&goto-driven&C/D/C\#/Go\\
+\hline
+\verb|-G1|&goto, expanded actions&C/D/C\#/Go\\
+\hline
+\verb|-G2|&goto, in-place actions&C/D/Go\\
+\hline
+\end{tabular}
+\end{center}
+
+\chapter{Beyond the Basic Model}
+
+\section{Parser Modularization}
+\label{modularization}
+
+It is possible to use Ragel's machine construction and action embedding
+operators to specify an entire parser using a single regular expression. In
+many cases this is the desired way to specify a parser in Ragel. However, in
+some scenarios the language to parse may be so large that it is difficult to
+think about it as a single regular expression. It may also shift between distinct
+parsing strategies, in which case modularization into several coherent blocks
+of the language may be appropriate.
+
+It may also be the case that patterns that compile to a large number of states
+must be used in a number of different contexts and referencing them in each
+context results in a very large state machine. In this case, an ability to reuse
+parsers would reduce code size.
+
+To address this, distinct regular expressions may be instantiated and linked
+together by means of a jumping and calling mechanism. This mechanism is
+analogous to the jumping to and calling of processor instructions. A jump
+command, given in action code, causes control to be immediately passed to
+another portion of the machine by way of setting the current state variable. A
+call command causes the target state of the current transition to be pushed to
+a state stack before control is transferred. Later on, the original location
+may be returned to with a return statement. In the following example, distinct
+state machines are used to handle the parsing of two types of headers.
+
+% GENERATE: call
+% %%{
+% machine call;
+\begin{inline_code}
+\begin{verbatim}
+action return { fret; }
+action call_date { fcall date; }
+action call_name { fcall name; }
+
+# A parser for date strings.
+date := [0-9][0-9] '/'
+ [0-9][0-9] '/'
+ [0-9][0-9][0-9][0-9] '\n' @return;
+
+# A parser for name strings.
+name := ( [a-zA-Z]+ | ' ' )** '\n' @return;
+
+# The main parser.
+headers =
+ ( 'from' | 'to' ) ':' @call_name |
+ ( 'departed' | 'arrived' ) ':' @call_date;
+
+main := headers*;
+\end{verbatim}
+\end{inline_code}
+% }%%
+% %% write data;
+% void f()
+% {
+% %% write init;
+% %% write exec;
+% }
+% END GENERATE
+
+Calling and jumping should be used carefully as they are operations that take
+one out of the domain of regular languages. A machine that contains a call or
+jump statement in one of its actions should be used as an argument to a machine
+construction operator only with considerable care. Since DFA transitions may
+actually represent several NFA transitions, a call or jump embedded in one
+machine can inadvertently terminate another machine that it shares prefixes
+with. Despite this danger, theses statements have proven useful for tying
+together sub-parsers of a language into a parser for the full language,
+especially for the purpose of modularizing code and reducing the number of
+states when the machine contains frequently recurring patterns.
+
+Section \ref{vals} describes the jump and call statements that are used to
+transfer control. These statements make use of two variables that must be
+declared by the user, \verb|stack| and \verb|top|. The \verb|stack| variable
+must be an array of integers and \verb|top| must be a single integer, which
+will point to the next available space in \verb|stack|. Sections \ref{prepush}
+and \ref{postpop} describe the Pre-Push and Post-Pop statements which can be
+used to implement a dynamically resizable array.
+
+\section{Referencing Names}
+\label{labels}
+
+This section describes how to reference names in epsilon transitions (Section
+\ref{state-charts}) and
+action-based control-flow statements such as \verb|fgoto|. There is a hierarchy
+of names implied in a Ragel specification. At the top level are the machine
+instantiations. Beneath the instantiations are labels and references to machine
+definitions. Beneath those are more labels and references to definitions, and
+so on.
+
+Any name reference may contain multiple components separated with the \verb|::|
+compound symbol. The search for the first component of a name reference is
+rooted at the join expression that the epsilon transition or action embedding
+is contained in. If the name reference is not contained in a join,
+the search is rooted at the machine definition that the epsilon transition or
+action embedding is contained in. Each component after the first is searched
+for beginning at the location in the name tree that the previous reference
+component refers to.
+
+In the case of action-based references, if the action is embedded more than
+once, the local search is performed for each embedding and the result is the
+union of all the searches. If no result is found for action-based references then
+the search is repeated at the root of the name tree. Any action-based name
+search may be forced into a strictly global search by prefixing the name
+reference with \verb|::|.
+
+The final component of the name reference must resolve to a unique entry point.
+If a name is unique in the entire name tree it can be referenced as is. If it
+is not unique it can be specified by qualifying it with names above it in the
+name tree. However, it can always be renamed.
+
+% FIXME: Should fit this in somewhere.
+% Some kinds of name references are illegal. Cannot call into longest-match
+% machine, can only call its start state. Cannot make a call to anywhere from
+% any part of a longest-match machine except a rule's action. This would result
+% in an eventual return to some point inside a longest-match other than the
+% start state. This is banned for the same reason a call into the LM machine is
+% banned.
+
+
+\section{Scanners}
+\label{generating-scanners}
+
+Scanners are very much intertwined with regular-languages and their
+corresponding processors. For this reason Ragel supports the definition of
+scanners. The generated code will repeatedly attempt to match patterns from a
+list, favouring longer patterns over shorter patterns. In the case of
+equal-length matches, the generated code will favour patterns that appear ahead
+of others. When a scanner makes a match it executes the user code associated
+with the match, consumes the input then resumes scanning.
+
+\verbspace
+\begin{verbatim}
+<machine_name> := |*
+ pattern1 => action1;
+ pattern2 => action2;
+ ...
+ *|;
+\end{verbatim}
+\verbspace
+
+On the surface, Ragel scanners are similar to those defined by Lex. Though
+there is a key distinguishing feature: patterns may be arbitrary Ragel
+expressions and can therefore contain embedded code. With a Ragel-based scanner
+the user need not wait until the end of a pattern before user code can be
+executed.
+
+Scanners can be used to process sub-languages, as well as for tokenizing
+programming languages. In the following example a scanner is used to tokenize
+the contents of a header field.
+
+\begin{inline_code}
+\begin{verbatim}
+word = [a-z]+;
+head_name = 'Header';
+
+header := |*
+ word;
+ ' ';
+ '\n' => { fret; };
+*|;
+
+main := ( head_name ':' @{ fcall header; } )*;
+\end{verbatim}
+\end{inline_code}
+\verbspace
+
+The scanner construction has a purpose similar to the longest-match kleene star
+operator \verb|**|. The key
+difference is that a scanner is able to backtrack to match a previously matched
+shorter string when the pursuit of a longer string fails. For this reason the
+scanner construction operator is not a pure state machine construction
+operator. It relies on several variables that enable it to backtrack and make
+pointers to the matched input text available to the user. For this reason
+scanners must be immediately instantiated. They cannot be defined inline or
+referenced by another expression. Scanners must be jumped to or called.
+
+Scanners rely on the \verb|ts|, \verb|te| and \verb|act|
+variables to be present so that they can backtrack and make pointers to the
+matched text available to the user. If input is processed using multiple calls
+to the execute code then the user must ensure that when a token is only
+partially matched that the prefix is preserved on the subsequent invocation of
+the execute code.
+
+The \verb|ts| variable must be defined as a pointer to the input data.
+It is used for recording where the current token match begins. This variable
+may be used in action code for retrieving the text of the current match. Ragel
+ensures that in between tokens and outside of the longest-match machines that
+this pointer is set to null. In between calls to the execute code the user must
+check if \verb|ts| is set and if so, ensure that the data it points to is
+preserved ahead of the next buffer block. This is described in more detail
+below.
+
+The \verb|te| variable must also be defined as a pointer to the input data.
+It is used for recording where a match ends and where scanning of the next
+token should begin. This can also be used in action code for retrieving the
+text of the current match.
+
+The \verb|act| variable must be defined as an integer type. It is used for
+recording the identity of the last pattern matched when the scanner must go
+past a matched pattern in an attempt to make a longer match. If the longer
+match fails it may need to consult the \verb|act| variable. In some cases, use
+of the \verb|act|
+variable can be avoided because the value of the current state is enough
+information to determine which token to accept, however in other cases this is
+not enough and so the \verb|act| variable is used.
+
+When the longest-match operator is in use, the user's driver code must take on
+some buffer management functions. The following algorithm gives an overview of
+the steps that should be taken to properly use the longest-match operator.
+
+\begin{itemize}
+\setlength{\parskip}{0pt}
+\item Read a block of input data.
+\item Run the execute code.
+\item If \verb|ts| is set, the execute code will expect the incomplete
+token to be preserved ahead of the buffer on the next invocation of the execute
+code.
+\begin{itemize}
+\item Shift the data beginning at \verb|ts| and ending at \verb|pe| to the
+beginning of the input buffer.
+\item Reset \verb|ts| to the beginning of the buffer.
+\item Shift \verb|te| by the distance from the old value of \verb|ts|
+to the new value. The \verb|te| variable may or may not be valid. There is
+no way to know if it holds a meaningful value because it is not kept at null
+when it is not in use. It can be shifted regardless.
+\end{itemize}
+\item Read another block of data into the buffer, immediately following any
+preserved data.
+\item Run the scanner on the new data.
+\end{itemize}
+
+Figure \ref{preserve_example} shows the required handling of an input stream in
+which a token is broken by the input block boundaries. After processing up to
+and including the ``t'' of ``characters'', the prefix of the string token must be
+retained and processing should resume at the ``e'' on the next iteration of
+the execute code.
+
+If one uses a large input buffer for collecting input then the number of times
+the shifting must be done will be small. Furthermore, if one takes care not to
+define tokens that are allowed to be very long and instead processes these
+items using pure state machines or sub-scanners, then only a small amount of
+data will ever need to be shifted.
+
+\begin{figure}
+\begin{verbatim}
+ a) A stream "of characters" to be scanned.
+ | | |
+ p ts pe
+
+ b) "of characters" to be scanned.
+ | | |
+ ts p pe
+\end{verbatim}
+\caption{Following an invocation of the execute code there may be a partially
+matched token (a). The data of the partially matched token
+must be preserved ahead of the new data on the next invocation (b).}
+\label{preserve_example}
+\end{figure}
+
+Since scanners attempt to make the longest possible match of input, patterns
+such as identifiers require one character of lookahead in order to trigger a
+match. In the case of the last token in the input stream the user must ensure
+that the \verb|eof| variable is set so that the final token is flushed out.
+
+An example scanner processing loop is given in Figure \ref{scanner-loop}.
+
+\begin{figure}
+\small
+\begin{verbatim}
+ int have = 0;
+ bool done = false;
+ while ( !done ) {
+ /* How much space is in the buffer? */
+ int space = BUFSIZE - have;
+ if ( space == 0 ) {
+ /* Buffer is full. */
+ cerr << "TOKEN TOO BIG" << endl;
+ exit(1);
+ }
+
+ /* Read in a block after any data we already have. */
+ char *p = inbuf + have;
+ cin.read( p, space );
+ int len = cin.gcount();
+
+ char *pe = p + len;
+ char *eof = 0;
+
+ /* If no data was read indicate EOF. */
+ if ( len == 0 ) {
+ eof = pe;
+ done = true;
+ }
+
+ %% write exec;
+
+ if ( cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is a prefix to preserve, shift it over. */
+ have = pe - ts;
+ memmove( inbuf, ts, have );
+ te = inbuf + (te-ts);
+ ts = inbuf;
+ }
+ }
+\end{verbatim}
+\caption{A processing loop for a scanner.}
+\label{scanner-loop}
+\end{figure}
+
+\section{State Charts}
+\label{state-charts}
+
+In addition to supporting the construction of state machines using regular
+languages, Ragel provides a way to manually specify state machines using
+state charts. The comma operator combines machines together without any
+implied transitions. The user can then manually link machines by specifying
+epsilon transitions with the \verb|->| operator. Epsilon transitions are drawn
+between the final states of a machine and entry points defined by labels. This
+makes it possible to build machines using the explicit state-chart method while
+making minimal changes to the Ragel language.
+
+An interesting feature of Ragel's state chart construction method is that it
+can be mixed freely with regular expression constructions. A state chart may be
+referenced from within a regular expression, or a regular expression may be
+used in the definition of a state chart transition.
+
+\subsection{Join}
+
+\verb|expr , expr , ...|
+\verbspace
+
+Join a list of machines together without
+drawing any transitions, without setting up a start state, and without
+designating any final states. Transitions between the machines may be specified
+using labels and epsilon transitions. The start state must be explicity
+specified with the ``start'' label. Final states may be specified with an
+epsilon transition to the implicitly created ``final'' state. The join
+operation allows one to build machines using a state chart model.
+
+\subsection{Label}
+
+\verb|label: expr|
+\verbspace
+
+Attaches a label to an expression. Labels can be
+used as the target of epsilon transitions and explicit control transfer
+statements such as \verb|fgoto| and \verb|fnext| in action
+code.
+
+\subsection{Epsilon}
+
+\verb|expr -> label|
+\verbspace
+
+Draws an epsilon transition to the state defined
+by \verb|label|. Epsilon transitions are made deterministic when join
+operators are evaluated. Epsilon transitions that are not in a join operation
+are made deterministic when the machine definition that contains the epsilon is
+complete. See Section \ref{labels} for information on referencing labels.
+
+\subsection{Simplifying State Charts}
+
+There are two benefits to providing state charts in Ragel. The first is that it
+allows us to take a state chart with a full listing of states and transitions
+and simplify it in selective places using regular expressions.
+
+The state chart method of specifying parsers is very common. It is an
+effective programming technique for producing robust code. The key disadvantage
+becomes clear when one attempts to comprehend a large parser specified in this
+way. These programs usually require many lines, causing logic to be spread out
+over large distances in the source file. Remembering the function of a large
+number of states can be difficult and organizing the parser in a sensible way
+requires discipline because branches and repetition present many file layout
+options. This kind of programming takes a specification with inherent
+structure such as looping, alternation and concatenation and expresses it in a
+flat form.
+
+If we could take an isolated component of a manually programmed state chart,
+that is, a subset of states that has only one entry point, and implement it
+using regular language operators then we could eliminate all the explicit
+naming of the states contained in it. By eliminating explicitly named states
+and replacing them with higher-level specifications we simplify a state machine
+specification.
+
+For example, sometimes chains of states are needed, with only a small number of
+possible characters appearing along the chain. These can easily be replaced
+with a concatenation of characters. Sometimes a group of common states
+implement a loop back to another single portion of the machine. Rather than
+manually duplicate all the transitions that loop back, we may be able to
+express the loop using a kleene star operator.
+
+Ragel allows one to take this state map simplification approach. We can build
+state machines using a state map model and implement portions of the state map
+using regular languages. In place of any transition in the state machine,
+entire sub-machines can be given. These can encapsulate functionality
+defined elsewhere. An important aspect of the Ragel approach is that when we
+wrap up a collection of states using a regular expression we do not lose
+access to the states and transitions. We can still execute code on the
+transitions that we have encapsulated.
+
+\subsection{Dropping Down One Level of Abstraction}
+\label{down}
+
+The second benefit of incorporating state charts into Ragel is that it permits
+us to bypass the regular language abstraction if we need to. Ragel's action
+embedding operators are sometimes insufficient for expressing certain parsing
+tasks. In the same way that is useful for C language programmers to drop down
+to assembly language programming using embedded assembler, it is sometimes
+useful for the Ragel programmer to drop down to programming with state charts.
+
+In the following example, we wish to buffer the characters of an XML CDATA
+sequence. The sequence is terminated by the string \verb|]]>|. The challenge
+in our application is that we do not wish the terminating characters to be
+buffered. An expression of the form \verb|any* @buffer :>> ']]>'| will not work
+because the buffer will always contain the characters \verb|]]| on the end.
+Instead, what we need is to delay the buffering of \hspace{0.25mm} \verb|]|
+characters until a time when we
+abandon the terminating sequence and go back into the main loop. There is no
+easy way to express this using Ragel's regular expression and action embedding
+operators, and so an ability to drop down to the state chart method is useful.
+
+% GENERATE: dropdown
+% OPT: -p
+% %%{
+% machine dropdown;
+\begin{inline_code}
+\begin{verbatim}
+action bchar { buff( fpc ); } # Buffer the current character.
+action bbrack1 { buff( "]" ); }
+action bbrack2 { buff( "]]" ); }
+
+CDATA_body =
+start: (
+ ']' -> one |
+ (any-']') @bchar ->start
+),
+one: (
+ ']' -> two |
+ [^\]] @bbrack1 @bchar ->start
+),
+two: (
+ '>' -> final |
+ ']' @bbrack1 -> two |
+ [^>\]] @bbrack2 @bchar ->start
+);
+\end{verbatim}
+\end{inline_code}
+% main := CDATA_body;
+% }%%
+% END GENERATE
+
+\graphspace
+\begin{center}
+\includegraphics[scale=0.55]{dropdown}
+\end{center}
+
+
+\section{Semantic Conditions}
+\label{semantic}
+
+Many communication protocols contain variable-length fields, where the length
+of the field is given ahead of the field as a value. This
+problem cannot be expressed using regular languages because of its
+context-dependent nature. The prevalence of variable-length fields in
+communication protocols motivated us to introduce semantic conditions into
+the Ragel language.
+
+A semantic condition is a block of user code that is interpreted as an
+expression and evaluated immediately
+before a transition is taken. If the code returns a value of true, the
+transition may be taken. We can now embed code that extracts the length of a
+field, then proceed to match $n$ data values.
+
+% GENERATE: conds1
+% OPT: -p
+% %%{
+% machine conds1;
+% number = digit+;
+\begin{inline_code}
+\begin{verbatim}
+action rec_num { i = 0; n = getnumber(); }
+action test_len { i++ < n }
+data_fields = (
+ 'd'
+ [0-9]+ %rec_num
+ ':'
+ ( [a-z] when test_len )*
+)**;
+\end{verbatim}
+\end{inline_code}
+% main := data_fields;
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{conds1}
+\end{center}
+\graphspace
+
+The Ragel implementation of semantic conditions does not force us to give up the
+compositional property of Ragel definitions. For example, a machine that tests
+the length of a field using conditions can be unioned with another machine
+that accepts some of the same strings, without the two machines interfering with
+one another. The user need not be concerned about whether or not the result of the
+semantic condition will affect the matching of the second machine.
+
+To see this, first consider that when a user associates a condition with an
+existing transition, the transition's label is translated from the base character
+to its corresponding value in the space that represents ``condition $c$ true''. Should
+the determinization process combine a state that has a conditional transition
+with another state that has a transition on the same input character but
+without a condition, then the condition-less transition first has its label
+translated into two values, one to its corresponding value in the space that
+represents ``condition $c$ true'' and another to its corresponding value in the
+space that represents ``condition $c$ false''. It
+is then safe to combine the two transitions. This is shown in the following
+example. Two intersecting patterns are unioned, one with a condition and one
+without. The condition embedded in the first pattern does not affect the second
+pattern.
+
+% GENERATE: conds2
+% OPT: -p
+% %%{
+% machine conds2;
+% number = digit+;
+\begin{inline_code}
+\begin{verbatim}
+action test_len { i++ < n }
+action one { /* accept pattern one */ }
+action two { /* accept pattern two */ }
+patterns =
+ ( [a-z] when test_len )+ %one |
+ [a-z][a-z0-9]* %two;
+main := patterns '\n';
+\end{verbatim}
+\end{inline_code}
+% }%%
+% END GENERATE
+
+\begin{center}
+\includegraphics[scale=0.55]{conds2}
+\end{center}
+\graphspace
+
+There are many more potential uses for semantic conditions. The user is free to
+use arbitrary code and may therefore perform actions such as looking up names
+in dictionaries, validating input using external parsing mechanisms or
+performing checks on the semantic structure of input seen so far. In the
+next section we describe how Ragel accommodates several common parser
+engineering problems.
+
+\vspace{10pt}
+
+\noindent {\large\bf Note:} The semantic condition feature works only with
+alphabet types that are smaller in width than the \verb|long| type. To
+implement semantic conditions Ragel needs to be able to allocate characters
+from the alphabet space. Ragel uses these allocated characters to express
+"character C with condition P true" or "C with P false." Since internally Ragel
+uses longs to store characters there is no room left in the alphabet space
+unless an alphabet type smaller than long is used.
+
+\section{Implementing Lookahead}
+
+There are a few strategies for implementing lookahead in Ragel programs.
+Leaving actions, which are described in Section \ref{out-actions}, can be
+used as a form of lookahead. Ragel also provides the \verb|fhold| directive
+which can be used in actions to prevent the machine from advancing over the
+current character. It is also possible to manually adjust the current character
+position by shifting it backwards using \verb|fexec|, however when this is
+done, care must be taken not to overstep the beginning of the current buffer
+block. In both the use of \verb|fhold| and \verb|fexec| the user must be
+cautious of combining the resulting machine with another in such a way that the
+transition on which the current position is adjusted is not combined with a
+transition from the other machine.
+
+\section{Parsing Recursive Language Structures}
+
+In general Ragel cannot handle recursive structures because the grammar is
+interpreted as a regular language. However, depending on what needs to be
+parsed it is sometimes practical to implement the recursive parts using manual
+coding techniques. This often works in cases where the recursive structures are
+simple and easy to recognize, such as in the balancing of parentheses
+
+One approach to parsing recursive structures is to use actions that increment
+and decrement counters or otherwise recognize the entry to and exit from
+recursive structures and then jump to the appropriate machine defnition using
+\verb|fcall| and \verb|fret|. Alternatively, semantic conditions can be used to
+test counter variables.
+
+A more traditional approach is to call a separate parsing function (expressed
+in the host language) when a recursive structure is entered, then later return
+when the end is recognized.
+
+\end{document}
diff --git a/doc/ragel.1.in b/doc/ragel.1.in
new file mode 100644
index 0000000..ca58f6e
--- /dev/null
+++ b/doc/ragel.1.in
@@ -0,0 +1,661 @@
+.\"
+.\" Copyright 2001-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
+
+.\" Process this file with
+.\" groff -man -Tascii ragel.1
+.\"
+.TH RAGEL 1 "@PUBDATE@" "Ragel @VERSION@" "Ragel State Machine Compiler"
+.SH NAME
+ragel \- compile regular languages into executable state machines
+.SH SYNOPSIS
+.B ragel
+.RI [ options ]
+.I file
+.SH DESCRIPTION
+Ragel compiles executable finite state machines from regular languages.
+Ragel can generate C, C++, Objective-C, D, Go, or Java code. Ragel state
+machines can not only recognize byte
+sequences as regular expression machines do, but can also execute code at
+arbitrary points in the recognition of a regular language. User code is
+embedded using inline operators that do not disrupt the regular language
+syntax.
+
+The core language consists of standard regular expression operators, such as
+union, concatenation and kleene star, accompanied by action embedding
+operators. Ragel also provides operators that let you control any
+non-determinism that you create, construct scanners using the longest match
+paradigm, and build state machines using the statechart model. It is also
+possible to influence the execution of a state machine from inside an embedded
+action by jumping or calling to other parts of the machine and reprocessing
+input.
+
+Ragel provides a very flexibile interface to the host language that attempts to
+place minimal restrictions on how the generated code is used and integrated
+into the application. The generated code has no dependencies.
+
+.SH OPTIONS
+.TP
+.BR \-h ", " \-H ", " \-? ", " \-\-help
+Display help and exit.
+.TP
+.B \-v
+Print version information and exit.
+.TP
+.B \-o " file"
+Write output to file. If -o is not given, a default file name is chosen by
+replacing the file extenstion of the input file. For source files ending in .rh
+the suffix .h is used. For all other source files a suffix based on the output
+language is used (.c, .cpp, .m, etc.). If -o is not given for Graphviz output
+the generated dot file is written to standard output.
+.TP
+.B \-s
+Print some statistics on standard error.
+.TP
+.B \--error-format=gnu
+Print error messages using the format "file:line:column:" (default)
+.TP
+.B \--error-format=msvc
+Print error messages using the format "file(line,column):"
+.TP
+.B \-d
+Do not remove duplicate actions from action lists.
+.TP
+.B \-I " dir"
+Add dir to the list of directories to search for included and imported files
+.TP
+.B \-n
+Do not perform state minimization.
+.TP
+.B \-m
+Perform minimization once, at the end of the state machine compilation.
+.TP
+.B \-l
+Minimize after nearly every operation. Lists of like operations such as unions
+are minimized once at the end. This is the default minimization option.
+.TP
+.B \-e
+Minimize after every operation.
+.TP
+.B \-x
+Compile the state machines and emit an XML representation of the host data and
+the machines.
+.TP
+.B \-V
+Generate a dot file for Graphviz.
+.TP
+.B \-p
+Display printable characters on labels.
+.TP
+.B \-S <spec>
+FSM specification to output.
+.TP
+.B \-M <machine>
+Machine definition/instantiation to output.
+.TP
+.B \-C
+The host language is C, C++, Obj-C or Obj-C++. This is the default host language option.
+.TP
+.B \-D
+The host language is D.
+.TP
+.B \-J
+The host language is Java.
+.TP
+.B \-Z
+The host language is Go.
+.TP
+.B \-R
+The host language is Ruby.
+.TP
+.B \-L
+Inhibit writing of #line directives.
+.TP
+.B \-T0
+(C/D/Java/Ruby/C#/Go) Generate a table driven FSM. This is the default code style.
+The table driven
+FSM represents the state machine as static data. There are tables of states,
+transitions, indicies and actions. The current state is stored in a variable.
+The execution is a loop that looks that given the current state and current
+character to process looks up the transition to take using a binary search,
+executes any actions and moves to the target state. In general, the table
+driven FSM produces a smaller binary and requires a less expensive host language
+compile but results in slower running code. The table driven FSM is suitable
+for any FSM.
+.TP
+.B \-T1
+(C/D/Ruby/C#/Go) Generate a faster table driven FSM by expanding action lists in the action
+execute code.
+.TP
+.B \-F0
+(C/D/Ruby/C#/Go) Generate a flat table driven FSM. Transitions are represented as an array
+indexed by the current alphabet character. This eliminates the need for a
+binary search to locate transitions and produces faster code, however it is
+only suitable for small alphabets.
+.TP
+.B \-F1
+(C/D/Ruby/C#/Go) Generate a faster flat table driven FSM by expanding action lists in the action
+execute code.
+.TP
+.B \-G0
+(C/D/C#/Go) Generate a goto driven FSM. The goto driven FSM represents the state machine
+as a series of goto statements. While in the machine, the current state is
+stored by the processor's instruction pointer. The execution is a flat function
+where control is passed from state to state using gotos. In general, the goto
+FSM produces faster code but results in a larger binary and a more expensive
+host language compile.
+.TP
+.B \-G1
+(C/D/C#/Go) Generate a faster goto driven FSM by expanding action lists in the action
+execute code.
+.TP
+.B \-G2
+(C/D/Go) Generate a really fast goto driven FSM by embedding action lists in the state
+machine control code.
+.TP
+.B \-P<N>
+(C/D) N-Way Split really fast goto-driven FSM.
+
+.SH RAGEL INPUT
+NOTE: This is a very brief description of Ragel input. Ragel is described in
+more detail in the user guide available from the homepage (see below).
+
+Ragel normally passes input files straight to the output. When it sees an FSM
+specification that contains machine instantiations it stops to generate the
+state machine. If there are write statements (such as "write exec") then ragel emits the
+corresponding code. There can be any number of FSM specifications in an input
+file. A multi-line FSM specification starts with '%%{' and ends with '}%%'. A
+single line FSM specification starts with %% and ends at the first newline.
+.SH FSM STATEMENTS
+.TP
+.I Machine Name:
+Set the the name of the machine. If given, it must be the first statement.
+.TP
+.I Alphabet Type:
+Set the data type of the alphabet.
+.TP
+.I GetKey:
+Specify how to retrieve the alphabet character from the element type.
+.TP
+.I Include:
+Include a machine of same name as the current or of a different name in either
+the current file or some other file.
+.TP
+.I Action Definition:
+Define an action that can be invoked by the FSM.
+.TP
+.I Fsm Definition, Instantiation and Longest Match Instantiation:
+Used to build FSMs. Syntax description in next few sections.
+.TP
+.I Access:
+Specify how to access the persistent state machine variables.
+.TP
+.I Write:
+Write some component of the machine.
+.TP
+.I Variable:
+Override the default variable names (p, pe, cs, act, etc).
+.SH BASIC MACHINES
+The basic machines are the base operands of the regular language expressions.
+.TP
+.I 'hello'
+Concat literal. Produces a concatenation of the characters in the string.
+Supports escape sequences with '\\'. The result will have a start state and a
+transition to a new state for each character in the string. The last state in
+the sequence will be made final. To make the string case-insensitive, append
+an 'i' to the string, as in 'cmd'i\fR.
+.TP
+.I \(dqhello\(dq
+Identical to single quote version.
+.TP
+.I [hello]
+Or literal. Produces a union of characters. Supports character ranges
+with '\-', negating the sense of the union with an initial '^' and escape
+sequences with '\\'. The result will have two states with a transition between
+them for each character or range.
+.LP
+NOTE: '', "", and [] produce null FSMs. Null machines have one state that is
+both a start state and a final state and match the zero length string. A null machine
+may be created with the null builtin machine.
+.TP
+.I integer
+Makes a two state machine with one transition on the given integer number.
+.TP
+.I hex
+Makes a two state machine with one transition on the given hexidecimal number.
+.TP
+.I "/simple_regex/"
+A simple regular expression. Supports the notation '.', '*' and '[]', character
+ranges with '\-', negating the sense of an OR expression with and initial '^'
+and escape sequences with '\\'. Also supports one trailing flag: i. Use it to
+produce a case-insensitive regular expression, as in /GET/i.
+.TP
+.I lit .. lit
+Specifies a range. The allowable upper and lower bounds are concat literals of
+length one and number machines.
+For example, 0x10..0x20, 0..63, and 'a'..'z' are valid ranges.
+.TP
+.I "variable_name"
+References the machine definition assigned to the variable name given.
+.TP
+.I "builtin_machine"
+There are several builtin machines available. They are all two state machines
+for the purpose of matching common classes of characters. They are:
+.RS
+.TP
+.B any
+Any character in the alphabet.
+.TP
+.B ascii
+Ascii characters 0..127.
+.TP
+.B extend
+Ascii extended characters. This is the range -128..127 for signed alphabets
+and the range 0..255 for unsigned alphabets.
+.TP
+.B alpha
+Alphabetic characters /[A-Za-z]/.
+.TP
+.B digit
+Digits /[0-9]/.
+.TP
+.B alnum
+Alpha numerics /[0-9A-Za-z]/.
+.TP
+.B lower
+Lowercase characters /[a-z]/.
+.TP
+.B upper
+Uppercase characters /[A-Z]/.
+.TP
+.B xdigit
+Hexidecimal digits /[0-9A-Fa-f]/.
+.TP
+.B cntrl
+Control characters 0..31.
+.TP
+.B graph
+Graphical characters /[!-~]/.
+.TP
+.B print
+Printable characters /[ -~]/.
+.TP
+.B punct
+Punctuation. Graphical characters that are not alpha-numerics
+/[!-/:-@\\[-`{-~]/.
+.TP
+.B space
+Whitespace /[\\t\\v\\f\\n\\r ]/.
+.TP
+.B null
+Zero length string. Equivalent to '', "" and [].
+.TP
+.B empty
+Empty set. Matches nothing.
+.RE
+.SH BRIEF OPERATOR REFERENCE
+Operators are grouped by precedence, group 1 being the lowest and group 6 the
+highest.
+.LP
+.B GROUP 1:
+.TP
+.I expr , expr
+Join machines together without drawing any transitions, setting up a start
+state or any final states. Start state must be explicitly specified with the
+"start" label. Final states may be specified with the an epsilon transitions to
+the implicitly created "final" state.
+.LP
+.B GROUP 2:
+.TP
+.I expr | expr
+Produces a machine that matches any string in machine one or machine two.
+.TP
+.I expr & expr
+Produces a machine that matches any string that is in both machine one and
+machine two.
+.TP
+.I expr - expr
+Produces a machine that matches any string that is in machine one but not in
+machine two.
+.TP
+.I expr -- expr
+Strong Subtraction. Matches any string in machine one that does not have any string
+in machine two as a substring.
+.LP
+.B GROUP 3:
+.TP
+.I expr . expr
+Produces a machine that matches all the strings in machine one followed
+by all the strings in machine two.
+.TP
+.I expr :> expr
+Entry-Guarded Concatenation: terminates machine one upon entry to machine two.
+.TP
+.I expr :>> expr
+Finish-Guarded Concatenation: terminates machine one when machine two finishes.
+.TP
+.I expr <: expr
+Left-Guarded Concatenation: gives a higher priority to machine one.
+.LP
+NOTE: Concatenation is the default operator. Two machines next to each other
+with no operator between them results in the concatenation operation.
+.LP
+.B GROUP 4:
+.TP
+.I label: expr
+Attaches a label to an expression. Labels can be used by epsilon transitions
+and fgoto and fcall statements in actions. Also note that the referencing of a
+machine definition causes the implicit creation of label by the same name.
+.LP
+.B GROUP 5:
+.TP
+.I expr -> label
+Draws an epsilon transition to the state defined by label. Label must
+be a name in the current scope. Epsilon transitions are resolved when
+comma operators are evaluated and at the root of the expression tree of
+machine assignment/instantiation.
+.LP
+.B GROUP 6: Actions
+.LP
+An action may be a name predefined with an action statement or may
+be specified directly with '{' and '}' in the expression.
+.TP
+.I expr > action
+Embeds action into starting transitions.
+.TP
+.I expr @ action
+Embeds action into transitions that go into a final state.
+.TP
+.I expr $ action
+Embeds action into all transitions. Does not include pending out transitions.
+.TP
+.I expr % action
+Embeds action into pending out transitions from final states.
+.LP
+.B GROUP 6: EOF Actions
+.LP
+When a machine's finish routine is called the current state's EOF actions are
+executed.
+.TP
+.I expr >/ action
+Embed an EOF action into the start state.
+.TP
+.I expr </ action
+Embed an EOF action into all states except the start state.
+.TP
+.I expr $/ action
+Embed an EOF action into all states.
+.TP
+.I expr %/ action
+Embed an EOF action into final states.
+.TP
+.I expr @/ action
+Embed an EOF action into all states that are not final.
+.TP
+.I expr <>/ action
+Embed an EOF action into all states that are not the start
+state and that are not final (middle states).
+.LP
+.B GROUP 6: Global Error Actions
+.LP
+Global error actions are stored in states until the final state machine has
+been fully constructed. They are then transferred to error transitions, giving
+the effect of a default action.
+.TP
+.I expr >! action
+Embed a global error action into the start state.
+.TP
+.I expr <! action
+Embed a global error action into all states except the start state.
+.TP
+.I expr $! action
+Embed a global error action into all states.
+.TP
+.I expr %! action
+Embed a global error action into the final states.
+.TP
+.I expr @! action
+Embed a global error action into all states which are not final.
+.TP
+.I expr <>! action
+Embed a global error action into all states which are not the start state and
+are not final (middle states).
+.LP
+.B GROUP 6: Local Error Actions
+.LP
+Local error actions are stored in states until the named machine is fully
+constructed. They are then transferred to error transitions, giving the effect
+of a default action for a section of the total machine. Note that the name may
+be omitted, in which case the action will be transferred to error actions upon
+construction of the current machine.
+.TP
+.I expr >^ action
+Embed a local error action into the start state.
+.TP
+.I expr <^ action
+Embed a local error action into all states except the start state.
+.TP
+.I expr $^ action
+Embed a local error action into all states.
+.TP
+.I expr %^ action
+Embed a local error action into the final states.
+.TP
+.I expr @^ action
+Embed a local error action into all states which are not final.
+.TP
+.I expr <>^ action
+Embed a local error action into all states which are not the start state and
+are not final (middle states).
+.LP
+.B GROUP 6: To-State Actions
+.LP
+To state actions are stored in states and executed any time the machine moves
+into a state. This includes regular transitions, and transfers of control such
+as fgoto. Note that setting the current state from outside the machine (for
+example during initialization) does not count as a transition into a state.
+.TP
+.I expr >~ action
+Embed a to-state action action into the start state.
+.TP
+.I expr <~ action
+Embed a to-state action into all states except the start state.
+.TP
+.I expr $~ action
+Embed a to-state action into all states.
+.TP
+.I expr %~ action
+Embed a to-state action into the final states.
+.TP
+.I expr @~ action
+Embed a to-state action into all states which are not final.
+.TP
+.I expr <>~ action
+Embed a to-state action into all states which are not the start state and
+are not final (middle states).
+.LP
+.B GROUP 6: From-State Actions
+.LP
+From state actions are executed whenever a state takes a transition on a character.
+This includes the error transition and a transition to self.
+.TP
+.I expr >* action
+Embed a from-state action into the start state.
+.TP
+.I expr <* action
+Embed a from-state action into every state except the start state.
+.TP
+.I expr $* action
+Embed a from-state action into all states.
+.TP
+.I expr %* action
+Embed a from-state action into the final states.
+.TP
+.I expr @* action
+Embed a from-state action into all states which are not final.
+.TP
+.I expr <>* action
+Embed a from-state action into all states which are not the start state and
+are not final (middle states).
+.LP
+.B GROUP 6: Priority Assignment
+.LP
+Priorities are assigned to names within transitions. Only priorities on the
+same name are allowed to interact. In the first form of priorities the name
+defaults to the name of the machine definition the priority is assigned in.
+Transitions do not have default priorities.
+.TP
+.I expr > int
+Assigns the priority int in all transitions leaving the start state.
+.TP
+.I expr @ int
+Assigns the priority int in all transitions that go into a final state.
+.TP
+.I expr $ int
+Assigns the priority int in all existing transitions.
+.TP
+.I expr % int
+Assigns the priority int in all pending out transitions.
+.LP
+A second form of priority assignment allows the programmer to specify the name
+to which the priority is assigned, allowing interactions to cross machine
+definition boundaries.
+.TP
+.I expr > (name,int)
+Assigns the priority int to name in all transitions leaving the start state.
+.TP
+.I expr @ (name, int)
+Assigns the priority int to name in all transitions that go into a final state.
+.TP
+.I expr $ (name, int)
+Assigns the priority int to name in all existing transitions.
+.TP
+.I expr % (name, int)
+Assigns the priority int to name in all pending out transitions.
+.LP
+.B GROUP 7:
+.TP
+.I expr *
+Produces the kleene star of a machine. Matches zero or more repetitions of the
+machine.
+.TP
+.I expr **
+Longest-Match Kleene Star. This version of kleene star puts a higher
+priority on staying in the machine over wrapping around and starting over. This
+operator is equivalent to ( ( expr ) $0 %1 )*.
+.TP
+.I expr ?
+Produces a machine that accepts the machine given or the null string. This operator
+is equivalent to ( expr | '' ).
+.TP
+.I expr +
+Produces the machine concatenated with the kleen star of itself. Matches one or
+more repetitions of the machine. This operator is equivalent to ( expr . expr* ).
+.TP
+.I expr {n}
+Produces a machine that matches exactly n repetitions of expr.
+.TP
+.I expr {,n}
+Produces a machine that matches anywhere from zero to n repetitions of expr.
+.TP
+.I expr {n,}
+Produces a machine that matches n or more repetitions of expr.
+.TP
+.I expr {n,m}
+Produces a machine that matches n to m repetitions of expr.
+.LP
+.B GROUP 8:
+.TP
+.I ! expr
+Produces a machine that matches any string not matched by the given machine.
+This operator is equivalent to ( *extend - expr ).
+.TP
+.I ^ expr
+Character-Level Negation. Matches any single character not matched by the
+single character machine expr.
+.LP
+.B GROUP 9:
+.TP
+.I ( expr )
+Forces precedence on operators.
+.SH VALUES AVAILABLE IN CODE BLOCKS
+.TP
+.I fc
+The current character. Equivalent to *p.
+.TP
+.I fpc
+A pointer to the current character. Equivalent to p.
+.TP
+.I fcurs
+An integer value representing the current state.
+.TP
+.I ftargs
+An integer value representing the target state.
+.TP
+.I fentry(<label>)
+An integer value representing the entry point <label>.
+.SH STATEMENTS AVAILABLE IN CODE BLOCKS
+.TP
+.I fhold;
+Do not advance over the current character. Equivalent to --p;.
+.TP
+.I fexec <expr>;
+Sets the current character to something else. Equivalent to p = (<expr>)-1;
+.TP
+.I fgoto <label>;
+Jump to the machine defined by <label>.
+.TP
+.I fgoto *<expr>;
+Jump to the entry point given by <expr>. The expression must
+evaluate to an integer value representing a state.
+.TP
+.I fnext <label>;
+Set the next state to be the entry point defined by <label>. The fnext
+statement does not immediately jump to the specified state. Any action code
+following the statement is executed.
+.TP
+.I fnext *<expr>;
+Set the next state to be the entry point given by <expr>. The expression must
+evaluate to an integer value representing a state.
+.TP
+.I fcall <label>;
+Call the machine defined by <label>. The next fret will jump to the
+target of the transition on which the action is invoked.
+.TP
+.I fcall *<expr>;
+Call the entry point given by <expr>. The next fret will jump to the target of
+the transition on which the action is invoked.
+.TP
+.I fret;
+Return to the target state of the transition on which the last fcall was made.
+.TP
+.I fbreak;
+Save the current state and immediately break out of the machine.
+.SH CREDITS
+Ragel was written by Adrian Thurston <thurston@complang.org>.
+Objective-C output contributed by Erich Ocean. D output contributed by
+Alan West. Ruby output contributed by Victor Hugo Borja. C Sharp code
+generation contributed by Daniel Tang. Contributions to Java code
+generation by Colin Fleming. Go code generation contributed by
+Justine Tunney.
+.SH "SEE ALSO"
+.BR re2c (1),
+.BR flex (1)
+
+Homepage: http://www.complang.org/ragel/
diff --git a/doc/smallscanner.fig b/doc/smallscanner.fig
new file mode 100644
index 0000000..c86750e
--- /dev/null
+++ b/doc/smallscanner.fig
@@ -0,0 +1,78 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+# Generated by dot version 2.2.1 (Fri Sep 30 13:22:44 UTC 2005)
+# For: (age) Adrian Thurston
+# Title: smallscanner
+# Pages: 1
+1200 2
+0 32 #d2d2d2
+# ENTRY
+1 1 0 1 0 0 0 0 20 0.000 0 0.0000 33 3850 33 33 33 3850 66 3883
+# 0
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3850 383 383 1400 3850 1783 4233
+1 1 0 1 0 32 0 0 -1 0.000 0 0.0000 1400 3850 450 450 1400 3850 1850 4300
+# 1
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5266 3850 383 383 5266 3850 5649 4233
+1 1 0 1 0 0 0 0 -1 0.000 0 0.0000 5266 3850 450 450 5266 3850 5716 4300
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 766 3783 933 3850 766 3900 766 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1116 3350 1083 3516 1016 3350 1116 3350
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4633 3783 4800 3850 4633 3883 4633 3783
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 1950 4183 1816 4066 2000 4083 1950 4183
+2 3 0 1 0 0 0 0 20 0.000 0 0 0 0 0 4
+ 4983 3350 4950 3516 4883 3350 4983 3350
+2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 7110 2835 -90 2835 -90 4455 7110 4455 7110 2835
+# ENTRY -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 7
+ 66 3850 132 3850 225 3850 341 3850 474 3850 617 3850
+ 766 3850
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+# 0 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 1716 3516 1741 3410 1734 3312 1695 3227 1626 3159 1527 3115
+ 1400 3100 1305 3108 1224 3131 1158 3168 1108 3218 1077 3279
+ 1066 3350
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+# 0 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 1866 3850 1916 3842 1966 3838 2016 3835 2066 3833 2116 3833
+ 2166 3833 2632 3833 3008 3833 3339 3833 3669 3833 4041 3833
+ 4500 3833 4523 3833 4545 3833 4566 3833 4587 3833 4609 3833
+ 4633 3833
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 0
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 19
+ 4866 4066 4807 4091 4745 4115 4683 4137 4620 4156 4559 4172
+ 4500 4183 4050 4266 3676 4316 3339 4333 3001 4316 2623 4266
+ 2166 4183 2133 4175 2100 4166 2066 4158 2033 4150 2000 4141
+ 1966 4133
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 0.000
+# 1 -> 1
+3 4 0 1 0 0 0 0 -1 0.000 0 0 0 13
+ 5583 3516 5608 3410 5601 3312 5562 3227 5493 3159 5394 3115
+ 5266 3100 5172 3108 5091 3131 5025 3168 4975 3218 4944 3279
+ 4933 3350
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 0.000
+4 1 0 0 0 0 14 0.0000 2 150 120 1400 3933 0\001
+4 1 0 0 0 0 14 0.0000 2 150 255 500 3800 IN\001
+4 1 0 0 0 0 14 0.0000 2 150 150 1400 3050 ' '\001
+4 1 0 0 0 0 14 0.0000 2 165 120 5266 3933 1\001
+4 1 0 0 0 0 14 0.0000 2 180 2310 3333 3783 'a'..'z' / start_str, on_char\001
+4 1 0 0 0 0 14 0.0000 2 180 1200 3333 4116 ' ' / finish_str\001
+4 1 0 0 0 0 14 0.0000 2 180 3300 5266 3050 'a'..'z' / on_char, finish_str, start_str\001
diff --git a/doc/stembed.fig b/doc/stembed.fig
new file mode 100644
index 0000000..eb3ce8d
--- /dev/null
+++ b/doc/stembed.fig
@@ -0,0 +1,72 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 463 1772 463 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 955 1772 955 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 1461 1772 1461 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 1948 1772 1948 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2403 1772 2403 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2906 1772 2906 1875
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3377 173 3510 173
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3377 881 3510 881
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3377 532 3510 532
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3377 1609 3510 1609
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3377 1260 3510 1260
+4 0 0 50 -1 12 12 0.0000 4 105 240 405 225 >~\001
+4 0 0 50 -1 0 12 0.0000 4 150 1545 3690 585 from-state actions\001
+4 0 0 50 -1 0 12 0.0000 4 150 1290 3690 225 to state actions\001
+4 0 0 50 -1 0 12 0.0000 4 150 1545 3690 1665 local error actions\001
+4 0 0 50 -1 0 12 0.0000 4 150 1095 3690 1305 error actions\001
+4 0 0 50 -1 0 12 0.0000 4 150 1065 3690 945 EOF actions\001
+4 0 0 50 -1 0 12 5.6723 4 120 855 405 2044 start state\001
+4 0 0 50 -1 0 12 5.6723 4 150 360 1409 2071 final\001
+4 0 0 50 -1 0 12 5.6723 4 150 750 901 2038 all states\001
+4 0 0 50 -1 12 12 0.0000 4 165 240 900 225 $~\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 1395 225 %~\001
+4 0 0 50 -1 12 12 0.0000 4 105 240 1890 225 <~\001
+4 0 0 50 -1 12 12 0.0000 4 135 360 2835 225 <>~\001
+4 0 0 50 -1 12 12 0.0000 4 120 360 405 585 >* \001
+4 0 0 50 -1 12 12 0.0000 4 165 240 900 585 $*\001
+4 0 0 50 -1 12 12 0.0000 4 135 360 2835 585 <>*\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 405 1305 >!\001
+4 0 0 50 -1 12 12 0.0000 4 150 240 405 945 >/\001
+4 0 0 50 -1 12 12 0.0000 4 165 240 900 945 $/\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 1395 585 %*\001
+4 0 0 50 -1 12 12 0.0000 4 150 240 1395 945 %/\001
+4 0 0 50 -1 12 12 0.0000 4 150 240 1890 945 </\001
+4 0 0 50 -1 12 12 0.0000 4 150 240 2340 945 @/\001
+4 0 0 50 -1 12 12 0.0000 4 150 360 2835 945 <>/\001
+4 0 0 50 -1 12 12 0.0000 4 105 240 1890 585 <*\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 1890 1305 <!\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 1395 1305 %!\001
+4 0 0 50 -1 12 12 0.0000 4 165 240 900 1305 $!\001
+4 0 0 50 -1 12 12 0.0000 4 165 240 900 1665 $^\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 405 1665 >^\001
+4 0 0 50 -1 12 12 0.0000 4 135 240 1395 1665 %^\001
+4 0 0 50 -1 12 12 0.0000 4 120 240 1890 1665 <^\001
+4 0 0 50 -1 12 12 0.0000 4 135 240 2340 1665 @^\001
+4 0 0 50 -1 12 12 0.0000 4 135 360 2835 1665 <>^\001
+4 0 0 50 -1 12 12 0.0000 4 135 240 2340 1305 @!\001
+4 0 0 50 -1 12 12 0.0000 4 135 360 2835 1305 <>!\001
+4 0 0 50 -1 12 12 0.0000 4 135 240 2340 585 @*\001
+4 0 0 50 -1 12 12 0.0000 4 135 240 2340 225 @~\001
+4 0 0 50 -1 0 12 5.6723 4 150 1635 2860 2053 not start & not final\001
+4 0 0 50 -1 0 12 5.6723 4 120 705 1883 2050 not start\001
+4 0 0 50 -1 0 12 5.6723 4 150 675 2359 2048 not final\001
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..b4c6a94
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,91 @@
+#
+# Copyright 2002-2009 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
+
+RAGEL = ../ragel/ragel
+FLEX = flex
+RE2C = re2c
+
+noinst_PROGRAMS = \
+ atoi awkemu clang concurrent cppscan format gotocallret mailbox params \
+ pullscan rlscan statechart
+
+EXTRA_DIST = \
+ gotocallret.rl pullscan.rl concurrent.rl rlscan.rl statechart.rl \
+ params.rl clang.rl cppscan.rl format.rl awkemu.rl mailbox.rl atoi.rl
+
+gotocallret_SOURCES = gotocallret.cpp
+pullscan_SOURCES = pullscan.c
+concurrent_SOURCES = concurrent.cpp
+rlscan_SOURCES = rlscan.cpp
+statechart_SOURCES = statechart.cpp
+params_SOURCES = params.c
+clang_SOURCES = clang.c
+cppscan_SOURCES = cppscan.cpp
+format_SOURCES = format.c
+awkemu_SOURCES = awkemu.c
+mailbox_SOURCES = mailbox.cpp
+atoi_SOURCES = atoi.cpp
+
+gotocallret.cpp: gotocallret.rl
+ $(RAGEL) -G2 -o gotocallret.cpp gotocallret.rl
+
+pullscan.c: pullscan.rl $(RAGEL)
+ $(RAGEL) -G2 -o $@ pullscan.rl
+
+concurrent.cpp: concurrent.rl $(RAGEL)
+ $(RAGEL) -G2 -o concurrent.cpp concurrent.rl
+
+rlscan.cpp: rlscan.rl
+ $(RAGEL) -G2 -o rlscan.cpp rlscan.rl
+
+statechart.cpp: statechart.rl
+ $(RAGEL) -G2 -o statechart.cpp statechart.rl
+
+params.c: params.rl
+ $(RAGEL) -G2 -o params.c params.rl
+
+clang.c: clang.rl
+ $(RAGEL) -G2 -o clang.c clang.rl
+
+cppscan.cpp: cppscan.rl
+ $(RAGEL) -G2 -o $@ cppscan.rl
+
+format.c: format.rl
+ $(RAGEL) -G2 -o format.c format.rl
+
+awkemu.c: awkemu.rl
+ $(RAGEL) -G2 -o awkemu.c awkemu.rl
+
+mailbox.cpp: mailbox.rl
+ $(RAGEL) -G2 -o mailbox.cpp mailbox.rl
+
+atoi.cpp: atoi.rl
+ $(RAGEL) -G2 -o atoi.cpp atoi.rl
+
+###
+
+lex-cppscan.cpp: cppscan.lex
+ $(FLEX) -f -o $@ $<
+
+re2c-cppscan.cpp: cppscan.rec
+ $(RE2C) -s $< > $@
+
+example.cpp: example.rec
+ $(RE2C) -s $< > $@
diff --git a/examples/Makefile.in b/examples/Makefile.in
new file mode 100644
index 0000000..957d7e7
--- /dev/null
+++ b/examples/Makefile.in
@@ -0,0 +1,728 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright 2002-2009 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
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+noinst_PROGRAMS = atoi$(EXEEXT) awkemu$(EXEEXT) clang$(EXEEXT) \
+ concurrent$(EXEEXT) cppscan$(EXEEXT) format$(EXEEXT) \
+ gotocallret$(EXEEXT) mailbox$(EXEEXT) params$(EXEEXT) \
+ pullscan$(EXEEXT) rlscan$(EXEEXT) statechart$(EXEEXT)
+subdir = examples
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_atoi_OBJECTS = atoi.$(OBJEXT)
+atoi_OBJECTS = $(am_atoi_OBJECTS)
+atoi_LDADD = $(LDADD)
+am_awkemu_OBJECTS = awkemu.$(OBJEXT)
+awkemu_OBJECTS = $(am_awkemu_OBJECTS)
+awkemu_LDADD = $(LDADD)
+am_clang_OBJECTS = clang.$(OBJEXT)
+clang_OBJECTS = $(am_clang_OBJECTS)
+clang_LDADD = $(LDADD)
+am_concurrent_OBJECTS = concurrent.$(OBJEXT)
+concurrent_OBJECTS = $(am_concurrent_OBJECTS)
+concurrent_LDADD = $(LDADD)
+am_cppscan_OBJECTS = cppscan.$(OBJEXT)
+cppscan_OBJECTS = $(am_cppscan_OBJECTS)
+cppscan_LDADD = $(LDADD)
+am_format_OBJECTS = format.$(OBJEXT)
+format_OBJECTS = $(am_format_OBJECTS)
+format_LDADD = $(LDADD)
+am_gotocallret_OBJECTS = gotocallret.$(OBJEXT)
+gotocallret_OBJECTS = $(am_gotocallret_OBJECTS)
+gotocallret_LDADD = $(LDADD)
+am_mailbox_OBJECTS = mailbox.$(OBJEXT)
+mailbox_OBJECTS = $(am_mailbox_OBJECTS)
+mailbox_LDADD = $(LDADD)
+am_params_OBJECTS = params.$(OBJEXT)
+params_OBJECTS = $(am_params_OBJECTS)
+params_LDADD = $(LDADD)
+am_pullscan_OBJECTS = pullscan.$(OBJEXT)
+pullscan_OBJECTS = $(am_pullscan_OBJECTS)
+pullscan_LDADD = $(LDADD)
+am_rlscan_OBJECTS = rlscan.$(OBJEXT)
+rlscan_OBJECTS = $(am_rlscan_OBJECTS)
+rlscan_LDADD = $(LDADD)
+am_statechart_OBJECTS = statechart.$(OBJEXT)
+statechart_OBJECTS = $(am_statechart_OBJECTS)
+statechart_LDADD = $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/ragel
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(atoi_SOURCES) $(awkemu_SOURCES) $(clang_SOURCES) \
+ $(concurrent_SOURCES) $(cppscan_SOURCES) $(format_SOURCES) \
+ $(gotocallret_SOURCES) $(mailbox_SOURCES) $(params_SOURCES) \
+ $(pullscan_SOURCES) $(rlscan_SOURCES) $(statechart_SOURCES)
+DIST_SOURCES = $(atoi_SOURCES) $(awkemu_SOURCES) $(clang_SOURCES) \
+ $(concurrent_SOURCES) $(cppscan_SOURCES) $(format_SOURCES) \
+ $(gotocallret_SOURCES) $(mailbox_SOURCES) $(params_SOURCES) \
+ $(pullscan_SOURCES) $(rlscan_SOURCES) $(statechart_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = ../ragel/ragel
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+FLEX = flex
+RE2C = re2c
+EXTRA_DIST = \
+ gotocallret.rl pullscan.rl concurrent.rl rlscan.rl statechart.rl \
+ params.rl clang.rl cppscan.rl format.rl awkemu.rl mailbox.rl atoi.rl
+
+gotocallret_SOURCES = gotocallret.cpp
+pullscan_SOURCES = pullscan.c
+concurrent_SOURCES = concurrent.cpp
+rlscan_SOURCES = rlscan.cpp
+statechart_SOURCES = statechart.cpp
+params_SOURCES = params.c
+clang_SOURCES = clang.c
+cppscan_SOURCES = cppscan.cpp
+format_SOURCES = format.c
+awkemu_SOURCES = awkemu.c
+mailbox_SOURCES = mailbox.cpp
+atoi_SOURCES = atoi.cpp
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cpp .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign examples/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+atoi$(EXEEXT): $(atoi_OBJECTS) $(atoi_DEPENDENCIES) $(EXTRA_atoi_DEPENDENCIES)
+ @rm -f atoi$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(atoi_OBJECTS) $(atoi_LDADD) $(LIBS)
+
+awkemu$(EXEEXT): $(awkemu_OBJECTS) $(awkemu_DEPENDENCIES) $(EXTRA_awkemu_DEPENDENCIES)
+ @rm -f awkemu$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(awkemu_OBJECTS) $(awkemu_LDADD) $(LIBS)
+
+clang$(EXEEXT): $(clang_OBJECTS) $(clang_DEPENDENCIES) $(EXTRA_clang_DEPENDENCIES)
+ @rm -f clang$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(clang_OBJECTS) $(clang_LDADD) $(LIBS)
+
+concurrent$(EXEEXT): $(concurrent_OBJECTS) $(concurrent_DEPENDENCIES) $(EXTRA_concurrent_DEPENDENCIES)
+ @rm -f concurrent$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(concurrent_OBJECTS) $(concurrent_LDADD) $(LIBS)
+
+cppscan$(EXEEXT): $(cppscan_OBJECTS) $(cppscan_DEPENDENCIES) $(EXTRA_cppscan_DEPENDENCIES)
+ @rm -f cppscan$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(cppscan_OBJECTS) $(cppscan_LDADD) $(LIBS)
+
+format$(EXEEXT): $(format_OBJECTS) $(format_DEPENDENCIES) $(EXTRA_format_DEPENDENCIES)
+ @rm -f format$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(format_OBJECTS) $(format_LDADD) $(LIBS)
+
+gotocallret$(EXEEXT): $(gotocallret_OBJECTS) $(gotocallret_DEPENDENCIES) $(EXTRA_gotocallret_DEPENDENCIES)
+ @rm -f gotocallret$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(gotocallret_OBJECTS) $(gotocallret_LDADD) $(LIBS)
+
+mailbox$(EXEEXT): $(mailbox_OBJECTS) $(mailbox_DEPENDENCIES) $(EXTRA_mailbox_DEPENDENCIES)
+ @rm -f mailbox$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(mailbox_OBJECTS) $(mailbox_LDADD) $(LIBS)
+
+params$(EXEEXT): $(params_OBJECTS) $(params_DEPENDENCIES) $(EXTRA_params_DEPENDENCIES)
+ @rm -f params$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(params_OBJECTS) $(params_LDADD) $(LIBS)
+
+pullscan$(EXEEXT): $(pullscan_OBJECTS) $(pullscan_DEPENDENCIES) $(EXTRA_pullscan_DEPENDENCIES)
+ @rm -f pullscan$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(pullscan_OBJECTS) $(pullscan_LDADD) $(LIBS)
+
+rlscan$(EXEEXT): $(rlscan_OBJECTS) $(rlscan_DEPENDENCIES) $(EXTRA_rlscan_DEPENDENCIES)
+ @rm -f rlscan$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(rlscan_OBJECTS) $(rlscan_LDADD) $(LIBS)
+
+statechart$(EXEEXT): $(statechart_OBJECTS) $(statechart_DEPENDENCIES) $(EXTRA_statechart_DEPENDENCIES)
+ @rm -f statechart$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(statechart_OBJECTS) $(statechart_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awkemu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clang.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/concurrent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppscan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotocallret.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mailbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pullscan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rlscan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statechart.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+
+gotocallret.cpp: gotocallret.rl
+ $(RAGEL) -G2 -o gotocallret.cpp gotocallret.rl
+
+pullscan.c: pullscan.rl $(RAGEL)
+ $(RAGEL) -G2 -o $@ pullscan.rl
+
+concurrent.cpp: concurrent.rl $(RAGEL)
+ $(RAGEL) -G2 -o concurrent.cpp concurrent.rl
+
+rlscan.cpp: rlscan.rl
+ $(RAGEL) -G2 -o rlscan.cpp rlscan.rl
+
+statechart.cpp: statechart.rl
+ $(RAGEL) -G2 -o statechart.cpp statechart.rl
+
+params.c: params.rl
+ $(RAGEL) -G2 -o params.c params.rl
+
+clang.c: clang.rl
+ $(RAGEL) -G2 -o clang.c clang.rl
+
+cppscan.cpp: cppscan.rl
+ $(RAGEL) -G2 -o $@ cppscan.rl
+
+format.c: format.rl
+ $(RAGEL) -G2 -o format.c format.rl
+
+awkemu.c: awkemu.rl
+ $(RAGEL) -G2 -o awkemu.c awkemu.rl
+
+mailbox.cpp: mailbox.rl
+ $(RAGEL) -G2 -o mailbox.cpp mailbox.rl
+
+atoi.cpp: atoi.rl
+ $(RAGEL) -G2 -o atoi.cpp atoi.rl
+
+###
+
+lex-cppscan.cpp: cppscan.lex
+ $(FLEX) -f -o $@ $<
+
+re2c-cppscan.cpp: cppscan.rec
+ $(RE2C) -s $< > $@
+
+example.cpp: example.rec
+ $(RE2C) -s $< > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000..12773cb
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,40 @@
+
+ Ragel State Machine Compiler -- Examples
+ ========================================
+
+atoi -- Converts a string to an integer.
+
+awkemu -- Perfoms the basic parsing that the awk program perfoms on input.
+ The awk equivalent to awkemu is in awkemu/awkequiv.awk
+
+clang -- A scanner for a simple C like language. It breaks input up into
+ words, numbers, strings and symbols and strips out whitespace
+ and comments. It is a suitable template for writing a parser
+ that finds a sequence of tokens.
+
+concurrent -- Demonstrates the ability of ragel to produce parsers that
+ perform independent tasks concurrently.
+
+cppscan -- A C++ scanner that uses the longest match scanning method. This
+ example differs from other examples of scanning. Each run of the
+ state machine matches one token. This method results in a
+ smaller state machine since the final kleene star is omitted and
+ therefore every state does not need to get all the transitions
+ of the start state.
+
+format -- Partial printf implementation.
+
+gotocallret -- Demonstrate the use of fgoto, fcall and fret.
+
+mailbox -- Parses unix mailbox files. It breaks files into messages, and
+ messages into headers and body. It demonstrates Ragel's ability
+ to make parsers for structured file formats.
+
+params -- Parses command line arguements.
+
+rlscan -- Lexes Ragel input files.
+
+statechart -- Demonstrate the use of labels, the epsilon operator, and the
+ join operator for creating machines using the named state and
+ transition list paradigm. This implementes the same machine as
+ the atoi example.
diff --git a/examples/atoi.cpp b/examples/atoi.cpp
new file mode 100644
index 0000000..45677f3
--- /dev/null
+++ b/examples/atoi.cpp
@@ -0,0 +1,120 @@
+
+#line 1 "atoi.rl"
+/*
+ * Convert a string to an integer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 13 "atoi.cpp"
+static const int atoi_start = 1;
+static const int atoi_first_final = 4;
+static const int atoi_error = 0;
+
+static const int atoi_en_main = 1;
+
+
+#line 12 "atoi.rl"
+
+
+long long atoi( char *str )
+{
+ char *p = str, *pe = str + strlen( str );
+ int cs;
+ long long val = 0;
+ bool neg = false;
+
+
+#line 32 "atoi.cpp"
+ {
+ cs = atoi_start;
+ }
+
+#line 37 "atoi.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+case 1:
+ switch( (*p) ) {
+ case 43: goto st2;
+ case 45: goto tr2;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3;
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+tr2:
+#line 22 "atoi.rl"
+ {
+ neg = true;
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 64 "atoi.cpp"
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3;
+ goto st0;
+tr3:
+#line 26 "atoi.rl"
+ {
+ val = val * 10 + ((*p) - '0');
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 78 "atoi.cpp"
+ if ( (*p) == 10 )
+ goto st4;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3;
+ goto st0;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ goto st0;
+ }
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 37 "atoi.rl"
+
+
+ if ( neg )
+ val = -1 * val;
+
+ if ( cs < atoi_first_final )
+ fprintf( stderr, "atoi: there was an error\n" );
+
+ return val;
+};
+
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 ) {
+ long long value = atoi( buf );
+ printf( "%lld\n", value );
+ }
+ return 0;
+}
diff --git a/examples/atoi.rl b/examples/atoi.rl
new file mode 100644
index 0000000..7164b68
--- /dev/null
+++ b/examples/atoi.rl
@@ -0,0 +1,59 @@
+/*
+ * Convert a string to an integer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+%%{
+ machine atoi;
+ write data;
+}%%
+
+long long atoi( char *str )
+{
+ char *p = str, *pe = str + strlen( str );
+ int cs;
+ long long val = 0;
+ bool neg = false;
+
+ %%{
+ action see_neg {
+ neg = true;
+ }
+
+ action add_digit {
+ val = val * 10 + (fc - '0');
+ }
+
+ main :=
+ ( '-'@see_neg | '+' )? ( digit @add_digit )+
+ '\n';
+
+ # Initialize and execute.
+ write init;
+ write exec;
+ }%%
+
+ if ( neg )
+ val = -1 * val;
+
+ if ( cs < atoi_first_final )
+ fprintf( stderr, "atoi: there was an error\n" );
+
+ return val;
+};
+
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 ) {
+ long long value = atoi( buf );
+ printf( "%lld\n", value );
+ }
+ return 0;
+}
diff --git a/examples/awkemu.c b/examples/awkemu.c
new file mode 100644
index 0000000..2fdcb01
--- /dev/null
+++ b/examples/awkemu.c
@@ -0,0 +1,217 @@
+
+#line 1 "awkemu.rl"
+/*
+ * Perform the basic line parsing of input performed by awk.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#line 55 "awkemu.rl"
+
+
+
+#line 18 "awkemu.c"
+static const int awkemu_start = 2;
+
+static const int awkemu_en_main = 2;
+
+
+#line 58 "awkemu.rl"
+
+#define MAXWORDS 256
+#define BUFSIZE 4096
+char buf[BUFSIZE];
+
+int main()
+{
+ int i, nwords = 0;
+ char *ls = 0;
+ char *ws[MAXWORDS];
+ char *we[MAXWORDS];
+
+ int cs;
+ int have = 0;
+
+
+#line 41 "awkemu.c"
+ {
+ cs = awkemu_start;
+ }
+
+#line 74 "awkemu.rl"
+
+ while ( 1 ) {
+ char *p, *pe, *data = buf + have;
+ int len, space = BUFSIZE - have;
+ /* fprintf( stderr, "space: %i\n", space ); */
+
+ if ( space == 0 ) {
+ fprintf(stderr, "buffer out of space\n");
+ exit(1);
+ }
+
+ len = fread( data, 1, space, stdin );
+ /* fprintf( stderr, "len: %i\n", len ); */
+ if ( len == 0 )
+ break;
+
+ /* Find the last newline by searching backwards. This is where
+ * we will stop processing on this iteration. */
+ p = buf;
+ pe = buf + have + len - 1;
+ while ( *pe != '\n' && pe >= buf )
+ pe--;
+ pe += 1;
+
+ /* fprintf( stderr, "running on: %i\n", pe - p ); */
+
+
+#line 74 "awkemu.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr2:
+#line 17 "awkemu.rl"
+ {
+ we[nwords++] = p;
+ }
+#line 26 "awkemu.rl"
+ {
+ printf("endline(%i): ", nwords );
+ fwrite( ls, 1, p - ls, stdout );
+ printf("\n");
+
+ for ( i = 0; i < nwords; i++ ) {
+ printf(" word: ");
+ fwrite( ws[i], 1, we[i] - ws[i], stdout );
+ printf("\n");
+ }
+ }
+ goto st2;
+tr5:
+#line 26 "awkemu.rl"
+ {
+ printf("endline(%i): ", nwords );
+ fwrite( ls, 1, p - ls, stdout );
+ printf("\n");
+
+ for ( i = 0; i < nwords; i++ ) {
+ printf(" word: ");
+ fwrite( ws[i], 1, we[i] - ws[i], stdout );
+ printf("\n");
+ }
+ }
+ goto st2;
+tr8:
+#line 21 "awkemu.rl"
+ {
+ nwords = 0;
+ ls = p;
+ }
+#line 26 "awkemu.rl"
+ {
+ printf("endline(%i): ", nwords );
+ fwrite( ls, 1, p - ls, stdout );
+ printf("\n");
+
+ for ( i = 0; i < nwords; i++ ) {
+ printf(" word: ");
+ fwrite( ws[i], 1, we[i] - ws[i], stdout );
+ printf("\n");
+ }
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 135 "awkemu.c"
+ switch( (*p) ) {
+ case 9: goto tr7;
+ case 10: goto tr8;
+ case 32: goto tr7;
+ }
+ goto tr6;
+tr3:
+#line 13 "awkemu.rl"
+ {
+ ws[nwords] = p;
+ }
+ goto st0;
+tr6:
+#line 21 "awkemu.rl"
+ {
+ nwords = 0;
+ ls = p;
+ }
+#line 13 "awkemu.rl"
+ {
+ ws[nwords] = p;
+ }
+ goto st0;
+st0:
+ if ( ++p == pe )
+ goto _test_eof0;
+case 0:
+#line 163 "awkemu.c"
+ switch( (*p) ) {
+ case 9: goto tr1;
+ case 10: goto tr2;
+ case 32: goto tr1;
+ }
+ goto st0;
+tr1:
+#line 17 "awkemu.rl"
+ {
+ we[nwords++] = p;
+ }
+ goto st1;
+tr7:
+#line 21 "awkemu.rl"
+ {
+ nwords = 0;
+ ls = p;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 187 "awkemu.c"
+ switch( (*p) ) {
+ case 9: goto st1;
+ case 10: goto tr5;
+ case 32: goto st1;
+ }
+ goto tr3;
+ }
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof0: cs = 0; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+
+ _test_eof: {}
+ }
+
+#line 101 "awkemu.rl"
+
+ /* How much is still in the buffer. */
+ have = data + len - pe;
+ if ( have > 0 )
+ memmove( buf, pe, have );
+
+ /* fprintf(stderr, "have: %i\n", have ); */
+
+ if ( len < space )
+ break;
+ }
+
+ if ( have > 0 )
+ fprintf(stderr, "input not newline terminated\n");
+ return 0;
+}
diff --git a/examples/awkemu.rl b/examples/awkemu.rl
new file mode 100644
index 0000000..6615943
--- /dev/null
+++ b/examples/awkemu.rl
@@ -0,0 +1,116 @@
+/*
+ * Perform the basic line parsing of input performed by awk.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+%%{
+ machine awkemu;
+
+ action start_word {
+ ws[nwords] = fpc;
+ }
+
+ action end_word {
+ we[nwords++] = fpc;
+ }
+
+ action start_line {
+ nwords = 0;
+ ls = fpc;
+ }
+
+ action end_line {
+ printf("endline(%i): ", nwords );
+ fwrite( ls, 1, p - ls, stdout );
+ printf("\n");
+
+ for ( i = 0; i < nwords; i++ ) {
+ printf(" word: ");
+ fwrite( ws[i], 1, we[i] - ws[i], stdout );
+ printf("\n");
+ }
+ }
+
+ # Words in a line.
+ word = ^[ \t\n]+;
+
+ # The whitespace separating words in a line.
+ whitespace = [ \t];
+
+ # The components in a line to break up. Either a word or a single char of
+ # whitespace. On the word capture characters.
+ blineElements = word >start_word %end_word | whitespace;
+
+ # Star the break line elements. Just be careful to decrement the leaving
+ # priority as we don't want multiple character identifiers to be treated as
+ # multiple single char identifiers.
+ line = ( blineElements** '\n' ) >start_line @end_line;
+
+ # Any number of lines.
+ main := line*;
+}%%
+
+%% write data noerror nofinal;
+
+#define MAXWORDS 256
+#define BUFSIZE 4096
+char buf[BUFSIZE];
+
+int main()
+{
+ int i, nwords = 0;
+ char *ls = 0;
+ char *ws[MAXWORDS];
+ char *we[MAXWORDS];
+
+ int cs;
+ int have = 0;
+
+ %% write init;
+
+ while ( 1 ) {
+ char *p, *pe, *data = buf + have;
+ int len, space = BUFSIZE - have;
+ /* fprintf( stderr, "space: %i\n", space ); */
+
+ if ( space == 0 ) {
+ fprintf(stderr, "buffer out of space\n");
+ exit(1);
+ }
+
+ len = fread( data, 1, space, stdin );
+ /* fprintf( stderr, "len: %i\n", len ); */
+ if ( len == 0 )
+ break;
+
+ /* Find the last newline by searching backwards. This is where
+ * we will stop processing on this iteration. */
+ p = buf;
+ pe = buf + have + len - 1;
+ while ( *pe != '\n' && pe >= buf )
+ pe--;
+ pe += 1;
+
+ /* fprintf( stderr, "running on: %i\n", pe - p ); */
+
+ %% write exec;
+
+ /* How much is still in the buffer. */
+ have = data + len - pe;
+ if ( have > 0 )
+ memmove( buf, pe, have );
+
+ /* fprintf(stderr, "have: %i\n", have ); */
+
+ if ( len < space )
+ break;
+ }
+
+ if ( have > 0 )
+ fprintf(stderr, "input not newline terminated\n");
+ return 0;
+}
diff --git a/examples/clang.c b/examples/clang.c
new file mode 100644
index 0000000..c8fb683
--- /dev/null
+++ b/examples/clang.c
@@ -0,0 +1,456 @@
+
+#line 1 "clang.rl"
+/*
+ * A mini C-like language scanner.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#line 91 "clang.rl"
+
+
+
+#line 17 "clang.c"
+static const int clang_start = 10;
+static const int clang_error = 0;
+
+static const int clang_en_c_comment = 8;
+static const int clang_en_main = 10;
+
+
+#line 94 "clang.rl"
+
+#define BUFSIZE 128
+
+void scanner()
+{
+ static char buf[BUFSIZE];
+ int cs, act, have = 0, curline = 1;
+ char *ts, *te = 0;
+ int done = 0;
+
+
+#line 37 "clang.c"
+ {
+ cs = clang_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 105 "clang.rl"
+
+ while ( !done ) {
+ char *p = buf + have, *pe, *eof = 0;
+ int len, space = BUFSIZE - have;
+
+ if ( space == 0 ) {
+ /* We've used up the entire buffer storing an already-parsed token
+ * prefix that must be preserved. */
+ fprintf(stderr, "OUT OF BUFFER SPACE\n" );
+ exit(1);
+ }
+
+ len = fread( p, 1, space, stdin );
+ pe = p + len;
+
+ /* Check if this is the end of file. */
+ if ( len < space ) {
+ eof = pe;
+ done = 1;
+ }
+
+
+#line 68 "clang.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr2:
+#line 50 "clang.rl"
+ {te = p+1;{
+ printf( "double_lit(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr6:
+#line 42 "clang.rl"
+ {te = p+1;{
+ printf( "single_lit(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr8:
+#line 28 "clang.rl"
+ {{p = ((te))-1;}{
+ printf( "symbol(%i): %c\n", curline, ts[0] );
+ }}
+ goto st10;
+tr10:
+#line 12 "clang.rl"
+ {curline += 1;}
+#line 62 "clang.rl"
+ {te = p+1;}
+ goto st10;
+tr11:
+#line 68 "clang.rl"
+ {{p = ((te))-1;}{
+ printf( "int(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr18:
+#line 57 "clang.rl"
+ {te = p+1;}
+ goto st10;
+tr19:
+#line 12 "clang.rl"
+ {curline += 1;}
+#line 57 "clang.rl"
+ {te = p+1;}
+ goto st10;
+tr20:
+#line 28 "clang.rl"
+ {te = p+1;{
+ printf( "symbol(%i): %c\n", curline, ts[0] );
+ }}
+ goto st10;
+tr25:
+#line 28 "clang.rl"
+ {te = p;p--;{
+ printf( "symbol(%i): %c\n", curline, ts[0] );
+ }}
+ goto st10;
+tr26:
+#line 64 "clang.rl"
+ {te = p+1;{ {goto st8;} }}
+ goto st10;
+tr27:
+#line 68 "clang.rl"
+ {te = p;p--;{
+ printf( "int(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr30:
+#line 76 "clang.rl"
+ {te = p;p--;{
+ printf( "float(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr31:
+#line 84 "clang.rl"
+ {te = p;p--;{
+ printf( "hex(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+tr32:
+#line 34 "clang.rl"
+ {te = p;p--;{
+ printf( "ident(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ }}
+ goto st10;
+st10:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 1 "NONE"
+ {ts = p;}
+#line 176 "clang.c"
+ switch( (*p) ) {
+ case 10: goto tr19;
+ case 34: goto st1;
+ case 39: goto st3;
+ case 47: goto tr21;
+ case 48: goto tr22;
+ case 95: goto st16;
+ }
+ if ( (*p) < 65 ) {
+ if ( (*p) < 49 ) {
+ if ( 33 <= (*p) && (*p) <= 46 )
+ goto tr20;
+ } else if ( (*p) > 57 ) {
+ if ( 58 <= (*p) && (*p) <= 64 )
+ goto tr20;
+ } else
+ goto tr23;
+ } else if ( (*p) > 90 ) {
+ if ( (*p) < 97 ) {
+ if ( 91 <= (*p) && (*p) <= 96 )
+ goto tr20;
+ } else if ( (*p) > 122 ) {
+ if ( 123 <= (*p) && (*p) <= 126 )
+ goto tr20;
+ } else
+ goto st16;
+ } else
+ goto st16;
+ goto tr18;
+tr1:
+#line 12 "clang.rl"
+ {curline += 1;}
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 214 "clang.c"
+ switch( (*p) ) {
+ case 10: goto tr1;
+ case 34: goto tr2;
+ case 92: goto st2;
+ }
+ goto st1;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ if ( (*p) == 10 )
+ goto tr1;
+ goto st1;
+tr5:
+#line 12 "clang.rl"
+ {curline += 1;}
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 236 "clang.c"
+ switch( (*p) ) {
+ case 10: goto tr5;
+ case 39: goto tr6;
+ case 92: goto st4;
+ }
+ goto st3;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ if ( (*p) == 10 )
+ goto tr5;
+ goto st3;
+tr21:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st11;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+#line 258 "clang.c"
+ switch( (*p) ) {
+ case 42: goto tr26;
+ case 47: goto st5;
+ }
+ goto tr25;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) == 10 )
+ goto tr10;
+ goto st5;
+tr22:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st12;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+#line 279 "clang.c"
+ switch( (*p) ) {
+ case 46: goto st6;
+ case 120: goto st7;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr23;
+ goto tr27;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st13;
+ goto tr11;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st13;
+ goto tr30;
+tr23:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st14;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+#line 309 "clang.c"
+ if ( (*p) == 46 )
+ goto st6;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr23;
+ goto tr27;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st15;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st15;
+ } else
+ goto st15;
+ goto tr11;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st15;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st15;
+ } else
+ goto st15;
+ goto tr31;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ if ( (*p) == 95 )
+ goto st16;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st16;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st16;
+ } else
+ goto st16;
+ goto tr32;
+tr15:
+#line 12 "clang.rl"
+ {curline += 1;}
+ goto st8;
+st8:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 366 "clang.c"
+ switch( (*p) ) {
+ case 10: goto tr15;
+ case 42: goto st9;
+ }
+ goto st8;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ switch( (*p) ) {
+ case 10: goto tr15;
+ case 42: goto st9;
+ case 47: goto tr17;
+ }
+ goto st8;
+tr17:
+#line 16 "clang.rl"
+ {{goto st10;}}
+ goto st17;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+#line 390 "clang.c"
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+ }
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 11: goto tr25;
+ case 5: goto tr8;
+ case 12: goto tr27;
+ case 6: goto tr11;
+ case 13: goto tr30;
+ case 14: goto tr27;
+ case 7: goto tr11;
+ case 15: goto tr31;
+ case 16: goto tr32;
+ }
+ }
+
+ _out: {}
+ }
+
+#line 127 "clang.rl"
+
+ if ( cs == clang_error ) {
+ fprintf(stderr, "PARSE ERROR\n" );
+ break;
+ }
+
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is a prefix to preserve, shift it over. */
+ have = pe - ts;
+ memmove( buf, ts, have );
+ te = buf + (te-ts);
+ ts = buf;
+ }
+ }
+}
+
+int main()
+{
+ scanner();
+ return 0;
+}
+
diff --git a/examples/clang.rl b/examples/clang.rl
new file mode 100644
index 0000000..60491e5
--- /dev/null
+++ b/examples/clang.rl
@@ -0,0 +1,150 @@
+/*
+ * A mini C-like language scanner.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+%%{
+ machine clang;
+
+ newline = '\n' @{curline += 1;};
+ any_count_line = any | newline;
+
+ # Consume a C comment.
+ c_comment := any_count_line* :>> '*/' @{fgoto main;};
+
+ main := |*
+
+ # Alpha numberic characters or underscore.
+ alnum_u = alnum | '_';
+
+ # Alpha charactres or underscore.
+ alpha_u = alpha | '_';
+
+ # Symbols. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving dump the symbol.
+ ( punct - [_'"] ) {
+ printf( "symbol(%i): %c\n", curline, ts[0] );
+ };
+
+ # Identifier. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving, dump the identifier.
+ alpha_u alnum_u* {
+ printf( "ident(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ # Single Quote.
+ sliteralChar = [^'\\] | newline | ( '\\' . any_count_line );
+ '\'' . sliteralChar* . '\'' {
+ printf( "single_lit(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ # Double Quote.
+ dliteralChar = [^"\\] | newline | ( '\\' any_count_line );
+ '"' . dliteralChar* . '"' {
+ printf( "double_lit(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ # Whitespace is standard ws, newlines and control codes.
+ any_count_line - 0x21..0x7e;
+
+ # Describe both c style comments and c++ style comments. The
+ # priority bump on tne terminator of the comments brings us
+ # out of the extend* which matches everything.
+ '//' [^\n]* newline;
+
+ '/*' { fgoto c_comment; };
+
+ # Match an integer. We don't bother clearing the buf or filling it.
+ # The float machine overlaps with int and it will do it.
+ digit+ {
+ printf( "int(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ # Match a float. Upon entering the machine clear the buf, buffer
+ # characters on every trans and dump the float upon leaving.
+ digit+ '.' digit+ {
+ printf( "float(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ # Match a hex. Upon entering the hex part, clear the buf, buffer characters
+ # on every trans and dump the hex on leaving transitions.
+ '0x' xdigit+ {
+ printf( "hex(%i): ", curline );
+ fwrite( ts, 1, te-ts, stdout );
+ printf("\n");
+ };
+
+ *|;
+}%%
+
+%% write data nofinal;
+
+#define BUFSIZE 128
+
+void scanner()
+{
+ static char buf[BUFSIZE];
+ int cs, act, have = 0, curline = 1;
+ char *ts, *te = 0;
+ int done = 0;
+
+ %% write init;
+
+ while ( !done ) {
+ char *p = buf + have, *pe, *eof = 0;
+ int len, space = BUFSIZE - have;
+
+ if ( space == 0 ) {
+ /* We've used up the entire buffer storing an already-parsed token
+ * prefix that must be preserved. */
+ fprintf(stderr, "OUT OF BUFFER SPACE\n" );
+ exit(1);
+ }
+
+ len = fread( p, 1, space, stdin );
+ pe = p + len;
+
+ /* Check if this is the end of file. */
+ if ( len < space ) {
+ eof = pe;
+ done = 1;
+ }
+
+ %% write exec;
+
+ if ( cs == clang_error ) {
+ fprintf(stderr, "PARSE ERROR\n" );
+ break;
+ }
+
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is a prefix to preserve, shift it over. */
+ have = pe - ts;
+ memmove( buf, ts, have );
+ te = buf + (te-ts);
+ ts = buf;
+ }
+ }
+}
+
+int main()
+{
+ scanner();
+ return 0;
+}
+
diff --git a/examples/concurrent.cpp b/examples/concurrent.cpp
new file mode 100644
index 0000000..c2278cb
--- /dev/null
+++ b/examples/concurrent.cpp
@@ -0,0 +1,986 @@
+
+#line 1 "concurrent.rl"
+/*
+ * Show off concurrent abilities.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+struct Concurrent
+{
+ int cur_char;
+ int start_word;
+ int start_comment;
+ int start_literal;
+
+ int cs;
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+
+#line 75 "concurrent.rl"
+
+
+
+#line 35 "concurrent.cpp"
+static const int Concurrent_start = 0;
+static const int Concurrent_first_final = 0;
+static const int Concurrent_error = -1;
+
+static const int Concurrent_en_main = 0;
+
+
+#line 78 "concurrent.rl"
+
+int Concurrent::init( )
+{
+
+#line 48 "concurrent.cpp"
+ {
+ cs = Concurrent_start;
+ }
+
+#line 82 "concurrent.rl"
+ cur_char = 0;
+ return 1;
+}
+
+int Concurrent::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+
+#line 65 "concurrent.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr1:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st0;
+tr5:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+ goto st0;
+tr19:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st0;
+tr46:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st0;
+st0:
+ if ( ++p == pe )
+ goto _test_eof0;
+case 0:
+#line 124 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr1;
+ case 39: goto tr2;
+ case 47: goto tr3;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr1;
+ goto tr0;
+tr0:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st1;
+tr4:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st1;
+tr18:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st1;
+tr45:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 175 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr5;
+ case 39: goto tr6;
+ case 47: goto tr7;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr5;
+ goto tr4;
+tr13:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st2;
+tr8:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st2;
+tr2:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st2;
+tr6:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st2;
+tr20:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st2;
+tr50:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st2;
+tr47:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 269 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr9;
+ case 39: goto tr10;
+ case 47: goto tr11;
+ case 92: goto tr12;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr9;
+ goto tr8;
+tr14:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st3;
+tr9:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+ goto st3;
+tr51:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 316 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr14;
+ case 39: goto tr15;
+ case 47: goto tr16;
+ case 92: goto tr17;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr14;
+ goto tr13;
+tr15:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st4;
+tr10:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st4;
+tr52:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 357 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr19;
+ case 39: goto tr20;
+ case 47: goto tr21;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr19;
+ goto tr18;
+tr3:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st5;
+tr7:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st5;
+tr21:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st5;
+tr48:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+#line 424 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr5;
+ case 39: goto tr6;
+ case 42: goto tr22;
+ case 47: goto tr7;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr5;
+ goto tr4;
+tr26:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st6;
+tr22:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st6;
+tr40:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st6;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+#line 465 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr23;
+ case 39: goto tr24;
+ case 42: goto tr25;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr23;
+ goto tr22;
+tr27:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st7;
+tr23:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+ goto st7;
+tr41:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+#line 511 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr27;
+ case 39: goto tr28;
+ case 42: goto tr29;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr27;
+ goto tr26;
+tr35:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st8;
+tr30:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st8;
+tr28:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st8;
+tr24:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st8;
+tr42:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+#line 50 "concurrent.rl"
+ {
+ start_literal = cur_char;
+ }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 579 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr31;
+ case 39: goto tr32;
+ case 42: goto tr33;
+ case 92: goto tr34;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr31;
+ goto tr30;
+tr36:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st9;
+tr31:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+ goto st9;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+#line 610 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr36;
+ case 39: goto tr37;
+ case 42: goto tr38;
+ case 92: goto tr39;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr36;
+ goto tr35;
+tr37:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st10;
+tr32:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 640 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr41;
+ case 39: goto tr42;
+ case 42: goto tr43;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr41;
+ goto tr40;
+tr29:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st11;
+tr25:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st11;
+tr43:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ goto st11;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+#line 680 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr23;
+ case 39: goto tr24;
+ case 42: goto tr25;
+ case 47: goto tr44;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr23;
+ goto tr22;
+tr44:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st12;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+#line 700 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr46;
+ case 39: goto tr47;
+ case 47: goto tr48;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr46;
+ goto tr45;
+tr38:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st13;
+tr33:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st13;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+#line 729 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr31;
+ case 39: goto tr32;
+ case 42: goto tr33;
+ case 47: goto tr49;
+ case 92: goto tr34;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr31;
+ goto tr30;
+tr49:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st14;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+#line 750 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr51;
+ case 39: goto tr52;
+ case 47: goto tr53;
+ case 92: goto tr54;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr51;
+ goto tr50;
+tr16:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st15;
+tr11:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st15;
+tr53:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+#line 42 "concurrent.rl"
+ {
+ start_comment = cur_char;
+ }
+ goto st15;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+#line 803 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr9;
+ case 39: goto tr10;
+ case 42: goto tr30;
+ case 47: goto tr11;
+ case 92: goto tr12;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr9;
+ goto tr8;
+tr17:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st16;
+tr12:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st16;
+tr54:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ goto st16;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+#line 845 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr9;
+ case 47: goto tr11;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr9;
+ goto tr8;
+tr39:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+#line 34 "concurrent.rl"
+ {
+ start_word = cur_char;
+ }
+ goto st17;
+tr34:
+#line 30 "concurrent.rl"
+ {
+ cur_char += 1;
+ }
+ goto st17;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+#line 873 "concurrent.cpp"
+ switch( (*p) ) {
+ case 32: goto tr31;
+ case 42: goto tr33;
+ }
+ if ( 9 <= (*p) && (*p) <= 13 )
+ goto tr31;
+ goto tr30;
+ }
+ _test_eof0: cs = 0; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 1:
+ case 2:
+ case 5:
+ case 6:
+ case 8:
+ case 11:
+ case 13:
+ case 15:
+ case 16:
+ case 17:
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+ break;
+ case 12:
+ case 14:
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 45 "concurrent.rl"
+ {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+ break;
+ case 4:
+ case 10:
+#line 37 "concurrent.rl"
+ {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+#line 53 "concurrent.rl"
+ {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+ break;
+#line 947 "concurrent.cpp"
+ }
+ }
+
+ }
+
+#line 93 "concurrent.rl"
+
+ if ( cs == Concurrent_error )
+ return -1;
+ if ( cs >= Concurrent_first_final )
+ return 1;
+ return 0;
+}
+
+int Concurrent::finish( )
+{
+ if ( cs == Concurrent_error )
+ return -1;
+ if ( cs >= Concurrent_first_final )
+ return 1;
+ return 0;
+}
+
+Concurrent concurrent;
+char buf[BUFSIZE];
+
+int main()
+{
+ concurrent.init();
+ while ( 1 ) {
+ int len = fread( buf, 1, BUFSIZE, stdin );
+ concurrent.execute( buf, len, len != BUFSIZE );
+ if ( len != BUFSIZE )
+ break;
+ }
+
+ if ( concurrent.finish() <= 0 )
+ cerr << "concurrent: error parsing input" << endl;
+ return 0;
+}
diff --git a/examples/concurrent.rl b/examples/concurrent.rl
new file mode 100644
index 0000000..224f960
--- /dev/null
+++ b/examples/concurrent.rl
@@ -0,0 +1,126 @@
+/*
+ * Show off concurrent abilities.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+struct Concurrent
+{
+ int cur_char;
+ int start_word;
+ int start_comment;
+ int start_literal;
+
+ int cs;
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+%%{
+ machine Concurrent;
+
+ action next_char {
+ cur_char += 1;
+ }
+
+ action start_word {
+ start_word = cur_char;
+ }
+ action end_word {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+
+ action start_comment {
+ start_comment = cur_char;
+ }
+ action end_comment {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+
+ action start_literal {
+ start_literal = cur_char;
+ }
+ action end_literal {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+
+ # Count characters.
+ chars = ( any @next_char )*;
+
+ # Words are non-whitespace.
+ word = ( any-space )+ >start_word %end_word;
+ words = ( ( word | space ) $1 %0 )*;
+
+ # Finds C style comments.
+ comment = ( '/*' any* :>> '*/' ) >start_comment %end_comment;
+ comments = ( comment | any )**;
+
+ # Finds single quoted strings.
+ literalChar = ( any - ['\\] ) | ( '\\' . any );
+ literal = ('\'' literalChar* '\'' ) >start_literal %end_literal;
+ literals = ( ( literal | (any-'\'') ) $1 %0 )*;
+
+ main := chars | words | comments | literals;
+}%%
+
+%% write data;
+
+int Concurrent::init( )
+{
+ %% write init;
+ cur_char = 0;
+ return 1;
+}
+
+int Concurrent::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+ %% write exec;
+
+ if ( cs == Concurrent_error )
+ return -1;
+ if ( cs >= Concurrent_first_final )
+ return 1;
+ return 0;
+}
+
+int Concurrent::finish( )
+{
+ if ( cs == Concurrent_error )
+ return -1;
+ if ( cs >= Concurrent_first_final )
+ return 1;
+ return 0;
+}
+
+Concurrent concurrent;
+char buf[BUFSIZE];
+
+int main()
+{
+ concurrent.init();
+ while ( 1 ) {
+ int len = fread( buf, 1, BUFSIZE, stdin );
+ concurrent.execute( buf, len, len != BUFSIZE );
+ if ( len != BUFSIZE )
+ break;
+ }
+
+ if ( concurrent.finish() <= 0 )
+ cerr << "concurrent: error parsing input" << endl;
+ return 0;
+}
diff --git a/examples/cppscan.cpp b/examples/cppscan.cpp
new file mode 100644
index 0000000..6894311
--- /dev/null
+++ b/examples/cppscan.cpp
@@ -0,0 +1,908 @@
+
+#line 1 "cppscan.rl"
+/*
+ * A C++ scanner. Uses the longest match construction.
+ * << <= <<= >> >= >>= are left out since angle brackets are used in templates.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+
+#define TK_Dlit 256
+#define TK_Slit 257
+#define TK_Float 258
+#define TK_Id 259
+#define TK_NameSep 260
+#define TK_Arrow 261
+#define TK_PlusPlus 262
+#define TK_MinusMinus 263
+#define TK_ArrowStar 264
+#define TK_DotStar 265
+#define TK_ShiftLeft 266
+#define TK_ShiftRight 267
+#define TK_IntegerDecimal 268
+#define TK_IntegerOctal 269
+#define TK_IntegerHex 270
+#define TK_EqualsEquals 271
+#define TK_NotEquals 272
+#define TK_AndAnd 273
+#define TK_OrOr 274
+#define TK_MultAssign 275
+#define TK_DivAssign 276
+#define TK_PercentAssign 277
+#define TK_PlusAssign 278
+#define TK_MinusAssign 279
+#define TK_AmpAssign 280
+#define TK_CaretAssign 281
+#define TK_BarAssign 282
+#define TK_DotDotDot 283
+#define TK_Whitespace 284
+#define TK_Comment 285
+
+#define BUFSIZE 16384
+
+/* EOF char used to flush out that last token. This should be a whitespace
+ * token. */
+
+#define LAST_CHAR 0
+
+using std::cerr;
+using std::cout;
+using std::cin;
+using std::endl;
+
+static char buf[BUFSIZE];
+static int line = 1, col = 1;
+static char *ts, *te;
+static int act, have = 0;
+static int cs;
+
+
+#line 63 "cppscan.cpp"
+static const int Scanner_start = 12;
+static const int Scanner_error = 0;
+
+static const int Scanner_en_c_comment = 10;
+static const int Scanner_en_main = 12;
+
+
+#line 132 "cppscan.rl"
+
+
+void token( int tok )
+{
+ char *data = ts;
+ int len = te - ts;
+
+ cout << '<' << tok << "> ";
+ cout.write( data, len );
+ cout << '\n';
+
+ /* Count newlines and columns. This code is here mainly for having some
+ * code in the token routine when commenting out the above output during
+ * performance testing. */
+ for ( int i = 0; i < len; i ++ ) {
+ if ( data[i] == '\n' ) {
+ line += 1;
+ col = 1;
+ }
+ else {
+ col += 1;
+ }
+ }
+}
+
+int main()
+{
+ std::ios::sync_with_stdio(false);
+
+
+#line 102 "cppscan.cpp"
+ {
+ cs = Scanner_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 162 "cppscan.rl"
+
+ /* Do the first read. */
+ bool done = false;
+ while ( !done ) {
+ char *p = buf + have;
+ int space = BUFSIZE - have;
+
+ if ( space == 0 ) {
+ /* We filled up the buffer trying to scan a token. */
+ cerr << "OUT OF BUFFER SPACE" << endl;
+ exit(1);
+ }
+
+ cin.read( p, space );
+ int len = cin.gcount();
+ char *pe = p + len;
+ char *eof = 0;
+
+ /* If we see eof then append the EOF char. */
+ if ( cin.eof() ) {
+ eof = pe;
+ done = true;
+ }
+
+
+#line 136 "cppscan.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr0:
+#line 1 "NONE"
+ { switch( act ) {
+ case 0:
+ {{goto st0;}}
+ break;
+ case 3:
+ {{p = ((te))-1;}token( TK_Id );}
+ break;
+ case 4:
+ {{p = ((te))-1;}token( TK_Float );}
+ break;
+ case 5:
+ {{p = ((te))-1;}token( TK_IntegerDecimal );}
+ break;
+ case 6:
+ {{p = ((te))-1;}token( TK_IntegerOctal );}
+ break;
+ }
+ }
+ goto st12;
+tr2:
+#line 78 "cppscan.rl"
+ {te = p+1;{token( TK_Dlit );}}
+ goto st12;
+tr5:
+#line 76 "cppscan.rl"
+ {te = p+1;{token( TK_Slit );}}
+ goto st12;
+tr7:
+#line 124 "cppscan.rl"
+ {{p = ((te))-1;}{token( ts[0] );}}
+ goto st12;
+tr8:
+#line 121 "cppscan.rl"
+ {te = p+1;{token( TK_DotDotDot );}}
+ goto st12;
+tr12:
+#line 128 "cppscan.rl"
+ {te = p+1;}
+ goto st12;
+tr13:
+#line 90 "cppscan.rl"
+ {{p = ((te))-1;}{token( TK_IntegerDecimal );}}
+ goto st12;
+tr20:
+#line 124 "cppscan.rl"
+ {te = p+1;{token( ts[0] );}}
+ goto st12;
+tr36:
+#line 129 "cppscan.rl"
+ {te = p;p--;}
+ goto st12;
+tr37:
+#line 124 "cppscan.rl"
+ {te = p;p--;{token( ts[0] );}}
+ goto st12;
+tr38:
+#line 103 "cppscan.rl"
+ {te = p+1;{token( TK_NotEquals );}}
+ goto st12;
+tr39:
+#line 108 "cppscan.rl"
+ {te = p+1;{token( TK_PercentAssign );}}
+ goto st12;
+tr40:
+#line 104 "cppscan.rl"
+ {te = p+1;{token( TK_AndAnd );}}
+ goto st12;
+tr41:
+#line 111 "cppscan.rl"
+ {te = p+1;{token( TK_AmpAssign );}}
+ goto st12;
+tr42:
+#line 106 "cppscan.rl"
+ {te = p+1;{token( TK_MultAssign );}}
+ goto st12;
+tr43:
+#line 114 "cppscan.rl"
+ {te = p+1;{token( TK_PlusPlus );}}
+ goto st12;
+tr44:
+#line 109 "cppscan.rl"
+ {te = p+1;{token( TK_PlusAssign );}}
+ goto st12;
+tr45:
+#line 115 "cppscan.rl"
+ {te = p+1;{token( TK_MinusMinus );}}
+ goto st12;
+tr46:
+#line 110 "cppscan.rl"
+ {te = p+1;{token( TK_MinusAssign );}}
+ goto st12;
+tr48:
+#line 116 "cppscan.rl"
+ {te = p;p--;{token( TK_Arrow );}}
+ goto st12;
+tr49:
+#line 117 "cppscan.rl"
+ {te = p+1;{token( TK_ArrowStar );}}
+ goto st12;
+tr50:
+#line 118 "cppscan.rl"
+ {te = p+1;{token( TK_DotStar );}}
+ goto st12;
+tr53:
+#line 86 "cppscan.rl"
+ {te = p;p--;{token( TK_Float );}}
+ goto st12;
+tr55:
+#line 86 "cppscan.rl"
+ {te = p+1;{token( TK_Float );}}
+ goto st12;
+tr56:
+#line 127 "cppscan.rl"
+ {te = p+1;{ {goto st10;} }}
+ goto st12;
+tr57:
+#line 107 "cppscan.rl"
+ {te = p+1;{token( TK_DivAssign );}}
+ goto st12;
+tr58:
+#line 90 "cppscan.rl"
+ {te = p;p--;{token( TK_IntegerDecimal );}}
+ goto st12;
+tr62:
+#line 94 "cppscan.rl"
+ {te = p;p--;{token( TK_IntegerOctal );}}
+ goto st12;
+tr64:
+#line 94 "cppscan.rl"
+ {te = p+1;{token( TK_IntegerOctal );}}
+ goto st12;
+tr66:
+#line 90 "cppscan.rl"
+ {te = p+1;{token( TK_IntegerDecimal );}}
+ goto st12;
+tr67:
+#line 98 "cppscan.rl"
+ {te = p;p--;{token( TK_IntegerHex );}}
+ goto st12;
+tr69:
+#line 98 "cppscan.rl"
+ {te = p+1;{token( TK_IntegerHex );}}
+ goto st12;
+tr70:
+#line 101 "cppscan.rl"
+ {te = p+1;{token( TK_NameSep );}}
+ goto st12;
+tr71:
+#line 102 "cppscan.rl"
+ {te = p+1;{token( TK_EqualsEquals );}}
+ goto st12;
+tr72:
+#line 82 "cppscan.rl"
+ {te = p;p--;{token( TK_Id );}}
+ goto st12;
+tr73:
+#line 112 "cppscan.rl"
+ {te = p+1;{token( TK_CaretAssign );}}
+ goto st12;
+tr74:
+#line 113 "cppscan.rl"
+ {te = p+1;{token( TK_BarAssign );}}
+ goto st12;
+tr75:
+#line 105 "cppscan.rl"
+ {te = p+1;{token( TK_OrOr );}}
+ goto st12;
+st12:
+#line 1 "NONE"
+ {ts = 0;}
+#line 1 "NONE"
+ {act = 0;}
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+#line 1 "NONE"
+ {ts = p;}
+#line 321 "cppscan.cpp"
+ switch( (*p) ) {
+ case 33: goto st14;
+ case 34: goto st1;
+ case 37: goto st15;
+ case 38: goto st16;
+ case 39: goto st3;
+ case 42: goto st17;
+ case 43: goto st18;
+ case 45: goto st19;
+ case 46: goto tr26;
+ case 47: goto tr27;
+ case 48: goto tr28;
+ case 58: goto st33;
+ case 61: goto st34;
+ case 76: goto tr33;
+ case 94: goto st37;
+ case 95: goto st35;
+ case 124: goto st38;
+ }
+ if ( (*p) < 65 ) {
+ if ( (*p) < 49 ) {
+ if ( 35 <= (*p) && (*p) <= 44 )
+ goto tr20;
+ } else if ( (*p) > 57 ) {
+ if ( 59 <= (*p) && (*p) <= 64 )
+ goto tr20;
+ } else
+ goto tr29;
+ } else if ( (*p) > 90 ) {
+ if ( (*p) < 97 ) {
+ if ( 91 <= (*p) && (*p) <= 96 )
+ goto tr20;
+ } else if ( (*p) > 122 ) {
+ if ( 123 <= (*p) && (*p) <= 126 )
+ goto tr20;
+ } else
+ goto st35;
+ } else
+ goto st35;
+ goto st13;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ if ( 33 <= (*p) && (*p) <= 126 )
+ goto tr36;
+ goto st13;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ if ( (*p) == 61 )
+ goto tr38;
+ goto tr37;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ switch( (*p) ) {
+ case 10: goto tr0;
+ case 34: goto tr2;
+ case 92: goto st2;
+ }
+ goto st1;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ goto st1;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ if ( (*p) == 61 )
+ goto tr39;
+ goto tr37;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ switch( (*p) ) {
+ case 38: goto tr40;
+ case 61: goto tr41;
+ }
+ goto tr37;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ switch( (*p) ) {
+ case 10: goto tr0;
+ case 39: goto tr5;
+ case 92: goto st4;
+ }
+ goto st3;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ goto st3;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ if ( (*p) == 61 )
+ goto tr42;
+ goto tr37;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+ switch( (*p) ) {
+ case 43: goto tr43;
+ case 61: goto tr44;
+ }
+ goto tr37;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ switch( (*p) ) {
+ case 45: goto tr45;
+ case 61: goto tr46;
+ case 62: goto st20;
+ }
+ goto tr37;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+ if ( (*p) == 42 )
+ goto tr49;
+ goto tr48;
+tr26:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st21;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+#line 463 "cppscan.cpp"
+ switch( (*p) ) {
+ case 42: goto tr50;
+ case 46: goto st5;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr52;
+ goto tr37;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) == 46 )
+ goto tr8;
+ goto tr7;
+tr52:
+#line 1 "NONE"
+ {te = p+1;}
+#line 86 "cppscan.rl"
+ {act = 4;}
+ goto st22;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+#line 488 "cppscan.cpp"
+ switch( (*p) ) {
+ case 69: goto st6;
+ case 70: goto tr55;
+ case 76: goto tr55;
+ case 101: goto st6;
+ case 102: goto tr55;
+ case 108: goto tr55;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr52;
+ goto tr53;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ switch( (*p) ) {
+ case 43: goto st7;
+ case 45: goto st7;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st23;
+ goto tr0;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st23;
+ goto tr0;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ switch( (*p) ) {
+ case 70: goto tr55;
+ case 76: goto tr55;
+ case 102: goto tr55;
+ case 108: goto tr55;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st23;
+ goto tr53;
+tr27:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st24;
+st24:
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+#line 539 "cppscan.cpp"
+ switch( (*p) ) {
+ case 42: goto tr56;
+ case 47: goto st8;
+ case 61: goto tr57;
+ }
+ goto tr37;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ if ( (*p) == 10 )
+ goto tr12;
+ goto st8;
+tr28:
+#line 1 "NONE"
+ {te = p+1;}
+#line 90 "cppscan.rl"
+ {act = 5;}
+ goto st25;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+#line 563 "cppscan.cpp"
+ switch( (*p) ) {
+ case 46: goto tr52;
+ case 69: goto st6;
+ case 76: goto st28;
+ case 85: goto st28;
+ case 101: goto st6;
+ case 108: goto st28;
+ case 117: goto st28;
+ case 120: goto st9;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr59;
+ goto tr58;
+tr59:
+#line 1 "NONE"
+ {te = p+1;}
+#line 94 "cppscan.rl"
+ {act = 6;}
+ goto st26;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+#line 587 "cppscan.cpp"
+ switch( (*p) ) {
+ case 46: goto tr52;
+ case 69: goto st6;
+ case 76: goto st27;
+ case 85: goto st27;
+ case 101: goto st6;
+ case 108: goto st27;
+ case 117: goto st27;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr59;
+ goto tr62;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+ switch( (*p) ) {
+ case 76: goto tr64;
+ case 85: goto tr64;
+ case 108: goto tr64;
+ case 117: goto tr64;
+ }
+ goto tr62;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+ switch( (*p) ) {
+ case 76: goto st29;
+ case 85: goto st29;
+ case 108: goto st29;
+ case 117: goto st29;
+ }
+ goto tr58;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+ switch( (*p) ) {
+ case 76: goto tr66;
+ case 85: goto tr66;
+ case 108: goto tr66;
+ case 117: goto tr66;
+ }
+ goto tr58;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st30;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st30;
+ } else
+ goto st30;
+ goto tr13;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+ switch( (*p) ) {
+ case 76: goto st31;
+ case 85: goto st31;
+ case 108: goto st31;
+ case 117: goto st31;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st30;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st30;
+ } else
+ goto st30;
+ goto tr67;
+st31:
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+ switch( (*p) ) {
+ case 76: goto tr69;
+ case 85: goto tr69;
+ case 108: goto tr69;
+ case 117: goto tr69;
+ }
+ goto tr67;
+tr29:
+#line 1 "NONE"
+ {te = p+1;}
+#line 90 "cppscan.rl"
+ {act = 5;}
+ goto st32;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+#line 686 "cppscan.cpp"
+ switch( (*p) ) {
+ case 46: goto tr52;
+ case 69: goto st6;
+ case 76: goto st28;
+ case 85: goto st28;
+ case 101: goto st6;
+ case 108: goto st28;
+ case 117: goto st28;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr29;
+ goto tr58;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+ if ( (*p) == 58 )
+ goto tr70;
+ goto tr37;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+ if ( (*p) == 61 )
+ goto tr71;
+ goto tr37;
+st35:
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+ if ( (*p) == 95 )
+ goto st35;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st35;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st35;
+ } else
+ goto st35;
+ goto tr72;
+tr33:
+#line 1 "NONE"
+ {te = p+1;}
+#line 82 "cppscan.rl"
+ {act = 3;}
+ goto st36;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+#line 738 "cppscan.cpp"
+ switch( (*p) ) {
+ case 34: goto st1;
+ case 39: goto st3;
+ case 95: goto st35;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st35;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st35;
+ } else
+ goto st35;
+ goto tr72;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+ if ( (*p) == 61 )
+ goto tr73;
+ goto tr37;
+st38:
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+ switch( (*p) ) {
+ case 61: goto tr74;
+ case 124: goto tr75;
+ }
+ goto tr37;
+st10:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 775 "cppscan.cpp"
+ if ( (*p) == 42 )
+ goto st11;
+ goto st10;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ switch( (*p) ) {
+ case 42: goto st11;
+ case 47: goto tr17;
+ }
+ goto st10;
+tr17:
+#line 70 "cppscan.rl"
+ { {goto st12;} }
+ goto st39;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+#line 796 "cppscan.cpp"
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+ }
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 13: goto tr36;
+ case 14: goto tr37;
+ case 1: goto tr0;
+ case 2: goto tr0;
+ case 15: goto tr37;
+ case 16: goto tr37;
+ case 3: goto tr0;
+ case 4: goto tr0;
+ case 17: goto tr37;
+ case 18: goto tr37;
+ case 19: goto tr37;
+ case 20: goto tr48;
+ case 21: goto tr37;
+ case 5: goto tr7;
+ case 22: goto tr53;
+ case 6: goto tr0;
+ case 7: goto tr0;
+ case 23: goto tr53;
+ case 24: goto tr37;
+ case 8: goto tr7;
+ case 25: goto tr58;
+ case 26: goto tr62;
+ case 27: goto tr62;
+ case 28: goto tr58;
+ case 29: goto tr58;
+ case 9: goto tr13;
+ case 30: goto tr67;
+ case 31: goto tr67;
+ case 32: goto tr58;
+ case 33: goto tr37;
+ case 34: goto tr37;
+ case 35: goto tr72;
+ case 36: goto tr72;
+ case 37: goto tr37;
+ case 38: goto tr37;
+ }
+ }
+
+ _out: {}
+ }
+
+#line 187 "cppscan.rl"
+
+ /* Check if we failed. */
+ if ( cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+
+ /* Now set up the prefix. */
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is data that needs to be shifted over. */
+ have = pe - ts;
+ memmove( buf, ts, have );
+ te -= (ts-buf);
+ ts = buf;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/cppscan.rl b/examples/cppscan.rl
new file mode 100644
index 0000000..1ead5aa
--- /dev/null
+++ b/examples/cppscan.rl
@@ -0,0 +1,208 @@
+/*
+ * A C++ scanner. Uses the longest match construction.
+ * << <= <<= >> >= >>= are left out since angle brackets are used in templates.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+
+#define TK_Dlit 256
+#define TK_Slit 257
+#define TK_Float 258
+#define TK_Id 259
+#define TK_NameSep 260
+#define TK_Arrow 261
+#define TK_PlusPlus 262
+#define TK_MinusMinus 263
+#define TK_ArrowStar 264
+#define TK_DotStar 265
+#define TK_ShiftLeft 266
+#define TK_ShiftRight 267
+#define TK_IntegerDecimal 268
+#define TK_IntegerOctal 269
+#define TK_IntegerHex 270
+#define TK_EqualsEquals 271
+#define TK_NotEquals 272
+#define TK_AndAnd 273
+#define TK_OrOr 274
+#define TK_MultAssign 275
+#define TK_DivAssign 276
+#define TK_PercentAssign 277
+#define TK_PlusAssign 278
+#define TK_MinusAssign 279
+#define TK_AmpAssign 280
+#define TK_CaretAssign 281
+#define TK_BarAssign 282
+#define TK_DotDotDot 283
+#define TK_Whitespace 284
+#define TK_Comment 285
+
+#define BUFSIZE 16384
+
+/* EOF char used to flush out that last token. This should be a whitespace
+ * token. */
+
+#define LAST_CHAR 0
+
+using std::cerr;
+using std::cout;
+using std::cin;
+using std::endl;
+
+static char buf[BUFSIZE];
+static int line = 1, col = 1;
+static char *ts, *te;
+static int act, have = 0;
+static int cs;
+
+%%{
+ machine Scanner;
+ write data nofinal;
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ c_comment :=
+ any* :>> '*/'
+ @{ fgoto main; };
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" )
+ {token( TK_Slit );};
+ ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' )
+ {token( TK_Dlit );};
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* )
+ {token( TK_Id );};
+
+ # Floating literals.
+ ( fract_const exponent? float_suffix? | digit+ exponent float_suffix? )
+ {token( TK_Float );};
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )
+ {token( TK_IntegerDecimal );};
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]{0,2} )
+ {token( TK_IntegerOctal );};
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) )
+ {token( TK_IntegerHex );};
+
+ # Only buffer the second item, first buffered by symbol. */
+ '::' {token( TK_NameSep );};
+ '==' {token( TK_EqualsEquals );};
+ '!=' {token( TK_NotEquals );};
+ '&&' {token( TK_AndAnd );};
+ '||' {token( TK_OrOr );};
+ '*=' {token( TK_MultAssign );};
+ '/=' {token( TK_DivAssign );};
+ '%=' {token( TK_PercentAssign );};
+ '+=' {token( TK_PlusAssign );};
+ '-=' {token( TK_MinusAssign );};
+ '&=' {token( TK_AmpAssign );};
+ '^=' {token( TK_CaretAssign );};
+ '|=' {token( TK_BarAssign );};
+ '++' {token( TK_PlusPlus );};
+ '--' {token( TK_MinusMinus );};
+ '->' {token( TK_Arrow );};
+ '->*' {token( TK_ArrowStar );};
+ '.*' {token( TK_DotStar );};
+
+ # Three char compounds, first item already buffered. */
+ '...' {token( TK_DotDotDot );};
+
+ # Single char symbols.
+ ( punct - [_"'] ) {token( ts[0] );};
+
+ # Comments and whitespace.
+ '/*' { fgoto c_comment; };
+ '//' [^\n]* '\n';
+ ( any - 33..126 )+;
+
+ *|;
+}%%
+
+void token( int tok )
+{
+ char *data = ts;
+ int len = te - ts;
+
+ cout << '<' << tok << "> ";
+ cout.write( data, len );
+ cout << '\n';
+
+ /* Count newlines and columns. This code is here mainly for having some
+ * code in the token routine when commenting out the above output during
+ * performance testing. */
+ for ( int i = 0; i < len; i ++ ) {
+ if ( data[i] == '\n' ) {
+ line += 1;
+ col = 1;
+ }
+ else {
+ col += 1;
+ }
+ }
+}
+
+int main()
+{
+ std::ios::sync_with_stdio(false);
+
+ %% write init;
+
+ /* Do the first read. */
+ bool done = false;
+ while ( !done ) {
+ char *p = buf + have;
+ int space = BUFSIZE - have;
+
+ if ( space == 0 ) {
+ /* We filled up the buffer trying to scan a token. */
+ cerr << "OUT OF BUFFER SPACE" << endl;
+ exit(1);
+ }
+
+ cin.read( p, space );
+ int len = cin.gcount();
+ char *pe = p + len;
+ char *eof = 0;
+
+ /* If we see eof then append the EOF char. */
+ if ( cin.eof() ) {
+ eof = pe;
+ done = true;
+ }
+
+ %% write exec;
+
+ /* Check if we failed. */
+ if ( cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+
+ /* Now set up the prefix. */
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is data that needs to be shifted over. */
+ have = pe - ts;
+ memmove( buf, ts, have );
+ te -= (ts-buf);
+ ts = buf;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/format.c b/examples/format.c
new file mode 100644
index 0000000..768b063
--- /dev/null
+++ b/examples/format.c
@@ -0,0 +1,544 @@
+
+#line 1 "format.rl"
+/*
+ * Partial printf implementation.
+ */
+
+#define BUFLEN 1024
+#include <stdio.h>
+
+typedef void (*WriteFunc)( char *data, int len );
+
+struct format
+{
+ char buf[BUFLEN+1];
+ int buflen;
+ WriteFunc write;
+
+ int flags;
+ int width;
+ int prec;
+ int cs;
+};
+
+void do_conv( struct format *fsm, char c )
+{
+ printf( "flags: %x\n", fsm->flags );
+ printf( "width: %i\n", fsm->width );
+ printf( "prec: %i\n", fsm->prec );
+ printf( "conv: %c\n", c );
+ printf( "\n" );
+}
+
+#define FL_HASH 0x01
+#define FL_ZERO 0x02
+#define FL_DASH 0x04
+#define FL_SPACE 0x08
+#define FL_PLUS 0x10
+
+#define FL_HAS_WIDTH 0x0100
+#define FL_WIDTH_ARG 0x0200
+#define FL_HAS_PREC 0x0400
+#define FL_PREC_ARG 0x0800
+
+#define FL_LEN_H 0x010000
+#define FL_LEN_HH 0x020000
+#define FL_LEN_L 0x040000
+#define FL_LEN_LL 0x080000
+
+
+#line 137 "format.rl"
+
+
+
+#line 55 "format.c"
+static const int format_start = 11;
+static const int format_first_final = 11;
+static const int format_error = 0;
+
+static const int format_en_main = 11;
+
+
+#line 140 "format.rl"
+
+void format_init( struct format *fsm )
+{
+ fsm->buflen = 0;
+
+#line 69 "format.c"
+ {
+ fsm->cs = format_start;
+ }
+
+#line 145 "format.rl"
+}
+
+void format_execute( struct format *fsm, const char *data, int len, int isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+
+#line 84 "format.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( fsm->cs )
+ {
+tr3:
+#line 113 "format.rl"
+ {
+ if ( fsm->buflen == BUFLEN ) {
+ fsm->write( fsm->buf, fsm->buflen );
+ fsm->buflen = 0;
+ }
+ fsm->buf[fsm->buflen++] = (*p);
+ }
+ goto st11;
+tr10:
+#line 99 "format.rl"
+ {
+ do_conv( fsm, (*p) );
+ }
+ goto st11;
+tr14:
+#line 63 "format.rl"
+ { fsm->flags |= FL_HAS_WIDTH; }
+#line 99 "format.rl"
+ {
+ do_conv( fsm, (*p) );
+ }
+ goto st11;
+tr19:
+#line 69 "format.rl"
+ { fsm->flags |= FL_HAS_PREC; }
+#line 99 "format.rl"
+ {
+ do_conv( fsm, (*p) );
+ }
+ goto st11;
+tr22:
+#line 86 "format.rl"
+ { fsm->flags |= FL_LEN_H; }
+#line 99 "format.rl"
+ {
+ do_conv( fsm, (*p) );
+ }
+ goto st11;
+tr24:
+#line 87 "format.rl"
+ { fsm->flags |= FL_LEN_L; }
+#line 99 "format.rl"
+ {
+ do_conv( fsm, (*p) );
+ }
+ goto st11;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+#line 142 "format.c"
+ if ( (*p) == 37 )
+ goto tr26;
+ goto tr3;
+tr26:
+#line 51 "format.rl"
+ {
+ fsm->flags = 0;
+ fsm->width = 0;
+ fsm->prec = 0;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 158 "format.c"
+ switch( (*p) ) {
+ case 32: goto tr1;
+ case 35: goto tr2;
+ case 37: goto tr3;
+ case 42: goto tr4;
+ case 43: goto tr5;
+ case 45: goto tr6;
+ case 46: goto st4;
+ case 48: goto tr8;
+ case 88: goto tr10;
+ case 104: goto st6;
+ case 105: goto tr10;
+ case 108: goto st8;
+ case 115: goto tr10;
+ case 117: goto tr10;
+ case 120: goto tr10;
+ }
+ if ( (*p) < 99 ) {
+ if ( 49 <= (*p) && (*p) <= 57 )
+ goto tr9;
+ } else if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr10;
+ } else
+ goto tr10;
+ goto tr0;
+tr0:
+#line 128 "format.rl"
+ {
+ printf("ERROR ON CHAR: 0x%x\n", (*p) );
+ }
+ goto st0;
+#line 191 "format.c"
+st0:
+ fsm->cs = 0;
+ goto _out;
+tr1:
+#line 76 "format.rl"
+ { fsm->flags |= FL_SPACE; }
+ goto st2;
+tr2:
+#line 73 "format.rl"
+ { fsm->flags |= FL_HASH; }
+ goto st2;
+tr5:
+#line 77 "format.rl"
+ { fsm->flags |= FL_PLUS; }
+ goto st2;
+tr6:
+#line 75 "format.rl"
+ { fsm->flags |= FL_DASH; }
+ goto st2;
+tr8:
+#line 74 "format.rl"
+ { fsm->flags |= FL_ZERO; }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 219 "format.c"
+ switch( (*p) ) {
+ case 32: goto tr1;
+ case 35: goto tr2;
+ case 42: goto tr4;
+ case 43: goto tr5;
+ case 45: goto tr6;
+ case 46: goto st4;
+ case 48: goto tr8;
+ case 88: goto tr10;
+ case 104: goto st6;
+ case 105: goto tr10;
+ case 108: goto st8;
+ case 115: goto tr10;
+ case 117: goto tr10;
+ case 120: goto tr10;
+ }
+ if ( (*p) < 99 ) {
+ if ( 49 <= (*p) && (*p) <= 57 )
+ goto tr9;
+ } else if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr10;
+ } else
+ goto tr10;
+ goto tr0;
+tr4:
+#line 62 "format.rl"
+ { fsm->flags |= FL_WIDTH_ARG; }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 253 "format.c"
+ switch( (*p) ) {
+ case 46: goto tr13;
+ case 88: goto tr14;
+ case 104: goto tr15;
+ case 105: goto tr14;
+ case 108: goto tr16;
+ case 115: goto tr14;
+ case 117: goto tr14;
+ case 120: goto tr14;
+ }
+ if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr14;
+ } else if ( (*p) >= 99 )
+ goto tr14;
+ goto tr0;
+tr13:
+#line 63 "format.rl"
+ { fsm->flags |= FL_HAS_WIDTH; }
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 278 "format.c"
+ switch( (*p) ) {
+ case 42: goto tr17;
+ case 88: goto tr19;
+ case 104: goto tr20;
+ case 105: goto tr19;
+ case 108: goto tr21;
+ case 115: goto tr19;
+ case 117: goto tr19;
+ case 120: goto tr19;
+ }
+ if ( (*p) < 99 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr18;
+ } else if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr19;
+ } else
+ goto tr19;
+ goto tr0;
+tr17:
+#line 68 "format.rl"
+ { fsm->flags |= FL_PREC_ARG; }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+#line 306 "format.c"
+ switch( (*p) ) {
+ case 88: goto tr10;
+ case 104: goto st6;
+ case 105: goto tr10;
+ case 108: goto st8;
+ case 115: goto tr10;
+ case 117: goto tr10;
+ case 120: goto tr10;
+ }
+ if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr10;
+ } else if ( (*p) >= 99 )
+ goto tr10;
+ goto tr0;
+tr15:
+#line 63 "format.rl"
+ { fsm->flags |= FL_HAS_WIDTH; }
+ goto st6;
+tr20:
+#line 69 "format.rl"
+ { fsm->flags |= FL_HAS_PREC; }
+ goto st6;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+#line 334 "format.c"
+ switch( (*p) ) {
+ case 88: goto tr22;
+ case 104: goto tr23;
+ case 105: goto tr22;
+ case 115: goto tr22;
+ case 117: goto tr22;
+ case 120: goto tr22;
+ }
+ if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr22;
+ } else if ( (*p) >= 99 )
+ goto tr22;
+ goto tr0;
+tr23:
+#line 88 "format.rl"
+ { fsm->flags |= FL_LEN_HH; }
+ goto st7;
+tr25:
+#line 89 "format.rl"
+ { fsm->flags |= FL_LEN_LL; }
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+#line 361 "format.c"
+ switch( (*p) ) {
+ case 88: goto tr10;
+ case 105: goto tr10;
+ case 115: goto tr10;
+ case 117: goto tr10;
+ case 120: goto tr10;
+ }
+ if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr10;
+ } else if ( (*p) >= 99 )
+ goto tr10;
+ goto tr0;
+tr16:
+#line 63 "format.rl"
+ { fsm->flags |= FL_HAS_WIDTH; }
+ goto st8;
+tr21:
+#line 69 "format.rl"
+ { fsm->flags |= FL_HAS_PREC; }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 387 "format.c"
+ switch( (*p) ) {
+ case 88: goto tr24;
+ case 105: goto tr24;
+ case 108: goto tr25;
+ case 115: goto tr24;
+ case 117: goto tr24;
+ case 120: goto tr24;
+ }
+ if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr24;
+ } else if ( (*p) >= 99 )
+ goto tr24;
+ goto tr0;
+tr18:
+#line 67 "format.rl"
+ { fsm->prec = 10 * fsm->prec + ((*p)-'0'); }
+ goto st9;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+#line 410 "format.c"
+ switch( (*p) ) {
+ case 88: goto tr19;
+ case 104: goto tr20;
+ case 105: goto tr19;
+ case 108: goto tr21;
+ case 115: goto tr19;
+ case 117: goto tr19;
+ case 120: goto tr19;
+ }
+ if ( (*p) < 99 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr18;
+ } else if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr19;
+ } else
+ goto tr19;
+ goto tr0;
+tr9:
+#line 61 "format.rl"
+ { fsm->width = 10 * fsm->width + ((*p)-'0'); }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 437 "format.c"
+ switch( (*p) ) {
+ case 46: goto tr13;
+ case 88: goto tr14;
+ case 104: goto tr15;
+ case 105: goto tr14;
+ case 108: goto tr16;
+ case 115: goto tr14;
+ case 117: goto tr14;
+ case 120: goto tr14;
+ }
+ if ( (*p) < 99 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr9;
+ } else if ( (*p) > 100 ) {
+ if ( 111 <= (*p) && (*p) <= 112 )
+ goto tr14;
+ } else
+ goto tr14;
+ goto tr0;
+ }
+ _test_eof11: fsm->cs = 11; goto _test_eof;
+ _test_eof1: fsm->cs = 1; goto _test_eof;
+ _test_eof2: fsm->cs = 2; goto _test_eof;
+ _test_eof3: fsm->cs = 3; goto _test_eof;
+ _test_eof4: fsm->cs = 4; goto _test_eof;
+ _test_eof5: fsm->cs = 5; goto _test_eof;
+ _test_eof6: fsm->cs = 6; goto _test_eof;
+ _test_eof7: fsm->cs = 7; goto _test_eof;
+ _test_eof8: fsm->cs = 8; goto _test_eof;
+ _test_eof9: fsm->cs = 9; goto _test_eof;
+ _test_eof10: fsm->cs = 10; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( fsm->cs ) {
+ case 11:
+#line 121 "format.rl"
+ {
+ if ( fsm->buflen > 0 )
+ fsm->write( fsm->buf, fsm->buflen );
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+#line 125 "format.rl"
+ {
+ printf("EOF IN FORMAT\n");
+ }
+#line 128 "format.rl"
+ {
+ printf("ERROR ON CHAR: 0x%x\n", (*p) );
+ }
+ break;
+#line 500 "format.c"
+ }
+ }
+
+ _out: {}
+ }
+
+#line 154 "format.rl"
+}
+
+int format_finish( struct format *fsm )
+{
+ if ( fsm->cs == format_error )
+ return -1;
+ if ( fsm->cs >= format_first_final )
+ return 1;
+ return 0;
+}
+
+
+#define INPUT_BUFSIZE 2048
+
+struct format fsm;
+char buf[INPUT_BUFSIZE];
+
+void write(char *data, int len )
+{
+ fwrite( data, 1, len, stdout );
+}
+
+int main()
+{
+ fsm.write = write;
+ format_init( &fsm );
+ while ( 1 ) {
+ int len = fread( buf, 1, INPUT_BUFSIZE, stdin );
+ int eof = len != INPUT_BUFSIZE;
+ format_execute( &fsm, buf, len, eof );
+ if ( eof )
+ break;
+ }
+ if ( format_finish( &fsm ) <= 0 )
+ printf("FAIL\n");
+ return 0;
+}
+
diff --git a/examples/format.rl b/examples/format.rl
new file mode 100644
index 0000000..f8a37be
--- /dev/null
+++ b/examples/format.rl
@@ -0,0 +1,191 @@
+/*
+ * Partial printf implementation.
+ */
+
+#define BUFLEN 1024
+#include <stdio.h>
+
+typedef void (*WriteFunc)( char *data, int len );
+
+struct format
+{
+ char buf[BUFLEN+1];
+ int buflen;
+ WriteFunc write;
+
+ int flags;
+ int width;
+ int prec;
+ int cs;
+};
+
+void do_conv( struct format *fsm, char c )
+{
+ printf( "flags: %x\n", fsm->flags );
+ printf( "width: %i\n", fsm->width );
+ printf( "prec: %i\n", fsm->prec );
+ printf( "conv: %c\n", c );
+ printf( "\n" );
+}
+
+#define FL_HASH 0x01
+#define FL_ZERO 0x02
+#define FL_DASH 0x04
+#define FL_SPACE 0x08
+#define FL_PLUS 0x10
+
+#define FL_HAS_WIDTH 0x0100
+#define FL_WIDTH_ARG 0x0200
+#define FL_HAS_PREC 0x0400
+#define FL_PREC_ARG 0x0800
+
+#define FL_LEN_H 0x010000
+#define FL_LEN_HH 0x020000
+#define FL_LEN_L 0x040000
+#define FL_LEN_LL 0x080000
+
+%%{
+ machine format;
+ access fsm->;
+
+ action clear {
+ fsm->flags = 0;
+ fsm->width = 0;
+ fsm->prec = 0;
+ }
+
+ # A non-zero number.
+ nznum = [1-9] [0-9]*;
+
+ # Width
+ action width_num { fsm->width = 10 * fsm->width + (fc-'0'); }
+ action width_arg { fsm->flags |= FL_WIDTH_ARG; }
+ action width { fsm->flags |= FL_HAS_WIDTH; }
+ width = ( ( nznum $width_num | '*' @width_arg ) %width )?;
+
+ # Precision
+ action prec_num { fsm->prec = 10 * fsm->prec + (fc-'0'); }
+ action prec_arg { fsm->flags |= FL_PREC_ARG; }
+ action prec { fsm->flags |= FL_HAS_PREC; }
+ precision = ( '.' ( digit* $prec_num %prec | '*' @prec_arg ) )?;
+
+ # Flags
+ action flags_hash { fsm->flags |= FL_HASH; }
+ action flags_zero { fsm->flags |= FL_ZERO; }
+ action flags_dash { fsm->flags |= FL_DASH; }
+ action flags_space { fsm->flags |= FL_SPACE; }
+ action flags_plus { fsm->flags |= FL_PLUS; }
+
+ flags = (
+ '#' @flags_hash |
+ '0' @flags_zero |
+ '-' @flags_dash |
+ ' ' @flags_space |
+ '+' @flags_plus )*;
+
+ action length_h { fsm->flags |= FL_LEN_H; }
+ action length_l { fsm->flags |= FL_LEN_L; }
+ action length_hh { fsm->flags |= FL_LEN_HH; }
+ action length_ll { fsm->flags |= FL_LEN_LL; }
+
+ # Must use leaving transitions on 'h' and 'l' because they are
+ # prefixes for 'hh' and 'll'.
+ length = (
+ 'h' %length_h |
+ 'l' %length_l |
+ 'hh' @length_hh |
+ 'll' @length_ll )?;
+
+ action conversion {
+ do_conv( fsm, fc );
+ }
+
+ conversion = [diouxXcsp] @conversion;
+
+ fmt_spec =
+ '%' @clear
+ flags
+ width
+ precision
+ length
+ conversion;
+
+ action emit {
+ if ( fsm->buflen == BUFLEN ) {
+ fsm->write( fsm->buf, fsm->buflen );
+ fsm->buflen = 0;
+ }
+ fsm->buf[fsm->buflen++] = fc;
+ }
+
+ action finish_ok {
+ if ( fsm->buflen > 0 )
+ fsm->write( fsm->buf, fsm->buflen );
+ }
+ action finish_err {
+ printf("EOF IN FORMAT\n");
+ }
+ action err_char {
+ printf("ERROR ON CHAR: 0x%x\n", fc );
+ }
+
+ main := (
+ [^%] @emit |
+ '%%' @emit |
+ fmt_spec
+ )* @/finish_err %/finish_ok $!err_char;
+}%%
+
+%% write data;
+
+void format_init( struct format *fsm )
+{
+ fsm->buflen = 0;
+ %% write init;
+}
+
+void format_execute( struct format *fsm, const char *data, int len, int isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+ %% write exec;
+}
+
+int format_finish( struct format *fsm )
+{
+ if ( fsm->cs == format_error )
+ return -1;
+ if ( fsm->cs >= format_first_final )
+ return 1;
+ return 0;
+}
+
+
+#define INPUT_BUFSIZE 2048
+
+struct format fsm;
+char buf[INPUT_BUFSIZE];
+
+void write(char *data, int len )
+{
+ fwrite( data, 1, len, stdout );
+}
+
+int main()
+{
+ fsm.write = write;
+ format_init( &fsm );
+ while ( 1 ) {
+ int len = fread( buf, 1, INPUT_BUFSIZE, stdin );
+ int eof = len != INPUT_BUFSIZE;
+ format_execute( &fsm, buf, len, eof );
+ if ( eof )
+ break;
+ }
+ if ( format_finish( &fsm ) <= 0 )
+ printf("FAIL\n");
+ return 0;
+}
+
diff --git a/examples/gotocallret.cpp b/examples/gotocallret.cpp
new file mode 100644
index 0000000..18a9531
--- /dev/null
+++ b/examples/gotocallret.cpp
@@ -0,0 +1,282 @@
+
+#line 1 "gotocallret.rl"
+/*
+ * Demonstrate the use of goto, call and return. This machine expects either a
+ * lower case char or a digit as a command then a space followed by the command
+ * arg. If the command is a char, then the arg must be an a string of chars.
+ * If the command is a digit, then the arg must be a string of digits. This
+ * choice is determined by action code, rather than though transition
+ * desitinations.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct GotoCallRet
+{
+ char comm;
+ int cs, top, stack[32];
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+
+#line 57 "gotocallret.rl"
+
+
+
+#line 35 "gotocallret.cpp"
+static const int GotoCallRet_start = 7;
+static const int GotoCallRet_first_final = 7;
+static const int GotoCallRet_error = 0;
+
+static const int GotoCallRet_en_garble_line = 3;
+static const int GotoCallRet_en_alp_comm = 5;
+static const int GotoCallRet_en_dig_comm = 6;
+static const int GotoCallRet_en_main = 7;
+
+
+#line 60 "gotocallret.rl"
+
+int GotoCallRet::init( )
+{
+
+#line 51 "gotocallret.cpp"
+ {
+ cs = GotoCallRet_start;
+ top = 0;
+ }
+
+#line 64 "gotocallret.rl"
+ return 1;
+}
+
+int GotoCallRet::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+
+#line 68 "gotocallret.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ goto _resume;
+
+_again:
+ switch ( cs ) {
+ case 7: goto st7;
+ case 0: goto st0;
+ case 1: goto st1;
+ case 2: goto st2;
+ case 3: goto st3;
+ case 4: goto st4;
+ case 8: goto st8;
+ case 5: goto st5;
+ case 9: goto st9;
+ case 6: goto st6;
+ case 10: goto st10;
+ default: break;
+ }
+
+ if ( ++p == pe )
+ goto _test_eof;
+_resume:
+ switch ( cs )
+ {
+tr2:
+#line 52 "gotocallret.rl"
+ {cout << "correct command" << endl;}
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+#line 103 "gotocallret.cpp"
+ if ( (*p) > 57 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr11;
+ } else if ( (*p) >= 48 )
+ goto tr11;
+ goto tr0;
+tr0:
+#line 56 "gotocallret.rl"
+ {p--;{goto st3;}}
+ goto st0;
+tr7:
+#line 38 "gotocallret.rl"
+ {p--;{cs = stack[--top];goto _again;}}
+ goto st0;
+tr9:
+#line 39 "gotocallret.rl"
+ {p--;{cs = stack[--top];goto _again;}}
+ goto st0;
+#line 122 "gotocallret.cpp"
+st0:
+cs = 0;
+ goto _out;
+tr11:
+#line 51 "gotocallret.rl"
+ {comm = (*p);}
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 134 "gotocallret.cpp"
+ if ( (*p) == 32 )
+ goto tr1;
+ goto tr0;
+tr1:
+#line 42 "gotocallret.rl"
+ {
+ if ( comm >= 'a' )
+ {stack[top++] = 2; goto st5;}
+ else
+ {stack[top++] = 2; goto st6;}
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 151 "gotocallret.cpp"
+ if ( (*p) == 10 )
+ goto tr2;
+ goto tr0;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ if ( (*p) == 10 )
+ goto tr4;
+ goto tr3;
+tr3:
+#line 34 "gotocallret.rl"
+ {cout << "error: garbling line" << endl;}
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 170 "gotocallret.cpp"
+ if ( (*p) == 10 )
+ goto tr6;
+ goto st4;
+tr4:
+#line 34 "gotocallret.rl"
+ {cout << "error: garbling line" << endl;}
+#line 34 "gotocallret.rl"
+ {{goto st7;}}
+ goto st8;
+tr6:
+#line 34 "gotocallret.rl"
+ {{goto st7;}}
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 188 "gotocallret.cpp"
+ goto st0;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st9;
+ } else if ( (*p) >= 65 )
+ goto st9;
+ goto tr7;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st9;
+ } else if ( (*p) >= 65 )
+ goto st9;
+ goto tr7;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st10;
+ goto tr9;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st10;
+ goto tr9;
+ }
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 5:
+#line 38 "gotocallret.rl"
+ {p--;{cs = stack[--top];goto _again;}}
+ break;
+ case 6:
+#line 39 "gotocallret.rl"
+ {p--;{cs = stack[--top];goto _again;}}
+ break;
+ case 1:
+ case 2:
+#line 56 "gotocallret.rl"
+ {p--;{goto st3;}}
+ break;
+#line 253 "gotocallret.cpp"
+ }
+ }
+
+ _out: {}
+ }
+
+#line 74 "gotocallret.rl"
+ if ( cs == GotoCallRet_error )
+ return -1;
+ if ( cs >= GotoCallRet_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+
+ GotoCallRet gcr;
+ gcr.init();
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 )
+ gcr.execute( buf, strlen(buf), false );
+
+ gcr.execute( 0, 0, true );
+ if ( gcr.cs < GotoCallRet_first_final )
+ cerr << "gotocallret: error: parsing input" << endl;
+ return 0;
+}
diff --git a/examples/gotocallret.rl b/examples/gotocallret.rl
new file mode 100644
index 0000000..32c01a2
--- /dev/null
+++ b/examples/gotocallret.rl
@@ -0,0 +1,96 @@
+/*
+ * Demonstrate the use of goto, call and return. This machine expects either a
+ * lower case char or a digit as a command then a space followed by the command
+ * arg. If the command is a char, then the arg must be an a string of chars.
+ * If the command is a digit, then the arg must be a string of digits. This
+ * choice is determined by action code, rather than though transition
+ * desitinations.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct GotoCallRet
+{
+ char comm;
+ int cs, top, stack[32];
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+%%{
+ machine GotoCallRet;
+
+ # Error machine, consumes to end of
+ # line, then starts the main line over.
+ garble_line := (
+ (any-'\n')*'\n'
+ ) >{cout << "error: garbling line" << endl;} @{fgoto main;};
+
+ # Look for a string of alphas or of digits,
+ # on anything else, hold the character and return.
+ alp_comm := alpha+ $!{fhold;fret;};
+ dig_comm := digit+ $!{fhold;fret;};
+
+ # Choose which to machine to call into based on the command.
+ action comm_arg {
+ if ( comm >= 'a' )
+ fcall alp_comm;
+ else
+ fcall dig_comm;
+ }
+
+ # Specifies command string. Note that the arg is left out.
+ command = (
+ [a-z0-9] @{comm = fc;} ' ' @comm_arg '\n'
+ ) @{cout << "correct command" << endl;};
+
+ # Any number of commands. If there is an
+ # error anywhere, garble the line.
+ main := command* $!{fhold;fgoto garble_line;};
+}%%
+
+%% write data;
+
+int GotoCallRet::init( )
+{
+ %% write init;
+ return 1;
+}
+
+int GotoCallRet::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+ %% write exec;
+ if ( cs == GotoCallRet_error )
+ return -1;
+ if ( cs >= GotoCallRet_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+
+ GotoCallRet gcr;
+ gcr.init();
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 )
+ gcr.execute( buf, strlen(buf), false );
+
+ gcr.execute( 0, 0, true );
+ if ( gcr.cs < GotoCallRet_first_final )
+ cerr << "gotocallret: error: parsing input" << endl;
+ return 0;
+}
diff --git a/examples/mailbox.cpp b/examples/mailbox.cpp
new file mode 100644
index 0000000..7e9c46e
--- /dev/null
+++ b/examples/mailbox.cpp
@@ -0,0 +1,1563 @@
+
+#line 1 "mailbox.rl"
+/*
+ * Parses unix mail boxes into headers and bodies.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+/* A growable buffer for collecting headers. */
+struct Buffer
+{
+ Buffer() : data(0), allocated(0), length(0) { }
+ ~Buffer() { empty(); }
+
+ void append( char p ) {
+ if ( ++length > allocated )
+ upAllocate( length*2 );
+ data[length-1] = p;
+ }
+
+ void clear() { length = 0; }
+ void upAllocate( int len );
+ void empty();
+
+ char *data;
+ int allocated;
+ int length;
+};
+
+
+struct MailboxScanner
+{
+ Buffer headName;
+ Buffer headContent;
+
+ int cs, top, stack[1];
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+
+#line 137 "mailbox.rl"
+
+
+
+#line 56 "mailbox.cpp"
+static const int MailboxScanner_start = 100;
+static const int MailboxScanner_first_final = 100;
+static const int MailboxScanner_error = 0;
+
+static const int MailboxScanner_en_consumeHeader = 102;
+static const int MailboxScanner_en_printHeader = 103;
+static const int MailboxScanner_en_main = 100;
+
+
+#line 140 "mailbox.rl"
+
+int MailboxScanner::init( )
+{
+
+#line 71 "mailbox.cpp"
+ {
+ cs = MailboxScanner_start;
+ top = 0;
+ }
+
+#line 144 "mailbox.rl"
+ return 1;
+}
+
+int MailboxScanner::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+
+#line 88 "mailbox.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ goto _resume;
+
+_again:
+ switch ( cs ) {
+ case 100: goto st100;
+ case 0: goto st0;
+ case 1: goto st1;
+ case 2: goto st2;
+ case 3: goto st3;
+ case 4: goto st4;
+ case 5: goto st5;
+ case 6: goto st6;
+ case 7: goto st7;
+ case 8: goto st8;
+ case 9: goto st9;
+ case 10: goto st10;
+ case 11: goto st11;
+ case 12: goto st12;
+ case 13: goto st13;
+ case 14: goto st14;
+ case 15: goto st15;
+ case 16: goto st16;
+ case 17: goto st17;
+ case 18: goto st18;
+ case 19: goto st19;
+ case 20: goto st20;
+ case 21: goto st21;
+ case 22: goto st22;
+ case 23: goto st23;
+ case 24: goto st24;
+ case 25: goto st25;
+ case 26: goto st26;
+ case 27: goto st27;
+ case 28: goto st28;
+ case 29: goto st29;
+ case 30: goto st30;
+ case 31: goto st31;
+ case 32: goto st32;
+ case 33: goto st33;
+ case 34: goto st34;
+ case 101: goto st101;
+ case 35: goto st35;
+ case 36: goto st36;
+ case 37: goto st37;
+ case 38: goto st38;
+ case 39: goto st39;
+ case 40: goto st40;
+ case 41: goto st41;
+ case 42: goto st42;
+ case 43: goto st43;
+ case 44: goto st44;
+ case 45: goto st45;
+ case 46: goto st46;
+ case 47: goto st47;
+ case 48: goto st48;
+ case 49: goto st49;
+ case 50: goto st50;
+ case 51: goto st51;
+ case 52: goto st52;
+ case 53: goto st53;
+ case 54: goto st54;
+ case 55: goto st55;
+ case 56: goto st56;
+ case 57: goto st57;
+ case 58: goto st58;
+ case 59: goto st59;
+ case 60: goto st60;
+ case 61: goto st61;
+ case 62: goto st62;
+ case 63: goto st63;
+ case 64: goto st64;
+ case 65: goto st65;
+ case 66: goto st66;
+ case 67: goto st67;
+ case 68: goto st68;
+ case 69: goto st69;
+ case 70: goto st70;
+ case 71: goto st71;
+ case 72: goto st72;
+ case 73: goto st73;
+ case 74: goto st74;
+ case 75: goto st75;
+ case 76: goto st76;
+ case 77: goto st77;
+ case 78: goto st78;
+ case 79: goto st79;
+ case 80: goto st80;
+ case 81: goto st81;
+ case 82: goto st82;
+ case 83: goto st83;
+ case 84: goto st84;
+ case 85: goto st85;
+ case 86: goto st86;
+ case 87: goto st87;
+ case 88: goto st88;
+ case 89: goto st89;
+ case 90: goto st90;
+ case 91: goto st91;
+ case 92: goto st92;
+ case 93: goto st93;
+ case 94: goto st94;
+ case 95: goto st95;
+ case 96: goto st96;
+ case 97: goto st97;
+ case 102: goto st102;
+ case 98: goto st98;
+ case 103: goto st103;
+ case 99: goto st99;
+ case 104: goto st104;
+ default: break;
+ }
+
+ if ( ++p == pe )
+ goto _test_eof;
+_resume:
+ switch ( cs )
+ {
+st100:
+ if ( ++p == pe )
+ goto _test_eof100;
+case 100:
+ if ( (*p) == 70 )
+ goto st1;
+ goto st0;
+tr101:
+#line 92 "mailbox.rl"
+ {
+ headContent.append(0);
+ cout << headContent.data << endl;
+ headContent.clear();
+ p--;
+ {cs = stack[--top];goto _again;}
+ }
+ goto st0;
+#line 226 "mailbox.cpp"
+st0:
+cs = 0;
+ goto _out;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ if ( (*p) == 114 )
+ goto st2;
+ goto st0;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ if ( (*p) == 111 )
+ goto st3;
+ goto st0;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ if ( (*p) == 109 )
+ goto st4;
+ goto st0;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ if ( (*p) == 32 )
+ goto st5;
+ goto st0;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ goto st5;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st7;
+ goto st5;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st8;
+ goto st5;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st9;
+ goto st5;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st10;
+ }
+ goto st5;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st11;
+ goto st5;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st12;
+ goto st5;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st13;
+ goto st5;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st14;
+ }
+ goto st5;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st15;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st11;
+ } else if ( (*p) >= 48 )
+ goto st97;
+ goto st5;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st7;
+ } else if ( (*p) >= 48 )
+ goto st16;
+ goto st5;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st17;
+ }
+ goto st5;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st7;
+ } else if ( (*p) >= 48 )
+ goto st18;
+ goto st5;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st19;
+ goto st5;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ case 58: goto st20;
+ }
+ goto st5;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st21;
+ goto st5;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st22;
+ goto st5;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st23;
+ case 58: goto st94;
+ }
+ goto st5;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ case 43: goto st24;
+ case 45: goto st24;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st92;
+ } else if ( (*p) >= 48 )
+ goto st84;
+ goto st5;
+st24:
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st25;
+ goto st5;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st26;
+ goto st5;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st27;
+ goto st5;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st28;
+ goto st5;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st29;
+ }
+ goto st5;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st7;
+ } else if ( (*p) >= 48 )
+ goto st30;
+ goto st5;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st31;
+ goto st5;
+st31:
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st32;
+ goto st5;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st33;
+ goto st5;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+ switch( (*p) ) {
+ case 10: goto st34;
+ case 32: goto st6;
+ }
+ goto st5;
+tr88:
+#line 108 "mailbox.rl"
+ {
+ headName.append(0);
+ if ( strcmp( headName.data, "From" ) == 0 ||
+ strcmp( headName.data, "To" ) == 0 ||
+ strcmp( headName.data, "Subject" ) == 0 )
+ {
+ /* Print the header name, then jump to a machine the will display
+ * the contents. */
+ cout << headName.data << ":";
+ headName.clear();
+ {stack[top++] = 34; goto st103;}
+ }
+
+ headName.clear();
+ {stack[top++] = 34; goto st102;}
+ }
+ goto st34;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+#line 603 "mailbox.cpp"
+ if ( (*p) == 10 )
+ goto tr38;
+ if ( (*p) > 57 ) {
+ if ( 59 <= (*p) && (*p) <= 126 )
+ goto tr39;
+ } else if ( (*p) >= 33 )
+ goto tr39;
+ goto st0;
+tr38:
+#line 55 "mailbox.rl"
+ { cout << endl; }
+ goto st101;
+st101:
+ if ( ++p == pe )
+ goto _test_eof101;
+case 101:
+#line 620 "mailbox.cpp"
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 70: goto st36;
+ }
+ goto st35;
+st35:
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+ if ( (*p) == 10 )
+ goto st101;
+ goto st35;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 114: goto st37;
+ }
+ goto st35;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 111: goto st38;
+ }
+ goto st35;
+st38:
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 109: goto st39;
+ }
+ goto st35;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st40;
+ }
+ goto st35;
+st40:
+ if ( ++p == pe )
+ goto _test_eof40;
+case 40:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ goto st40;
+st41:
+ if ( ++p == pe )
+ goto _test_eof41;
+case 41:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st42;
+ goto st40;
+st42:
+ if ( ++p == pe )
+ goto _test_eof42;
+case 42:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st43;
+ goto st40;
+st43:
+ if ( ++p == pe )
+ goto _test_eof43;
+case 43:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st44;
+ goto st40;
+st44:
+ if ( ++p == pe )
+ goto _test_eof44;
+case 44:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st45;
+ }
+ goto st40;
+st45:
+ if ( ++p == pe )
+ goto _test_eof45;
+case 45:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st46;
+ goto st40;
+st46:
+ if ( ++p == pe )
+ goto _test_eof46;
+case 46:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st47;
+ goto st40;
+st47:
+ if ( ++p == pe )
+ goto _test_eof47;
+case 47:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st48;
+ goto st40;
+st48:
+ if ( ++p == pe )
+ goto _test_eof48;
+case 48:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st49;
+ }
+ goto st40;
+st49:
+ if ( ++p == pe )
+ goto _test_eof49;
+case 49:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st50;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st46;
+ } else if ( (*p) >= 48 )
+ goto st82;
+ goto st40;
+st50:
+ if ( ++p == pe )
+ goto _test_eof50;
+case 50:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st42;
+ } else if ( (*p) >= 48 )
+ goto st51;
+ goto st40;
+st51:
+ if ( ++p == pe )
+ goto _test_eof51;
+case 51:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st52;
+ }
+ goto st40;
+st52:
+ if ( ++p == pe )
+ goto _test_eof52;
+case 52:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st42;
+ } else if ( (*p) >= 48 )
+ goto st53;
+ goto st40;
+st53:
+ if ( ++p == pe )
+ goto _test_eof53;
+case 53:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st54;
+ goto st40;
+st54:
+ if ( ++p == pe )
+ goto _test_eof54;
+case 54:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ case 58: goto st55;
+ }
+ goto st40;
+st55:
+ if ( ++p == pe )
+ goto _test_eof55;
+case 55:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st56;
+ goto st40;
+st56:
+ if ( ++p == pe )
+ goto _test_eof56;
+case 56:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st57;
+ goto st40;
+st57:
+ if ( ++p == pe )
+ goto _test_eof57;
+case 57:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st58;
+ case 58: goto st79;
+ }
+ goto st40;
+st58:
+ if ( ++p == pe )
+ goto _test_eof58;
+case 58:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ case 43: goto st59;
+ case 45: goto st59;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st77;
+ } else if ( (*p) >= 48 )
+ goto st69;
+ goto st40;
+st59:
+ if ( ++p == pe )
+ goto _test_eof59;
+case 59:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st60;
+ goto st40;
+st60:
+ if ( ++p == pe )
+ goto _test_eof60;
+case 60:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st61;
+ goto st40;
+st61:
+ if ( ++p == pe )
+ goto _test_eof61;
+case 61:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st62;
+ goto st40;
+st62:
+ if ( ++p == pe )
+ goto _test_eof62;
+case 62:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st63;
+ goto st40;
+st63:
+ if ( ++p == pe )
+ goto _test_eof63;
+case 63:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st64;
+ }
+ goto st40;
+st64:
+ if ( ++p == pe )
+ goto _test_eof64;
+case 64:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st42;
+ } else if ( (*p) >= 48 )
+ goto st65;
+ goto st40;
+st65:
+ if ( ++p == pe )
+ goto _test_eof65;
+case 65:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st66;
+ goto st40;
+st66:
+ if ( ++p == pe )
+ goto _test_eof66;
+case 66:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st67;
+ goto st40;
+st67:
+ if ( ++p == pe )
+ goto _test_eof67;
+case 67:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st68;
+ goto st40;
+st68:
+ if ( ++p == pe )
+ goto _test_eof68;
+case 68:
+ switch( (*p) ) {
+ case 10: goto st34;
+ case 32: goto st41;
+ }
+ goto st40;
+st69:
+ if ( ++p == pe )
+ goto _test_eof69;
+case 69:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st70;
+ goto st40;
+st70:
+ if ( ++p == pe )
+ goto _test_eof70;
+case 70:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st71;
+ goto st40;
+st71:
+ if ( ++p == pe )
+ goto _test_eof71;
+case 71:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st72;
+ goto st40;
+st72:
+ if ( ++p == pe )
+ goto _test_eof72;
+case 72:
+ switch( (*p) ) {
+ case 10: goto st34;
+ case 32: goto st73;
+ }
+ goto st40;
+st73:
+ if ( ++p == pe )
+ goto _test_eof73;
+case 73:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ case 43: goto st74;
+ case 45: goto st74;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st75;
+ goto st40;
+st74:
+ if ( ++p == pe )
+ goto _test_eof74;
+case 74:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st65;
+ goto st40;
+st75:
+ if ( ++p == pe )
+ goto _test_eof75;
+case 75:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st43;
+ } else if ( (*p) >= 65 )
+ goto st76;
+ goto st40;
+st76:
+ if ( ++p == pe )
+ goto _test_eof76;
+case 76:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st68;
+ goto st40;
+st77:
+ if ( ++p == pe )
+ goto _test_eof77;
+case 77:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st43;
+ } else if ( (*p) >= 65 )
+ goto st78;
+ goto st40;
+st78:
+ if ( ++p == pe )
+ goto _test_eof78;
+case 78:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st63;
+ goto st40;
+st79:
+ if ( ++p == pe )
+ goto _test_eof79;
+case 79:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st80;
+ goto st40;
+st80:
+ if ( ++p == pe )
+ goto _test_eof80;
+case 80:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st81;
+ goto st40;
+st81:
+ if ( ++p == pe )
+ goto _test_eof81;
+case 81:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st58;
+ }
+ goto st40;
+st82:
+ if ( ++p == pe )
+ goto _test_eof82;
+case 82:
+ switch( (*p) ) {
+ case 10: goto st101;
+ case 32: goto st41;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st51;
+ goto st40;
+tr39:
+#line 52 "mailbox.rl"
+ { headName.append((*p)); }
+ goto st83;
+st83:
+ if ( ++p == pe )
+ goto _test_eof83;
+case 83:
+#line 1157 "mailbox.cpp"
+ if ( (*p) == 58 )
+ goto tr88;
+ if ( 33 <= (*p) && (*p) <= 126 )
+ goto tr39;
+ goto st0;
+st84:
+ if ( ++p == pe )
+ goto _test_eof84;
+case 84:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st85;
+ goto st5;
+st85:
+ if ( ++p == pe )
+ goto _test_eof85;
+case 85:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st86;
+ goto st5;
+st86:
+ if ( ++p == pe )
+ goto _test_eof86;
+case 86:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st87;
+ goto st5;
+st87:
+ if ( ++p == pe )
+ goto _test_eof87;
+case 87:
+ switch( (*p) ) {
+ case 10: goto st34;
+ case 32: goto st88;
+ }
+ goto st5;
+st88:
+ if ( ++p == pe )
+ goto _test_eof88;
+case 88:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ case 43: goto st89;
+ case 45: goto st89;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st90;
+ goto st5;
+st89:
+ if ( ++p == pe )
+ goto _test_eof89;
+case 89:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st30;
+ goto st5;
+st90:
+ if ( ++p == pe )
+ goto _test_eof90;
+case 90:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st8;
+ } else if ( (*p) >= 65 )
+ goto st91;
+ goto st5;
+st91:
+ if ( ++p == pe )
+ goto _test_eof91;
+case 91:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st33;
+ goto st5;
+st92:
+ if ( ++p == pe )
+ goto _test_eof92;
+case 92:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st8;
+ } else if ( (*p) >= 65 )
+ goto st93;
+ goto st5;
+st93:
+ if ( ++p == pe )
+ goto _test_eof93;
+case 93:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st28;
+ goto st5;
+st94:
+ if ( ++p == pe )
+ goto _test_eof94;
+case 94:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st95;
+ goto st5;
+st95:
+ if ( ++p == pe )
+ goto _test_eof95;
+case 95:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st96;
+ goto st5;
+st96:
+ if ( ++p == pe )
+ goto _test_eof96;
+case 96:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st23;
+ }
+ goto st5;
+st97:
+ if ( ++p == pe )
+ goto _test_eof97;
+case 97:
+ switch( (*p) ) {
+ case 10: goto st0;
+ case 32: goto st6;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st16;
+ goto st5;
+tr99:
+#line 86 "mailbox.rl"
+ {p--; {cs = stack[--top];goto _again;}}
+ goto st102;
+st102:
+ if ( ++p == pe )
+ goto _test_eof102;
+case 102:
+#line 1329 "mailbox.cpp"
+ if ( (*p) == 10 )
+ goto st98;
+ goto st102;
+st98:
+ if ( ++p == pe )
+ goto _test_eof98;
+case 98:
+ switch( (*p) ) {
+ case 9: goto st102;
+ case 32: goto st102;
+ }
+ goto tr99;
+tr106:
+#line 89 "mailbox.rl"
+ {headContent.append((*p));}
+ goto st103;
+tr108:
+#line 90 "mailbox.rl"
+ {headContent.append(' ');}
+#line 89 "mailbox.rl"
+ {headContent.append((*p));}
+ goto st103;
+st103:
+ if ( ++p == pe )
+ goto _test_eof103;
+case 103:
+#line 1356 "mailbox.cpp"
+ if ( (*p) == 10 )
+ goto st99;
+ goto tr106;
+st99:
+ if ( ++p == pe )
+ goto _test_eof99;
+case 99:
+ switch( (*p) ) {
+ case 9: goto st104;
+ case 32: goto st104;
+ }
+ goto tr101;
+st104:
+ if ( ++p == pe )
+ goto _test_eof104;
+case 104:
+ switch( (*p) ) {
+ case 9: goto st104;
+ case 10: goto st99;
+ case 32: goto st104;
+ }
+ goto tr108;
+ }
+ _test_eof100: cs = 100; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof101: cs = 101; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+ _test_eof40: cs = 40; goto _test_eof;
+ _test_eof41: cs = 41; goto _test_eof;
+ _test_eof42: cs = 42; goto _test_eof;
+ _test_eof43: cs = 43; goto _test_eof;
+ _test_eof44: cs = 44; goto _test_eof;
+ _test_eof45: cs = 45; goto _test_eof;
+ _test_eof46: cs = 46; goto _test_eof;
+ _test_eof47: cs = 47; goto _test_eof;
+ _test_eof48: cs = 48; goto _test_eof;
+ _test_eof49: cs = 49; goto _test_eof;
+ _test_eof50: cs = 50; goto _test_eof;
+ _test_eof51: cs = 51; goto _test_eof;
+ _test_eof52: cs = 52; goto _test_eof;
+ _test_eof53: cs = 53; goto _test_eof;
+ _test_eof54: cs = 54; goto _test_eof;
+ _test_eof55: cs = 55; goto _test_eof;
+ _test_eof56: cs = 56; goto _test_eof;
+ _test_eof57: cs = 57; goto _test_eof;
+ _test_eof58: cs = 58; goto _test_eof;
+ _test_eof59: cs = 59; goto _test_eof;
+ _test_eof60: cs = 60; goto _test_eof;
+ _test_eof61: cs = 61; goto _test_eof;
+ _test_eof62: cs = 62; goto _test_eof;
+ _test_eof63: cs = 63; goto _test_eof;
+ _test_eof64: cs = 64; goto _test_eof;
+ _test_eof65: cs = 65; goto _test_eof;
+ _test_eof66: cs = 66; goto _test_eof;
+ _test_eof67: cs = 67; goto _test_eof;
+ _test_eof68: cs = 68; goto _test_eof;
+ _test_eof69: cs = 69; goto _test_eof;
+ _test_eof70: cs = 70; goto _test_eof;
+ _test_eof71: cs = 71; goto _test_eof;
+ _test_eof72: cs = 72; goto _test_eof;
+ _test_eof73: cs = 73; goto _test_eof;
+ _test_eof74: cs = 74; goto _test_eof;
+ _test_eof75: cs = 75; goto _test_eof;
+ _test_eof76: cs = 76; goto _test_eof;
+ _test_eof77: cs = 77; goto _test_eof;
+ _test_eof78: cs = 78; goto _test_eof;
+ _test_eof79: cs = 79; goto _test_eof;
+ _test_eof80: cs = 80; goto _test_eof;
+ _test_eof81: cs = 81; goto _test_eof;
+ _test_eof82: cs = 82; goto _test_eof;
+ _test_eof83: cs = 83; goto _test_eof;
+ _test_eof84: cs = 84; goto _test_eof;
+ _test_eof85: cs = 85; goto _test_eof;
+ _test_eof86: cs = 86; goto _test_eof;
+ _test_eof87: cs = 87; goto _test_eof;
+ _test_eof88: cs = 88; goto _test_eof;
+ _test_eof89: cs = 89; goto _test_eof;
+ _test_eof90: cs = 90; goto _test_eof;
+ _test_eof91: cs = 91; goto _test_eof;
+ _test_eof92: cs = 92; goto _test_eof;
+ _test_eof93: cs = 93; goto _test_eof;
+ _test_eof94: cs = 94; goto _test_eof;
+ _test_eof95: cs = 95; goto _test_eof;
+ _test_eof96: cs = 96; goto _test_eof;
+ _test_eof97: cs = 97; goto _test_eof;
+ _test_eof102: cs = 102; goto _test_eof;
+ _test_eof98: cs = 98; goto _test_eof;
+ _test_eof103: cs = 103; goto _test_eof;
+ _test_eof99: cs = 99; goto _test_eof;
+ _test_eof104: cs = 104; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 104:
+#line 90 "mailbox.rl"
+ {headContent.append(' ');}
+ break;
+ case 99:
+#line 92 "mailbox.rl"
+ {
+ headContent.append(0);
+ cout << headContent.data << endl;
+ headContent.clear();
+ p--;
+ {cs = stack[--top];goto _again;}
+ }
+ break;
+#line 1503 "mailbox.cpp"
+ }
+ }
+
+ _out: {}
+ }
+
+#line 154 "mailbox.rl"
+
+ if ( cs == MailboxScanner_error )
+ return -1;
+ if ( cs >= MailboxScanner_first_final )
+ return 1;
+ return 0;
+}
+
+int MailboxScanner::finish( )
+{
+ if ( cs == MailboxScanner_error )
+ return -1;
+ if ( cs >= MailboxScanner_first_final )
+ return 1;
+ return 0;
+}
+
+
+void Buffer::empty()
+{
+ if ( data != 0 ) {
+ free( data );
+
+ data = 0;
+ length = 0;
+ allocated = 0;
+ }
+}
+
+void Buffer::upAllocate( int len )
+{
+ if ( data == 0 )
+ data = (char*) malloc( len );
+ else
+ data = (char*) realloc( data, len );
+ allocated = len;
+}
+
+MailboxScanner mailbox;
+char buf[BUFSIZE];
+
+int main()
+{
+ mailbox.init();
+ while ( 1 ) {
+ int len = fread( buf, 1, BUFSIZE, stdin );
+ mailbox.execute( buf, len, len != BUFSIZE );
+ if ( len != BUFSIZE )
+ break;
+ }
+ if ( mailbox.finish() <= 0 )
+ cerr << "mailbox: error parsing input" << endl;
+ return 0;
+}
diff --git a/examples/mailbox.rl b/examples/mailbox.rl
new file mode 100644
index 0000000..94590fd
--- /dev/null
+++ b/examples/mailbox.rl
@@ -0,0 +1,207 @@
+/*
+ * Parses unix mail boxes into headers and bodies.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+/* A growable buffer for collecting headers. */
+struct Buffer
+{
+ Buffer() : data(0), allocated(0), length(0) { }
+ ~Buffer() { empty(); }
+
+ void append( char p ) {
+ if ( ++length > allocated )
+ upAllocate( length*2 );
+ data[length-1] = p;
+ }
+
+ void clear() { length = 0; }
+ void upAllocate( int len );
+ void empty();
+
+ char *data;
+ int allocated;
+ int length;
+};
+
+
+struct MailboxScanner
+{
+ Buffer headName;
+ Buffer headContent;
+
+ int cs, top, stack[1];
+
+ int init( );
+ int execute( const char *data, int len, bool isEof );
+ int finish( );
+};
+
+%%{
+ machine MailboxScanner;
+
+ # Buffer the header names.
+ action bufHeadName { headName.append(fc); }
+
+ # Prints a blank line after the end of the headers of each message.
+ action blankLine { cout << endl; }
+
+ # Helpers we will use in matching the date section of the from line.
+ day = /[A-Z][a-z][a-z]/;
+ month = /[A-Z][a-z][a-z]/;
+ year = /[0-9][0-9][0-9][0-9]/;
+ time = /[0-9][0-9]:[0-9][0-9]/ . ( /:[0-9][0-9]/ | '' );
+ letterZone = /[A-Z][A-Z][A-Z]/;
+ numZone = /[+\-][0-9][0-9][0-9][0-9]/;
+ zone = letterZone | numZone;
+ 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.
+ date = day . ' ' . month . ' ' . dayNum . ' ' . time . ' ' .
+ ( year | year . ' ' . zone | zone . ' ' . year );
+
+ # From lines separate messages. We will exclude fromLine from a message
+ # body line. This will cause us to stay in message line up until an
+ # entirely correct from line is matched.
+ fromLine = 'From ' . (any-'\n')* . ' ' . date . '\n';
+
+ # The types of characters that can be used as a header name.
+ hchar = print - [ :];
+
+ # Simply eat up an uninteresting header. Return at the first non-ws
+ # character following a newline.
+ consumeHeader := (
+ [^\n] |
+ '\n' [ \t] |
+ '\n' [^ \t] @{fhold; fret;}
+ )*;
+
+ action hchar {headContent.append(fc);}
+ action hspace {headContent.append(' ');}
+
+ action hfinish {
+ headContent.append(0);
+ cout << headContent.data << endl;
+ headContent.clear();
+ fhold;
+ fret;
+ }
+
+ # Display the contents of a header as it is consumed. Collapses line
+ # continuations to a single space.
+ printHeader := (
+ [^\n] @hchar |
+ ( '\n' ( [ \t]+ '\n' )* [ \t]+ ) %hspace
+ )** $!hfinish;
+
+ action onHeader
+ {
+ headName.append(0);
+ if ( strcmp( headName.data, "From" ) == 0 ||
+ strcmp( headName.data, "To" ) == 0 ||
+ strcmp( headName.data, "Subject" ) == 0 )
+ {
+ /* Print the header name, then jump to a machine the will display
+ * the contents. */
+ cout << headName.data << ":";
+ headName.clear();
+ fcall printHeader;
+ }
+
+ headName.clear();
+ fcall consumeHeader;
+ }
+
+ header = hchar+ $bufHeadName ':' @onHeader;
+
+ # Exclude fromLine from a messageLine, otherwise when encountering a
+ # fromLine we will be simultaneously matching the old message and a new
+ # message.
+ messageLine = ( [^\n]* '\n' - fromLine );
+
+ # An entire message.
+ message = ( fromLine . header* . '\n' @blankLine . messageLine* );
+
+ # File is a series of messages.
+ main := message*;
+}%%
+
+%% write data;
+
+int MailboxScanner::init( )
+{
+ %% write init;
+ return 1;
+}
+
+int MailboxScanner::execute( const char *data, int len, bool isEof )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = isEof ? pe : 0;
+
+ %% write exec;
+
+ if ( cs == MailboxScanner_error )
+ return -1;
+ if ( cs >= MailboxScanner_first_final )
+ return 1;
+ return 0;
+}
+
+int MailboxScanner::finish( )
+{
+ if ( cs == MailboxScanner_error )
+ return -1;
+ if ( cs >= MailboxScanner_first_final )
+ return 1;
+ return 0;
+}
+
+
+void Buffer::empty()
+{
+ if ( data != 0 ) {
+ free( data );
+
+ data = 0;
+ length = 0;
+ allocated = 0;
+ }
+}
+
+void Buffer::upAllocate( int len )
+{
+ if ( data == 0 )
+ data = (char*) malloc( len );
+ else
+ data = (char*) realloc( data, len );
+ allocated = len;
+}
+
+MailboxScanner mailbox;
+char buf[BUFSIZE];
+
+int main()
+{
+ mailbox.init();
+ while ( 1 ) {
+ int len = fread( buf, 1, BUFSIZE, stdin );
+ mailbox.execute( buf, len, len != BUFSIZE );
+ if ( len != BUFSIZE )
+ break;
+ }
+ if ( mailbox.finish() <= 0 )
+ cerr << "mailbox: error parsing input" << endl;
+ return 0;
+}
diff --git a/examples/params.c b/examples/params.c
new file mode 100644
index 0000000..485e1c3
--- /dev/null
+++ b/examples/params.c
@@ -0,0 +1,374 @@
+
+#line 1 "params.rl"
+/*
+ * Parse command line arguments.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define BUFLEN 1024
+
+struct params
+{
+ char buffer[BUFLEN+1];
+ int buflen;
+ int cs;
+};
+
+
+#line 61 "params.rl"
+
+
+
+#line 25 "params.c"
+static const int params_start = 23;
+static const int params_first_final = 23;
+static const int params_error = 0;
+
+static const int params_en_main = 23;
+
+
+#line 64 "params.rl"
+
+void params_init( struct params *fsm )
+{
+ fsm->buflen = 0;
+
+#line 39 "params.c"
+ {
+ fsm->cs = params_start;
+ }
+
+#line 69 "params.rl"
+}
+
+void params_execute( struct params *fsm, const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+
+
+#line 53 "params.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( fsm->cs )
+ {
+tr11:
+#line 38 "params.rl"
+ { printf("help\n"); }
+ goto st23;
+tr17:
+#line 39 "params.rl"
+ { printf("version\n"); }
+ goto st23;
+tr21:
+#line 30 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = 0;
+ }
+#line 42 "params.rl"
+ { printf("machine: \"%s\"\n", fsm->buffer); }
+ goto st23;
+tr25:
+#line 30 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = 0;
+ }
+#line 41 "params.rl"
+ { printf("spec: \"%s\"\n", fsm->buffer); }
+ goto st23;
+tr29:
+#line 30 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = 0;
+ }
+#line 40 "params.rl"
+ { printf("output: \"%s\"\n", fsm->buffer); }
+ goto st23;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+#line 98 "params.c"
+ if ( (*p) == 45 )
+ goto st1;
+ goto st0;
+st0:
+ fsm->cs = 0;
+ goto _out;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ switch( (*p) ) {
+ case 45: goto st2;
+ case 63: goto st6;
+ case 72: goto st6;
+ case 77: goto st14;
+ case 83: goto st17;
+ case 104: goto st6;
+ case 111: goto st20;
+ case 118: goto st13;
+ }
+ goto st0;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ switch( (*p) ) {
+ case 104: goto st3;
+ case 118: goto st7;
+ }
+ goto st0;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ if ( (*p) == 101 )
+ goto st4;
+ goto st0;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ if ( (*p) == 108 )
+ goto st5;
+ goto st0;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) == 112 )
+ goto st6;
+ goto st0;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ if ( (*p) == 0 )
+ goto tr11;
+ goto st0;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( (*p) == 101 )
+ goto st8;
+ goto st0;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ if ( (*p) == 114 )
+ goto st9;
+ goto st0;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) == 115 )
+ goto st10;
+ goto st0;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ if ( (*p) == 105 )
+ goto st11;
+ goto st0;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ if ( (*p) == 111 )
+ goto st12;
+ goto st0;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ if ( (*p) == 110 )
+ goto st13;
+ goto st0;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ if ( (*p) == 0 )
+ goto tr17;
+ goto st0;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ if ( (*p) == 0 )
+ goto st16;
+ goto tr18;
+tr18:
+#line 36 "params.rl"
+ { fsm->buflen = 0; }
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st15;
+tr20:
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st15;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+#line 233 "params.c"
+ if ( (*p) == 0 )
+ goto tr21;
+ goto tr20;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ if ( (*p) == 0 )
+ goto st0;
+ goto tr18;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ if ( (*p) == 0 )
+ goto st19;
+ goto tr22;
+tr22:
+#line 36 "params.rl"
+ { fsm->buflen = 0; }
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st18;
+tr24:
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st18;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+#line 271 "params.c"
+ if ( (*p) == 0 )
+ goto tr25;
+ goto tr24;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ if ( (*p) == 0 )
+ goto st0;
+ goto tr22;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+ if ( (*p) == 0 )
+ goto st22;
+ goto tr26;
+tr26:
+#line 36 "params.rl"
+ { fsm->buflen = 0; }
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st21;
+tr28:
+#line 24 "params.rl"
+ {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = (*p);
+ }
+ goto st21;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+#line 309 "params.c"
+ if ( (*p) == 0 )
+ goto tr29;
+ goto tr28;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+ if ( (*p) == 0 )
+ goto st0;
+ goto tr26;
+ }
+ _test_eof23: fsm->cs = 23; goto _test_eof;
+ _test_eof1: fsm->cs = 1; goto _test_eof;
+ _test_eof2: fsm->cs = 2; goto _test_eof;
+ _test_eof3: fsm->cs = 3; goto _test_eof;
+ _test_eof4: fsm->cs = 4; goto _test_eof;
+ _test_eof5: fsm->cs = 5; goto _test_eof;
+ _test_eof6: fsm->cs = 6; goto _test_eof;
+ _test_eof7: fsm->cs = 7; goto _test_eof;
+ _test_eof8: fsm->cs = 8; goto _test_eof;
+ _test_eof9: fsm->cs = 9; goto _test_eof;
+ _test_eof10: fsm->cs = 10; goto _test_eof;
+ _test_eof11: fsm->cs = 11; goto _test_eof;
+ _test_eof12: fsm->cs = 12; goto _test_eof;
+ _test_eof13: fsm->cs = 13; goto _test_eof;
+ _test_eof14: fsm->cs = 14; goto _test_eof;
+ _test_eof15: fsm->cs = 15; goto _test_eof;
+ _test_eof16: fsm->cs = 16; goto _test_eof;
+ _test_eof17: fsm->cs = 17; goto _test_eof;
+ _test_eof18: fsm->cs = 18; goto _test_eof;
+ _test_eof19: fsm->cs = 19; goto _test_eof;
+ _test_eof20: fsm->cs = 20; goto _test_eof;
+ _test_eof21: fsm->cs = 21; goto _test_eof;
+ _test_eof22: fsm->cs = 22; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 77 "params.rl"
+}
+
+int params_finish( struct params *fsm )
+{
+ if ( fsm->cs == params_error )
+ return -1;
+ if ( fsm->cs >= params_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 2048
+
+int main( int argc, char **argv )
+{
+ int a;
+ struct params params;
+
+ params_init( &params );
+ for ( a = 1; a < argc; a++ )
+ params_execute( &params, argv[a], strlen(argv[a])+1 );
+ if ( params_finish( &params ) != 1 )
+ fprintf( stderr, "params: error processing arguments\n" );
+
+ return 0;
+}
diff --git a/examples/params.rl b/examples/params.rl
new file mode 100644
index 0000000..a8ffeae
--- /dev/null
+++ b/examples/params.rl
@@ -0,0 +1,102 @@
+/*
+ * Parse command line arguments.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define BUFLEN 1024
+
+struct params
+{
+ char buffer[BUFLEN+1];
+ int buflen;
+ int cs;
+};
+
+%%{
+ machine params;
+ access fsm->;
+
+ # A buffer to collect argurments
+
+ # Append to the buffer.
+ action append {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = fc;
+ }
+
+ # Terminate a buffer.
+ action term {
+ if ( fsm->buflen < BUFLEN )
+ fsm->buffer[fsm->buflen++] = 0;
+ }
+
+ # Clear out the buffer
+ action clear { fsm->buflen = 0; }
+
+ action help { printf("help\n"); }
+ action version { printf("version\n"); }
+ action output { printf("output: \"%s\"\n", fsm->buffer); }
+ action spec { printf("spec: \"%s\"\n", fsm->buffer); }
+ action mach { printf("machine: \"%s\"\n", fsm->buffer); }
+
+ # Helpers that collect strings
+ string = [^\0]+ >clear $append %term;
+
+ # Different arguments.
+ help = ( '-h' | '-H' | '-?' | '--help' ) 0 @help;
+ version = ( '-v' | '--version' ) 0 @version;
+ output = '-o' 0? string 0 @output;
+ spec = '-S' 0? string 0 @spec;
+ mach = '-M' 0? string 0 @mach;
+
+ main := (
+ help |
+ version |
+ output |
+ spec |
+ mach
+ )*;
+}%%
+
+%% write data;
+
+void params_init( struct params *fsm )
+{
+ fsm->buflen = 0;
+ %% write init;
+}
+
+void params_execute( struct params *fsm, const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+
+ %% write exec;
+}
+
+int params_finish( struct params *fsm )
+{
+ if ( fsm->cs == params_error )
+ return -1;
+ if ( fsm->cs >= params_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 2048
+
+int main( int argc, char **argv )
+{
+ int a;
+ struct params params;
+
+ params_init( &params );
+ for ( a = 1; a < argc; a++ )
+ params_execute( &params, argv[a], strlen(argv[a])+1 );
+ if ( params_finish( &params ) != 1 )
+ fprintf( stderr, "params: error processing arguments\n" );
+
+ return 0;
+}
diff --git a/examples/pullscan.c b/examples/pullscan.c
new file mode 100644
index 0000000..a72ca2f
--- /dev/null
+++ b/examples/pullscan.c
@@ -0,0 +1,294 @@
+
+#line 1 "pullscan.rl"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFSIZE 4096
+
+typedef struct _Scanner {
+ /* Scanner state. */
+ int cs;
+ int act;
+ int have;
+ int curline;
+ char *ts;
+ char *te;
+ char *p;
+ char *pe;
+ char *eof;
+ FILE *file;
+ int done;
+
+ /* Token data */
+ char *data;
+ int len;
+ int value;
+
+ char buf[BUFSIZE];
+} Scanner;
+
+
+
+#line 34 "pullscan.c"
+static const int Scanner_start = 2;
+static const int Scanner_first_final = 2;
+static const int Scanner_error = -1;
+
+static const int Scanner_en_main = 2;
+
+
+#line 33 "pullscan.rl"
+
+
+void scan_init( Scanner *s, FILE *file )
+{
+ memset (s, '\0', sizeof(Scanner));
+ s->curline = 1;
+ s->file = file;
+ s->eof = 0;
+
+#line 52 "pullscan.c"
+ {
+ s->cs = Scanner_start;
+ s->ts = 0;
+ s->te = 0;
+ s->act = 0;
+ }
+
+#line 42 "pullscan.rl"
+}
+
+#define TK_NO_TOKEN (-1)
+#define TK_ERR 128
+#define TK_EOF 129
+#define TK_Identifier 130
+#define TK_Number 131
+#define TK_String 132
+
+#define ret_tok( _tok ) token = _tok; s->data = s->ts
+
+int scan( Scanner *s )
+{
+ int token = TK_NO_TOKEN;
+ int space, readlen;
+
+ while ( 1 ) {
+ if ( s->p == s->pe ) {
+ printf("scanner: need more data\n");
+
+ if ( s->ts == 0 )
+ s->have = 0;
+ else {
+ /* There is data that needs to be shifted over. */
+ printf("scanner: buffer broken mid token\n");
+ s->have = s->pe - s->ts;
+ memmove( s->buf, s->ts, s->have );
+ s->te -= (s->ts-s->buf);
+ s->ts = s->buf;
+ }
+
+ s->p = s->buf + s->have;
+ space = BUFSIZE - s->have;
+
+ if ( space == 0 ) {
+ /* We filled up the buffer trying to scan a token. */
+ printf("scanner: out of buffer space\n");
+ return TK_ERR;
+ }
+
+ if ( s->done ) {
+ printf("scanner: end of file\n");
+ s->p[0] = 0;
+ readlen = 1;
+ }
+ else {
+ readlen = fread( s->p, 1, space, s->file );
+ if ( readlen < space )
+ s->done = 1;
+ }
+
+ s->pe = s->p + readlen;
+ }
+
+
+#line 116 "pullscan.c"
+ {
+ if ( ( s->p) == ( s->pe) )
+ goto _test_eof;
+ switch ( s->cs )
+ {
+tr0:
+#line 125 "pullscan.rl"
+ {{( s->p) = (( s->te))-1;}{ ret_tok( *s->p ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr2:
+#line 113 "pullscan.rl"
+ { s->te = ( s->p)+1;{ ret_tok( TK_String ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr4:
+#line 125 "pullscan.rl"
+ { s->te = ( s->p)+1;{ ret_tok( *s->p ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr5:
+#line 121 "pullscan.rl"
+ { s->te = ( s->p)+1;{ ret_tok( TK_EOF ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr6:
+#line 110 "pullscan.rl"
+ { s->te = ( s->p)+1;}
+ goto st2;
+tr10:
+#line 125 "pullscan.rl"
+ { s->te = ( s->p);( s->p)--;{ ret_tok( *s->p ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr11:
+#line 117 "pullscan.rl"
+ { s->te = ( s->p);( s->p)--;{ ret_tok( TK_Number ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+tr12:
+#line 107 "pullscan.rl"
+ { s->te = ( s->p);( s->p)--;{ ret_tok( TK_Identifier ); {( s->p)++; s->cs = 2; goto _out;} }}
+ goto st2;
+st2:
+#line 1 "NONE"
+ { s->ts = 0;}
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof2;
+case 2:
+#line 1 "NONE"
+ { s->ts = ( s->p);}
+#line 162 "pullscan.c"
+ switch( (*( s->p)) ) {
+ case 0: goto tr5;
+ case 32: goto tr6;
+ case 34: goto tr7;
+ case 95: goto st5;
+ }
+ if ( (*( s->p)) < 48 ) {
+ if ( 9 <= (*( s->p)) && (*( s->p)) <= 10 )
+ goto tr6;
+ } else if ( (*( s->p)) > 57 ) {
+ if ( (*( s->p)) > 90 ) {
+ if ( 97 <= (*( s->p)) && (*( s->p)) <= 122 )
+ goto st5;
+ } else if ( (*( s->p)) >= 65 )
+ goto st5;
+ } else
+ goto st4;
+ goto tr4;
+tr7:
+#line 1 "NONE"
+ { s->te = ( s->p)+1;}
+ goto st3;
+st3:
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof3;
+case 3:
+#line 189 "pullscan.c"
+ switch( (*( s->p)) ) {
+ case 34: goto tr2;
+ case 92: goto st1;
+ }
+ goto st0;
+st0:
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof0;
+case 0:
+ switch( (*( s->p)) ) {
+ case 34: goto tr2;
+ case 92: goto st1;
+ }
+ goto st0;
+st1:
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof1;
+case 1:
+ goto st0;
+st4:
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof4;
+case 4:
+ if ( 48 <= (*( s->p)) && (*( s->p)) <= 57 )
+ goto st4;
+ goto tr11;
+st5:
+ if ( ++( s->p) == ( s->pe) )
+ goto _test_eof5;
+case 5:
+ if ( (*( s->p)) == 95 )
+ goto st5;
+ if ( (*( s->p)) < 65 ) {
+ if ( 48 <= (*( s->p)) && (*( s->p)) <= 57 )
+ goto st5;
+ } else if ( (*( s->p)) > 90 ) {
+ if ( 97 <= (*( s->p)) && (*( s->p)) <= 122 )
+ goto st5;
+ } else
+ goto st5;
+ goto tr12;
+ }
+ _test_eof2: s->cs = 2; goto _test_eof;
+ _test_eof3: s->cs = 3; goto _test_eof;
+ _test_eof0: s->cs = 0; goto _test_eof;
+ _test_eof1: s->cs = 1; goto _test_eof;
+ _test_eof4: s->cs = 4; goto _test_eof;
+ _test_eof5: s->cs = 5; goto _test_eof;
+
+ _test_eof: {}
+ if ( ( s->p) == ( s->eof) )
+ {
+ switch ( s->cs ) {
+ case 3: goto tr10;
+ case 0: goto tr0;
+ case 1: goto tr0;
+ case 4: goto tr11;
+ case 5: goto tr12;
+ }
+ }
+
+ _out: {}
+ }
+
+#line 130 "pullscan.rl"
+
+
+ if ( s->cs == Scanner_error )
+ return TK_ERR;
+
+ if ( token != TK_NO_TOKEN ) {
+ s->len = s->p - s->data;
+ return token;
+ }
+ }
+}
+
+
+int main (int argc, char** argv)
+{
+ Scanner ss;
+ int tok;
+
+ scan_init(&ss, stdin);
+
+ while ( 1 ) {
+ tok = scan (&ss);
+ if ( tok == TK_EOF ) {
+ printf ("parser: EOF\n");
+ break;
+ }
+ else if ( tok == TK_ERR ) {
+ printf ("parser: ERR\n");
+ break;
+ }
+ else {
+ printf ("parser: %d \"", tok);
+ fwrite ( ss.data, 1, ss.len, stdout );
+ printf ("\"\n" );
+ }
+ }
+
+ return 0;
+}
+
+
diff --git a/examples/pullscan.rl b/examples/pullscan.rl
new file mode 100644
index 0000000..d9e8a57
--- /dev/null
+++ b/examples/pullscan.rl
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFSIZE 4096
+
+typedef struct _Scanner {
+ /* Scanner state. */
+ int cs;
+ int act;
+ int have;
+ int curline;
+ char *ts;
+ char *te;
+ char *p;
+ char *pe;
+ char *eof;
+ FILE *file;
+ int done;
+
+ /* Token data */
+ char *data;
+ int len;
+ int value;
+
+ char buf[BUFSIZE];
+} Scanner;
+
+
+%%{
+ machine Scanner;
+ write data;
+}%%
+
+void scan_init( Scanner *s, FILE *file )
+{
+ memset (s, '\0', sizeof(Scanner));
+ s->curline = 1;
+ s->file = file;
+ s->eof = 0;
+ %% write init;
+}
+
+#define TK_NO_TOKEN (-1)
+#define TK_ERR 128
+#define TK_EOF 129
+#define TK_Identifier 130
+#define TK_Number 131
+#define TK_String 132
+
+#define ret_tok( _tok ) token = _tok; s->data = s->ts
+
+int scan( Scanner *s )
+{
+ int token = TK_NO_TOKEN;
+ int space, readlen;
+
+ while ( 1 ) {
+ if ( s->p == s->pe ) {
+ printf("scanner: need more data\n");
+
+ if ( s->ts == 0 )
+ s->have = 0;
+ else {
+ /* There is data that needs to be shifted over. */
+ printf("scanner: buffer broken mid token\n");
+ s->have = s->pe - s->ts;
+ memmove( s->buf, s->ts, s->have );
+ s->te -= (s->ts-s->buf);
+ s->ts = s->buf;
+ }
+
+ s->p = s->buf + s->have;
+ space = BUFSIZE - s->have;
+
+ if ( space == 0 ) {
+ /* We filled up the buffer trying to scan a token. */
+ printf("scanner: out of buffer space\n");
+ return TK_ERR;
+ }
+
+ if ( s->done ) {
+ printf("scanner: end of file\n");
+ s->p[0] = 0;
+ readlen = 1;
+ }
+ else {
+ readlen = fread( s->p, 1, space, s->file );
+ if ( readlen < space )
+ s->done = 1;
+ }
+
+ s->pe = s->p + readlen;
+ }
+
+ %%{
+ machine Scanner;
+ access s->;
+ variable p s->p;
+ variable pe s->pe;
+ variable eof s->eof;
+
+ main := |*
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* ) =>
+ { ret_tok( TK_Identifier ); fbreak; };
+
+ # Whitespace
+ [ \t\n];
+
+ '"' ( [^\\"] | '\\' any ) * '"' =>
+ { ret_tok( TK_String ); fbreak; };
+
+ # Number
+ digit+ =>
+ { ret_tok( TK_Number ); fbreak; };
+
+ # EOF
+ 0 =>
+ { ret_tok( TK_EOF ); fbreak; };
+
+ # Anything else
+ any =>
+ { ret_tok( *s->p ); fbreak; };
+
+ *|;
+
+ write exec;
+ }%%
+
+ if ( s->cs == Scanner_error )
+ return TK_ERR;
+
+ if ( token != TK_NO_TOKEN ) {
+ s->len = s->p - s->data;
+ return token;
+ }
+ }
+}
+
+
+int main (int argc, char** argv)
+{
+ Scanner ss;
+ int tok;
+
+ scan_init(&ss, stdin);
+
+ while ( 1 ) {
+ tok = scan (&ss);
+ if ( tok == TK_EOF ) {
+ printf ("parser: EOF\n");
+ break;
+ }
+ else if ( tok == TK_ERR ) {
+ printf ("parser: ERR\n");
+ break;
+ }
+ else {
+ printf ("parser: %d \"", tok);
+ fwrite ( ss.data, 1, ss.len, stdout );
+ printf ("\"\n" );
+ }
+ }
+
+ return 0;
+}
+
+
diff --git a/examples/rlscan.cpp b/examples/rlscan.cpp
new file mode 100644
index 0000000..1c428f8
--- /dev/null
+++ b/examples/rlscan.cpp
@@ -0,0 +1,1055 @@
+
+#line 1 "rlscan.rl"
+/*
+ * Lexes Ragel input files.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+void escapeXML( char *data )
+{
+ while ( *data != 0 ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ data += 1;
+ }
+}
+
+void escapeXML( char c )
+{
+ switch ( c ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << c; break;
+ }
+}
+
+void escapeXML( char *data, int len )
+{
+ for ( char *end = data + len; data != end; data++ ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ }
+}
+
+inline void write( const char *data )
+{
+ cout << data;
+}
+
+inline void write( char c )
+{
+ cout << c;
+}
+
+inline void write( char *data, int len )
+{
+ cout.write( data, len );
+}
+
+
+
+#line 237 "rlscan.rl"
+
+
+
+#line 71 "rlscan.cpp"
+static const int RagelScan_start = 24;
+static const int RagelScan_error = 0;
+
+static const int RagelScan_en_c_comment = 6;
+static const int RagelScan_en_ilscan = 31;
+static const int RagelScan_en_rlscan = 35;
+static const int RagelScan_en_main = 24;
+
+
+#line 240 "rlscan.rl"
+
+#define BUFSIZE 2048
+
+int main()
+{
+ std::ios::sync_with_stdio(false);
+
+ int cs, act;
+ char *ts, *te;
+ int stack[1], top;
+
+ static char inbuf[BUFSIZE];
+ bool single_line = false;
+ int inline_depth = 0;
+
+
+#line 98 "rlscan.cpp"
+ {
+ cs = RagelScan_start;
+ top = 0;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 256 "rlscan.rl"
+
+ bool done = false;
+ int have = 0;
+ while ( !done ) {
+ /* How much space is in the buffer? */
+ int space = BUFSIZE - have;
+ if ( space == 0 ) {
+ /* Buffer is full. */
+ cerr << "TOKEN TOO BIG" << endl;
+ exit(1);
+ }
+
+ /* Read in a block. */
+ char *p = inbuf + have;
+ cin.read( p, space );
+ int len = cin.gcount();
+ char *pe = p + len;
+ char *eof = 0;
+
+ /* Check for EOF. */
+ if ( len == 0 ) {
+ eof = pe;
+ done = true;
+ }
+
+
+#line 134 "rlscan.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ goto _resume;
+
+_again:
+ switch ( cs ) {
+ case 24: goto st24;
+ case 25: goto st25;
+ case 1: goto st1;
+ case 2: goto st2;
+ case 26: goto st26;
+ case 27: goto st27;
+ case 28: goto st28;
+ case 3: goto st3;
+ case 4: goto st4;
+ case 29: goto st29;
+ case 5: goto st5;
+ case 6: goto st6;
+ case 0: goto st0;
+ case 7: goto st7;
+ case 30: goto st30;
+ case 31: goto st31;
+ case 32: goto st32;
+ case 8: goto st8;
+ case 9: goto st9;
+ case 33: goto st33;
+ case 10: goto st10;
+ case 11: goto st11;
+ case 34: goto st34;
+ case 12: goto st12;
+ case 35: goto st35;
+ case 36: goto st36;
+ case 13: goto st13;
+ case 14: goto st14;
+ case 37: goto st37;
+ case 15: goto st15;
+ case 38: goto st38;
+ case 16: goto st16;
+ case 17: goto st17;
+ case 39: goto st39;
+ case 18: goto st18;
+ case 19: goto st19;
+ case 40: goto st40;
+ case 41: goto st41;
+ case 20: goto st20;
+ case 42: goto st42;
+ case 43: goto st43;
+ case 44: goto st44;
+ case 21: goto st21;
+ case 22: goto st22;
+ case 45: goto st45;
+ case 23: goto st23;
+ default: break;
+ }
+
+ if ( ++p == pe )
+ goto _test_eof;
+_resume:
+ switch ( cs )
+ {
+tr0:
+#line 230 "rlscan.rl"
+ {{p = ((te))-1;}{
+ escapeXML( *ts );
+ }}
+ goto st24;
+tr2:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st24;
+tr5:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st24;
+tr8:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st24;
+tr40:
+#line 230 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( *ts );
+ }}
+ goto st24;
+tr41:
+#line 235 "rlscan.rl"
+ {te = p+1;}
+ goto st24;
+tr46:
+#line 230 "rlscan.rl"
+ {te = p;p--;{
+ escapeXML( *ts );
+ }}
+ goto st24;
+tr48:
+#line 224 "rlscan.rl"
+ {te = p;p--;{
+ write( "<section>\n" );
+ single_line = true;
+ {goto st35;}
+ }}
+ goto st24;
+tr49:
+#line 218 "rlscan.rl"
+ {te = p+1;{
+ write( "<section>\n" );
+ single_line = false;
+ {goto st35;}
+ }}
+ goto st24;
+tr50:
+#line 211 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ {stack[top++] = 24; goto st6;}
+ }}
+ goto st24;
+st24:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+#line 1 "NONE"
+ {ts = p;}
+#line 267 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr41;
+ case 34: goto tr42;
+ case 37: goto st26;
+ case 39: goto tr44;
+ case 47: goto tr45;
+ }
+ goto tr40;
+tr42:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st25;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+#line 284 "rlscan.cpp"
+ switch( (*p) ) {
+ case 34: goto tr2;
+ case 92: goto st2;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ switch( (*p) ) {
+ case 34: goto tr2;
+ case 92: goto st2;
+ }
+ goto st1;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ goto st1;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+ if ( (*p) == 37 )
+ goto st27;
+ goto tr46;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+ if ( (*p) == 123 )
+ goto tr49;
+ goto tr48;
+tr44:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st28;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+#line 326 "rlscan.cpp"
+ switch( (*p) ) {
+ case 39: goto tr5;
+ case 92: goto st4;
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ switch( (*p) ) {
+ case 39: goto tr5;
+ case 92: goto st4;
+ }
+ goto st3;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ goto st3;
+tr45:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st29;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+#line 354 "rlscan.cpp"
+ switch( (*p) ) {
+ case 42: goto tr50;
+ case 47: goto st5;
+ }
+ goto tr46;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ if ( (*p) == 10 )
+ goto tr8;
+ goto st5;
+tr9:
+#line 76 "rlscan.rl"
+ { escapeXML( (*p) ); }
+ goto st6;
+st6:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+#line 377 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto st0;
+ case 42: goto tr11;
+ }
+ goto tr9;
+st0:
+cs = 0;
+ goto _out;
+tr11:
+#line 76 "rlscan.rl"
+ { escapeXML( (*p) ); }
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+#line 394 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto st0;
+ case 42: goto tr11;
+ case 47: goto tr12;
+ }
+ goto tr9;
+tr12:
+#line 76 "rlscan.rl"
+ { escapeXML( (*p) ); }
+#line 77 "rlscan.rl"
+ { {cs = stack[--top];goto _again;} }
+ goto st30;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+#line 411 "rlscan.cpp"
+ goto st0;
+tr13:
+#line 112 "rlscan.rl"
+ {{p = ((te))-1;}{ escapeXML( *ts ); }}
+ goto st31;
+tr15:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st31;
+tr18:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st31;
+tr21:
+#line 79 "rlscan.rl"
+ {te = p+1;{
+ escapeXML( ts, te-ts );
+ }}
+ goto st31;
+tr51:
+#line 112 "rlscan.rl"
+ {te = p+1;{ escapeXML( *ts ); }}
+ goto st31;
+tr55:
+#line 97 "rlscan.rl"
+ {te = p+1;{
+ write( '{' );
+ inline_depth += 1;
+ }}
+ goto st31;
+tr56:
+#line 102 "rlscan.rl"
+ {te = p+1;{
+ write( '}' );
+ /* If dropping down to the last } then return
+ * to ragel code. */
+ if ( --inline_depth == 0 ) {
+ write( "</inline>\n" );
+ {goto st35;}
+ }
+ }}
+ goto st31;
+tr57:
+#line 112 "rlscan.rl"
+ {te = p;p--;{ escapeXML( *ts ); }}
+ goto st31;
+tr58:
+#line 91 "rlscan.rl"
+ {te = p+1;{
+ write( "/*" );
+ {stack[top++] = 31; goto st6;}
+ }}
+ goto st31;
+st31:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+#line 1 "NONE"
+ {ts = p;}
+#line 477 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto st0;
+ case 34: goto tr52;
+ case 39: goto tr53;
+ case 47: goto tr54;
+ case 123: goto tr55;
+ case 125: goto tr56;
+ }
+ goto tr51;
+tr52:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st32;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+#line 495 "rlscan.cpp"
+ switch( (*p) ) {
+ case 34: goto tr15;
+ case 92: goto st9;
+ }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ switch( (*p) ) {
+ case 34: goto tr15;
+ case 92: goto st9;
+ }
+ goto st8;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ goto st8;
+tr53:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st33;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+#line 523 "rlscan.cpp"
+ switch( (*p) ) {
+ case 39: goto tr18;
+ case 92: goto st11;
+ }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ switch( (*p) ) {
+ case 39: goto tr18;
+ case 92: goto st11;
+ }
+ goto st10;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ goto st10;
+tr54:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st34;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+#line 551 "rlscan.cpp"
+ switch( (*p) ) {
+ case 42: goto tr58;
+ case 47: goto st12;
+ }
+ goto tr57;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ if ( (*p) == 10 )
+ goto tr21;
+ goto st12;
+tr22:
+#line 193 "rlscan.rl"
+ {{p = ((te))-1;}{
+ write( "<symbol>" );
+ escapeXML( (*p) );
+ write( "</symbol>\n" );
+ }}
+ goto st35;
+tr24:
+#line 166 "rlscan.rl"
+ {te = p+1;{
+ write( "<double_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</double_lit>\n" );
+ }}
+ goto st35;
+tr27:
+#line 156 "rlscan.rl"
+ {te = p+1;}
+ goto st35;
+tr29:
+#line 159 "rlscan.rl"
+ {te = p+1;{
+ write( "<single_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</single_lit>\n" );
+ }}
+ goto st35;
+tr32:
+#line 180 "rlscan.rl"
+ {te = p+1;{
+ write( "<re_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</re_lit>\n" );
+ }}
+ goto st35;
+tr34:
+#line 142 "rlscan.rl"
+ {{p = ((te))-1;}{
+ write( "<int>" );
+ write( ts, te-ts );
+ write( "</int>\n" );
+ }}
+ goto st35;
+tr38:
+#line 173 "rlscan.rl"
+ {te = p+1;{
+ write( "<or_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</or_lit>\n" );
+ }}
+ goto st35;
+tr39:
+#line 120 "rlscan.rl"
+ {te = p+1;{
+ if ( !single_line ) {
+ write( "</section>\n" );
+ {goto st24;}
+ }
+ }}
+ goto st35;
+tr59:
+#line 199 "rlscan.rl"
+ {te = p+1;}
+ goto st35;
+tr60:
+#line 127 "rlscan.rl"
+ {te = p+1;{
+ if ( single_line ) {
+ write( "</section>\n" );
+ {goto st24;}
+ }
+ }}
+ goto st35;
+tr61:
+#line 193 "rlscan.rl"
+ {te = p+1;{
+ write( "<symbol>" );
+ escapeXML( (*p) );
+ write( "</symbol>\n" );
+ }}
+ goto st35;
+tr70:
+#line 187 "rlscan.rl"
+ {te = p+1;{
+ inline_depth = 1;
+ write( "<inline>{" );
+ {goto st31;}
+ }}
+ goto st35;
+tr72:
+#line 193 "rlscan.rl"
+ {te = p;p--;{
+ write( "<symbol>" );
+ escapeXML( (*p) );
+ write( "</symbol>\n" );
+ }}
+ goto st35;
+tr73:
+#line 142 "rlscan.rl"
+ {te = p;p--;{
+ write( "<int>" );
+ write( ts, te-ts );
+ write( "</int>\n" );
+ }}
+ goto st35;
+tr75:
+#line 149 "rlscan.rl"
+ {te = p;p--;{
+ write( "<hex>" );
+ write( ts, te-ts );
+ write( "</hex>\n" );
+ }}
+ goto st35;
+tr76:
+#line 135 "rlscan.rl"
+ {te = p;p--;{
+ write( "<word>" );
+ write( ts, te-ts );
+ write( "</word>\n" );
+ }}
+ goto st35;
+st35:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+#line 1 "NONE"
+ {ts = p;}
+#line 694 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto st0;
+ case 10: goto tr60;
+ case 34: goto tr62;
+ case 35: goto tr63;
+ case 39: goto tr64;
+ case 47: goto tr65;
+ case 48: goto tr66;
+ case 91: goto tr69;
+ case 95: goto st43;
+ case 123: goto tr70;
+ case 125: goto tr71;
+ }
+ if ( (*p) < 65 ) {
+ if ( (*p) < 49 ) {
+ if ( 33 <= (*p) && (*p) <= 46 )
+ goto tr61;
+ } else if ( (*p) > 57 ) {
+ if ( 58 <= (*p) && (*p) <= 64 )
+ goto tr61;
+ } else
+ goto st41;
+ } else if ( (*p) > 90 ) {
+ if ( (*p) < 97 ) {
+ if ( 92 <= (*p) && (*p) <= 96 )
+ goto tr61;
+ } else if ( (*p) > 122 ) {
+ if ( 124 <= (*p) && (*p) <= 126 )
+ goto tr61;
+ } else
+ goto st43;
+ } else
+ goto st43;
+ goto tr59;
+tr62:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st36;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+#line 737 "rlscan.cpp"
+ switch( (*p) ) {
+ case 34: goto tr24;
+ case 92: goto st14;
+ }
+ goto st13;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ switch( (*p) ) {
+ case 34: goto tr24;
+ case 92: goto st14;
+ }
+ goto st13;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ goto st13;
+tr63:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st37;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+#line 765 "rlscan.cpp"
+ if ( (*p) == 10 )
+ goto tr27;
+ goto st15;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ if ( (*p) == 10 )
+ goto tr27;
+ goto st15;
+tr64:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st38;
+st38:
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+#line 784 "rlscan.cpp"
+ switch( (*p) ) {
+ case 39: goto tr29;
+ case 92: goto st17;
+ }
+ goto st16;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ switch( (*p) ) {
+ case 39: goto tr29;
+ case 92: goto st17;
+ }
+ goto st16;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ goto st16;
+tr65:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st39;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+#line 812 "rlscan.cpp"
+ switch( (*p) ) {
+ case 47: goto tr32;
+ case 92: goto st19;
+ }
+ goto st18;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+ switch( (*p) ) {
+ case 47: goto tr32;
+ case 92: goto st19;
+ }
+ goto st18;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ goto st18;
+tr66:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st40;
+st40:
+ if ( ++p == pe )
+ goto _test_eof40;
+case 40:
+#line 840 "rlscan.cpp"
+ if ( (*p) == 120 )
+ goto st20;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st41;
+ goto tr73;
+st41:
+ if ( ++p == pe )
+ goto _test_eof41;
+case 41:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st41;
+ goto tr73;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st42;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st42;
+ } else
+ goto st42;
+ goto tr34;
+st42:
+ if ( ++p == pe )
+ goto _test_eof42;
+case 42:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st42;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st42;
+ } else
+ goto st42;
+ goto tr75;
+st43:
+ if ( ++p == pe )
+ goto _test_eof43;
+case 43:
+ if ( (*p) == 95 )
+ goto st43;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st43;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st43;
+ } else
+ goto st43;
+ goto tr76;
+tr69:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st44;
+st44:
+ if ( ++p == pe )
+ goto _test_eof44;
+case 44:
+#line 902 "rlscan.cpp"
+ switch( (*p) ) {
+ case 92: goto st22;
+ case 93: goto tr38;
+ }
+ goto st21;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+ switch( (*p) ) {
+ case 92: goto st22;
+ case 93: goto tr38;
+ }
+ goto st21;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+ goto st21;
+tr71:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st45;
+st45:
+ if ( ++p == pe )
+ goto _test_eof45;
+case 45:
+#line 930 "rlscan.cpp"
+ if ( (*p) == 37 )
+ goto st23;
+ goto tr72;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ if ( (*p) == 37 )
+ goto tr39;
+ goto tr22;
+ }
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof40: cs = 40; goto _test_eof;
+ _test_eof41: cs = 41; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof42: cs = 42; goto _test_eof;
+ _test_eof43: cs = 43; goto _test_eof;
+ _test_eof44: cs = 44; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof45: cs = 45; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 25: goto tr46;
+ case 1: goto tr0;
+ case 2: goto tr0;
+ case 26: goto tr46;
+ case 27: goto tr48;
+ case 28: goto tr46;
+ case 3: goto tr0;
+ case 4: goto tr0;
+ case 29: goto tr46;
+ case 5: goto tr0;
+ case 32: goto tr57;
+ case 8: goto tr13;
+ case 9: goto tr13;
+ case 33: goto tr57;
+ case 10: goto tr13;
+ case 11: goto tr13;
+ case 34: goto tr57;
+ case 12: goto tr13;
+ case 36: goto tr72;
+ case 13: goto tr22;
+ case 14: goto tr22;
+ case 37: goto tr72;
+ case 15: goto tr22;
+ case 38: goto tr72;
+ case 16: goto tr22;
+ case 17: goto tr22;
+ case 39: goto tr72;
+ case 18: goto tr22;
+ case 19: goto tr22;
+ case 40: goto tr73;
+ case 41: goto tr73;
+ case 20: goto tr34;
+ case 42: goto tr75;
+ case 43: goto tr76;
+ case 44: goto tr72;
+ case 21: goto tr22;
+ case 22: goto tr22;
+ case 45: goto tr72;
+ case 23: goto tr22;
+ }
+ }
+
+ _out: {}
+ }
+
+#line 282 "rlscan.rl"
+
+ if ( cs == RagelScan_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is a prefix to preserve, shift it over. */
+ have = pe - ts;
+ memmove( inbuf, ts, have );
+ te = inbuf + (te-ts);
+ ts = inbuf;
+ }
+ }
+ return 0;
+}
diff --git a/examples/rlscan.rl b/examples/rlscan.rl
new file mode 100644
index 0000000..d4d4bf9
--- /dev/null
+++ b/examples/rlscan.rl
@@ -0,0 +1,300 @@
+/*
+ * Lexes Ragel input files.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+void escapeXML( char *data )
+{
+ while ( *data != 0 ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ data += 1;
+ }
+}
+
+void escapeXML( char c )
+{
+ switch ( c ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << c; break;
+ }
+}
+
+void escapeXML( char *data, int len )
+{
+ for ( char *end = data + len; data != end; data++ ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ }
+}
+
+inline void write( const char *data )
+{
+ cout << data;
+}
+
+inline void write( char c )
+{
+ cout << c;
+}
+
+inline void write( char *data, int len )
+{
+ cout.write( data, len );
+}
+
+
+%%{
+ machine RagelScan;
+
+ word = [a-zA-Z_][a-zA-Z_0-9]*;
+ integer = [0-9]+;
+ hex = '0x' [0-9a-fA-F] [0-9a-fA-F]*;
+
+ default = ^0;
+ EOF = 0;
+
+ # Handles comments in outside code and inline blocks.
+ c_comment :=
+ ( default* :>> '*/' )
+ ${ escapeXML( fc ); }
+ @{ fret; };
+
+ action emit {
+ escapeXML( ts, te-ts );
+ }
+
+ #
+ # Inline action code
+ #
+
+ ilscan := |*
+
+ "'" ( [^'\\] | /\\./ )* "'" => emit;
+ '"' ( [^"\\] | /\\./ )* '"' => emit;
+ '/*' {
+ write( "/*" );
+ fcall c_comment;
+ };
+ '//' [^\n]* '\n' => emit;
+
+ '{' {
+ write( '{' );
+ inline_depth += 1;
+ };
+
+ '}' {
+ write( '}' );
+ /* If dropping down to the last } then return
+ * to ragel code. */
+ if ( --inline_depth == 0 ) {
+ write( "</inline>\n" );
+ fgoto rlscan;
+ }
+ };
+
+ default => { escapeXML( *ts ); };
+ *|;
+
+ #
+ # Ragel Tokens
+ #
+
+ rlscan := |*
+ '}%%' {
+ if ( !single_line ) {
+ write( "</section>\n" );
+ fgoto main;
+ }
+ };
+
+ '\n' {
+ if ( single_line ) {
+ write( "</section>\n" );
+ fgoto main;
+ }
+ };
+
+ # Word
+ word {
+ write( "<word>" );
+ write( ts, te-ts );
+ write( "</word>\n" );
+ };
+
+ # Decimal integer.
+ integer {
+ write( "<int>" );
+ write( ts, te-ts );
+ write( "</int>\n" );
+ };
+
+ # Hexidecimal integer.
+ hex {
+ write( "<hex>" );
+ write( ts, te-ts );
+ write( "</hex>\n" );
+ };
+
+ # Consume comments.
+ '#' [^\n]* '\n';
+
+ # Single literal string.
+ "'" ( [^'\\] | /\\./ )* "'" {
+ write( "<single_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</single_lit>\n" );
+ };
+
+ # Double literal string.
+ '"' ( [^"\\] | /\\./ )* '"' {
+ write( "<double_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</double_lit>\n" );
+ };
+
+ # Or literal.
+ '[' ( [^\]\\] | /\\./ )* ']' {
+ write( "<or_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</or_lit>\n" );
+ };
+
+ # Regex Literal.
+ '/' ( [^/\\] | /\\./ ) * '/' {
+ write( "<re_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</re_lit>\n" );
+ };
+
+ # Open an inline block
+ '{' {
+ inline_depth = 1;
+ write( "<inline>{" );
+ fgoto ilscan;
+ };
+
+ punct {
+ write( "<symbol>" );
+ escapeXML( fc );
+ write( "</symbol>\n" );
+ };
+
+ default;
+ *|;
+
+ #
+ # Outside code.
+ #
+
+ main := |*
+
+ "'" ( [^'\\] | /\\./ )* "'" => emit;
+ '"' ( [^"\\] | /\\./ )* '"' => emit;
+
+ '/*' {
+ escapeXML( ts, te-ts );
+ fcall c_comment;
+ };
+
+ '//' [^\n]* '\n' => emit;
+
+ '%%{' {
+ write( "<section>\n" );
+ single_line = false;
+ fgoto rlscan;
+ };
+
+ '%%' {
+ write( "<section>\n" );
+ single_line = true;
+ fgoto rlscan;
+ };
+
+ default {
+ escapeXML( *ts );
+ };
+
+ # EOF.
+ EOF;
+ *|;
+}%%
+
+%% write data nofinal;
+
+#define BUFSIZE 2048
+
+int main()
+{
+ std::ios::sync_with_stdio(false);
+
+ int cs, act;
+ char *ts, *te;
+ int stack[1], top;
+
+ static char inbuf[BUFSIZE];
+ bool single_line = false;
+ int inline_depth = 0;
+
+ %% write init;
+
+ bool done = false;
+ int have = 0;
+ while ( !done ) {
+ /* How much space is in the buffer? */
+ int space = BUFSIZE - have;
+ if ( space == 0 ) {
+ /* Buffer is full. */
+ cerr << "TOKEN TOO BIG" << endl;
+ exit(1);
+ }
+
+ /* Read in a block. */
+ char *p = inbuf + have;
+ cin.read( p, space );
+ int len = cin.gcount();
+ char *pe = p + len;
+ char *eof = 0;
+
+ /* Check for EOF. */
+ if ( len == 0 ) {
+ eof = pe;
+ done = true;
+ }
+
+ %% write exec;
+
+ if ( cs == RagelScan_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+
+ if ( ts == 0 )
+ have = 0;
+ else {
+ /* There is a prefix to preserve, shift it over. */
+ have = pe - ts;
+ memmove( inbuf, ts, have );
+ te = inbuf + (te-ts);
+ ts = inbuf;
+ }
+ }
+ return 0;
+}
diff --git a/examples/statechart.cpp b/examples/statechart.cpp
new file mode 100644
index 0000000..afe3b9c
--- /dev/null
+++ b/examples/statechart.cpp
@@ -0,0 +1,187 @@
+
+#line 1 "statechart.rl"
+/*
+ * Demonstrate the use of labels, the epsilon operator, and the join operator
+ * for creating machines using the named state and transition list paradigm.
+ * This implementes the same machine as the atoi example.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct StateChart
+{
+ bool neg;
+ int val;
+ int cs;
+
+ int init( );
+ int execute( const char *data, int len );
+ int finish( );
+};
+
+
+#line 66 "statechart.rl"
+
+
+
+#line 33 "statechart.cpp"
+static const int StateChart_start = 3;
+static const int StateChart_first_final = 3;
+static const int StateChart_error = 0;
+
+static const int StateChart_en_main = 3;
+
+
+#line 69 "statechart.rl"
+
+int StateChart::init( )
+{
+ neg = false;
+ val = false;
+
+#line 48 "statechart.cpp"
+ {
+ cs = StateChart_start;
+ }
+
+#line 75 "statechart.rl"
+ return 1;
+}
+
+int StateChart::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+
+
+#line 63 "statechart.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr2:
+#line 41 "statechart.rl"
+ {
+ if ( neg )
+ val = -1 * val;
+ }
+#line 65 "statechart.rl"
+ { cout << val << endl; }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 82 "statechart.cpp"
+ switch( (*p) ) {
+ case 43: goto tr3;
+ case 45: goto tr4;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr5;
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+tr3:
+#line 28 "statechart.rl"
+ {
+ neg = false;
+ val = 0;
+ }
+ goto st1;
+tr4:
+#line 28 "statechart.rl"
+ {
+ neg = false;
+ val = 0;
+ }
+#line 33 "statechart.rl"
+ {
+ neg = true;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 115 "statechart.cpp"
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr0;
+ goto st0;
+tr0:
+#line 37 "statechart.rl"
+ {
+ val = val * 10 + ((*p) - '0');
+ }
+ goto st2;
+tr5:
+#line 28 "statechart.rl"
+ {
+ neg = false;
+ val = 0;
+ }
+#line 37 "statechart.rl"
+ {
+ val = val * 10 + ((*p) - '0');
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 140 "statechart.cpp"
+ if ( (*p) == 10 )
+ goto tr2;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr0;
+ goto st0;
+ }
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 84 "statechart.rl"
+
+ if ( cs == StateChart_error )
+ return -1;
+ if ( cs >= StateChart_first_final )
+ return 1;
+ return 0;
+}
+
+int StateChart::finish( )
+{
+ if ( cs == StateChart_error )
+ return -1;
+ if ( cs >= StateChart_first_final )
+ return 1;
+ return 0;
+}
+
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+
+ StateChart atoi;
+ atoi.init();
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 ) {
+ atoi.execute( buf, strlen(buf) );
+ }
+ if ( atoi.finish() <= 0 )
+ cerr << "statechart: error: parsing input" << endl;
+ return 0;
+}
diff --git a/examples/statechart.rl b/examples/statechart.rl
new file mode 100644
index 0000000..a04471b
--- /dev/null
+++ b/examples/statechart.rl
@@ -0,0 +1,116 @@
+/*
+ * Demonstrate the use of labels, the epsilon operator, and the join operator
+ * for creating machines using the named state and transition list paradigm.
+ * This implementes the same machine as the atoi example.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct StateChart
+{
+ bool neg;
+ int val;
+ int cs;
+
+ int init( );
+ int execute( const char *data, int len );
+ int finish( );
+};
+
+%%{
+ machine StateChart;
+
+ action begin {
+ neg = false;
+ val = 0;
+ }
+
+ action see_neg {
+ neg = true;
+ }
+
+ action add_digit {
+ val = val * 10 + (fc - '0');
+ }
+
+ action finish {
+ if ( neg )
+ val = -1 * val;
+ }
+
+ atoi = (
+ start: (
+ '-' @see_neg ->om_num |
+ '+' ->om_num |
+ [0-9] @add_digit ->more_nums
+ ),
+
+ # One or more nums.
+ om_num: (
+ [0-9] @add_digit ->more_nums
+ ),
+
+ # Zero ore more nums.
+ more_nums: (
+ [0-9] @add_digit ->more_nums |
+ '' -> final
+ )
+ ) >begin %finish;
+
+ main := ( atoi '\n' @{ cout << val << endl; } )*;
+}%%
+
+%% write data;
+
+int StateChart::init( )
+{
+ neg = false;
+ val = false;
+ %% write init;
+ return 1;
+}
+
+int StateChart::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+
+ %% write exec;
+
+ if ( cs == StateChart_error )
+ return -1;
+ if ( cs >= StateChart_first_final )
+ return 1;
+ return 0;
+}
+
+int StateChart::finish( )
+{
+ if ( cs == StateChart_error )
+ return -1;
+ if ( cs >= StateChart_first_final )
+ return 1;
+ return 0;
+}
+
+
+#define BUFSIZE 1024
+
+int main()
+{
+ char buf[BUFSIZE];
+
+ StateChart atoi;
+ atoi.init();
+ while ( fgets( buf, sizeof(buf), stdin ) != 0 ) {
+ atoi.execute( buf, strlen(buf) );
+ }
+ if ( atoi.finish() <= 0 )
+ cerr << "statechart: error: parsing input" << endl;
+ return 0;
+}
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..377bb86
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/missing b/missing
new file mode 100755
index 0000000..db98974
--- /dev/null
+++ b/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ragel.vim b/ragel.vim
new file mode 100644
index 0000000..f94ae0f
--- /dev/null
+++ b/ragel.vim
@@ -0,0 +1,153 @@
+" Vim syntax file
+"
+" Language: Ragel
+" Author: Adrian Thurston
+
+syntax clear
+
+"
+" Outside code
+"
+
+" Comments
+syntax region ocComment start="\/\*" end="\*\/"
+syntax match ocComment "\/\/.*$"
+
+" Anything preprocessor
+syntax match ocPreproc "#\(.\|\\\n\)*$"
+syntax region ocPreproc start="#" end="[^\\]$"
+
+" Strings
+syntax match ocLiteral "'\(\\.\|[^'\\]\)*'"
+syntax match ocLiteral "\"\(\\.\|[^\"\\]\)*\""
+
+" C/C++ Keywords
+syntax keyword ocType unsigned signed void char short int long float double bool
+syntax keyword ocType inline static extern register const volatile auto
+syntax keyword ocType union enum struct class typedef
+syntax keyword ocType namespace template typename mutable
+syntax keyword ocKeyword break continue default do else for
+syntax keyword ocKeyword goto if return switch while
+syntax keyword ocKeyword new delete this using friend public private protected sizeof
+syntax keyword ocKeyword throw try catch operator typeid
+syntax keyword ocKeyword and bitor xor compl bitand and_eq or_eq xor_eq not not_eq
+syntax keyword ocKeyword static_cast dynamic_cast
+
+" Numbers
+syntax match ocNumber "[0-9][0-9]*[Ll]\?[Ll]\?"
+syntax match ocNumber "0x[0-9a-fA-F][0-9a-fA-F]*"
+
+" Booleans
+syntax keyword ocBoolean true false
+
+" Identifiers
+syntax match anyId "[a-zA-Z_][a-zA-Z_0-9]*"
+
+" Inline code only
+syntax keyword fsmType fpc fc fcurs fbuf fblen ftargs fstack
+syntax keyword fsmKeyword fhold fgoto fcall fret fentry fnext fexec fbreak
+
+syntax cluster rlItems contains=rlComment,rlLiteral,rlAugmentOps,rlOtherOps,rlKeywords,rlWrite,rlCodeCurly,rlCodeSemi,rlNumber,anyId,rlLabelColon,rlExprKeywords,rlBuiltIns
+
+syntax region machineSpec1 matchgroup=beginRL start="%%{" end="}%%" contains=@rlItems
+syntax region machineSpec2 matchgroup=beginRL start="%%[^{]"rs=e-1 end="$" keepend contains=@rlItems
+syntax region machineSpec2 matchgroup=beginRL start="%%$" end="$" keepend contains=@rlItems
+
+" Comments
+syntax match rlComment "#.*$" contained
+
+" Literals
+syntax match rlLiteral "'\(\\.\|[^'\\]\)*'[i]*" contained
+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 rlAugmentOps "[>$%@]" contained
+syntax match rlAugmentOps "<>\|<" contained
+syntax match rlAugmentOps "[>\<$%@][!\^/*~]" contained
+syntax match rlAugmentOps "[>$%]?" contained
+syntax match rlAugmentOps "<>[!\^/*~]" contained
+syntax match rlAugmentOps "=>" contained
+syntax match rlOtherOps "->" contained
+
+syntax match rlOtherOps ":>" contained
+syntax match rlOtherOps ":>>" contained
+syntax match rlOtherOps "<:" contained
+
+" Keywords
+" FIXME: Enable the range keyword post 5.17.
+" syntax keyword rlKeywords machine action context include range contained
+syntax keyword rlKeywords machine action context include import export prepush postpop contained
+syntax keyword rlExprKeywords when inwhen outwhen err lerr eof from to contained
+
+" Built-in rules
+syntax keyword rlBuiltIns any ascii extend alpha digit alnum lower upper xdigit cntrl graph print punct space zlen empty contained
+
+" Case Labels
+syntax keyword caseLabelKeyword case contained
+syntax cluster caseLabelItems contains=ocComment,ocPreproc,ocLiteral,ocType,ocKeyword,caseLabelKeyword,ocNumber,ocBoolean,anyId,fsmType,fsmKeyword
+syntax match caseLabelColon "case" contains=@caseLabelItems
+syntax match caseLabelColon "case[\t ]\+.*:$" contains=@caseLabelItems
+syntax match caseLabelColon "case[\t ]\+.*:[^=:]"me=e-1 contains=@caseLabelItems
+
+" Labels
+syntax match ocLabelColon "^[\t ]*[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:$" contains=anyLabel
+syntax match ocLabelColon "^[\t ]*[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:[^=:]"me=e-1 contains=anyLabel
+
+syntax match rlLabelColon "[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:$" contained contains=anyLabel
+syntax match rlLabelColon "[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:[^=:>]"me=e-1 contained contains=anyLabel
+syntax match anyLabel "[a-zA-Z_][a-zA-Z_0-9]*" contained
+
+" All items that can go in a code block.
+
+syntax cluster inlineItems contains=rlCodeCurly,ocComment,ocPreproc,ocLiteral,ocType,ocKeyword,ocNumber,ocBoolean,ocLabelColon,anyId,fsmType,fsmKeyword,caseLabelColon
+
+" Blocks of code. rlCodeCurly is recursive.
+syntax region rlCodeCurly matchgroup=NONE start="{" end="}" contained contains=@inlineItems
+syntax region rlCodeSemi matchgroup=Type start="\<alphtype\>" start="\<getkey\>" start="\<access\>" start="\<variable\>" matchgroup=NONE end=";" contained contains=@inlineItems
+
+syntax region rlWrite matchgroup=Type start="\<write\>" matchgroup=NONE end="[;)]" contained contains=rlWriteKeywords,rlWriteOptions
+
+syntax keyword rlWriteKeywords init data exec exports start error first_final contained
+syntax keyword rlWriteOptions noerror nofinal noprefix noend nocs contained
+
+"
+" Sync at the start of machine specs.
+"
+" Match The ragel delimiters only if there quotes no ahead on the same line.
+" On the open marker, use & to consume the leader.
+syntax sync match ragelSyncPat grouphere NONE "^[^\'\"%]*%%{&^[^\'\"%]*"
+syntax sync match ragelSyncPat grouphere NONE "^[^\'\"%]*%%[^{]&^[^\'\"%]*"
+syntax sync match ragelSyncPat grouphere NONE "^[^\'\"]*}%%"
+
+"
+" Specifying Groups
+"
+hi link ocComment Comment
+hi link ocPreproc Macro
+hi link ocLiteral String
+hi link ocType Type
+hi link ocKeyword Keyword
+hi link ocNumber Number
+hi link ocBoolean Boolean
+hi link rlComment Comment
+hi link rlNumber Number
+hi link rlLiteral String
+hi link rlAugmentOps Keyword
+hi link rlExprKeywords Keyword
+hi link rlWriteKeywords Keyword
+hi link rlWriteOptions Keyword
+hi link rlKeywords Type
+hi link fsmType Type
+hi link fsmKeyword Keyword
+hi link anyLabel Label
+hi link caseLabelKeyword Keyword
+hi link beginRL Type
+hi link rlBuiltIns Constant
+
+let b:current_syntax = "ragel"
diff --git a/ragel/Makefile.am b/ragel/Makefile.am
new file mode 100644
index 0000000..48999ad
--- /dev/null
+++ b/ragel/Makefile.am
@@ -0,0 +1,58 @@
+
+INCLUDES = -I$(top_srcdir)/aapl
+
+bin_PROGRAMS = ragel
+
+ragel_CXXFLAGS = -Wall
+
+ragel_SOURCES = \
+ buffer.h cdgoto.h cscodegen.h csipgoto.h inputdata.h rbxgoto.h \
+ rubyflat.h cdcodegen.h cdipgoto.h csfflat.h cssplit.h javacodegen.h \
+ redfsm.h rubyftable.h cdfflat.h cdsplit.h csfgoto.h cstable.h \
+ parsedata.h rlparse.h rubytable.h cdfgoto.h cdtable.h csflat.h \
+ dotcodegen.h parsetree.h rlscan.h version.h cdflat.h common.h \
+ csftable.h fsmgraph.h pcheck.h rubycodegen.h xmlcodegen.h cdftable.h \
+ csgoto.h gendata.h ragel.h rubyfflat.h \
+ gocodegen.h gotable.h goftable.h goflat.h gofflat.h gogoto.h gofgoto.h \
+ goipgoto.h gotablish.h \
+ mlcodegen.h mltable.h mlftable.h mlflat.h mlfflat.h mlgoto.h mlfgoto.h \
+ main.cpp parsetree.cpp parsedata.cpp fsmstate.cpp fsmbase.cpp \
+ fsmattach.cpp fsmmin.cpp fsmgraph.cpp fsmap.cpp rlscan.cpp rlparse.cpp \
+ inputdata.cpp common.cpp redfsm.cpp gendata.cpp cdcodegen.cpp \
+ cdtable.cpp cdftable.cpp cdflat.cpp cdfflat.cpp cdgoto.cpp cdfgoto.cpp \
+ cdipgoto.cpp cdsplit.cpp javacodegen.cpp rubycodegen.cpp rubytable.cpp \
+ rubyftable.cpp rubyflat.cpp rubyfflat.cpp rbxgoto.cpp cscodegen.cpp \
+ cstable.cpp csftable.cpp csflat.cpp csfflat.cpp csgoto.cpp csfgoto.cpp \
+ csipgoto.cpp cssplit.cpp dotcodegen.cpp xmlcodegen.cpp \
+ gocodegen.cpp gotable.cpp goftable.cpp goflat.cpp gofflat.cpp gogoto.cpp gofgoto.cpp \
+ goipgoto.cpp gotablish.cpp \
+ mlcodegen.cpp mltable.cpp mlftable.cpp mlflat.cpp mlfflat.cpp mlgoto.cpp mlfgoto.cpp
+
+BUILT_SOURCES = \
+ rlscan.cpp rlparse.h rlparse.cpp version.h
+
+version.h: Makefile
+ echo '#define VERSION "$(PACKAGE_VERSION)"' > version.h
+ echo '#define PUBDATE "$(PUBDATE)"' >> version.h
+
+EXTRA_DIST = rlscan.rl rlparse.kh rlparse.kl
+
+if BUILD_PARSERS
+
+CLEANFILES = \
+ rlscan.cpp rlparse.h rlparse.cpp
+
+rlparse.h: rlparse.kh
+ kelbt -o $@ $<
+
+rlparse.cpp: rlparse.kl rlparse.kh
+ kelbt -o $@ $<
+
+# This dependency comes from the import of the parser defines
+# into the scanner.
+rlscan.cpp: rlparse.h
+
+rlscan.cpp: rlscan.rl
+ ragel -G2 -I$(builddir) -o $@ $<
+
+endif
diff --git a/ragel/Makefile.in b/ragel/Makefile.in
new file mode 100644
index 0000000..8760e48
--- /dev/null
+++ b/ragel/Makefile.in
@@ -0,0 +1,1549 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = ragel$(EXEEXT)
+subdir = ragel
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/config.h.in $(top_srcdir)/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_ragel_OBJECTS = ragel-main.$(OBJEXT) ragel-parsetree.$(OBJEXT) \
+ ragel-parsedata.$(OBJEXT) ragel-fsmstate.$(OBJEXT) \
+ ragel-fsmbase.$(OBJEXT) ragel-fsmattach.$(OBJEXT) \
+ ragel-fsmmin.$(OBJEXT) ragel-fsmgraph.$(OBJEXT) \
+ ragel-fsmap.$(OBJEXT) ragel-rlscan.$(OBJEXT) \
+ ragel-rlparse.$(OBJEXT) ragel-inputdata.$(OBJEXT) \
+ ragel-common.$(OBJEXT) ragel-redfsm.$(OBJEXT) \
+ ragel-gendata.$(OBJEXT) ragel-cdcodegen.$(OBJEXT) \
+ ragel-cdtable.$(OBJEXT) ragel-cdftable.$(OBJEXT) \
+ ragel-cdflat.$(OBJEXT) ragel-cdfflat.$(OBJEXT) \
+ ragel-cdgoto.$(OBJEXT) ragel-cdfgoto.$(OBJEXT) \
+ ragel-cdipgoto.$(OBJEXT) ragel-cdsplit.$(OBJEXT) \
+ ragel-javacodegen.$(OBJEXT) ragel-rubycodegen.$(OBJEXT) \
+ ragel-rubytable.$(OBJEXT) ragel-rubyftable.$(OBJEXT) \
+ ragel-rubyflat.$(OBJEXT) ragel-rubyfflat.$(OBJEXT) \
+ ragel-rbxgoto.$(OBJEXT) ragel-cscodegen.$(OBJEXT) \
+ ragel-cstable.$(OBJEXT) ragel-csftable.$(OBJEXT) \
+ ragel-csflat.$(OBJEXT) ragel-csfflat.$(OBJEXT) \
+ ragel-csgoto.$(OBJEXT) ragel-csfgoto.$(OBJEXT) \
+ ragel-csipgoto.$(OBJEXT) ragel-cssplit.$(OBJEXT) \
+ ragel-dotcodegen.$(OBJEXT) ragel-xmlcodegen.$(OBJEXT) \
+ ragel-gocodegen.$(OBJEXT) ragel-gotable.$(OBJEXT) \
+ ragel-goftable.$(OBJEXT) ragel-goflat.$(OBJEXT) \
+ ragel-gofflat.$(OBJEXT) ragel-gogoto.$(OBJEXT) \
+ ragel-gofgoto.$(OBJEXT) ragel-goipgoto.$(OBJEXT) \
+ ragel-gotablish.$(OBJEXT) ragel-mlcodegen.$(OBJEXT) \
+ ragel-mltable.$(OBJEXT) ragel-mlftable.$(OBJEXT) \
+ ragel-mlflat.$(OBJEXT) ragel-mlfflat.$(OBJEXT) \
+ ragel-mlgoto.$(OBJEXT) ragel-mlfgoto.$(OBJEXT)
+ragel_OBJECTS = $(am_ragel_OBJECTS)
+ragel_LDADD = $(LDADD)
+ragel_LINK = $(CXXLD) $(ragel_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(ragel_SOURCES)
+DIST_SOURCES = $(ragel_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)/aapl
+ragel_CXXFLAGS = -Wall
+ragel_SOURCES = \
+ buffer.h cdgoto.h cscodegen.h csipgoto.h inputdata.h rbxgoto.h \
+ rubyflat.h cdcodegen.h cdipgoto.h csfflat.h cssplit.h javacodegen.h \
+ redfsm.h rubyftable.h cdfflat.h cdsplit.h csfgoto.h cstable.h \
+ parsedata.h rlparse.h rubytable.h cdfgoto.h cdtable.h csflat.h \
+ dotcodegen.h parsetree.h rlscan.h version.h cdflat.h common.h \
+ csftable.h fsmgraph.h pcheck.h rubycodegen.h xmlcodegen.h cdftable.h \
+ csgoto.h gendata.h ragel.h rubyfflat.h \
+ gocodegen.h gotable.h goftable.h goflat.h gofflat.h gogoto.h gofgoto.h \
+ goipgoto.h gotablish.h \
+ mlcodegen.h mltable.h mlftable.h mlflat.h mlfflat.h mlgoto.h mlfgoto.h \
+ main.cpp parsetree.cpp parsedata.cpp fsmstate.cpp fsmbase.cpp \
+ fsmattach.cpp fsmmin.cpp fsmgraph.cpp fsmap.cpp rlscan.cpp rlparse.cpp \
+ inputdata.cpp common.cpp redfsm.cpp gendata.cpp cdcodegen.cpp \
+ cdtable.cpp cdftable.cpp cdflat.cpp cdfflat.cpp cdgoto.cpp cdfgoto.cpp \
+ cdipgoto.cpp cdsplit.cpp javacodegen.cpp rubycodegen.cpp rubytable.cpp \
+ rubyftable.cpp rubyflat.cpp rubyfflat.cpp rbxgoto.cpp cscodegen.cpp \
+ cstable.cpp csftable.cpp csflat.cpp csfflat.cpp csgoto.cpp csfgoto.cpp \
+ csipgoto.cpp cssplit.cpp dotcodegen.cpp xmlcodegen.cpp \
+ gocodegen.cpp gotable.cpp goftable.cpp goflat.cpp gofflat.cpp gogoto.cpp gofgoto.cpp \
+ goipgoto.cpp gotablish.cpp \
+ mlcodegen.cpp mltable.cpp mlftable.cpp mlflat.cpp mlfflat.cpp mlgoto.cpp mlfgoto.cpp
+
+BUILT_SOURCES = \
+ rlscan.cpp rlparse.h rlparse.cpp version.h
+
+EXTRA_DIST = rlscan.rl rlparse.kh rlparse.kl
+@BUILD_PARSERS_TRUE@CLEANFILES = \
+@BUILD_PARSERS_TRUE@ rlscan.cpp rlparse.h rlparse.cpp
+
+all: $(BUILT_SOURCES) config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ragel/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ragel/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status ragel/config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+ragel$(EXEEXT): $(ragel_OBJECTS) $(ragel_DEPENDENCIES) $(EXTRA_ragel_DEPENDENCIES)
+ @rm -f ragel$(EXEEXT)
+ $(AM_V_CXXLD)$(ragel_LINK) $(ragel_OBJECTS) $(ragel_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdcodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdfflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdfgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdftable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdipgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdsplit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cdtable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cscodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csfflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csfgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csftable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-csipgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cssplit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-cstable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-dotcodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmattach.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmbase.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmgraph.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmmin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-fsmstate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gendata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gocodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gofflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gofgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-goflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-goftable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gogoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-goipgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gotable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-gotablish.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-inputdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-javacodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlcodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlfflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlfgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlftable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mlgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-mltable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-parsedata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-parsetree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rbxgoto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-redfsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rlparse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rlscan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rubycodegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rubyfflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rubyflat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rubyftable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-rubytable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ragel-xmlcodegen.Po@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ragel-main.o: main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-main.o -MD -MP -MF $(DEPDIR)/ragel-main.Tpo -c -o ragel-main.o `test -f 'main.cpp' || echo '$(srcdir)/'`main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-main.Tpo $(DEPDIR)/ragel-main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='main.cpp' object='ragel-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-main.o `test -f 'main.cpp' || echo '$(srcdir)/'`main.cpp
+
+ragel-main.obj: main.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-main.obj -MD -MP -MF $(DEPDIR)/ragel-main.Tpo -c -o ragel-main.obj `if test -f 'main.cpp'; then $(CYGPATH_W) 'main.cpp'; else $(CYGPATH_W) '$(srcdir)/main.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-main.Tpo $(DEPDIR)/ragel-main.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='main.cpp' object='ragel-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-main.obj `if test -f 'main.cpp'; then $(CYGPATH_W) 'main.cpp'; else $(CYGPATH_W) '$(srcdir)/main.cpp'; fi`
+
+ragel-parsetree.o: parsetree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-parsetree.o -MD -MP -MF $(DEPDIR)/ragel-parsetree.Tpo -c -o ragel-parsetree.o `test -f 'parsetree.cpp' || echo '$(srcdir)/'`parsetree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-parsetree.Tpo $(DEPDIR)/ragel-parsetree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parsetree.cpp' object='ragel-parsetree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-parsetree.o `test -f 'parsetree.cpp' || echo '$(srcdir)/'`parsetree.cpp
+
+ragel-parsetree.obj: parsetree.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-parsetree.obj -MD -MP -MF $(DEPDIR)/ragel-parsetree.Tpo -c -o ragel-parsetree.obj `if test -f 'parsetree.cpp'; then $(CYGPATH_W) 'parsetree.cpp'; else $(CYGPATH_W) '$(srcdir)/parsetree.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-parsetree.Tpo $(DEPDIR)/ragel-parsetree.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parsetree.cpp' object='ragel-parsetree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-parsetree.obj `if test -f 'parsetree.cpp'; then $(CYGPATH_W) 'parsetree.cpp'; else $(CYGPATH_W) '$(srcdir)/parsetree.cpp'; fi`
+
+ragel-parsedata.o: parsedata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-parsedata.o -MD -MP -MF $(DEPDIR)/ragel-parsedata.Tpo -c -o ragel-parsedata.o `test -f 'parsedata.cpp' || echo '$(srcdir)/'`parsedata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-parsedata.Tpo $(DEPDIR)/ragel-parsedata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parsedata.cpp' object='ragel-parsedata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-parsedata.o `test -f 'parsedata.cpp' || echo '$(srcdir)/'`parsedata.cpp
+
+ragel-parsedata.obj: parsedata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-parsedata.obj -MD -MP -MF $(DEPDIR)/ragel-parsedata.Tpo -c -o ragel-parsedata.obj `if test -f 'parsedata.cpp'; then $(CYGPATH_W) 'parsedata.cpp'; else $(CYGPATH_W) '$(srcdir)/parsedata.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-parsedata.Tpo $(DEPDIR)/ragel-parsedata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parsedata.cpp' object='ragel-parsedata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-parsedata.obj `if test -f 'parsedata.cpp'; then $(CYGPATH_W) 'parsedata.cpp'; else $(CYGPATH_W) '$(srcdir)/parsedata.cpp'; fi`
+
+ragel-fsmstate.o: fsmstate.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmstate.o -MD -MP -MF $(DEPDIR)/ragel-fsmstate.Tpo -c -o ragel-fsmstate.o `test -f 'fsmstate.cpp' || echo '$(srcdir)/'`fsmstate.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmstate.Tpo $(DEPDIR)/ragel-fsmstate.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmstate.cpp' object='ragel-fsmstate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmstate.o `test -f 'fsmstate.cpp' || echo '$(srcdir)/'`fsmstate.cpp
+
+ragel-fsmstate.obj: fsmstate.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmstate.obj -MD -MP -MF $(DEPDIR)/ragel-fsmstate.Tpo -c -o ragel-fsmstate.obj `if test -f 'fsmstate.cpp'; then $(CYGPATH_W) 'fsmstate.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmstate.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmstate.Tpo $(DEPDIR)/ragel-fsmstate.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmstate.cpp' object='ragel-fsmstate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmstate.obj `if test -f 'fsmstate.cpp'; then $(CYGPATH_W) 'fsmstate.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmstate.cpp'; fi`
+
+ragel-fsmbase.o: fsmbase.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmbase.o -MD -MP -MF $(DEPDIR)/ragel-fsmbase.Tpo -c -o ragel-fsmbase.o `test -f 'fsmbase.cpp' || echo '$(srcdir)/'`fsmbase.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmbase.Tpo $(DEPDIR)/ragel-fsmbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmbase.cpp' object='ragel-fsmbase.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmbase.o `test -f 'fsmbase.cpp' || echo '$(srcdir)/'`fsmbase.cpp
+
+ragel-fsmbase.obj: fsmbase.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmbase.obj -MD -MP -MF $(DEPDIR)/ragel-fsmbase.Tpo -c -o ragel-fsmbase.obj `if test -f 'fsmbase.cpp'; then $(CYGPATH_W) 'fsmbase.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmbase.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmbase.Tpo $(DEPDIR)/ragel-fsmbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmbase.cpp' object='ragel-fsmbase.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmbase.obj `if test -f 'fsmbase.cpp'; then $(CYGPATH_W) 'fsmbase.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmbase.cpp'; fi`
+
+ragel-fsmattach.o: fsmattach.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmattach.o -MD -MP -MF $(DEPDIR)/ragel-fsmattach.Tpo -c -o ragel-fsmattach.o `test -f 'fsmattach.cpp' || echo '$(srcdir)/'`fsmattach.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmattach.Tpo $(DEPDIR)/ragel-fsmattach.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmattach.cpp' object='ragel-fsmattach.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmattach.o `test -f 'fsmattach.cpp' || echo '$(srcdir)/'`fsmattach.cpp
+
+ragel-fsmattach.obj: fsmattach.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmattach.obj -MD -MP -MF $(DEPDIR)/ragel-fsmattach.Tpo -c -o ragel-fsmattach.obj `if test -f 'fsmattach.cpp'; then $(CYGPATH_W) 'fsmattach.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmattach.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmattach.Tpo $(DEPDIR)/ragel-fsmattach.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmattach.cpp' object='ragel-fsmattach.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmattach.obj `if test -f 'fsmattach.cpp'; then $(CYGPATH_W) 'fsmattach.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmattach.cpp'; fi`
+
+ragel-fsmmin.o: fsmmin.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmmin.o -MD -MP -MF $(DEPDIR)/ragel-fsmmin.Tpo -c -o ragel-fsmmin.o `test -f 'fsmmin.cpp' || echo '$(srcdir)/'`fsmmin.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmmin.Tpo $(DEPDIR)/ragel-fsmmin.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmmin.cpp' object='ragel-fsmmin.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmmin.o `test -f 'fsmmin.cpp' || echo '$(srcdir)/'`fsmmin.cpp
+
+ragel-fsmmin.obj: fsmmin.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmmin.obj -MD -MP -MF $(DEPDIR)/ragel-fsmmin.Tpo -c -o ragel-fsmmin.obj `if test -f 'fsmmin.cpp'; then $(CYGPATH_W) 'fsmmin.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmmin.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmmin.Tpo $(DEPDIR)/ragel-fsmmin.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmmin.cpp' object='ragel-fsmmin.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmmin.obj `if test -f 'fsmmin.cpp'; then $(CYGPATH_W) 'fsmmin.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmmin.cpp'; fi`
+
+ragel-fsmgraph.o: fsmgraph.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmgraph.o -MD -MP -MF $(DEPDIR)/ragel-fsmgraph.Tpo -c -o ragel-fsmgraph.o `test -f 'fsmgraph.cpp' || echo '$(srcdir)/'`fsmgraph.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmgraph.Tpo $(DEPDIR)/ragel-fsmgraph.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmgraph.cpp' object='ragel-fsmgraph.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmgraph.o `test -f 'fsmgraph.cpp' || echo '$(srcdir)/'`fsmgraph.cpp
+
+ragel-fsmgraph.obj: fsmgraph.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmgraph.obj -MD -MP -MF $(DEPDIR)/ragel-fsmgraph.Tpo -c -o ragel-fsmgraph.obj `if test -f 'fsmgraph.cpp'; then $(CYGPATH_W) 'fsmgraph.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmgraph.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmgraph.Tpo $(DEPDIR)/ragel-fsmgraph.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmgraph.cpp' object='ragel-fsmgraph.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmgraph.obj `if test -f 'fsmgraph.cpp'; then $(CYGPATH_W) 'fsmgraph.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmgraph.cpp'; fi`
+
+ragel-fsmap.o: fsmap.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmap.o -MD -MP -MF $(DEPDIR)/ragel-fsmap.Tpo -c -o ragel-fsmap.o `test -f 'fsmap.cpp' || echo '$(srcdir)/'`fsmap.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmap.Tpo $(DEPDIR)/ragel-fsmap.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmap.cpp' object='ragel-fsmap.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmap.o `test -f 'fsmap.cpp' || echo '$(srcdir)/'`fsmap.cpp
+
+ragel-fsmap.obj: fsmap.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-fsmap.obj -MD -MP -MF $(DEPDIR)/ragel-fsmap.Tpo -c -o ragel-fsmap.obj `if test -f 'fsmap.cpp'; then $(CYGPATH_W) 'fsmap.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmap.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-fsmap.Tpo $(DEPDIR)/ragel-fsmap.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fsmap.cpp' object='ragel-fsmap.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-fsmap.obj `if test -f 'fsmap.cpp'; then $(CYGPATH_W) 'fsmap.cpp'; else $(CYGPATH_W) '$(srcdir)/fsmap.cpp'; fi`
+
+ragel-rlscan.o: rlscan.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rlscan.o -MD -MP -MF $(DEPDIR)/ragel-rlscan.Tpo -c -o ragel-rlscan.o `test -f 'rlscan.cpp' || echo '$(srcdir)/'`rlscan.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rlscan.Tpo $(DEPDIR)/ragel-rlscan.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rlscan.cpp' object='ragel-rlscan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rlscan.o `test -f 'rlscan.cpp' || echo '$(srcdir)/'`rlscan.cpp
+
+ragel-rlscan.obj: rlscan.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rlscan.obj -MD -MP -MF $(DEPDIR)/ragel-rlscan.Tpo -c -o ragel-rlscan.obj `if test -f 'rlscan.cpp'; then $(CYGPATH_W) 'rlscan.cpp'; else $(CYGPATH_W) '$(srcdir)/rlscan.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rlscan.Tpo $(DEPDIR)/ragel-rlscan.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rlscan.cpp' object='ragel-rlscan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rlscan.obj `if test -f 'rlscan.cpp'; then $(CYGPATH_W) 'rlscan.cpp'; else $(CYGPATH_W) '$(srcdir)/rlscan.cpp'; fi`
+
+ragel-rlparse.o: rlparse.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rlparse.o -MD -MP -MF $(DEPDIR)/ragel-rlparse.Tpo -c -o ragel-rlparse.o `test -f 'rlparse.cpp' || echo '$(srcdir)/'`rlparse.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rlparse.Tpo $(DEPDIR)/ragel-rlparse.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rlparse.cpp' object='ragel-rlparse.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rlparse.o `test -f 'rlparse.cpp' || echo '$(srcdir)/'`rlparse.cpp
+
+ragel-rlparse.obj: rlparse.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rlparse.obj -MD -MP -MF $(DEPDIR)/ragel-rlparse.Tpo -c -o ragel-rlparse.obj `if test -f 'rlparse.cpp'; then $(CYGPATH_W) 'rlparse.cpp'; else $(CYGPATH_W) '$(srcdir)/rlparse.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rlparse.Tpo $(DEPDIR)/ragel-rlparse.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rlparse.cpp' object='ragel-rlparse.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rlparse.obj `if test -f 'rlparse.cpp'; then $(CYGPATH_W) 'rlparse.cpp'; else $(CYGPATH_W) '$(srcdir)/rlparse.cpp'; fi`
+
+ragel-inputdata.o: inputdata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-inputdata.o -MD -MP -MF $(DEPDIR)/ragel-inputdata.Tpo -c -o ragel-inputdata.o `test -f 'inputdata.cpp' || echo '$(srcdir)/'`inputdata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-inputdata.Tpo $(DEPDIR)/ragel-inputdata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='inputdata.cpp' object='ragel-inputdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-inputdata.o `test -f 'inputdata.cpp' || echo '$(srcdir)/'`inputdata.cpp
+
+ragel-inputdata.obj: inputdata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-inputdata.obj -MD -MP -MF $(DEPDIR)/ragel-inputdata.Tpo -c -o ragel-inputdata.obj `if test -f 'inputdata.cpp'; then $(CYGPATH_W) 'inputdata.cpp'; else $(CYGPATH_W) '$(srcdir)/inputdata.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-inputdata.Tpo $(DEPDIR)/ragel-inputdata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='inputdata.cpp' object='ragel-inputdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-inputdata.obj `if test -f 'inputdata.cpp'; then $(CYGPATH_W) 'inputdata.cpp'; else $(CYGPATH_W) '$(srcdir)/inputdata.cpp'; fi`
+
+ragel-common.o: common.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-common.o -MD -MP -MF $(DEPDIR)/ragel-common.Tpo -c -o ragel-common.o `test -f 'common.cpp' || echo '$(srcdir)/'`common.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-common.Tpo $(DEPDIR)/ragel-common.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common.cpp' object='ragel-common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-common.o `test -f 'common.cpp' || echo '$(srcdir)/'`common.cpp
+
+ragel-common.obj: common.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-common.obj -MD -MP -MF $(DEPDIR)/ragel-common.Tpo -c -o ragel-common.obj `if test -f 'common.cpp'; then $(CYGPATH_W) 'common.cpp'; else $(CYGPATH_W) '$(srcdir)/common.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-common.Tpo $(DEPDIR)/ragel-common.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common.cpp' object='ragel-common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-common.obj `if test -f 'common.cpp'; then $(CYGPATH_W) 'common.cpp'; else $(CYGPATH_W) '$(srcdir)/common.cpp'; fi`
+
+ragel-redfsm.o: redfsm.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-redfsm.o -MD -MP -MF $(DEPDIR)/ragel-redfsm.Tpo -c -o ragel-redfsm.o `test -f 'redfsm.cpp' || echo '$(srcdir)/'`redfsm.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-redfsm.Tpo $(DEPDIR)/ragel-redfsm.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='redfsm.cpp' object='ragel-redfsm.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-redfsm.o `test -f 'redfsm.cpp' || echo '$(srcdir)/'`redfsm.cpp
+
+ragel-redfsm.obj: redfsm.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-redfsm.obj -MD -MP -MF $(DEPDIR)/ragel-redfsm.Tpo -c -o ragel-redfsm.obj `if test -f 'redfsm.cpp'; then $(CYGPATH_W) 'redfsm.cpp'; else $(CYGPATH_W) '$(srcdir)/redfsm.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-redfsm.Tpo $(DEPDIR)/ragel-redfsm.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='redfsm.cpp' object='ragel-redfsm.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-redfsm.obj `if test -f 'redfsm.cpp'; then $(CYGPATH_W) 'redfsm.cpp'; else $(CYGPATH_W) '$(srcdir)/redfsm.cpp'; fi`
+
+ragel-gendata.o: gendata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gendata.o -MD -MP -MF $(DEPDIR)/ragel-gendata.Tpo -c -o ragel-gendata.o `test -f 'gendata.cpp' || echo '$(srcdir)/'`gendata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gendata.Tpo $(DEPDIR)/ragel-gendata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gendata.cpp' object='ragel-gendata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gendata.o `test -f 'gendata.cpp' || echo '$(srcdir)/'`gendata.cpp
+
+ragel-gendata.obj: gendata.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gendata.obj -MD -MP -MF $(DEPDIR)/ragel-gendata.Tpo -c -o ragel-gendata.obj `if test -f 'gendata.cpp'; then $(CYGPATH_W) 'gendata.cpp'; else $(CYGPATH_W) '$(srcdir)/gendata.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gendata.Tpo $(DEPDIR)/ragel-gendata.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gendata.cpp' object='ragel-gendata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gendata.obj `if test -f 'gendata.cpp'; then $(CYGPATH_W) 'gendata.cpp'; else $(CYGPATH_W) '$(srcdir)/gendata.cpp'; fi`
+
+ragel-cdcodegen.o: cdcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdcodegen.o -MD -MP -MF $(DEPDIR)/ragel-cdcodegen.Tpo -c -o ragel-cdcodegen.o `test -f 'cdcodegen.cpp' || echo '$(srcdir)/'`cdcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdcodegen.Tpo $(DEPDIR)/ragel-cdcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdcodegen.cpp' object='ragel-cdcodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdcodegen.o `test -f 'cdcodegen.cpp' || echo '$(srcdir)/'`cdcodegen.cpp
+
+ragel-cdcodegen.obj: cdcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdcodegen.obj -MD -MP -MF $(DEPDIR)/ragel-cdcodegen.Tpo -c -o ragel-cdcodegen.obj `if test -f 'cdcodegen.cpp'; then $(CYGPATH_W) 'cdcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/cdcodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdcodegen.Tpo $(DEPDIR)/ragel-cdcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdcodegen.cpp' object='ragel-cdcodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdcodegen.obj `if test -f 'cdcodegen.cpp'; then $(CYGPATH_W) 'cdcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/cdcodegen.cpp'; fi`
+
+ragel-cdtable.o: cdtable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdtable.o -MD -MP -MF $(DEPDIR)/ragel-cdtable.Tpo -c -o ragel-cdtable.o `test -f 'cdtable.cpp' || echo '$(srcdir)/'`cdtable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdtable.Tpo $(DEPDIR)/ragel-cdtable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdtable.cpp' object='ragel-cdtable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdtable.o `test -f 'cdtable.cpp' || echo '$(srcdir)/'`cdtable.cpp
+
+ragel-cdtable.obj: cdtable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdtable.obj -MD -MP -MF $(DEPDIR)/ragel-cdtable.Tpo -c -o ragel-cdtable.obj `if test -f 'cdtable.cpp'; then $(CYGPATH_W) 'cdtable.cpp'; else $(CYGPATH_W) '$(srcdir)/cdtable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdtable.Tpo $(DEPDIR)/ragel-cdtable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdtable.cpp' object='ragel-cdtable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdtable.obj `if test -f 'cdtable.cpp'; then $(CYGPATH_W) 'cdtable.cpp'; else $(CYGPATH_W) '$(srcdir)/cdtable.cpp'; fi`
+
+ragel-cdftable.o: cdftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdftable.o -MD -MP -MF $(DEPDIR)/ragel-cdftable.Tpo -c -o ragel-cdftable.o `test -f 'cdftable.cpp' || echo '$(srcdir)/'`cdftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdftable.Tpo $(DEPDIR)/ragel-cdftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdftable.cpp' object='ragel-cdftable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdftable.o `test -f 'cdftable.cpp' || echo '$(srcdir)/'`cdftable.cpp
+
+ragel-cdftable.obj: cdftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdftable.obj -MD -MP -MF $(DEPDIR)/ragel-cdftable.Tpo -c -o ragel-cdftable.obj `if test -f 'cdftable.cpp'; then $(CYGPATH_W) 'cdftable.cpp'; else $(CYGPATH_W) '$(srcdir)/cdftable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdftable.Tpo $(DEPDIR)/ragel-cdftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdftable.cpp' object='ragel-cdftable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdftable.obj `if test -f 'cdftable.cpp'; then $(CYGPATH_W) 'cdftable.cpp'; else $(CYGPATH_W) '$(srcdir)/cdftable.cpp'; fi`
+
+ragel-cdflat.o: cdflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdflat.o -MD -MP -MF $(DEPDIR)/ragel-cdflat.Tpo -c -o ragel-cdflat.o `test -f 'cdflat.cpp' || echo '$(srcdir)/'`cdflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdflat.Tpo $(DEPDIR)/ragel-cdflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdflat.cpp' object='ragel-cdflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdflat.o `test -f 'cdflat.cpp' || echo '$(srcdir)/'`cdflat.cpp
+
+ragel-cdflat.obj: cdflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdflat.obj -MD -MP -MF $(DEPDIR)/ragel-cdflat.Tpo -c -o ragel-cdflat.obj `if test -f 'cdflat.cpp'; then $(CYGPATH_W) 'cdflat.cpp'; else $(CYGPATH_W) '$(srcdir)/cdflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdflat.Tpo $(DEPDIR)/ragel-cdflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdflat.cpp' object='ragel-cdflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdflat.obj `if test -f 'cdflat.cpp'; then $(CYGPATH_W) 'cdflat.cpp'; else $(CYGPATH_W) '$(srcdir)/cdflat.cpp'; fi`
+
+ragel-cdfflat.o: cdfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdfflat.o -MD -MP -MF $(DEPDIR)/ragel-cdfflat.Tpo -c -o ragel-cdfflat.o `test -f 'cdfflat.cpp' || echo '$(srcdir)/'`cdfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdfflat.Tpo $(DEPDIR)/ragel-cdfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdfflat.cpp' object='ragel-cdfflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdfflat.o `test -f 'cdfflat.cpp' || echo '$(srcdir)/'`cdfflat.cpp
+
+ragel-cdfflat.obj: cdfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdfflat.obj -MD -MP -MF $(DEPDIR)/ragel-cdfflat.Tpo -c -o ragel-cdfflat.obj `if test -f 'cdfflat.cpp'; then $(CYGPATH_W) 'cdfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/cdfflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdfflat.Tpo $(DEPDIR)/ragel-cdfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdfflat.cpp' object='ragel-cdfflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdfflat.obj `if test -f 'cdfflat.cpp'; then $(CYGPATH_W) 'cdfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/cdfflat.cpp'; fi`
+
+ragel-cdgoto.o: cdgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdgoto.o -MD -MP -MF $(DEPDIR)/ragel-cdgoto.Tpo -c -o ragel-cdgoto.o `test -f 'cdgoto.cpp' || echo '$(srcdir)/'`cdgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdgoto.Tpo $(DEPDIR)/ragel-cdgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdgoto.cpp' object='ragel-cdgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdgoto.o `test -f 'cdgoto.cpp' || echo '$(srcdir)/'`cdgoto.cpp
+
+ragel-cdgoto.obj: cdgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdgoto.obj -MD -MP -MF $(DEPDIR)/ragel-cdgoto.Tpo -c -o ragel-cdgoto.obj `if test -f 'cdgoto.cpp'; then $(CYGPATH_W) 'cdgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdgoto.Tpo $(DEPDIR)/ragel-cdgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdgoto.cpp' object='ragel-cdgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdgoto.obj `if test -f 'cdgoto.cpp'; then $(CYGPATH_W) 'cdgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdgoto.cpp'; fi`
+
+ragel-cdfgoto.o: cdfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdfgoto.o -MD -MP -MF $(DEPDIR)/ragel-cdfgoto.Tpo -c -o ragel-cdfgoto.o `test -f 'cdfgoto.cpp' || echo '$(srcdir)/'`cdfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdfgoto.Tpo $(DEPDIR)/ragel-cdfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdfgoto.cpp' object='ragel-cdfgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdfgoto.o `test -f 'cdfgoto.cpp' || echo '$(srcdir)/'`cdfgoto.cpp
+
+ragel-cdfgoto.obj: cdfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdfgoto.obj -MD -MP -MF $(DEPDIR)/ragel-cdfgoto.Tpo -c -o ragel-cdfgoto.obj `if test -f 'cdfgoto.cpp'; then $(CYGPATH_W) 'cdfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdfgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdfgoto.Tpo $(DEPDIR)/ragel-cdfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdfgoto.cpp' object='ragel-cdfgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdfgoto.obj `if test -f 'cdfgoto.cpp'; then $(CYGPATH_W) 'cdfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdfgoto.cpp'; fi`
+
+ragel-cdipgoto.o: cdipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdipgoto.o -MD -MP -MF $(DEPDIR)/ragel-cdipgoto.Tpo -c -o ragel-cdipgoto.o `test -f 'cdipgoto.cpp' || echo '$(srcdir)/'`cdipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdipgoto.Tpo $(DEPDIR)/ragel-cdipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdipgoto.cpp' object='ragel-cdipgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdipgoto.o `test -f 'cdipgoto.cpp' || echo '$(srcdir)/'`cdipgoto.cpp
+
+ragel-cdipgoto.obj: cdipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdipgoto.obj -MD -MP -MF $(DEPDIR)/ragel-cdipgoto.Tpo -c -o ragel-cdipgoto.obj `if test -f 'cdipgoto.cpp'; then $(CYGPATH_W) 'cdipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdipgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdipgoto.Tpo $(DEPDIR)/ragel-cdipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdipgoto.cpp' object='ragel-cdipgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdipgoto.obj `if test -f 'cdipgoto.cpp'; then $(CYGPATH_W) 'cdipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/cdipgoto.cpp'; fi`
+
+ragel-cdsplit.o: cdsplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdsplit.o -MD -MP -MF $(DEPDIR)/ragel-cdsplit.Tpo -c -o ragel-cdsplit.o `test -f 'cdsplit.cpp' || echo '$(srcdir)/'`cdsplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdsplit.Tpo $(DEPDIR)/ragel-cdsplit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdsplit.cpp' object='ragel-cdsplit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdsplit.o `test -f 'cdsplit.cpp' || echo '$(srcdir)/'`cdsplit.cpp
+
+ragel-cdsplit.obj: cdsplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cdsplit.obj -MD -MP -MF $(DEPDIR)/ragel-cdsplit.Tpo -c -o ragel-cdsplit.obj `if test -f 'cdsplit.cpp'; then $(CYGPATH_W) 'cdsplit.cpp'; else $(CYGPATH_W) '$(srcdir)/cdsplit.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cdsplit.Tpo $(DEPDIR)/ragel-cdsplit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdsplit.cpp' object='ragel-cdsplit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cdsplit.obj `if test -f 'cdsplit.cpp'; then $(CYGPATH_W) 'cdsplit.cpp'; else $(CYGPATH_W) '$(srcdir)/cdsplit.cpp'; fi`
+
+ragel-javacodegen.o: javacodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-javacodegen.o -MD -MP -MF $(DEPDIR)/ragel-javacodegen.Tpo -c -o ragel-javacodegen.o `test -f 'javacodegen.cpp' || echo '$(srcdir)/'`javacodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-javacodegen.Tpo $(DEPDIR)/ragel-javacodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='javacodegen.cpp' object='ragel-javacodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-javacodegen.o `test -f 'javacodegen.cpp' || echo '$(srcdir)/'`javacodegen.cpp
+
+ragel-javacodegen.obj: javacodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-javacodegen.obj -MD -MP -MF $(DEPDIR)/ragel-javacodegen.Tpo -c -o ragel-javacodegen.obj `if test -f 'javacodegen.cpp'; then $(CYGPATH_W) 'javacodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/javacodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-javacodegen.Tpo $(DEPDIR)/ragel-javacodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='javacodegen.cpp' object='ragel-javacodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-javacodegen.obj `if test -f 'javacodegen.cpp'; then $(CYGPATH_W) 'javacodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/javacodegen.cpp'; fi`
+
+ragel-rubycodegen.o: rubycodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubycodegen.o -MD -MP -MF $(DEPDIR)/ragel-rubycodegen.Tpo -c -o ragel-rubycodegen.o `test -f 'rubycodegen.cpp' || echo '$(srcdir)/'`rubycodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubycodegen.Tpo $(DEPDIR)/ragel-rubycodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubycodegen.cpp' object='ragel-rubycodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubycodegen.o `test -f 'rubycodegen.cpp' || echo '$(srcdir)/'`rubycodegen.cpp
+
+ragel-rubycodegen.obj: rubycodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubycodegen.obj -MD -MP -MF $(DEPDIR)/ragel-rubycodegen.Tpo -c -o ragel-rubycodegen.obj `if test -f 'rubycodegen.cpp'; then $(CYGPATH_W) 'rubycodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/rubycodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubycodegen.Tpo $(DEPDIR)/ragel-rubycodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubycodegen.cpp' object='ragel-rubycodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubycodegen.obj `if test -f 'rubycodegen.cpp'; then $(CYGPATH_W) 'rubycodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/rubycodegen.cpp'; fi`
+
+ragel-rubytable.o: rubytable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubytable.o -MD -MP -MF $(DEPDIR)/ragel-rubytable.Tpo -c -o ragel-rubytable.o `test -f 'rubytable.cpp' || echo '$(srcdir)/'`rubytable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubytable.Tpo $(DEPDIR)/ragel-rubytable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubytable.cpp' object='ragel-rubytable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubytable.o `test -f 'rubytable.cpp' || echo '$(srcdir)/'`rubytable.cpp
+
+ragel-rubytable.obj: rubytable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubytable.obj -MD -MP -MF $(DEPDIR)/ragel-rubytable.Tpo -c -o ragel-rubytable.obj `if test -f 'rubytable.cpp'; then $(CYGPATH_W) 'rubytable.cpp'; else $(CYGPATH_W) '$(srcdir)/rubytable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubytable.Tpo $(DEPDIR)/ragel-rubytable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubytable.cpp' object='ragel-rubytable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubytable.obj `if test -f 'rubytable.cpp'; then $(CYGPATH_W) 'rubytable.cpp'; else $(CYGPATH_W) '$(srcdir)/rubytable.cpp'; fi`
+
+ragel-rubyftable.o: rubyftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyftable.o -MD -MP -MF $(DEPDIR)/ragel-rubyftable.Tpo -c -o ragel-rubyftable.o `test -f 'rubyftable.cpp' || echo '$(srcdir)/'`rubyftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyftable.Tpo $(DEPDIR)/ragel-rubyftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyftable.cpp' object='ragel-rubyftable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyftable.o `test -f 'rubyftable.cpp' || echo '$(srcdir)/'`rubyftable.cpp
+
+ragel-rubyftable.obj: rubyftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyftable.obj -MD -MP -MF $(DEPDIR)/ragel-rubyftable.Tpo -c -o ragel-rubyftable.obj `if test -f 'rubyftable.cpp'; then $(CYGPATH_W) 'rubyftable.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyftable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyftable.Tpo $(DEPDIR)/ragel-rubyftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyftable.cpp' object='ragel-rubyftable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyftable.obj `if test -f 'rubyftable.cpp'; then $(CYGPATH_W) 'rubyftable.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyftable.cpp'; fi`
+
+ragel-rubyflat.o: rubyflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyflat.o -MD -MP -MF $(DEPDIR)/ragel-rubyflat.Tpo -c -o ragel-rubyflat.o `test -f 'rubyflat.cpp' || echo '$(srcdir)/'`rubyflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyflat.Tpo $(DEPDIR)/ragel-rubyflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyflat.cpp' object='ragel-rubyflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyflat.o `test -f 'rubyflat.cpp' || echo '$(srcdir)/'`rubyflat.cpp
+
+ragel-rubyflat.obj: rubyflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyflat.obj -MD -MP -MF $(DEPDIR)/ragel-rubyflat.Tpo -c -o ragel-rubyflat.obj `if test -f 'rubyflat.cpp'; then $(CYGPATH_W) 'rubyflat.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyflat.Tpo $(DEPDIR)/ragel-rubyflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyflat.cpp' object='ragel-rubyflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyflat.obj `if test -f 'rubyflat.cpp'; then $(CYGPATH_W) 'rubyflat.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyflat.cpp'; fi`
+
+ragel-rubyfflat.o: rubyfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyfflat.o -MD -MP -MF $(DEPDIR)/ragel-rubyfflat.Tpo -c -o ragel-rubyfflat.o `test -f 'rubyfflat.cpp' || echo '$(srcdir)/'`rubyfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyfflat.Tpo $(DEPDIR)/ragel-rubyfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyfflat.cpp' object='ragel-rubyfflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyfflat.o `test -f 'rubyfflat.cpp' || echo '$(srcdir)/'`rubyfflat.cpp
+
+ragel-rubyfflat.obj: rubyfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rubyfflat.obj -MD -MP -MF $(DEPDIR)/ragel-rubyfflat.Tpo -c -o ragel-rubyfflat.obj `if test -f 'rubyfflat.cpp'; then $(CYGPATH_W) 'rubyfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyfflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rubyfflat.Tpo $(DEPDIR)/ragel-rubyfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rubyfflat.cpp' object='ragel-rubyfflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rubyfflat.obj `if test -f 'rubyfflat.cpp'; then $(CYGPATH_W) 'rubyfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/rubyfflat.cpp'; fi`
+
+ragel-rbxgoto.o: rbxgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rbxgoto.o -MD -MP -MF $(DEPDIR)/ragel-rbxgoto.Tpo -c -o ragel-rbxgoto.o `test -f 'rbxgoto.cpp' || echo '$(srcdir)/'`rbxgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rbxgoto.Tpo $(DEPDIR)/ragel-rbxgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rbxgoto.cpp' object='ragel-rbxgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rbxgoto.o `test -f 'rbxgoto.cpp' || echo '$(srcdir)/'`rbxgoto.cpp
+
+ragel-rbxgoto.obj: rbxgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-rbxgoto.obj -MD -MP -MF $(DEPDIR)/ragel-rbxgoto.Tpo -c -o ragel-rbxgoto.obj `if test -f 'rbxgoto.cpp'; then $(CYGPATH_W) 'rbxgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/rbxgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-rbxgoto.Tpo $(DEPDIR)/ragel-rbxgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rbxgoto.cpp' object='ragel-rbxgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-rbxgoto.obj `if test -f 'rbxgoto.cpp'; then $(CYGPATH_W) 'rbxgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/rbxgoto.cpp'; fi`
+
+ragel-cscodegen.o: cscodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cscodegen.o -MD -MP -MF $(DEPDIR)/ragel-cscodegen.Tpo -c -o ragel-cscodegen.o `test -f 'cscodegen.cpp' || echo '$(srcdir)/'`cscodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cscodegen.Tpo $(DEPDIR)/ragel-cscodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cscodegen.cpp' object='ragel-cscodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cscodegen.o `test -f 'cscodegen.cpp' || echo '$(srcdir)/'`cscodegen.cpp
+
+ragel-cscodegen.obj: cscodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cscodegen.obj -MD -MP -MF $(DEPDIR)/ragel-cscodegen.Tpo -c -o ragel-cscodegen.obj `if test -f 'cscodegen.cpp'; then $(CYGPATH_W) 'cscodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/cscodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cscodegen.Tpo $(DEPDIR)/ragel-cscodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cscodegen.cpp' object='ragel-cscodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cscodegen.obj `if test -f 'cscodegen.cpp'; then $(CYGPATH_W) 'cscodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/cscodegen.cpp'; fi`
+
+ragel-cstable.o: cstable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cstable.o -MD -MP -MF $(DEPDIR)/ragel-cstable.Tpo -c -o ragel-cstable.o `test -f 'cstable.cpp' || echo '$(srcdir)/'`cstable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cstable.Tpo $(DEPDIR)/ragel-cstable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cstable.cpp' object='ragel-cstable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cstable.o `test -f 'cstable.cpp' || echo '$(srcdir)/'`cstable.cpp
+
+ragel-cstable.obj: cstable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cstable.obj -MD -MP -MF $(DEPDIR)/ragel-cstable.Tpo -c -o ragel-cstable.obj `if test -f 'cstable.cpp'; then $(CYGPATH_W) 'cstable.cpp'; else $(CYGPATH_W) '$(srcdir)/cstable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cstable.Tpo $(DEPDIR)/ragel-cstable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cstable.cpp' object='ragel-cstable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cstable.obj `if test -f 'cstable.cpp'; then $(CYGPATH_W) 'cstable.cpp'; else $(CYGPATH_W) '$(srcdir)/cstable.cpp'; fi`
+
+ragel-csftable.o: csftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csftable.o -MD -MP -MF $(DEPDIR)/ragel-csftable.Tpo -c -o ragel-csftable.o `test -f 'csftable.cpp' || echo '$(srcdir)/'`csftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csftable.Tpo $(DEPDIR)/ragel-csftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csftable.cpp' object='ragel-csftable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csftable.o `test -f 'csftable.cpp' || echo '$(srcdir)/'`csftable.cpp
+
+ragel-csftable.obj: csftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csftable.obj -MD -MP -MF $(DEPDIR)/ragel-csftable.Tpo -c -o ragel-csftable.obj `if test -f 'csftable.cpp'; then $(CYGPATH_W) 'csftable.cpp'; else $(CYGPATH_W) '$(srcdir)/csftable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csftable.Tpo $(DEPDIR)/ragel-csftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csftable.cpp' object='ragel-csftable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csftable.obj `if test -f 'csftable.cpp'; then $(CYGPATH_W) 'csftable.cpp'; else $(CYGPATH_W) '$(srcdir)/csftable.cpp'; fi`
+
+ragel-csflat.o: csflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csflat.o -MD -MP -MF $(DEPDIR)/ragel-csflat.Tpo -c -o ragel-csflat.o `test -f 'csflat.cpp' || echo '$(srcdir)/'`csflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csflat.Tpo $(DEPDIR)/ragel-csflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csflat.cpp' object='ragel-csflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csflat.o `test -f 'csflat.cpp' || echo '$(srcdir)/'`csflat.cpp
+
+ragel-csflat.obj: csflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csflat.obj -MD -MP -MF $(DEPDIR)/ragel-csflat.Tpo -c -o ragel-csflat.obj `if test -f 'csflat.cpp'; then $(CYGPATH_W) 'csflat.cpp'; else $(CYGPATH_W) '$(srcdir)/csflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csflat.Tpo $(DEPDIR)/ragel-csflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csflat.cpp' object='ragel-csflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csflat.obj `if test -f 'csflat.cpp'; then $(CYGPATH_W) 'csflat.cpp'; else $(CYGPATH_W) '$(srcdir)/csflat.cpp'; fi`
+
+ragel-csfflat.o: csfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csfflat.o -MD -MP -MF $(DEPDIR)/ragel-csfflat.Tpo -c -o ragel-csfflat.o `test -f 'csfflat.cpp' || echo '$(srcdir)/'`csfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csfflat.Tpo $(DEPDIR)/ragel-csfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csfflat.cpp' object='ragel-csfflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csfflat.o `test -f 'csfflat.cpp' || echo '$(srcdir)/'`csfflat.cpp
+
+ragel-csfflat.obj: csfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csfflat.obj -MD -MP -MF $(DEPDIR)/ragel-csfflat.Tpo -c -o ragel-csfflat.obj `if test -f 'csfflat.cpp'; then $(CYGPATH_W) 'csfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/csfflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csfflat.Tpo $(DEPDIR)/ragel-csfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csfflat.cpp' object='ragel-csfflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csfflat.obj `if test -f 'csfflat.cpp'; then $(CYGPATH_W) 'csfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/csfflat.cpp'; fi`
+
+ragel-csgoto.o: csgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csgoto.o -MD -MP -MF $(DEPDIR)/ragel-csgoto.Tpo -c -o ragel-csgoto.o `test -f 'csgoto.cpp' || echo '$(srcdir)/'`csgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csgoto.Tpo $(DEPDIR)/ragel-csgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csgoto.cpp' object='ragel-csgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csgoto.o `test -f 'csgoto.cpp' || echo '$(srcdir)/'`csgoto.cpp
+
+ragel-csgoto.obj: csgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csgoto.obj -MD -MP -MF $(DEPDIR)/ragel-csgoto.Tpo -c -o ragel-csgoto.obj `if test -f 'csgoto.cpp'; then $(CYGPATH_W) 'csgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csgoto.Tpo $(DEPDIR)/ragel-csgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csgoto.cpp' object='ragel-csgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csgoto.obj `if test -f 'csgoto.cpp'; then $(CYGPATH_W) 'csgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csgoto.cpp'; fi`
+
+ragel-csfgoto.o: csfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csfgoto.o -MD -MP -MF $(DEPDIR)/ragel-csfgoto.Tpo -c -o ragel-csfgoto.o `test -f 'csfgoto.cpp' || echo '$(srcdir)/'`csfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csfgoto.Tpo $(DEPDIR)/ragel-csfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csfgoto.cpp' object='ragel-csfgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csfgoto.o `test -f 'csfgoto.cpp' || echo '$(srcdir)/'`csfgoto.cpp
+
+ragel-csfgoto.obj: csfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csfgoto.obj -MD -MP -MF $(DEPDIR)/ragel-csfgoto.Tpo -c -o ragel-csfgoto.obj `if test -f 'csfgoto.cpp'; then $(CYGPATH_W) 'csfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csfgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csfgoto.Tpo $(DEPDIR)/ragel-csfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csfgoto.cpp' object='ragel-csfgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csfgoto.obj `if test -f 'csfgoto.cpp'; then $(CYGPATH_W) 'csfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csfgoto.cpp'; fi`
+
+ragel-csipgoto.o: csipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csipgoto.o -MD -MP -MF $(DEPDIR)/ragel-csipgoto.Tpo -c -o ragel-csipgoto.o `test -f 'csipgoto.cpp' || echo '$(srcdir)/'`csipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csipgoto.Tpo $(DEPDIR)/ragel-csipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csipgoto.cpp' object='ragel-csipgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csipgoto.o `test -f 'csipgoto.cpp' || echo '$(srcdir)/'`csipgoto.cpp
+
+ragel-csipgoto.obj: csipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-csipgoto.obj -MD -MP -MF $(DEPDIR)/ragel-csipgoto.Tpo -c -o ragel-csipgoto.obj `if test -f 'csipgoto.cpp'; then $(CYGPATH_W) 'csipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csipgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-csipgoto.Tpo $(DEPDIR)/ragel-csipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csipgoto.cpp' object='ragel-csipgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-csipgoto.obj `if test -f 'csipgoto.cpp'; then $(CYGPATH_W) 'csipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/csipgoto.cpp'; fi`
+
+ragel-cssplit.o: cssplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cssplit.o -MD -MP -MF $(DEPDIR)/ragel-cssplit.Tpo -c -o ragel-cssplit.o `test -f 'cssplit.cpp' || echo '$(srcdir)/'`cssplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cssplit.Tpo $(DEPDIR)/ragel-cssplit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cssplit.cpp' object='ragel-cssplit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cssplit.o `test -f 'cssplit.cpp' || echo '$(srcdir)/'`cssplit.cpp
+
+ragel-cssplit.obj: cssplit.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-cssplit.obj -MD -MP -MF $(DEPDIR)/ragel-cssplit.Tpo -c -o ragel-cssplit.obj `if test -f 'cssplit.cpp'; then $(CYGPATH_W) 'cssplit.cpp'; else $(CYGPATH_W) '$(srcdir)/cssplit.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-cssplit.Tpo $(DEPDIR)/ragel-cssplit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cssplit.cpp' object='ragel-cssplit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-cssplit.obj `if test -f 'cssplit.cpp'; then $(CYGPATH_W) 'cssplit.cpp'; else $(CYGPATH_W) '$(srcdir)/cssplit.cpp'; fi`
+
+ragel-dotcodegen.o: dotcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-dotcodegen.o -MD -MP -MF $(DEPDIR)/ragel-dotcodegen.Tpo -c -o ragel-dotcodegen.o `test -f 'dotcodegen.cpp' || echo '$(srcdir)/'`dotcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-dotcodegen.Tpo $(DEPDIR)/ragel-dotcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dotcodegen.cpp' object='ragel-dotcodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-dotcodegen.o `test -f 'dotcodegen.cpp' || echo '$(srcdir)/'`dotcodegen.cpp
+
+ragel-dotcodegen.obj: dotcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-dotcodegen.obj -MD -MP -MF $(DEPDIR)/ragel-dotcodegen.Tpo -c -o ragel-dotcodegen.obj `if test -f 'dotcodegen.cpp'; then $(CYGPATH_W) 'dotcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/dotcodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-dotcodegen.Tpo $(DEPDIR)/ragel-dotcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dotcodegen.cpp' object='ragel-dotcodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-dotcodegen.obj `if test -f 'dotcodegen.cpp'; then $(CYGPATH_W) 'dotcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/dotcodegen.cpp'; fi`
+
+ragel-xmlcodegen.o: xmlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-xmlcodegen.o -MD -MP -MF $(DEPDIR)/ragel-xmlcodegen.Tpo -c -o ragel-xmlcodegen.o `test -f 'xmlcodegen.cpp' || echo '$(srcdir)/'`xmlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-xmlcodegen.Tpo $(DEPDIR)/ragel-xmlcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xmlcodegen.cpp' object='ragel-xmlcodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-xmlcodegen.o `test -f 'xmlcodegen.cpp' || echo '$(srcdir)/'`xmlcodegen.cpp
+
+ragel-xmlcodegen.obj: xmlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-xmlcodegen.obj -MD -MP -MF $(DEPDIR)/ragel-xmlcodegen.Tpo -c -o ragel-xmlcodegen.obj `if test -f 'xmlcodegen.cpp'; then $(CYGPATH_W) 'xmlcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/xmlcodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-xmlcodegen.Tpo $(DEPDIR)/ragel-xmlcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xmlcodegen.cpp' object='ragel-xmlcodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-xmlcodegen.obj `if test -f 'xmlcodegen.cpp'; then $(CYGPATH_W) 'xmlcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/xmlcodegen.cpp'; fi`
+
+ragel-gocodegen.o: gocodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gocodegen.o -MD -MP -MF $(DEPDIR)/ragel-gocodegen.Tpo -c -o ragel-gocodegen.o `test -f 'gocodegen.cpp' || echo '$(srcdir)/'`gocodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gocodegen.Tpo $(DEPDIR)/ragel-gocodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gocodegen.cpp' object='ragel-gocodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gocodegen.o `test -f 'gocodegen.cpp' || echo '$(srcdir)/'`gocodegen.cpp
+
+ragel-gocodegen.obj: gocodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gocodegen.obj -MD -MP -MF $(DEPDIR)/ragel-gocodegen.Tpo -c -o ragel-gocodegen.obj `if test -f 'gocodegen.cpp'; then $(CYGPATH_W) 'gocodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/gocodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gocodegen.Tpo $(DEPDIR)/ragel-gocodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gocodegen.cpp' object='ragel-gocodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gocodegen.obj `if test -f 'gocodegen.cpp'; then $(CYGPATH_W) 'gocodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/gocodegen.cpp'; fi`
+
+ragel-gotable.o: gotable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gotable.o -MD -MP -MF $(DEPDIR)/ragel-gotable.Tpo -c -o ragel-gotable.o `test -f 'gotable.cpp' || echo '$(srcdir)/'`gotable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gotable.Tpo $(DEPDIR)/ragel-gotable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gotable.cpp' object='ragel-gotable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gotable.o `test -f 'gotable.cpp' || echo '$(srcdir)/'`gotable.cpp
+
+ragel-gotable.obj: gotable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gotable.obj -MD -MP -MF $(DEPDIR)/ragel-gotable.Tpo -c -o ragel-gotable.obj `if test -f 'gotable.cpp'; then $(CYGPATH_W) 'gotable.cpp'; else $(CYGPATH_W) '$(srcdir)/gotable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gotable.Tpo $(DEPDIR)/ragel-gotable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gotable.cpp' object='ragel-gotable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gotable.obj `if test -f 'gotable.cpp'; then $(CYGPATH_W) 'gotable.cpp'; else $(CYGPATH_W) '$(srcdir)/gotable.cpp'; fi`
+
+ragel-goftable.o: goftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goftable.o -MD -MP -MF $(DEPDIR)/ragel-goftable.Tpo -c -o ragel-goftable.o `test -f 'goftable.cpp' || echo '$(srcdir)/'`goftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goftable.Tpo $(DEPDIR)/ragel-goftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goftable.cpp' object='ragel-goftable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goftable.o `test -f 'goftable.cpp' || echo '$(srcdir)/'`goftable.cpp
+
+ragel-goftable.obj: goftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goftable.obj -MD -MP -MF $(DEPDIR)/ragel-goftable.Tpo -c -o ragel-goftable.obj `if test -f 'goftable.cpp'; then $(CYGPATH_W) 'goftable.cpp'; else $(CYGPATH_W) '$(srcdir)/goftable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goftable.Tpo $(DEPDIR)/ragel-goftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goftable.cpp' object='ragel-goftable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goftable.obj `if test -f 'goftable.cpp'; then $(CYGPATH_W) 'goftable.cpp'; else $(CYGPATH_W) '$(srcdir)/goftable.cpp'; fi`
+
+ragel-goflat.o: goflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goflat.o -MD -MP -MF $(DEPDIR)/ragel-goflat.Tpo -c -o ragel-goflat.o `test -f 'goflat.cpp' || echo '$(srcdir)/'`goflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goflat.Tpo $(DEPDIR)/ragel-goflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goflat.cpp' object='ragel-goflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goflat.o `test -f 'goflat.cpp' || echo '$(srcdir)/'`goflat.cpp
+
+ragel-goflat.obj: goflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goflat.obj -MD -MP -MF $(DEPDIR)/ragel-goflat.Tpo -c -o ragel-goflat.obj `if test -f 'goflat.cpp'; then $(CYGPATH_W) 'goflat.cpp'; else $(CYGPATH_W) '$(srcdir)/goflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goflat.Tpo $(DEPDIR)/ragel-goflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goflat.cpp' object='ragel-goflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goflat.obj `if test -f 'goflat.cpp'; then $(CYGPATH_W) 'goflat.cpp'; else $(CYGPATH_W) '$(srcdir)/goflat.cpp'; fi`
+
+ragel-gofflat.o: gofflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gofflat.o -MD -MP -MF $(DEPDIR)/ragel-gofflat.Tpo -c -o ragel-gofflat.o `test -f 'gofflat.cpp' || echo '$(srcdir)/'`gofflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gofflat.Tpo $(DEPDIR)/ragel-gofflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gofflat.cpp' object='ragel-gofflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gofflat.o `test -f 'gofflat.cpp' || echo '$(srcdir)/'`gofflat.cpp
+
+ragel-gofflat.obj: gofflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gofflat.obj -MD -MP -MF $(DEPDIR)/ragel-gofflat.Tpo -c -o ragel-gofflat.obj `if test -f 'gofflat.cpp'; then $(CYGPATH_W) 'gofflat.cpp'; else $(CYGPATH_W) '$(srcdir)/gofflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gofflat.Tpo $(DEPDIR)/ragel-gofflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gofflat.cpp' object='ragel-gofflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gofflat.obj `if test -f 'gofflat.cpp'; then $(CYGPATH_W) 'gofflat.cpp'; else $(CYGPATH_W) '$(srcdir)/gofflat.cpp'; fi`
+
+ragel-gogoto.o: gogoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gogoto.o -MD -MP -MF $(DEPDIR)/ragel-gogoto.Tpo -c -o ragel-gogoto.o `test -f 'gogoto.cpp' || echo '$(srcdir)/'`gogoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gogoto.Tpo $(DEPDIR)/ragel-gogoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gogoto.cpp' object='ragel-gogoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gogoto.o `test -f 'gogoto.cpp' || echo '$(srcdir)/'`gogoto.cpp
+
+ragel-gogoto.obj: gogoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gogoto.obj -MD -MP -MF $(DEPDIR)/ragel-gogoto.Tpo -c -o ragel-gogoto.obj `if test -f 'gogoto.cpp'; then $(CYGPATH_W) 'gogoto.cpp'; else $(CYGPATH_W) '$(srcdir)/gogoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gogoto.Tpo $(DEPDIR)/ragel-gogoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gogoto.cpp' object='ragel-gogoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gogoto.obj `if test -f 'gogoto.cpp'; then $(CYGPATH_W) 'gogoto.cpp'; else $(CYGPATH_W) '$(srcdir)/gogoto.cpp'; fi`
+
+ragel-gofgoto.o: gofgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gofgoto.o -MD -MP -MF $(DEPDIR)/ragel-gofgoto.Tpo -c -o ragel-gofgoto.o `test -f 'gofgoto.cpp' || echo '$(srcdir)/'`gofgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gofgoto.Tpo $(DEPDIR)/ragel-gofgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gofgoto.cpp' object='ragel-gofgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gofgoto.o `test -f 'gofgoto.cpp' || echo '$(srcdir)/'`gofgoto.cpp
+
+ragel-gofgoto.obj: gofgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gofgoto.obj -MD -MP -MF $(DEPDIR)/ragel-gofgoto.Tpo -c -o ragel-gofgoto.obj `if test -f 'gofgoto.cpp'; then $(CYGPATH_W) 'gofgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/gofgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gofgoto.Tpo $(DEPDIR)/ragel-gofgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gofgoto.cpp' object='ragel-gofgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gofgoto.obj `if test -f 'gofgoto.cpp'; then $(CYGPATH_W) 'gofgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/gofgoto.cpp'; fi`
+
+ragel-goipgoto.o: goipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goipgoto.o -MD -MP -MF $(DEPDIR)/ragel-goipgoto.Tpo -c -o ragel-goipgoto.o `test -f 'goipgoto.cpp' || echo '$(srcdir)/'`goipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goipgoto.Tpo $(DEPDIR)/ragel-goipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goipgoto.cpp' object='ragel-goipgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goipgoto.o `test -f 'goipgoto.cpp' || echo '$(srcdir)/'`goipgoto.cpp
+
+ragel-goipgoto.obj: goipgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-goipgoto.obj -MD -MP -MF $(DEPDIR)/ragel-goipgoto.Tpo -c -o ragel-goipgoto.obj `if test -f 'goipgoto.cpp'; then $(CYGPATH_W) 'goipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/goipgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-goipgoto.Tpo $(DEPDIR)/ragel-goipgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='goipgoto.cpp' object='ragel-goipgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-goipgoto.obj `if test -f 'goipgoto.cpp'; then $(CYGPATH_W) 'goipgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/goipgoto.cpp'; fi`
+
+ragel-gotablish.o: gotablish.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gotablish.o -MD -MP -MF $(DEPDIR)/ragel-gotablish.Tpo -c -o ragel-gotablish.o `test -f 'gotablish.cpp' || echo '$(srcdir)/'`gotablish.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gotablish.Tpo $(DEPDIR)/ragel-gotablish.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gotablish.cpp' object='ragel-gotablish.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gotablish.o `test -f 'gotablish.cpp' || echo '$(srcdir)/'`gotablish.cpp
+
+ragel-gotablish.obj: gotablish.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-gotablish.obj -MD -MP -MF $(DEPDIR)/ragel-gotablish.Tpo -c -o ragel-gotablish.obj `if test -f 'gotablish.cpp'; then $(CYGPATH_W) 'gotablish.cpp'; else $(CYGPATH_W) '$(srcdir)/gotablish.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-gotablish.Tpo $(DEPDIR)/ragel-gotablish.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gotablish.cpp' object='ragel-gotablish.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-gotablish.obj `if test -f 'gotablish.cpp'; then $(CYGPATH_W) 'gotablish.cpp'; else $(CYGPATH_W) '$(srcdir)/gotablish.cpp'; fi`
+
+ragel-mlcodegen.o: mlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlcodegen.o -MD -MP -MF $(DEPDIR)/ragel-mlcodegen.Tpo -c -o ragel-mlcodegen.o `test -f 'mlcodegen.cpp' || echo '$(srcdir)/'`mlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlcodegen.Tpo $(DEPDIR)/ragel-mlcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlcodegen.cpp' object='ragel-mlcodegen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlcodegen.o `test -f 'mlcodegen.cpp' || echo '$(srcdir)/'`mlcodegen.cpp
+
+ragel-mlcodegen.obj: mlcodegen.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlcodegen.obj -MD -MP -MF $(DEPDIR)/ragel-mlcodegen.Tpo -c -o ragel-mlcodegen.obj `if test -f 'mlcodegen.cpp'; then $(CYGPATH_W) 'mlcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/mlcodegen.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlcodegen.Tpo $(DEPDIR)/ragel-mlcodegen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlcodegen.cpp' object='ragel-mlcodegen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlcodegen.obj `if test -f 'mlcodegen.cpp'; then $(CYGPATH_W) 'mlcodegen.cpp'; else $(CYGPATH_W) '$(srcdir)/mlcodegen.cpp'; fi`
+
+ragel-mltable.o: mltable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mltable.o -MD -MP -MF $(DEPDIR)/ragel-mltable.Tpo -c -o ragel-mltable.o `test -f 'mltable.cpp' || echo '$(srcdir)/'`mltable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mltable.Tpo $(DEPDIR)/ragel-mltable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mltable.cpp' object='ragel-mltable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mltable.o `test -f 'mltable.cpp' || echo '$(srcdir)/'`mltable.cpp
+
+ragel-mltable.obj: mltable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mltable.obj -MD -MP -MF $(DEPDIR)/ragel-mltable.Tpo -c -o ragel-mltable.obj `if test -f 'mltable.cpp'; then $(CYGPATH_W) 'mltable.cpp'; else $(CYGPATH_W) '$(srcdir)/mltable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mltable.Tpo $(DEPDIR)/ragel-mltable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mltable.cpp' object='ragel-mltable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mltable.obj `if test -f 'mltable.cpp'; then $(CYGPATH_W) 'mltable.cpp'; else $(CYGPATH_W) '$(srcdir)/mltable.cpp'; fi`
+
+ragel-mlftable.o: mlftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlftable.o -MD -MP -MF $(DEPDIR)/ragel-mlftable.Tpo -c -o ragel-mlftable.o `test -f 'mlftable.cpp' || echo '$(srcdir)/'`mlftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlftable.Tpo $(DEPDIR)/ragel-mlftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlftable.cpp' object='ragel-mlftable.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlftable.o `test -f 'mlftable.cpp' || echo '$(srcdir)/'`mlftable.cpp
+
+ragel-mlftable.obj: mlftable.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlftable.obj -MD -MP -MF $(DEPDIR)/ragel-mlftable.Tpo -c -o ragel-mlftable.obj `if test -f 'mlftable.cpp'; then $(CYGPATH_W) 'mlftable.cpp'; else $(CYGPATH_W) '$(srcdir)/mlftable.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlftable.Tpo $(DEPDIR)/ragel-mlftable.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlftable.cpp' object='ragel-mlftable.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlftable.obj `if test -f 'mlftable.cpp'; then $(CYGPATH_W) 'mlftable.cpp'; else $(CYGPATH_W) '$(srcdir)/mlftable.cpp'; fi`
+
+ragel-mlflat.o: mlflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlflat.o -MD -MP -MF $(DEPDIR)/ragel-mlflat.Tpo -c -o ragel-mlflat.o `test -f 'mlflat.cpp' || echo '$(srcdir)/'`mlflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlflat.Tpo $(DEPDIR)/ragel-mlflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlflat.cpp' object='ragel-mlflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlflat.o `test -f 'mlflat.cpp' || echo '$(srcdir)/'`mlflat.cpp
+
+ragel-mlflat.obj: mlflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlflat.obj -MD -MP -MF $(DEPDIR)/ragel-mlflat.Tpo -c -o ragel-mlflat.obj `if test -f 'mlflat.cpp'; then $(CYGPATH_W) 'mlflat.cpp'; else $(CYGPATH_W) '$(srcdir)/mlflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlflat.Tpo $(DEPDIR)/ragel-mlflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlflat.cpp' object='ragel-mlflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlflat.obj `if test -f 'mlflat.cpp'; then $(CYGPATH_W) 'mlflat.cpp'; else $(CYGPATH_W) '$(srcdir)/mlflat.cpp'; fi`
+
+ragel-mlfflat.o: mlfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlfflat.o -MD -MP -MF $(DEPDIR)/ragel-mlfflat.Tpo -c -o ragel-mlfflat.o `test -f 'mlfflat.cpp' || echo '$(srcdir)/'`mlfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlfflat.Tpo $(DEPDIR)/ragel-mlfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlfflat.cpp' object='ragel-mlfflat.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlfflat.o `test -f 'mlfflat.cpp' || echo '$(srcdir)/'`mlfflat.cpp
+
+ragel-mlfflat.obj: mlfflat.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlfflat.obj -MD -MP -MF $(DEPDIR)/ragel-mlfflat.Tpo -c -o ragel-mlfflat.obj `if test -f 'mlfflat.cpp'; then $(CYGPATH_W) 'mlfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/mlfflat.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlfflat.Tpo $(DEPDIR)/ragel-mlfflat.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlfflat.cpp' object='ragel-mlfflat.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlfflat.obj `if test -f 'mlfflat.cpp'; then $(CYGPATH_W) 'mlfflat.cpp'; else $(CYGPATH_W) '$(srcdir)/mlfflat.cpp'; fi`
+
+ragel-mlgoto.o: mlgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlgoto.o -MD -MP -MF $(DEPDIR)/ragel-mlgoto.Tpo -c -o ragel-mlgoto.o `test -f 'mlgoto.cpp' || echo '$(srcdir)/'`mlgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlgoto.Tpo $(DEPDIR)/ragel-mlgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlgoto.cpp' object='ragel-mlgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlgoto.o `test -f 'mlgoto.cpp' || echo '$(srcdir)/'`mlgoto.cpp
+
+ragel-mlgoto.obj: mlgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlgoto.obj -MD -MP -MF $(DEPDIR)/ragel-mlgoto.Tpo -c -o ragel-mlgoto.obj `if test -f 'mlgoto.cpp'; then $(CYGPATH_W) 'mlgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/mlgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlgoto.Tpo $(DEPDIR)/ragel-mlgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlgoto.cpp' object='ragel-mlgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlgoto.obj `if test -f 'mlgoto.cpp'; then $(CYGPATH_W) 'mlgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/mlgoto.cpp'; fi`
+
+ragel-mlfgoto.o: mlfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlfgoto.o -MD -MP -MF $(DEPDIR)/ragel-mlfgoto.Tpo -c -o ragel-mlfgoto.o `test -f 'mlfgoto.cpp' || echo '$(srcdir)/'`mlfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlfgoto.Tpo $(DEPDIR)/ragel-mlfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlfgoto.cpp' object='ragel-mlfgoto.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlfgoto.o `test -f 'mlfgoto.cpp' || echo '$(srcdir)/'`mlfgoto.cpp
+
+ragel-mlfgoto.obj: mlfgoto.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -MT ragel-mlfgoto.obj -MD -MP -MF $(DEPDIR)/ragel-mlfgoto.Tpo -c -o ragel-mlfgoto.obj `if test -f 'mlfgoto.cpp'; then $(CYGPATH_W) 'mlfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/mlfgoto.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ragel-mlfgoto.Tpo $(DEPDIR)/ragel-mlfgoto.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mlfgoto.cpp' object='ragel-mlfgoto.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ragel_CXXFLAGS) $(CXXFLAGS) -c -o ragel-mlfgoto.obj `if test -f 'mlfgoto.cpp'; then $(CYGPATH_W) 'mlfgoto.cpp'; else $(CYGPATH_W) '$(srcdir)/mlfgoto.cpp'; fi`
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) config.h
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-binPROGRAMS
+
+
+version.h: Makefile
+ echo '#define VERSION "$(PACKAGE_VERSION)"' > version.h
+ echo '#define PUBDATE "$(PUBDATE)"' >> version.h
+
+@BUILD_PARSERS_TRUE@rlparse.h: rlparse.kh
+@BUILD_PARSERS_TRUE@ kelbt -o $@ $<
+
+@BUILD_PARSERS_TRUE@rlparse.cpp: rlparse.kl rlparse.kh
+@BUILD_PARSERS_TRUE@ kelbt -o $@ $<
+
+# This dependency comes from the import of the parser defines
+# into the scanner.
+@BUILD_PARSERS_TRUE@rlscan.cpp: rlparse.h
+
+@BUILD_PARSERS_TRUE@rlscan.cpp: rlscan.rl
+@BUILD_PARSERS_TRUE@ ragel -G2 -I$(builddir) -o $@ $<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ragel/buffer.h b/ragel/buffer.h
new file mode 100644
index 0000000..9c49c1f
--- /dev/null
+++ b/ragel/buffer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2003 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
+ */
+
+#ifndef _BUFFER_H
+#define _BUFFER_H
+
+#define BUFFER_INITIAL_SIZE 4096
+
+/* An automatically grown buffer for collecting tokens. Always reuses space;
+ * never down resizes. */
+struct Buffer
+{
+ Buffer()
+ {
+ data = (char*) malloc( BUFFER_INITIAL_SIZE );
+ allocated = BUFFER_INITIAL_SIZE;
+ length = 0;
+ }
+ ~Buffer() { free(data); }
+
+ void append( char p )
+ {
+ if ( length == allocated ) {
+ allocated *= 2;
+ data = (char*) realloc( data, allocated );
+ }
+ data[length++] = p;
+ }
+
+ void clear() { length = 0; }
+
+ char *data;
+ int allocated;
+ int length;
+};
+
+#endif
diff --git a/ragel/cdcodegen.cpp b/ragel/cdcodegen.cpp
new file mode 100644
index 0000000..3d7cafc
--- /dev/null
+++ b/ragel/cdcodegen.cpp
@@ -0,0 +1,1006 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "cdcodegen.h"
+#include "ragel.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <sstream>
+#include <string>
+#include <assert.h>
+
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
+void cdLineDirective( ostream &out, const char *fileName, int line )
+{
+ if ( noLineDirectives )
+ out << "/* ";
+
+ /* Write the preprocessor line info for to the input file. */
+ out << "#line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+ out << '"';
+
+ if ( noLineDirectives )
+ out << " */";
+
+ out << '\n';
+}
+
+void FsmCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ cdLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+
+/* Init code gen with in parameters. */
+FsmCodeGen::FsmCodeGen( ostream &out )
+:
+ CodeGenData(out)
+{
+}
+
+unsigned int FsmCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string FsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+
+/* Write out the fsm name. */
+string FsmCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string FsmCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &FsmCodeGen::ACTIONS_ARRAY()
+{
+ out << "\t0, ";
+ int totalActions = 1;
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ out << act->key.length() << ", ";
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
+ out << item->value->actionId;
+ if ( ! (act.last() && item.last()) )
+ out << ", ";
+
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+string FsmCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false, false );
+ return ret.str();
+}
+
+
+string FsmCodeGen::P()
+{
+ ostringstream ret;
+ if ( pExpr == 0 )
+ ret << "p";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, pExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::PE()
+{
+ ostringstream ret;
+ if ( peExpr == 0 )
+ ret << "pe";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, peExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::vEOF()
+{
+ ostringstream ret;
+ if ( eofExpr == 0 )
+ ret << "eof";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, eofExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::vCS()
+{
+ ostringstream ret;
+ if ( csExpr == 0 )
+ ret << ACCESS() << "cs";
+ else {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, csExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::TOP()
+{
+ ostringstream ret;
+ if ( topExpr == 0 )
+ ret << ACCESS() + "top";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, topExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::STACK()
+{
+ ostringstream ret;
+ if ( stackExpr == 0 )
+ ret << ACCESS() + "stack";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, stackExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::ACT()
+{
+ ostringstream ret;
+ if ( actExpr == 0 )
+ ret << ACCESS() + "act";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, actExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::TOKSTART()
+{
+ ostringstream ret;
+ if ( tokstartExpr == 0 )
+ ret << ACCESS() + "ts";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokstartExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::TOKEND()
+{
+ ostringstream ret;
+ if ( tokendExpr == 0 )
+ ret << ACCESS() + "te";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokendExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string FsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string FsmCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << "(*" << P() << ")";
+ }
+ return ret.str();
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string FsmCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+/* Write out a key from the fsm code gen. Depends on wether or not the key is
+ * signed. */
+string FsmCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+}
+
+bool FsmCodeGen::isAlphTypeSigned()
+{
+ return keyOps->isSigned;
+}
+
+bool FsmCodeGen::isWideAlphTypeSigned()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ return isAlphTypeSigned();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ return wideType->isSigned;
+ }
+}
+
+string FsmCodeGen::WIDE_KEY( RedStateAp *state, Key key )
+{
+ if ( state->stateCondList.length() > 0 ) {
+ ostringstream ret;
+ if ( isWideAlphTypeSigned() )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+ }
+ else {
+ return KEY( key );
+ }
+}
+
+
+
+void FsmCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+ /* The parser gives fexec two children. The double brackets are for D
+ * code. If the inline list is a single word it will get interpreted as a
+ * C-style cast by the D compiler. */
+ ret << "{" << P() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish, false );
+ ret << "))-1;}";
+}
+
+void FsmCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish, bool csForced )
+{
+ ret <<
+ " switch( " << ACT() << " ) {\n";
+
+ bool haveDefault = false;
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 ) {
+ ret << " default:\n";
+ haveDefault = true;
+ }
+ else
+ ret << " case " << lma->lmId << ":\n";
+
+ /* Write the block and close it off. */
+ ret << " {";
+ INLINE_LIST( ret, lma->children, targState, inFinish, csForced );
+ ret << "}\n";
+
+ ret << " break;\n";
+ }
+
+ if ( (hostLang->lang == HostLang::D || hostLang->lang == HostLang::D2) && !haveDefault )
+ ret << " default: break;";
+
+ ret <<
+ " }\n"
+ "\t";
+}
+
+void FsmCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void FsmCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << ";";
+}
+
+void FsmCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void FsmCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void FsmCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = 0;";
+}
+
+void FsmCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << ";";
+}
+
+void FsmCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{";
+ INLINE_LIST( ret, item->children, targState, inFinish, csForced );
+ ret << "}";
+ }
+}
+
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void FsmCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish, bool csForced )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << "--;";
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ CURS( ret, inFinish );
+ break;
+ case GenInlineItem::Targs:
+ TARGS( ret, inFinish, targState );
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish, csForced );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish, csForced );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState, csForced );
+ break;
+ }
+ }
+}
+/* Write out paths in line directives. Escapes any special characters. */
+string FsmCodeGen::LDIR_PATH( char *path )
+{
+ ostringstream ret;
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ ret << "\\\\";
+ else
+ ret << *pc;
+ }
+ return ret.str();
+}
+
+void FsmCodeGen::ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ cdLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t{";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced );
+ ret << "}\n";
+}
+
+void FsmCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ ret << "\n";
+ cdLineDirective( ret, condition->loc.fileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false, false );
+}
+
+string FsmCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string FsmCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void FsmCodeGen::writeInit()
+{
+ out << " {\n";
+
+ if ( !noCS )
+ out << "\t" << vCS() << " = " << START() << ";\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\t" << TOP() << " = 0;\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
+ " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
+ " " << ACT() << " = 0;\n";
+ }
+ out << " }\n";
+}
+
+string FsmCodeGen::DATA_PREFIX()
+{
+ if ( !noPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string FsmCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string FsmCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+void FsmCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
+
+ if ( !noFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
+
+ if ( !noError )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+void FsmCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void FsmCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void FsmCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+/*
+ * Language specific, but style independent code generators functions.
+ */
+
+string CCodeGen::PTR_CONST()
+{
+ return "const ";
+}
+
+string CCodeGen::PTR_CONST_END()
+{
+ return "";
+}
+
+std::ostream &CCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "static const " << type << " " << name << "[] = {\n";
+ return out;
+}
+
+std::ostream &CCodeGen::CLOSE_ARRAY()
+{
+ return out << "};\n";
+}
+
+std::ostream &CCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "static const " << type << " " << name;
+ return out;
+}
+
+string CCodeGen::UINT( )
+{
+ return "unsigned int";
+}
+
+string CCodeGen::ARR_OFF( string ptr, string offset )
+{
+ return ptr + " + " + offset;
+}
+
+string CCodeGen::CAST( string type )
+{
+ return "(" + type + ")";
+}
+
+string CCodeGen::NULL_ITEM()
+{
+ return "0";
+}
+
+string CCodeGen::POINTER()
+{
+ return " *";
+}
+
+std::ostream &CCodeGen::SWITCH_DEFAULT()
+{
+ return out;
+}
+
+string CCodeGen::CTRL_FLOW()
+{
+ return "";
+}
+
+void CCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "#define " << DATA_PREFIX() << "ex_" << ex->name << " " <<
+ KEY(ex->key) << "\n";
+ }
+ out << "\n";
+ }
+}
+
+/*
+ * D Specific
+ */
+
+string DCodeGen::NULL_ITEM()
+{
+ return "null";
+}
+
+string DCodeGen::POINTER()
+{
+ // multiple items seperated by commas can also be pointer types.
+ return "* ";
+}
+
+string DCodeGen::PTR_CONST()
+{
+ return "";
+}
+
+string DCodeGen::PTR_CONST_END()
+{
+ return "";
+}
+
+std::ostream &DCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "static const " << type << "[] " << name << " = [\n";
+ return out;
+}
+
+std::ostream &DCodeGen::CLOSE_ARRAY()
+{
+ return out << "];\n";
+}
+
+std::ostream &DCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "static const " << type << " " << name;
+ return out;
+}
+
+string DCodeGen::ARR_OFF( string ptr, string offset )
+{
+ return "&" + ptr + "[" + offset + "]";
+}
+
+string DCodeGen::CAST( string type )
+{
+ return "cast(" + type + ")";
+}
+
+string DCodeGen::UINT( )
+{
+ return "uint";
+}
+
+std::ostream &DCodeGen::SWITCH_DEFAULT()
+{
+ out << " default: break;\n";
+ return out;
+}
+
+string DCodeGen::CTRL_FLOW()
+{
+ return "if (true) ";
+}
+
+void DCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "static const " << ALPH_TYPE() << " " << DATA_PREFIX() <<
+ "ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+/*
+ * End D-specific code.
+ */
+
+/*
+ * D2 Specific
+ */
+
+string D2CodeGen::NULL_ITEM()
+{
+ return "null";
+}
+
+string D2CodeGen::POINTER()
+{
+ // multiple items seperated by commas can also be pointer types.
+ return "* ";
+}
+
+string D2CodeGen::PTR_CONST()
+{
+ return "const(";
+}
+
+string D2CodeGen::PTR_CONST_END()
+{
+ return ")";
+}
+
+std::ostream &D2CodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "enum " << type << "[] " << name << " = [\n";
+ return out;
+}
+
+std::ostream &D2CodeGen::CLOSE_ARRAY()
+{
+ return out << "];\n";
+}
+
+std::ostream &D2CodeGen::STATIC_VAR( string type, string name )
+{
+ out << "enum " << type << " " << name;
+ return out;
+}
+
+string D2CodeGen::ARR_OFF( string ptr, string offset )
+{
+ return "&" + ptr + "[" + offset + "]";
+}
+
+string D2CodeGen::CAST( string type )
+{
+ return "cast(" + type + ")";
+}
+
+string D2CodeGen::UINT( )
+{
+ return "uint";
+}
+
+std::ostream &D2CodeGen::SWITCH_DEFAULT()
+{
+ out << " default: break;\n";
+ return out;
+}
+
+string D2CodeGen::CTRL_FLOW()
+{
+ return "if (true) ";
+}
+
+void D2CodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "enum " << ALPH_TYPE() << " " << DATA_PREFIX() <<
+ "ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+void D2CodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{{";
+ INLINE_LIST( ret, item->children, targState, inFinish, csForced );
+ ret << "}}";
+ }
+}
+
+void D2CodeGen::ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ cdLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t{{";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced );
+ ret << "}}\n";
+}
+
+/*
+ * End D2-specific code.
+ */
+
+void FsmCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &FsmCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &FsmCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
diff --git a/ragel/cdcodegen.h b/ragel/cdcodegen.h
new file mode 100644
index 0000000..d8fe62d
--- /dev/null
+++ b/ragel/cdcodegen.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDCODEGEN_H
+#define _CDCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/* Integer array line length. */
+#define IALL 8
+
+/* Forwards. */
+struct RedFsmAp;
+struct RedStateAp;
+struct CodeGenData;
+struct GenAction;
+struct NameInst;
+struct GenInlineItem;
+struct GenInlineList;
+struct RedAction;
+struct LongestMatch;
+struct LongestMatchPart;
+
+string itoa( int i );
+
+/*
+ * class FsmCodeGen
+ */
+class FsmCodeGen : public CodeGenData
+{
+public:
+ FsmCodeGen( ostream &out );
+ virtual ~FsmCodeGen() {}
+
+ virtual void finishRagelDef();
+ virtual void writeInit();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+
+protected:
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string WIDE_KEY( RedStateAp *state, Key key );
+ string LDIR_PATH( char *path );
+ virtual void ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+
+ bool isAlphTypeSigned();
+ bool isWideAlphTypeSigned();
+
+ virtual string ARR_OFF( string ptr, string offset ) = 0;
+ virtual string CAST( string type ) = 0;
+ virtual string UINT() = 0;
+ virtual string NULL_ITEM() = 0;
+ virtual string POINTER() = 0;
+ virtual string GET_KEY();
+ virtual ostream &SWITCH_DEFAULT() = 0;
+
+ string P();
+ string PE();
+ string vEOF();
+
+ string ACCESS();
+ string vCS();
+ string STACK();
+ string TOP();
+ string TOKSTART();
+ string TOKEND();
+ string ACT();
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish, bool csForced );
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem,
+ int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+ virtual void BREAK( ostream &ret, int targState, bool csForced ) = 0;
+ virtual void CURS( ostream &ret, bool inFinish ) = 0;
+ virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0;
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState,
+ int inFinish, bool csForced );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ virtual void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced );
+ void STATE_IDS();
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ virtual string PTR_CONST() = 0;
+ virtual string PTR_CONST_END() = 0;
+ virtual ostream &OPEN_ARRAY( string type, string name ) = 0;
+ virtual ostream &CLOSE_ARRAY() = 0;
+ virtual ostream &STATIC_VAR( string type, string name ) = 0;
+
+ virtual string CTRL_FLOW() = 0;
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool testEofUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+ void genLineDirective( ostream &out );
+
+public:
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize() {}
+};
+
+class CCodeGen : virtual public FsmCodeGen
+{
+public:
+ CCodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string PTR_CONST_END();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+};
+
+class DCodeGen : virtual public FsmCodeGen
+{
+public:
+ DCodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string PTR_CONST_END();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+};
+
+class D2CodeGen : virtual public FsmCodeGen
+{
+public:
+ D2CodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string PTR_CONST_END();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+ virtual void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced );
+ virtual void ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced );
+
+};
+
+#endif
diff --git a/ragel/cdfflat.cpp b/ragel/cdfflat.cpp
new file mode 100644
index 0000000..79cc5be
--- /dev/null
+++ b/ragel/cdfflat.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdfflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &FFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+/* Write out the function for a transition. */
+std::ostream &FFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void FFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out << ";\n";
+ out << " int _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+
+ out << ";\n";
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << PTR_CONST_END() << POINTER() << "_inds;\n";
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxCond) << PTR_CONST_END() << POINTER() << "_conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdfflat.h b/ragel/cdfflat.h
new file mode 100644
index 0000000..e5cbfbd
--- /dev/null
+++ b/ragel/cdfflat.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDFFLAT_H
+#define _CDFFLAT_H
+
+#include <iostream>
+#include "cdflat.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * FFlatCodeGen
+ */
+class FFlatCodeGen : public FlatCodeGen
+{
+protected:
+ FFlatCodeGen( ostream &out ) : FsmCodeGen(out), FlatCodeGen(out) {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+/*
+ * CFFlatCodeGen
+ */
+struct CFFlatCodeGen
+ : public FFlatCodeGen, public CCodeGen
+{
+ CFFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FFlatCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DFFlatCodeGen
+ */
+struct DFFlatCodeGen
+ : public FFlatCodeGen, public DCodeGen
+{
+ DFFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FFlatCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * D2FFlatCodeGen
+ */
+struct D2FFlatCodeGen
+ : public FFlatCodeGen, public D2CodeGen
+{
+ D2FFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FFlatCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdfgoto.cpp b/ragel/cdfgoto.cpp
new file mode 100644
index 0000000..3b229de
--- /dev/null
+++ b/ragel/cdfgoto.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdfgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+std::ostream &FGotoCodeGen::EXEC_ACTIONS()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* We are at the start of a glob, write the case. */
+ out << "f" << redAct->actListId << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tgoto _again;\n";
+ }
+ }
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Jump to the func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+unsigned int FGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+unsigned int FGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+unsigned int FGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+void FGotoCodeGen::writeData()
+{
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_ACTIONS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdfgoto.h b/ragel/cdfgoto.h
new file mode 100644
index 0000000..27e980e
--- /dev/null
+++ b/ragel/cdfgoto.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDFGOTO_H
+#define _CDFGOTO_H
+
+#include <iostream>
+#include "cdgoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * class FGotoCodeGen
+ */
+class FGotoCodeGen : public GotoCodeGen
+{
+public:
+ FGotoCodeGen( ostream &out ) : FsmCodeGen(out), GotoCodeGen(out) {}
+
+ std::ostream &EXEC_ACTIONS();
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &FINISH_CASES();
+ std::ostream &EOF_ACTION_SWITCH();
+ unsigned int TO_STATE_ACTION( RedStateAp *state );
+ unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ unsigned int EOF_ACTION( RedStateAp *state );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+/*
+ * class CFGotoCodeGen
+ */
+struct CFGotoCodeGen
+ : public FGotoCodeGen, public CCodeGen
+{
+ CFGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), FGotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DFGotoCodeGen
+ */
+struct DFGotoCodeGen
+ : public FGotoCodeGen, public DCodeGen
+{
+ DFGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), FGotoCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * class DFGotoCodeGen
+ */
+struct D2FGotoCodeGen
+ : public FGotoCodeGen, public D2CodeGen
+{
+ D2FGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), FGotoCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdflat.cpp b/ragel/cdflat.cpp
new file mode 100644
index 0000000..6010f98
--- /dev/null
+++ b/ragel/cdflat.cpp
@@ -0,0 +1,851 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &FlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ out << KEY( st->condLowKey ) << ", ";
+ out << KEY( st->condHighKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::COND_KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::CONDS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ out << st->condList[pos]->condSpaceId + 1 << ", ";
+ else
+ out << "0, ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::COND_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ out << KEY( st->lowKey ) << ", ";
+ out << KEY( st->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ out << st->transList[pos]->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 )
+ out << st->defTrans->id << ", ";
+
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Save the position. Needed for eofTargs. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void FlatCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << ARR_OFF( K(), "(" + vCS() + "<<1)" ) << ";\n"
+ " _inds = " << ARR_OFF( I(), IO() + "[" + vCS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << SP() << "[" << vCS() << "];\n"
+ " _trans = _inds[ _slen > 0 && _keys[0] <=" << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= _keys[1] ?\n"
+ " " << GET_WIDE_KEY() << " - _keys[0] : _slen ];\n"
+ "\n";
+}
+
+void FlatCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void FlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void FlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void FlatCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ");";
+}
+
+void FlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+
+void FlatCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+
+void FlatCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void FlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n";
+
+ out <<
+ " _keys = " << ARR_OFF( CK(), "(" + vCS() + "<<1)" ) << ";\n"
+ " _conds = " << ARR_OFF( C(), CO() + "[" + vCS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << CSP() << "[" << vCS() << "];\n"
+ " _cond = _slen > 0 && _keys[0] <=" << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= _keys[1] ?\n"
+ " _conds[" << GET_WIDE_KEY() << " - _keys[0]] : 0;\n"
+ "\n";
+
+ out <<
+ " switch ( _cond ) {\n";
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId + 1 << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out << " }\n";
+ out << " break;\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n";
+}
+
+void FlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " int _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+ out << ";\n";
+
+ if ( redFsm->anyToStateActions() ||
+ redFsm->anyRegActions() || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() << POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << PTR_CONST_END() << POINTER() << "_inds;\n";
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxCond) << PTR_CONST_END() << POINTER() << "_conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << ARR_OFF( A(), TA() + "[_trans]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *(_acts++) )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() <<
+ POINTER() << "__acts = " <<
+ ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
+ " " << UINT() << " __nacts = " << CAST(UINT()) << " *__acts++;\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( *__acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdflat.h b/ragel/cdflat.h
new file mode 100644
index 0000000..96c65cb
--- /dev/null
+++ b/ragel/cdflat.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDFLAT_H
+#define _CDFLAT_H
+
+#include <iostream>
+#include "cdcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * FlatCodeGen
+ */
+class FlatCodeGen : virtual public FsmCodeGen
+{
+public:
+ FlatCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ virtual ~FlatCodeGen() { }
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState, bool csForced );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+/*
+ * CFlatCodeGen
+ */
+struct CFlatCodeGen
+ : public FlatCodeGen, public CCodeGen
+{
+ CFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FlatCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DFlatCodeGen
+ */
+struct DFlatCodeGen
+ : public FlatCodeGen, public DCodeGen
+{
+ DFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FlatCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * D2FlatCodeGen
+ */
+struct D2FlatCodeGen
+ : public FlatCodeGen, public D2CodeGen
+{
+ D2FlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FlatCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdftable.cpp b/ragel/cdftable.cpp
new file mode 100644
index 0000000..f5584e5
--- /dev/null
+++ b/ragel/cdftable.cpp
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdftable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void FTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &FTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+
+/* Write out the function for a transition. */
+std::ostream &FTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void FTabCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_keys;\n"
+ " int _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdftable.h b/ragel/cdftable.h
new file mode 100644
index 0000000..4a8264c
--- /dev/null
+++ b/ragel/cdftable.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDFTABLE_H
+#define _CDFTABLE_H
+
+#include <iostream>
+#include "cdtable.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * FTabCodeG\verb|e
+ */
+class FTabCodeGen : public TabCodeGen
+{
+protected:
+ FTabCodeGen( ostream &out ) : FsmCodeGen(out), TabCodeGen(out) {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void writeData();
+ virtual void writeExec();
+ virtual void calcIndexSize();
+};
+
+
+/*
+ * CFTabCodeGen
+ */
+struct CFTabCodeGen
+ : public FTabCodeGen, public CCodeGen
+{
+ CFTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), FTabCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DFTabCodeGen
+ */
+struct DFTabCodeGen
+ : public FTabCodeGen, public DCodeGen
+{
+ DFTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), FTabCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * class D2FTabCodeGen
+ */
+struct D2FTabCodeGen
+ : public FTabCodeGen, public D2CodeGen
+{
+ D2FTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), FTabCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdgoto.cpp b/ragel/cdgoto.cpp
new file mode 100644
index 0000000..e434143
--- /dev/null
+++ b/ragel/cdgoto.cpp
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdgoto.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+/* Emit the goto to take for a given transition. */
+std::ostream &GotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ return out;
+}
+
+std::ostream &GotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void GotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ /* Label the state. */
+ out << "case " << state->id << ":\n";
+}
+
+
+void GotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << "\tif ( " << GET_WIDE_KEY(state) << " == " <<
+ WIDE_KEY(state, data[0].lowKey) << " )\n\t\t";
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, 0) << "\n";
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << "\tswitch( " << GET_WIDE_KEY(state) << " ) {\n";
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << "\t\tcase " << WIDE_KEY(state, data[j].lowKey) << ": ";
+ TRANS_GOTO(data[j].value, 0) << "\n";
+ }
+
+ /* Emits a default case for D code. */
+ SWITCH_DEFAULT();
+
+ /* Close off the transition switch. */
+ out << "\t}\n";
+ }
+}
+
+void GotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ RedTransEl *data = state->outRange.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ WIDE_KEY(state, data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " > " <<
+ WIDE_KEY(state, data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ WIDE_KEY(state, data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " > " <<
+ WIDE_KEY(state, data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " >= " <<
+ WIDE_KEY(state, data[mid].lowKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << WIDE_KEY(state, data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << WIDE_KEY(state, data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+}
+
+void GotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << "case " << state->id << ":\n";
+ out << " goto _out;\n";
+}
+
+void GotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
+{
+ GenCondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+}
+
+void GotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ GenStateCond **data = state->stateCondVect.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " )\n {";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &GotoCodeGen::STATE_GOTOS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &GotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ out << " tr" << trans->id << ": ";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << vCS() << ";";
+ out << vCS() << " = " << trans->targ->id << "; ";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ out << "goto f" << trans->action->actListId << ";\n";
+ }
+ else {
+ /* No code to execute, just loop around. */
+ out << "goto _again;\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &GotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ out << " f" << redAct->actListId << ": " <<
+ "_acts = " << ARR_OFF(A(), itoa( redAct->location+1 ) ) << ";"
+ " goto execFuncs;\n";
+ }
+ }
+
+ out <<
+ "\n"
+ "execFuncs:\n"
+ " _nacts = *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " goto _again;\n";
+ return out;
+}
+
+unsigned int GotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+unsigned int GotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+unsigned int GotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &GotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Write the goto func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+void GotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void GotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void GotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void GotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ");";
+}
+
+void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void GotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void GotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void GotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void GotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() << POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() <<
+ POINTER() << "__acts = " <<
+ ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
+ " " << UINT() << " __nacts = " << CAST(UINT()) << " *__acts++;\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( *__acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdgoto.h b/ragel/cdgoto.h
new file mode 100644
index 0000000..e0869c8
--- /dev/null
+++ b/ragel/cdgoto.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDGOTO_H
+#define _CDGOTO_H
+
+#include <iostream>
+#include "cdcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+struct GenStateCond;
+
+/*
+ * Goto driven fsm.
+ */
+class GotoCodeGen : virtual public FsmCodeGen
+{
+public:
+ GotoCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &STATE_GOTOS();
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState, bool csForced );
+
+ virtual unsigned int TO_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int EOF_ACTION( RedStateAp *state );
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+ void COND_TRANSLATE( GenStateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+ void emitSingleSwitch( RedStateAp *state );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state );
+ virtual void STATE_GOTO_ERROR();
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+/*
+ * class CGotoCodeGen
+ */
+struct CGotoCodeGen
+ : public GotoCodeGen, public CCodeGen
+{
+ CGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), GotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DGotoCodeGen
+ */
+struct DGotoCodeGen
+ : public GotoCodeGen, public DCodeGen
+{
+ DGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), GotoCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * class D2GotoCodeGen
+ */
+struct D2GotoCodeGen
+ : public GotoCodeGen, public D2CodeGen
+{
+ D2GotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), GotoCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdipgoto.cpp b/ragel/cdipgoto.cpp
new file mode 100644
index 0000000..298bf36
--- /dev/null
+++ b/ragel/cdipgoto.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdipgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+bool IpGotoCodeGen::useAgainLabel()
+{
+ return redFsm->anyRegActionRets() ||
+ redFsm->anyRegActionByValControl() ||
+ redFsm->anyRegNextStmt();
+}
+
+void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CTRL_FLOW() << "goto st" << gotoDest << ";}";
+}
+
+void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState <<
+ "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void IpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void IpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ");";
+}
+
+void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << targState;
+}
+
+void IpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; ";
+ if ( !csForced )
+ ret << vCS() << " = " << targState << "; ";
+ ret << CTRL_FLOW() << "goto _out;}";
+}
+
+bool IpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
+{
+ bool anyWritten = false;
+
+ /* Emit any transitions that have actions and that go to this state. */
+ for ( int it = 0; it < state->numInTrans; it++ ) {
+ RedTransAp *trans = state->inTrans[it];
+ if ( trans->action != 0 && trans->labelNeeded ) {
+ /* Remember that we wrote an action so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write the label for the transition so it can be jumped to. */
+ out << "tr" << trans->id << ":\n";
+
+ /* If the action contains a next, then we must preload the current
+ * state since the action may or may not set it. */
+ if ( trans->action->anyNextStmt() )
+ out << " " << vCS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
+ ACTION( out, item->value, trans->targ->id, false,
+ trans->action->anyNextStmt() );
+ }
+
+ /* If the action contains a next then we need to reload, otherwise
+ * jump directly to the target state. */
+ if ( trans->action->anyNextStmt() )
+ out << "\tgoto _again;\n";
+ else
+ out << "\tgoto st" << trans->targ->id << ";\n";
+ }
+ }
+
+ return anyWritten;
+}
+
+/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
+ * state. */
+void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->toStateAction->anyNextStmt() );
+ }
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _test_eof" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->fromStateAction->anyNextStmt() );
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+void IpGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* In the error state we need to emit some stuff that usually goes into
+ * the header. */
+ RedStateAp *state = redFsm->errState;
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ /* No case label needed since we don't switch on the error state. */
+ if ( anyWritten )
+ genLineDirective( out );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ /* Break out here. */
+ outLabelUsed = true;
+ out << vCS() << " = " << state->id << ";\n";
+ out << " goto _out;\n";
+}
+
+
+/* Emit the goto to take for a given transition. */
+std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::EXIT_STATES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->outNeeded ) {
+ testEofUsed = true;
+ out << " _test_eof" << st->id << ": " << vCS() << " = " <<
+ st->id << "; goto _test_eof; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::AGAIN_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ out <<
+ " case " << st->id << ": goto st" << st->id << ";\n";
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::FINISH_CASES()
+{
+ bool anyWritten = false;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofAction != 0 ) {
+ if ( st->eofAction->eofRefs == 0 )
+ st->eofAction->eofRefs = new IntSet;
+ st->eofAction->eofRefs->insert( st->id );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ if ( act->eofRefs != 0 ) {
+ for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
+ out << " case " << *pst << ": \n";
+
+ /* Remember that we wrote a trans so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write each action in the eof action list. */
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
+ ACTION( out, item->value, STATE_ERR_STATE, true, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+ return out;
+}
+
+void IpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call: {
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( item->children );
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void IpGotoCodeGen::setLabelsNeeded()
+{
+ /* If we use the _again label, then we the _again switch, which uses all
+ * labels. */
+ if ( useAgainLabel() ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = true;
+ }
+ else {
+ /* Do not use all labels by default, init all labelNeeded vars to false. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = false;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->targ->labelNeeded = true;
+
+ /* Need labels for states that have goto or calls in action code
+ * invoked on characters (ie, not from out action code). */
+ if ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( act->value->inlineList );
+ }
+ }
+ }
+ }
+
+ if ( !noEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st != redFsm->errState )
+ st->outNeeded = st->labelNeeded;
+ }
+ }
+}
+
+void IpGotoCodeGen::writeData()
+{
+ STATE_IDS();
+}
+
+void IpGotoCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << vCS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " )\n {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ EXIT_STATES() <<
+ "\n";
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n"
+ " switch ( " << vCS() << " ) {\n";
+ FINISH_CASES();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+}
diff --git a/ragel/cdipgoto.h b/ragel/cdipgoto.h
new file mode 100644
index 0000000..c869e1f
--- /dev/null
+++ b/ragel/cdipgoto.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDIPGOTO_H
+#define _CDIPGOTO_H
+
+#include <iostream>
+#include "cdgoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * class FGotoCodeGen
+ */
+class IpGotoCodeGen : public GotoCodeGen
+{
+public:
+ IpGotoCodeGen( ostream &out ) : FsmCodeGen(out), GotoCodeGen(out) {}
+
+ std::ostream &EXIT_STATES();
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ std::ostream &FINISH_CASES();
+ std::ostream &AGAIN_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void BREAK( ostream &ret, int targState, bool csForced );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ bool useAgainLabel();
+
+ /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for
+ * each state. */
+ bool IN_TRANS_ACTIONS( RedStateAp *state );
+ void GOTO_HEADER( RedStateAp *state );
+ void STATE_GOTO_ERROR();
+
+ /* Set up labelNeeded flag for each state. */
+ void setLabelsNeeded( GenInlineList *inlineList );
+ void setLabelsNeeded();
+};
+
+
+/*
+ * class CIpGotoCodeGen
+ */
+struct CIpGotoCodeGen
+ : public IpGotoCodeGen, public CCodeGen
+{
+ CIpGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), IpGotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DIpGotoCodeGen
+ */
+struct DIpGotoCodeGen
+ : public IpGotoCodeGen, public DCodeGen
+{
+ DIpGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), IpGotoCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * class D2IpGotoCodeGen
+ */
+struct D2IpGotoCodeGen
+ : public IpGotoCodeGen, public D2CodeGen
+{
+ D2IpGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), IpGotoCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdsplit.cpp b/ragel/cdsplit.cpp
new file mode 100644
index 0000000..f494b73
--- /dev/null
+++ b/ragel/cdsplit.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2006 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 "ragel.h"
+#include "cdsplit.h"
+#include "gendata.h"
+#include <assert.h>
+
+using std::ostream;
+using std::ios;
+using std::endl;
+
+/* Emit the goto to take for a given transition. */
+std::ostream &SplitCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->targ->partition == currentPartition ) {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ }
+ else {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto ptr" << trans->id << ";";
+ trans->partitionBoundary = true;
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto pst" << trans->targ->id << ";";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+ return out;
+}
+
+/* Called from before writing the gotos for each state. */
+void SplitCodeGen::GOTO_HEADER( RedStateAp *state, bool stateInPartition )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->toStateAction->anyNextStmt() );
+ }
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->fromStateAction->anyNextStmt() );
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+std::ostream &SplitCodeGen::STATE_GOTOS( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* We call into the base of the goto which calls back into us
+ * using virtual functions. Set the current partition rather
+ * than coding parameter passing throughout. */
+ currentPartition = partition;
+
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st, st->partition == partition );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ }
+ return out;
+}
+
+
+std::ostream &SplitCodeGen::PART_TRANS( int partition )
+{
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ if ( trans->partitionBoundary ) {
+ out <<
+ "ptr" << trans->id << ":\n";
+
+ if ( trans->action != 0 ) {
+ /* If the action contains a next, then we must preload the current
+ * state since the action may or may not set it. */
+ if ( trans->action->anyNextStmt() )
+ out << " " << vCS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
+ ACTION( out, item->value, trans->targ->id, false,
+ trans->action->anyNextStmt() );
+ }
+ }
+
+ out <<
+ " goto pst" << trans->targ->id << ";\n";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partitionBoundary ) {
+ out <<
+ " pst" << st->id << ":\n"
+ " " << vCS() << " = " << st->id << ";\n";
+
+ if ( st->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, st->id, false,
+ st->toStateAction->anyNextStmt() );
+ }
+ genLineDirective( out );
+ }
+
+ ptOutLabelUsed = true;
+ out << " goto _pt_out; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &SplitCodeGen::EXIT_STATES( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition && st->outNeeded ) {
+ outLabelUsed = true;
+ out << " _out" << st->id << ": " << vCS() << " = " <<
+ st->id << "; goto _out; \n";
+ }
+ }
+ return out;
+}
+
+
+std::ostream &SplitCodeGen::PARTITION( int partition )
+{
+ outLabelUsed = false;
+ ptOutLabelUsed = false;
+
+ /* Initialize the partition boundaries, which get set during the writing
+ * of states. After the state writing we will */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ trans->partitionBoundary = false;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->partitionBoundary = false;
+
+ out << " " << ALPH_TYPE() << " *p = *_pp, *pe = *_ppe;\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << vCS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+
+ if ( !noEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out <<
+ "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " )\n {\n";
+ STATE_GOTOS( partition );
+ SWITCH_DEFAULT() <<
+ " }\n";
+ PART_TRANS( partition );
+ EXIT_STATES( partition );
+
+ if ( outLabelUsed ) {
+ out <<
+ "\n"
+ " _out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 0;\n";
+ }
+
+ if ( ptOutLabelUsed ) {
+ out <<
+ "\n"
+ " _pt_out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 1;\n";
+ }
+
+ return out;
+}
+
+std::ostream &SplitCodeGen::PART_MAP()
+{
+ int *partMap = new int[redFsm->stateList.length()];
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ partMap[st->id] = st->partition;
+
+ out << "\t";
+ int totalItem = 0;
+ for ( int i = 0; i < redFsm->stateList.length(); i++ ) {
+ out << partMap[i];
+ if ( i != redFsm->stateList.length() - 1 ) {
+ out << ", ";
+ if ( ++totalItem % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ delete[] partMap;
+ return out;
+}
+
+void SplitCodeGen::writeData()
+{
+ out <<
+ "static const int " << START() << " = " << START_STATE_ID() << ";\n"
+ "\n";
+
+ if ( !noFinal ) {
+ out <<
+ "static const int " << FIRST_FINAL() << " = " << FIRST_FINAL_STATE() << ";\n"
+ "\n";
+ }
+
+ if ( !noError ) {
+ out <<
+ "static const int " << ERROR() << " = " << ERROR_STATE() << ";\n"
+ "\n";
+ }
+
+
+ OPEN_ARRAY( ARRAY_TYPE(numSplitPartitions), PM() );
+ PART_MAP();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out << "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm );\n";
+ }
+ out << "\n";
+}
+
+std::ostream &SplitCodeGen::ALL_PARTITIONS()
+{
+ /* compute the format string. */
+ int width = 0, high = redFsm->nParts - 1;
+ while ( high > 0 ) {
+ width++;
+ high /= 10;
+ }
+ assert( width <= 8 );
+ char suffFormat[] = "_%6.6d.c";
+ suffFormat[2] = suffFormat[4] = ( '0' + width );
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ char suffix[10];
+ sprintf( suffix, suffFormat, p );
+ const char *fn = fileNameFromStem( sourceFileName, suffix );
+ const char *include = fileNameFromStem( sourceFileName, ".h" );
+
+ /* Create the filter on the output and open it. */
+ output_filter *partFilter = new output_filter( fn );
+ partFilter->open( fn, ios::out|ios::trunc );
+ if ( !partFilter->is_open() ) {
+ error() << "error opening " << fn << " for writing" << endl;
+ exit(1);
+ }
+
+ /* Attach the new file to the output stream. */
+ std::streambuf *prev_rdbuf = out.rdbuf( partFilter );
+
+ out <<
+ "#include \"" << include << "\"\n"
+ "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm )\n"
+ "{\n";
+ PARTITION( p ) <<
+ "}\n\n";
+ out.flush();
+
+ /* Fix the output stream. */
+ out.rdbuf( prev_rdbuf );
+ }
+ return out;
+}
+
+
+void SplitCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ out <<
+ " {\n"
+ " int _stat = 0;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << " goto _resume;\n";
+
+ /* In this reentry, to-state actions have already been executed on the
+ * partition-switch exit from the last partition. */
+ out << "_reenter:\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+
+ out <<
+ " switch ( " << PM() << "[" << vCS() << "] ) {\n";
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out <<
+ " case " << p << ":\n"
+ " _stat = partition" << p << "( &p, &pe, fsm );\n"
+ " break;\n";
+ }
+ out <<
+ " }\n"
+ " if ( _stat )\n"
+ " goto _reenter;\n";
+
+ if ( !noEnd )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+
+ ALL_PARTITIONS();
+}
+
+void SplitCodeGen::setLabelsNeeded( RedStateAp *fromState, GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call: {
+ /* In split code gen we only need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == item->targState->partition ){
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( fromState, item->children );
+ }
+}
+
+void SplitCodeGen::setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans )
+{
+ /* In the split code gen we don't need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == trans->targ->partition ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ trans->labelNeeded = true;
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->targ->labelNeeded = true;
+ }
+
+ /* Need labels for states that have goto or calls in action code
+ * invoked on characters (ie, not from out action code). */
+ if ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( fromState, act->value->inlineList );
+ }
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void SplitCodeGen::setLabelsNeeded()
+{
+ /* If we use the _again label, then we the _again switch, which uses all
+ * labels. */
+ if ( useAgainLabel() ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = true;
+ }
+ else {
+ /* Do not use all labels by default, init all labelNeeded vars to false. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = false;
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ trans->labelNeeded = false;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ for ( RedTransList::Iter tel = st->outSingle; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ if ( st->defTrans != 0 )
+ setLabelsNeeded( st, st->defTrans );
+ }
+ }
+
+ if ( !noEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->outNeeded = st->labelNeeded;
+ }
+ else {
+ if ( redFsm->errState != 0 )
+ redFsm->errState->outNeeded = true;
+
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Any state with a transition in that has a break will need an
+ * out label. */
+ if ( trans->action != 0 && trans->action->anyBreakStmt() )
+ trans->targ->outNeeded = true;
+ }
+ }
+}
+
diff --git a/ragel/cdsplit.h b/ragel/cdsplit.h
new file mode 100644
index 0000000..03dea78
--- /dev/null
+++ b/ragel/cdsplit.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2006 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
+ */
+
+#ifndef _CDSPLIT_H
+#define _CDSPLIT_H
+
+#include "cdipgoto.h"
+
+class SplitCodeGen : public IpGotoCodeGen
+{
+public:
+ SplitCodeGen( ostream &out ) : FsmCodeGen(out), IpGotoCodeGen(out) {}
+
+ bool ptOutLabelUsed;
+
+ std::ostream &PART_MAP();
+ std::ostream &EXIT_STATES( int partition );
+ std::ostream &PART_TRANS( int partition );
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ void GOTO_HEADER( RedStateAp *state, bool stateInPartition );
+ std::ostream &STATE_GOTOS( int partition );
+ std::ostream &PARTITION( int partition );
+ std::ostream &ALL_PARTITIONS();
+ void writeData();
+ void writeExec();
+ void writeParts();
+
+ void setLabelsNeeded( RedStateAp *fromState, GenInlineList *inlineList );
+ void setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans );
+ void setLabelsNeeded();
+
+ int currentPartition;
+};
+
+struct CSplitCodeGen
+ : public SplitCodeGen, public CCodeGen
+{
+ CSplitCodeGen( ostream &out ) :
+ FsmCodeGen(out), SplitCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DIpGotoCodeGen
+ */
+struct DSplitCodeGen
+ : public SplitCodeGen, public DCodeGen
+{
+ DSplitCodeGen( ostream &out ) :
+ FsmCodeGen(out), SplitCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * class D2SplitCodeGen
+ */
+struct D2SplitCodeGen
+ : public SplitCodeGen, public D2CodeGen
+{
+ D2SplitCodeGen( ostream &out ) :
+ FsmCodeGen(out), SplitCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/cdtable.cpp b/ragel/cdtable.cpp
new file mode 100644
index 0000000..2218839
--- /dev/null
+++ b/ragel/cdtable.cpp
@@ -0,0 +1,1096 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cdtable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void TabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &TabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::KEY_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::INDEX_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->stateCondList.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::SINGLE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->outSingle.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::RANGE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ out << st->outRange.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ out << KEY( sc->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << KEY( sc->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_SPACES()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ out << sc->condSpace->condSpaceId << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << KEY( stel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ out << KEY( rtel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << KEY( rtel->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << stel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ out << rtel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Add any eof transitions that have not yet been written out above. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTIONS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Add any eof transitions that have not yet been written out above. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void TabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << ARR_OFF( K(), KO() + "[" + vCS() + "]" ) << ";\n"
+ " _trans = " << IO() << "[" << vCS() << "];\n"
+ "\n"
+ " _klen = " << SL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_upper = _keys + _klen - 1;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + ((_upper-_lower) >> 1);\n"
+ " if ( " << GET_WIDE_KEY() << " < *_mid )\n"
+ " _upper = _mid - 1;\n"
+ " else if ( " << GET_WIDE_KEY() << " > *_mid )\n"
+ " _lower = _mid + 1;\n"
+ " else {\n"
+ " _trans += " << CAST(UINT()) << "(_mid - _keys);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _keys += _klen;\n"
+ " _trans += _klen;\n"
+ " }\n"
+ "\n"
+ " _klen = " << RL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_upper = _keys + (_klen<<1) - 2;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < _mid[0] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > _mid[1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " _trans += " << CAST(UINT()) << "((_mid - _keys)>>1);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _trans += _klen;\n"
+ " }\n"
+ "\n";
+}
+
+void TabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void TabCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void TabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void TabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ");";
+}
+
+void TabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void TabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void TabCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" <<
+ TOP() << "]; ";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void TabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void TabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n"
+ " _klen = " << CL() << "[" << vCS() << "];\n"
+ " _keys = " << ARR_OFF( CK(), "(" + CO() + "[" + vCS() + "]*2)" ) << ";\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_upper = _keys + (_klen<<1) - 2;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < _mid[0] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > _mid[1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " switch ( " << C() << "[" << CO() << "[" << vCS() << "]"
+ " + ((_mid - _keys)>>1)] ) {\n";
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out <<
+ " break;\n"
+ " }\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+}
+
+void TabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << UINT() << " _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() <<
+ POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << PTR_CONST_END() << POINTER() << "_keys;\n"
+ "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << ARR_OFF( A(), TA() + "[_trans]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 )\n {\n"
+ " switch ( *_acts++ )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() <<
+ POINTER() << "__acts = " <<
+ ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
+ " " << UINT() << " __nacts = " << CAST(UINT()) << " *__acts++;\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( *__acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/cdtable.h b/ragel/cdtable.h
new file mode 100644
index 0000000..b8df71b
--- /dev/null
+++ b/ragel/cdtable.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CDTABLE_H
+#define _CDTABLE_H
+
+#include <iostream>
+#include "cdcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * TabCodeGen
+ */
+class TabCodeGen : virtual public FsmCodeGen
+{
+public:
+ TabCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ virtual ~TabCodeGen() { }
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+ void LOCATE_TRANS();
+
+ void COND_TRANSLATE();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState, bool csForced );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void calcIndexSize();
+};
+
+
+/*
+ * CTabCodeGen
+ */
+struct CTabCodeGen
+ : public TabCodeGen, public CCodeGen
+{
+ CTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), TabCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DTabCodeGen
+ */
+struct DTabCodeGen
+ : public TabCodeGen, public DCodeGen
+{
+ DTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), TabCodeGen(out), DCodeGen(out) {}
+};
+
+/*
+ * D2TabCodeGen
+ */
+struct D2TabCodeGen
+ : public TabCodeGen, public D2CodeGen
+{
+ D2TabCodeGen( ostream &out ) :
+ FsmCodeGen(out), TabCodeGen(out), D2CodeGen(out) {}
+};
+
+#endif
diff --git a/ragel/common.cpp b/ragel/common.cpp
new file mode 100644
index 0000000..3047e70
--- /dev/null
+++ b/ragel/common.cpp
@@ -0,0 +1,381 @@
+/*
+ * 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 "pcheck.h"
+#include "common.h"
+#include "stdlib.h"
+#include <string.h>
+#include <assert.h>
+
+HostType hostTypesC[] =
+{
+ { "char", 0, "char", true, true, false, CHAR_MIN, CHAR_MAX, sizeof(char) },
+ { "unsigned", "char", "uchar", false, true, false, 0, UCHAR_MAX, sizeof(unsigned char) },
+ { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, sizeof(short) },
+ { "unsigned", "short", "ushort", false, true, false, 0, USHRT_MAX, sizeof(unsigned short) },
+ { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, sizeof(int) },
+ { "unsigned", "int", "uint", false, true, false, 0, UINT_MAX, sizeof(unsigned int) },
+ { "long", 0, "long", true, true, false, LONG_MIN, LONG_MAX, sizeof(long) },
+ { "unsigned", "long", "ulong", false, true, false, 0, ULONG_MAX, sizeof(unsigned long) }
+};
+
+#define S8BIT_MIN -128
+#define S8BIT_MAX 127
+
+#define U8BIT_MIN 0
+#define U8BIT_MAX 255
+
+#define S16BIT_MIN -32768
+#define S16BIT_MAX 32767
+
+#define U16BIT_MIN 0
+#define U16BIT_MAX 65535
+
+#define S31BIT_MIN -1073741824L
+#define S31BIT_MAX 1073741823L
+
+#define S32BIT_MIN -2147483648L
+#define S32BIT_MAX 2147483647L
+
+#define U32BIT_MIN 0
+#define U32BIT_MAX 4294967295UL
+
+#define S64BIT_MIN -9223372036854775807LL
+#define S64BIT_MAX 9223372036854775807LL
+
+#define U64BIT_MIN 0
+#define U64BIT_MAX 18446744073709551615ULL
+
+HostType hostTypesD[] =
+{
+ { "byte", 0, "byte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
+ { "ubyte", 0, "ubyte", false, true, false, 0, UCHAR_MAX, 1 },
+ { "char", 0, "char", false, true, false, 0, UCHAR_MAX, 1 },
+ { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
+ { "ushort", 0, "ushort", false, true, false, 0, USHRT_MAX, 2 },
+ { "wchar", 0, "wchar", false, true, false, 0, USHRT_MAX, 2 },
+ { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
+ { "uint", 0, "uint", false, true, false, 0, UINT_MAX, 4 },
+ { "dchar", 0, "dchar", false, true, false, 0, UINT_MAX, 4 }
+};
+
+HostType hostTypesGo[] =
+{
+ { "byte", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 },
+ { "int8", 0, "int8", true, true, false, S8BIT_MIN, S8BIT_MAX, 1 },
+ { "uint8", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 },
+ { "int16", 0, "int16", true, true, false, S16BIT_MIN, S16BIT_MAX, 2 },
+ { "uint16", 0, "uint16", false, true, false, U16BIT_MIN, U16BIT_MAX, 2 },
+ { "int32", 0, "int32", true, true, false, S32BIT_MIN, S32BIT_MAX, 4 },
+ { "uint32", 0, "uint32", false, true, false, U32BIT_MIN, U32BIT_MAX, 4 },
+ { "int64", 0, "int64", true, true, false, S64BIT_MIN, S64BIT_MAX, 8 },
+ { "uint64", 0, "uint64", false, true, false, U64BIT_MIN, U64BIT_MAX, 8 },
+ { "rune", 0, "int32", true, true, true, S32BIT_MIN, S32BIT_MAX, 4 }
+};
+
+HostType hostTypesJava[] =
+{
+ { "byte", 0, "byte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
+ { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
+ { "char", 0, "char", false, true, false, 0, USHRT_MAX, 2 },
+ { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
+};
+
+/* What are the appropriate types for ruby? */
+HostType hostTypesRuby[] =
+{
+ { "char", 0, "char", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
+ { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
+};
+
+HostType hostTypesCSharp[] =
+{
+ { "sbyte", 0, "sbyte", true, true, false, CHAR_MIN, CHAR_MAX, 1 },
+ { "byte", 0, "byte", false, true, false, 0, UCHAR_MAX, 1 },
+ { "short", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 },
+ { "ushort", 0, "ushort", false, true, false, 0, USHRT_MAX, 2 },
+ { "char", 0, "char", false, true, true, 0, USHRT_MAX, 2 },
+ { "int", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 },
+ { "uint", 0, "uint", false, true, false, 0, UINT_MAX, 4 },
+ { "long", 0, "long", true, true, false, LONG_MIN, LONG_MAX, 8 },
+ { "ulong", 0, "ulong", false, true, false, 0, ULONG_MAX, 8 }
+};
+
+HostType hostTypesOCaml[] =
+{
+// { "char", 0, "char", false, true, false, 0, UCHAR_MAX, 1 },
+ { "int", 0, "int", true, true, false, S31BIT_MIN, S31BIT_MAX, 4 },
+};
+
+HostLang hostLangC = { HostLang::C, hostTypesC, 8, hostTypesC+0, true };
+HostLang hostLangD = { HostLang::D, hostTypesD, 9, hostTypesD+2, true };
+HostLang hostLangD2 = { HostLang::D2, hostTypesD, 9, hostTypesD+2, true };
+HostLang hostLangGo = { HostLang::Go, hostTypesGo, 10, hostTypesGo+0, false };
+HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
+HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
+HostLang hostLangCSharp = { HostLang::CSharp, hostTypesCSharp, 9, hostTypesCSharp+4, true };
+HostLang hostLangOCaml = { HostLang::OCaml, hostTypesOCaml, 1, hostTypesOCaml+0, false };
+
+HostLang *hostLang = &hostLangC;
+
+HostType *findAlphType( const char *s1 )
+{
+ for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
+ if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 &&
+ hostLang->hostTypes[i].data2 == 0 )
+ {
+ return hostLang->hostTypes + i;
+ }
+ }
+
+ return 0;
+}
+
+HostType *findAlphType( const char *s1, const char *s2 )
+{
+ for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
+ if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 &&
+ hostLang->hostTypes[i].data2 != 0 &&
+ strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
+ {
+ return hostLang->hostTypes + i;
+ }
+ }
+
+ return 0;
+}
+
+HostType *findAlphTypeInternal( const char *s1 )
+{
+ for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
+ if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
+ return hostLang->hostTypes + i;
+ }
+
+ return 0;
+}
+
+/* Construct a new parameter checker with for paramSpec. */
+ParamCheck::ParamCheck( const char *paramSpec, int argc, const char **argv )
+:
+ state(noparam),
+ argOffset(0),
+ curArg(0),
+ iCurArg(1),
+ paramSpec(paramSpec),
+ argc(argc),
+ argv(argv)
+{
+}
+
+/* Check a single option. Returns the index of the next parameter. Sets p to
+ * the arg character if valid, 0 otherwise. Sets parg to the parameter arg if
+ * there is one, NULL otherwise. */
+bool ParamCheck::check()
+{
+ bool requiresParam;
+
+ if ( iCurArg >= argc ) { /* Off the end of the arg list. */
+ state = noparam;
+ return false;
+ }
+
+ if ( argOffset != 0 && *argOffset == 0 ) {
+ /* We are at the end of an arg string. */
+ iCurArg += 1;
+ if ( iCurArg >= argc ) {
+ state = noparam;
+ return false;
+ }
+ argOffset = 0;
+ }
+
+ if ( argOffset == 0 ) {
+ /* Set the current arg. */
+ curArg = argv[iCurArg];
+
+ /* We are at the beginning of an arg string. */
+ if ( argv[iCurArg] == 0 || /* Argv[iCurArg] is null. */
+ argv[iCurArg][0] != '-' || /* Not a param. */
+ argv[iCurArg][1] == 0 ) { /* Only a dash. */
+ parameter = 0;
+ paramArg = 0;
+
+ iCurArg += 1;
+ state = noparam;
+ return true;
+ }
+ argOffset = argv[iCurArg] + 1;
+ }
+
+ /* Get the arg char. */
+ char argChar = *argOffset;
+
+ /* Loop over all the parms and look for a match. */
+ const char *pSpec = paramSpec;
+ while ( *pSpec != 0 ) {
+ char pSpecChar = *pSpec;
+
+ /* If there is a ':' following the char then
+ * it requires a parm. If a parm is required
+ * then move ahead two in the parmspec. Otherwise
+ * move ahead one in the parm spec. */
+ if ( pSpec[1] == ':' ) {
+ requiresParam = true;
+ pSpec += 2;
+ }
+ else {
+ requiresParam = false;
+ pSpec += 1;
+ }
+
+ /* Do we have a match. */
+ if ( argChar == pSpecChar ) {
+ if ( requiresParam ) {
+ if ( argOffset[1] == 0 ) {
+ /* The param must follow. */
+ if ( iCurArg + 1 == argc ) {
+ /* We are the last arg so there
+ * cannot be a parameter to it. */
+ parameter = argChar;
+ paramArg = 0;
+ iCurArg += 1;
+ argOffset = 0;
+ state = invalid;
+ return true;
+ }
+ else {
+ /* the parameter to the arg is the next arg. */
+ parameter = pSpecChar;
+ paramArg = argv[iCurArg + 1];
+ iCurArg += 2;
+ argOffset = 0;
+ state = match;
+ return true;
+ }
+ }
+ else {
+ /* The param for the arg is built in. */
+ parameter = pSpecChar;
+ paramArg = argOffset + 1;
+ iCurArg += 1;
+ argOffset = 0;
+ state = match;
+ return true;
+ }
+ }
+ else {
+ /* Good, we matched the parm and no
+ * arg is required. */
+ parameter = pSpecChar;
+ paramArg = 0;
+ argOffset += 1;
+ state = match;
+ return true;
+ }
+ }
+ }
+
+ /* We did not find a match. Bad Argument. */
+ parameter = argChar;
+ paramArg = 0;
+ argOffset += 1;
+ state = invalid;
+ return true;
+}
+
+/* Counts newlines before sending sync. */
+int output_filter::sync( )
+{
+ line += 1;
+ return std::filebuf::sync();
+}
+
+/* Counts newlines before sending data out to file. */
+std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
+{
+ for ( int i = 0; i < n; i++ ) {
+ if ( s[i] == '\n' )
+ line += 1;
+ }
+ return std::filebuf::xsputn( s, n );
+}
+
+/* Scans a string looking for the file extension. If there is a file
+ * extension then pointer returned points to inside the string
+ * passed in. Otherwise returns null. */
+const char *findFileExtension( const char *stemFile )
+{
+ const char *ppos = stemFile + strlen(stemFile) - 1;
+
+ /* Scan backwards from the end looking for the first dot.
+ * If we encounter a '/' before the first dot, then stop the scan. */
+ while ( 1 ) {
+ /* If we found a dot or got to the beginning of the string then
+ * we are done. */
+ if ( ppos == stemFile || *ppos == '.' )
+ break;
+
+ /* If we hit a / then there is no extension. Done. */
+ if ( *ppos == '/' ) {
+ ppos = stemFile;
+ break;
+ }
+ ppos--;
+ }
+
+ /* If we got to the front of the string then bail we
+ * did not find an extension */
+ if ( ppos == stemFile )
+ ppos = 0;
+
+ return ppos;
+}
+
+/* Make a file name from a stem. Removes the old filename suffix and
+ * replaces it with a new one. Returns a newed up string. */
+const char *fileNameFromStem( const char *stemFile, const char *suffix )
+{
+ long len = strlen( stemFile );
+ assert( len > 0 );
+
+ /* Get the extension. */
+ const char *ppos = findFileExtension( stemFile );
+
+ /* If an extension was found, then shorten what we think the len is. */
+ if ( ppos != 0 )
+ len = ppos - stemFile;
+
+ /* Make the return string from the stem and the suffix. */
+ char *retVal = new char[ len + strlen( suffix ) + 1 ];
+ strncpy( retVal, stemFile, len );
+ strcpy( retVal + len, suffix );
+
+ return retVal;
+}
+
+exit_object endp;
+
+void operator<<( std::ostream &out, exit_object & )
+{
+ out << std::endl;
+ exit(1);
+}
diff --git a/ragel/common.h b/ragel/common.h
new file mode 100644
index 0000000..b26da68
--- /dev/null
+++ b/ragel/common.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2001-2006 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
+ */
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#include <fstream>
+#include <climits>
+#include "dlist.h"
+
+/* Location in an input file. */
+struct InputLoc
+{
+ const char *fileName;
+ long line;
+ long col;
+};
+
+
+typedef unsigned long long Size;
+
+struct Key
+{
+private:
+ long key;
+
+public:
+ friend inline Key operator+(const Key key1, const Key key2);
+ friend inline Key operator-(const Key key1, const Key key2);
+ friend inline Key operator/(const Key key1, const Key key2);
+ friend inline long operator&(const Key key1, const Key key2);
+
+ friend inline bool operator<( const Key key1, const Key key2 );
+ friend inline bool operator<=( const Key key1, const Key key2 );
+ friend inline bool operator>( const Key key1, const Key key2 );
+ friend inline bool operator>=( const Key key1, const Key key2 );
+ friend inline bool operator==( const Key key1, const Key key2 );
+ friend inline bool operator!=( const Key key1, const Key key2 );
+
+ friend struct KeyOps;
+
+ Key( ) {}
+ Key( const Key &key ) : key(key.key) {}
+ Key( long key ) : key(key) {}
+
+ /* Returns the value used to represent the key. This value must be
+ * interpreted based on signedness. */
+ long getVal() const { return key; };
+
+ /* Returns the key casted to a long long. This form of the key does not
+ * require any signedness interpretation. */
+ long long getLongLong() const;
+
+ /* Returns the distance from the key value to the maximum value that the
+ * key implementation can hold. */
+ Size availableSpace() const;
+
+ bool isUpper() const { return ( 'A' <= key && key <= 'Z' ); }
+ bool isLower() const { return ( 'a' <= key && key <= 'z' ); }
+ bool isPrintable() const
+ {
+ return ( 7 <= key && key <= 13 ) || ( 32 <= key && key < 127 );
+ }
+
+ Key toUpper() const
+ { return Key( 'A' + ( key - 'a' ) ); }
+ Key toLower() const
+ { return Key( 'a' + ( key - 'A' ) ); }
+
+ void operator+=( const Key other )
+ {
+ /* FIXME: must be made aware of isSigned. */
+ key += other.key;
+ }
+
+ void operator-=( const Key other )
+ {
+ /* FIXME: must be made aware of isSigned. */
+ key -= other.key;
+ }
+
+ void operator|=( const Key other )
+ {
+ /* FIXME: must be made aware of isSigned. */
+ key |= other.key;
+ }
+
+ /* Decrement. Needed only for ranges. */
+ inline void decrement();
+ inline void increment();
+};
+
+struct HostType
+{
+ const char *data1;
+ const char *data2;
+ const char *internalName;
+ bool isSigned;
+ bool isOrd;
+ bool isChar;
+ long long minVal;
+ long long maxVal;
+ unsigned int size;
+};
+
+struct HostLang
+{
+ /* Target language. */
+ enum Lang
+ {
+ C, D, D2, Go, Java, Ruby, CSharp, OCaml
+ };
+
+ Lang lang;
+ HostType *hostTypes;
+ int numHostTypes;
+ HostType *defaultAlphType;
+ bool explicitUnsigned;
+};
+
+extern HostLang *hostLang;
+
+extern HostLang hostLangC;
+extern HostLang hostLangD;
+extern HostLang hostLangD2;
+extern HostLang hostLangGo;
+extern HostLang hostLangJava;
+extern HostLang hostLangRuby;
+extern HostLang hostLangCSharp;
+extern HostLang hostLangOCaml;
+
+HostType *findAlphType( const char *s1 );
+HostType *findAlphType( const char *s1, const char *s2 );
+HostType *findAlphTypeInternal( const char *s1 );
+
+/* An abstraction of the key operators that manages key operations such as
+ * comparison and increment according the signedness of the key. */
+struct KeyOps
+{
+ /* Default to signed alphabet. */
+ KeyOps() :
+ isSigned(true),
+ alphType(0)
+ {}
+
+ /* Default to signed alphabet. */
+ KeyOps( bool isSigned )
+ :isSigned(isSigned) {}
+
+ bool isSigned;
+ Key minKey, maxKey;
+ HostType *alphType;
+
+ void setAlphType( HostType *alphType )
+ {
+ this->alphType = alphType;
+ isSigned = alphType->isSigned;
+ if ( isSigned ) {
+ minKey = (long) alphType->minVal;
+ maxKey = (long) alphType->maxVal;
+ }
+ else {
+ minKey = (long) (unsigned long) alphType->minVal;
+ maxKey = (long) (unsigned long) alphType->maxVal;
+ }
+ }
+
+ /* Compute the distance between two keys. */
+ Size span( Key key1, Key key2 )
+ {
+ return isSigned ?
+ (unsigned long long)(
+ (long long)key2.key -
+ (long long)key1.key + 1) :
+ (unsigned long long)(
+ (unsigned long)key2.key) -
+ (unsigned long long)((unsigned long)key1.key) + 1;
+ }
+
+ Size alphSize()
+ { return span( minKey, maxKey ); }
+
+ HostType *typeSubsumes( long long maxVal )
+ {
+ for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
+ if ( maxVal <= hostLang->hostTypes[i].maxVal )
+ return hostLang->hostTypes + i;
+ }
+ return 0;
+ }
+
+ HostType *typeSubsumes( bool isSigned, long long maxVal )
+ {
+ for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
+ if ( ( ( isSigned && hostLang->hostTypes[i].isSigned ) || !isSigned ) &&
+ maxVal <= hostLang->hostTypes[i].maxVal )
+ return hostLang->hostTypes + i;
+ }
+ return 0;
+ }
+};
+
+extern KeyOps *keyOps;
+
+inline bool operator<( const Key key1, const Key key2 )
+{
+ return keyOps->isSigned ? key1.key < key2.key :
+ (unsigned long)key1.key < (unsigned long)key2.key;
+}
+
+inline bool operator<=( const Key key1, const Key key2 )
+{
+ return keyOps->isSigned ? key1.key <= key2.key :
+ (unsigned long)key1.key <= (unsigned long)key2.key;
+}
+
+inline bool operator>( const Key key1, const Key key2 )
+{
+ return keyOps->isSigned ? key1.key > key2.key :
+ (unsigned long)key1.key > (unsigned long)key2.key;
+}
+
+inline bool operator>=( const Key key1, const Key key2 )
+{
+ return keyOps->isSigned ? key1.key >= key2.key :
+ (unsigned long)key1.key >= (unsigned long)key2.key;
+}
+
+inline bool operator==( const Key key1, const Key key2 )
+{
+ return key1.key == key2.key;
+}
+
+inline bool operator!=( const Key key1, const Key key2 )
+{
+ return key1.key != key2.key;
+}
+
+/* Decrement. Needed only for ranges. */
+inline void Key::decrement()
+{
+ key = keyOps->isSigned ? key - 1 : ((unsigned long)key)-1;
+}
+
+/* Increment. Needed only for ranges. */
+inline void Key::increment()
+{
+ key = keyOps->isSigned ? key+1 : ((unsigned long)key)+1;
+}
+
+inline long long Key::getLongLong() const
+{
+ return keyOps->isSigned ? (long long)key : (long long)(unsigned long)key;
+}
+
+inline Size Key::availableSpace() const
+{
+ if ( keyOps->isSigned )
+ return (long long)LONG_MAX - (long long)key;
+ else
+ return (unsigned long long)ULONG_MAX - (unsigned long long)(unsigned long)key;
+}
+
+inline Key operator+(const Key key1, const Key key2)
+{
+ /* FIXME: must be made aware of isSigned. */
+ return Key( key1.key + key2.key );
+}
+
+inline Key operator-(const Key key1, const Key key2)
+{
+ /* FIXME: must be made aware of isSigned. */
+ return Key( key1.key - key2.key );
+}
+
+inline long operator&(const Key key1, const Key key2)
+{
+ /* FIXME: must be made aware of isSigned. */
+ return key1.key & key2.key;
+}
+
+inline Key operator/(const Key key1, const Key key2)
+{
+ /* FIXME: must be made aware of isSigned. */
+ return key1.key / key2.key;
+}
+
+/* Filter on the output stream that keeps track of the number of lines
+ * output. */
+class output_filter : public std::filebuf
+{
+public:
+ output_filter( const char *fileName ) : fileName(fileName), line(1) { }
+
+ virtual int sync();
+ virtual std::streamsize xsputn(const char* s, std::streamsize n);
+
+ const char *fileName;
+ int line;
+};
+
+class cfilebuf : public std::streambuf
+{
+public:
+ cfilebuf( char *fileName, FILE* file ) : fileName(fileName), file(file) { }
+ char *fileName;
+ FILE *file;
+
+ int sync()
+ {
+ fflush( file );
+ return 0;
+ }
+
+ int overflow( int c )
+ {
+ if ( c != EOF )
+ fputc( c, file );
+ return 0;
+ }
+
+ std::streamsize xsputn( const char* s, std::streamsize n )
+ {
+ std::streamsize written = fwrite( s, 1, n, file );
+ return written;
+ }
+};
+
+class costream : public std::ostream
+{
+public:
+ costream( cfilebuf *b ) :
+ std::ostream(b), b(b) {}
+
+ ~costream()
+ { delete b; }
+
+ void fclose()
+ { ::fclose( b->file ); }
+
+ cfilebuf *b;
+};
+
+
+const char *findFileExtension( const char *stemFile );
+const char *fileNameFromStem( const char *stemFile, const char *suffix );
+
+struct Export
+{
+ Export( const char *name, Key key )
+ : name(name), key(key) {}
+
+ const char *name;
+ Key key;
+
+ Export *prev, *next;
+};
+
+typedef DList<Export> ExportList;
+
+struct exit_object { };
+extern exit_object endp;
+void operator<<( std::ostream &out, exit_object & );
+
+#endif
diff --git a/ragel/config.h.in b/ragel/config.h.in
new file mode 100644
index 0000000..2dd9bdb
--- /dev/null
+++ b/ragel/config.h.in
@@ -0,0 +1,25 @@
+/* ragel/config.h.in. Generated from configure.in by autoheader. */
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Version number of package */
+#undef VERSION
diff --git a/ragel/cscodegen.cpp b/ragel/cscodegen.cpp
new file mode 100644
index 0000000..6de1506
--- /dev/null
+++ b/ragel/cscodegen.cpp
@@ -0,0 +1,824 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cscodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <sstream>
+#include <iomanip>
+#include <string>
+#include <assert.h>
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+void csharpLineDirective( ostream &out, const char *fileName, int line )
+{
+ if ( noLineDirectives )
+ out << "/* ";
+
+ /* Write the preprocessor line info for to the input file. */
+ out << "#line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+ out << '"';
+
+ if ( noLineDirectives )
+ out << " */";
+
+ out << '\n';
+}
+
+void CSharpFsmCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ csharpLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+
+/* Init code gen with in parameters. */
+CSharpFsmCodeGen::CSharpFsmCodeGen( ostream &out )
+:
+ CodeGenData(out)
+{
+}
+
+unsigned int CSharpFsmCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string CSharpFsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ return ARRAY_TYPE( maxVal, false );
+}
+
+string CSharpFsmCodeGen::ARRAY_TYPE( unsigned long maxVal, bool forceSigned )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType;
+ if (forceSigned)
+ arrayType = keyOps->typeSubsumes(true, maxValLL);
+ else
+ arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+/* Write out the fsm name. */
+string CSharpFsmCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string CSharpFsmCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &CSharpFsmCodeGen::ACTIONS_ARRAY()
+{
+ out << "\t0, ";
+ int totalActions = 1;
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ out << act->key.length() << ", ";
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
+ out << item->value->actionId;
+ if ( ! (act.last() && item.last()) )
+ out << ", ";
+
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+string CSharpFsmCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false );
+ return ret.str();
+}
+
+
+string CSharpFsmCodeGen::P()
+{
+ ostringstream ret;
+ if ( pExpr == 0 )
+ ret << "p";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, pExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::PE()
+{
+ ostringstream ret;
+ if ( peExpr == 0 )
+ ret << "pe";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, peExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::vEOF()
+{
+ ostringstream ret;
+ if ( eofExpr == 0 )
+ ret << "eof";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, eofExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::vCS()
+{
+ ostringstream ret;
+ if ( csExpr == 0 )
+ ret << ACCESS() << "cs";
+ else {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, csExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::TOP()
+{
+ ostringstream ret;
+ if ( topExpr == 0 )
+ ret << ACCESS() + "top";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, topExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::STACK()
+{
+ ostringstream ret;
+ if ( stackExpr == 0 )
+ ret << ACCESS() + "stack";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, stackExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::ACT()
+{
+ ostringstream ret;
+ if ( actExpr == 0 )
+ ret << ACCESS() + "act";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, actExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::TOKSTART()
+{
+ ostringstream ret;
+ if ( tokstartExpr == 0 )
+ ret << ACCESS() + "ts";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokstartExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::TOKEND()
+{
+ ostringstream ret;
+ if ( tokendExpr == 0 )
+ ret << ACCESS() + "te";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokendExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string CSharpFsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string CSharpFsmCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << "(*" << P() << ")";
+ }
+ return ret.str();
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string CSharpFsmCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+/* Write out a key from the fsm code gen. Depends on wether or not the key is
+ * signed. */
+string CSharpFsmCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::ALPHA_KEY( Key key )
+{
+ ostringstream ret;
+ if (key.getVal() > 0xFFFF) {
+ ret << key.getVal();
+ } else {
+ if ( keyOps->alphType->isChar )
+ ret << "'\\u" << std::hex << std::setw(4) << std::setfill('0') << key.getVal() << "'";
+ else
+ ret << key.getVal();
+ }
+ //ret << "(char) " << key.getVal();
+ return ret.str();
+}
+
+void CSharpFsmCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+ /* The parser gives fexec two children. The double brackets are for D
+ * code. If the inline list is a single word it will get interpreted as a
+ * C-style cast by the D compiler. */
+ ret << "{" << P() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "))-1;}";
+}
+
+void CSharpFsmCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish )
+{
+ ret <<
+ " switch( " << ACT() << " ) {\n";
+
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 )
+ ret << " default:\n";
+ else
+ ret << " case " << lma->lmId << ":\n";
+
+ /* Write the block and close it off. */
+ ret << " {";
+ INLINE_LIST( ret, lma->children, targState, inFinish );
+ ret << "}\n";
+
+ ret << " break;\n";
+ }
+
+ ret <<
+ " }\n"
+ "\t";
+}
+
+void CSharpFsmCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void CSharpFsmCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << ";";
+}
+
+void CSharpFsmCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void CSharpFsmCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void CSharpFsmCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = 0;";
+}
+
+void CSharpFsmCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << ";";
+}
+
+void CSharpFsmCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "}";
+ }
+}
+
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void CSharpFsmCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << "--;";
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ CURS( ret, inFinish );
+ break;
+ case GenInlineItem::Targs:
+ TARGS( ret, inFinish, targState );
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState );
+ break;
+ }
+ }
+}
+/* Write out paths in line directives. Escapes any special characters. */
+string CSharpFsmCodeGen::LDIR_PATH( char *path )
+{
+ ostringstream ret;
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ ret << "\\\\";
+ else
+ ret << *pc;
+ }
+ return ret.str();
+}
+
+void CSharpFsmCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ csharpLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t{";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish );
+ ret << "}\n";
+}
+
+void CSharpFsmCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ ret << "\n";
+ csharpLineDirective( ret, condition->loc.fileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+string CSharpFsmCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string CSharpFsmCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void CSharpFsmCodeGen::writeInit()
+{
+ out << " {\n";
+
+ if ( !noCS )
+ out << "\t" << vCS() << " = " << START() << ";\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\t" << TOP() << " = 0;\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
+ " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
+ " " << ACT() << " = 0;\n";
+ }
+ out << " }\n";
+}
+
+string CSharpFsmCodeGen::DATA_PREFIX()
+{
+ if ( !noPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string CSharpFsmCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string CSharpFsmCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+void CSharpFsmCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
+
+ if ( !noFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
+
+ if ( !noError )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+
+void CSharpFsmCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void CSharpFsmCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void CSharpFsmCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+/*
+ * C# Specific
+ */
+string CSharpCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ if ( dataExpr == 0 )
+ ret << "data";
+ else
+ INLINE_LIST( ret, dataExpr, 0, false );
+
+ ret << "[" << P() << "]";
+ }
+ return ret.str();
+}
+string CSharpCodeGen::NULL_ITEM()
+{
+ return "-1";
+}
+
+string CSharpCodeGen::POINTER()
+{
+ // XXX C# has no pointers
+ // multiple items seperated by commas can also be pointer types.
+ return " ";
+}
+
+string CSharpCodeGen::PTR_CONST()
+{
+ return "";
+}
+
+std::ostream &CSharpCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "static readonly " << type << "[] " << name << " = ";
+ /*
+ if (type == "char")
+ out << "Encoding.ASCII.Get";
+ else */
+ out << "new " << type << " [] {\n";
+ return out;
+}
+
+std::ostream &CSharpCodeGen::CLOSE_ARRAY()
+{
+ return out << "};\n";
+}
+
+std::ostream &CSharpCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "const " << type << " " << name;
+ return out;
+}
+
+string CSharpCodeGen::ARR_OFF( string ptr, string offset )
+{
+ // XXX C# can't do pointer arithmetic
+ return "&" + ptr + "[" + offset + "]";
+}
+
+string CSharpCodeGen::CAST( string type )
+{
+ return "(" + type + ")";
+}
+
+string CSharpCodeGen::UINT( )
+{
+ return "uint";
+}
+
+std::ostream &CSharpCodeGen::SWITCH_DEFAULT()
+{
+ out << " default: break;\n";
+ return out;
+}
+
+string CSharpCodeGen::CTRL_FLOW()
+{
+ return "if (true) ";
+}
+
+void CSharpCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "const " << ALPH_TYPE() << " " << DATA_PREFIX() <<
+ "ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+/*
+ * End C#-specific code.
+ */
+
+void CSharpFsmCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &CSharpFsmCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &CSharpFsmCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
diff --git a/ragel/cscodegen.h b/ragel/cscodegen.h
new file mode 100644
index 0000000..0471ea9
--- /dev/null
+++ b/ragel/cscodegen.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CSCODEGEN_H
+#define _CSCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/* Integer array line length. */
+#define IALL 8
+
+/* Forwards. */
+struct RedFsmAp;
+struct RedStateAp;
+struct CodeGenData;
+struct GenAction;
+struct NameInst;
+struct GenInlineItem;
+struct GenInlineList;
+struct RedAction;
+struct LongestMatch;
+struct LongestMatchPart;
+
+string itoa( int i );
+
+/*
+ * class CSharpFsmCodeGen
+ */
+class CSharpFsmCodeGen : public CodeGenData
+{
+public:
+ CSharpFsmCodeGen( ostream &out );
+ virtual ~CSharpFsmCodeGen() {}
+
+ virtual void finishRagelDef();
+ virtual void writeInit();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+
+protected:
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string ALPHA_KEY( Key key );
+ string LDIR_PATH( char *path );
+ void ACTION( ostream &ret, GenAction *action, int targState, bool inFinish );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+ string ARRAY_TYPE( unsigned long maxVal, bool forceSigned );
+
+ virtual string ARR_OFF( string ptr, string offset ) = 0;
+ virtual string CAST( string type ) = 0;
+ virtual string UINT() = 0;
+ virtual string NULL_ITEM() = 0;
+ virtual string POINTER() = 0;
+ virtual string GET_KEY();
+ virtual ostream &SWITCH_DEFAULT() = 0;
+
+ string P();
+ string PE();
+ string vEOF();
+
+ string ACCESS();
+ string vCS();
+ string STACK();
+ string TOP();
+ string TOKSTART();
+ string TOKEND();
+ string ACT();
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, GenInlineList *inlineList, int targState, bool inFinish );
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem,
+ int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+ virtual void BREAK( ostream &ret, int targState ) = 0;
+ virtual void CURS( ostream &ret, bool inFinish ) = 0;
+ virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0;
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish );
+ void STATE_IDS();
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ virtual string PTR_CONST() = 0;
+ virtual ostream &OPEN_ARRAY( string type, string name ) = 0;
+ virtual ostream &CLOSE_ARRAY() = 0;
+ virtual ostream &STATIC_VAR( string type, string name ) = 0;
+
+ virtual string CTRL_FLOW() = 0;
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool testEofUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+public:
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize() {}
+
+ void genLineDirective( ostream &out );
+};
+
+class CSharpCodeGen : virtual public CSharpFsmCodeGen
+{
+public:
+ CSharpCodeGen( ostream &out ) : CSharpFsmCodeGen(out) {}
+
+ virtual string GET_KEY();
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+};
+
+#define MAX(a, b) (a > b ? a : b)
+
+#endif
diff --git a/ragel/csfflat.cpp b/ragel/csfflat.cpp
new file mode 100644
index 0000000..f504eb2
--- /dev/null
+++ b/ragel/csfflat.cpp
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csfflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &CSharpFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+/* Write out the function for a transition. */
+std::ostream &CSharpFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpFFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFFlatCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void CSharpFFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpFFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " {\n"
+ " " << slenType << " _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out << ";\n";
+ out << " " << transType << " _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+
+ out << ";\n";
+
+ out <<
+ " " << "int _keys;\n"
+ " " << indsType << " _inds;\n";
+ /*
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";*/
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << condsType << " _conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << CAST(transType) << " (" << ET() <<
+ "[" << vCS() << "] - 1);\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/csfflat.h b/ragel/csfflat.h
new file mode 100644
index 0000000..b102fe5
--- /dev/null
+++ b/ragel/csfflat.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CSFFLAT_H
+#define _CSFFLAT_H
+
+#include <iostream>
+#include "csflat.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * CSharpFFlatCodeGen
+ */
+class CSharpFFlatCodeGen : public CSharpFlatCodeGen
+{
+public:
+ CSharpFFlatCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpFlatCodeGen(out) {}
+private:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/csfgoto.cpp b/ragel/csfgoto.cpp
new file mode 100644
index 0000000..5a26424
--- /dev/null
+++ b/ragel/csfgoto.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csfgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+std::ostream &CSharpFGotoCodeGen::EXEC_ACTIONS()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* We are at the start of a glob, write the case. */
+ out << "f" << redAct->actListId << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tgoto _again;\n";
+ }
+ }
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpFGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &CSharpFGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Jump to the func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+unsigned int CSharpFGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+unsigned int CSharpFGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+unsigned int CSharpFGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+void CSharpFGotoCodeGen::writeData()
+{
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpFGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_ACTIONS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/csfgoto.h b/ragel/csfgoto.h
new file mode 100644
index 0000000..fa9447b
--- /dev/null
+++ b/ragel/csfgoto.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CSFGOTO_H
+#define _CSFGOTO_H
+
+#include <iostream>
+#include "csgoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * class CSharpFGotoCodeGen
+ */
+class CSharpFGotoCodeGen : public CSharpGotoCodeGen
+{
+public:
+ CSharpFGotoCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpGotoCodeGen(out) {}
+
+ std::ostream &EXEC_ACTIONS();
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &FINISH_CASES();
+ std::ostream &EOF_ACTION_SWITCH();
+ unsigned int TO_STATE_ACTION( RedStateAp *state );
+ unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ unsigned int EOF_ACTION( RedStateAp *state );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/csflat.cpp b/ragel/csflat.cpp
new file mode 100644
index 0000000..4d5bafa
--- /dev/null
+++ b/ragel/csflat.cpp
@@ -0,0 +1,890 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &CSharpFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &CSharpFlatCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &CSharpFlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpFlatCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ out << ALPHA_KEY( st->condLowKey ) << ", ";
+ out << ALPHA_KEY( st->condHighKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ if ( keyOps->alphType->isChar )
+ out << "(char) " << 0 << "\n";
+ else
+ out << 0 << "\n";
+
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::COND_KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::CONDS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ out << st->condList[pos]->condSpaceId + 1 << ", ";
+ else
+ out << "0, ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::COND_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpFlatCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ out << ALPHA_KEY( st->lowKey ) << ", ";
+ out << ALPHA_KEY( st->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ if ( keyOps->alphType->isChar )
+ out << "(char) " << 0 << "\n";
+ else
+ out << 0 << "\n";
+
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ out << st->transList[pos]->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 )
+ out << st->defTrans->id << ", ";
+
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &CSharpFlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &CSharpFlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void CSharpFlatCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << vCS() << "<<1;\n"
+ " _inds = " << IO() << "[" << vCS() << "];\n"
+ "\n"
+ " _slen = " << SP() << "[" << vCS() << "];\n"
+ " _trans = " << I() << "[_inds + (\n"
+ " _slen > 0 && " << K() << "[_keys] <=" << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << K() <<"[_keys+1] ?\n"
+ " " << GET_WIDE_KEY() << " - " << K() << "[_keys] : _slen ) ];\n"
+ "\n";
+}
+
+void CSharpFlatCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpFlatCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpFlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void CSharpFlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void CSharpFlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void CSharpFlatCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void CSharpFlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+
+void CSharpFlatCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+
+void CSharpFlatCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpFlatCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void CSharpFlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpFlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n";
+
+ out <<
+ " _keys = " << vCS() << "<<1;\n"
+ " _conds = " << CO() << "[" << vCS() << "];\n"
+// " _keys = " << ARR_OFF( CK(), "(" + vCS() + "<<1)" ) << ";\n"
+// " _conds = " << ARR_OFF( C(), CO() + "[" + vCS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << CSP() << "[" << vCS() << "];\n"
+ " if (_slen > 0 && " << CK() << "[_keys] <="
+ << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << CK() << "[_keys+1])\n"
+ " _cond = " << C() << "[_conds+" << GET_WIDE_KEY() << " - " <<
+ CK() << "[_keys]];\n"
+ " else\n"
+ " _cond = 0;"
+ "\n";
+ /* XXX This version of the code doesn't work because Mono is weird. Works
+ * fine in Microsoft's csc, even though the bug report filed claimed it
+ * didn't.
+ " _slen = " << CSP() << "[" << vCS() << "];\n"
+ " _cond = _slen > 0 && " << CK() << "[_keys] <="
+ << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << CK() << "[_keys+1] ?\n"
+ " " << C() << "[_conds+" << GET_WIDE_KEY() << " - " << CK()
+ << "[_keys]] : 0;\n"
+ "\n";
+ */
+ out <<
+ " switch ( _cond ) {\n";
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId + 1 << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out << " }\n";
+ out << " break;\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n";
+}
+
+void CSharpFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " {\n"
+ " " << slenType << " _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << transType << " _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+ out << ";\n";
+
+ if ( redFsm->anyToStateActions() ||
+ redFsm->anyRegActions() || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " int _acts;\n"
+ " int _nacts;\n";
+ }
+
+ out <<
+ " " << "int _keys;\n"
+ " " << indsType << " _inds;\n";
+ /*
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";*/
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << condsType << " _conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" << vCS() << "];\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << TA() << "[_trans];\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "];\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << CAST(transType) << " (" << ET() <<
+ "[" << vCS() << "] - 1);\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) <<
+ POINTER() << "__acts = " <<
+ EA() << "[" << vCS() << "];\n"
+ " " << UINT() << " __nacts = " << CAST(UINT()) << " " <<
+ A() << "[__acts++];\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[__acts++] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void CSharpFlatCodeGen::initVarTypes()
+{
+ slenType = ARRAY_TYPE(MAX(redFsm->maxSpan, redFsm->maxCondSpan));
+ transType = ARRAY_TYPE(redFsm->maxIndex+1);
+ indsType = ARRAY_TYPE(redFsm->maxFlatIndexOffset);
+ condsType = ARRAY_TYPE(redFsm->maxCondIndexOffset);
+}
diff --git a/ragel/csflat.h b/ragel/csflat.h
new file mode 100644
index 0000000..a576cd9
--- /dev/null
+++ b/ragel/csflat.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CSFLAT_H
+#define _CSFLAT_H
+
+#include <iostream>
+#include "cscodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * CSharpFlatCodeGen
+ */
+class CSharpFlatCodeGen : virtual public CSharpFsmCodeGen, public CSharpCodeGen
+{
+public:
+ CSharpFlatCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpCodeGen(out) {}
+ virtual ~CSharpFlatCodeGen() { }
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+ void initVarTypes();
+ string slenType, transType, indsType, condsType;
+};
+
+#endif
diff --git a/ragel/csftable.cpp b/ragel/csftable.cpp
new file mode 100644
index 0000000..44378e8
--- /dev/null
+++ b/ragel/csftable.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csftable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void CSharpFTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &CSharpFTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpFTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+
+/* Write out the function for a transition. */
+std::ostream &CSharpFTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpFTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &CSharpFTabCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void CSharpFTabCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpFTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " {\n"
+ " " << klenType << " _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << keysType << " _keys;\n"
+ " " << transType << " _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << vCS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( useIndicies )
+ out << " _trans = " << CAST(transType) << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << vCS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << CAST(transType) << " (" << ET() <<
+ "[" << vCS() << "] - 1);\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch ( " << EA() << "[" << vCS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/csftable.h b/ragel/csftable.h
new file mode 100644
index 0000000..612ec32
--- /dev/null
+++ b/ragel/csftable.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _CSFTABLE_H
+#define _CSFTABLE_H
+
+#include <iostream>
+#include "cstable.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * CSharpFTabCodeGen
+ */
+class CSharpFTabCodeGen : public CSharpTabCodeGen
+{
+public:
+ CSharpFTabCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpTabCodeGen(out) {}
+private:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void writeData();
+ virtual void writeExec();
+ virtual void calcIndexSize();
+};
+
+#endif
diff --git a/ragel/csgoto.cpp b/ragel/csgoto.cpp
new file mode 100644
index 0000000..4bb2ec1
--- /dev/null
+++ b/ragel/csgoto.cpp
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csgoto.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+/* Emit the goto to take for a given transition. */
+std::ostream &CSharpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void CSharpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ /* Label the state. */
+ out << "case " << state->id << ":\n";
+}
+
+
+void CSharpGotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << "\tif ( " << GET_WIDE_KEY(state) << " == " <<
+ KEY(data[0].lowKey) << " )\n\t\t";
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, 0) << "\n";
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << "\tswitch( " << GET_WIDE_KEY(state) << " ) {\n";
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << "\t\tcase " << ALPHA_KEY(data[j].lowKey) << ": ";
+ TRANS_GOTO(data[j].value, 0) << "\n";
+ }
+
+ /* Emits a default case for D code. */
+ SWITCH_DEFAULT();
+
+ /* Close off the transition switch. */
+ out << "\t}\n";
+ }
+}
+
+void CSharpGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ RedTransEl *data = state->outRange.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " >= " <<
+ KEY(data[mid].lowKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+}
+
+void CSharpGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << "case " << state->id << ":\n";
+ out << " goto _out;\n";
+}
+
+void CSharpGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
+{
+ GenCondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+}
+
+void CSharpGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ GenStateCond **data = state->stateCondVect.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " )\n {";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &CSharpGotoCodeGen::STATE_GOTOS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ out << " tr" << trans->id << ": ";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << vCS() << ";";
+ out << vCS() << " = " << trans->targ->id << "; ";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ out << "goto f" << trans->action->actListId << ";\n";
+ }
+ else {
+ /* No code to execute, just loop around. */
+ out << "goto _again;\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ out << " f" << redAct->actListId << ": " <<
+ "_acts = " << itoa( redAct->location+1 ) << ";"
+ " goto execFuncs;\n";
+ }
+ }
+
+ out <<
+ "\n"
+ "execFuncs:\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " goto _again;\n";
+ return out;
+}
+
+unsigned int CSharpGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+unsigned int CSharpGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+unsigned int CSharpGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &CSharpGotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &CSharpGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Write the goto func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+void CSharpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void CSharpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void CSharpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void CSharpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void CSharpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void CSharpGotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << ARRAY_TYPE(redFsm->maxActionLoc) << " _acts;\n"
+ " " << ARRAY_TYPE(redFsm->maxActArrItem) << " _nacts;\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" << vCS() << "];\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "];\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch ( " << vCS() << " ) {\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ SWITCH_DEFAULT() <<
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " " << ARRAY_TYPE(redFsm->maxActionLoc) << " __acts = " <<
+ EA() << "[" << vCS() << "];\n"
+ " " << ARRAY_TYPE(redFsm->maxActArrItem) << " __nacts = " <<
+ A() << "[__acts++];\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[__acts++] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
diff --git a/ragel/csgoto.h b/ragel/csgoto.h
new file mode 100644
index 0000000..7491884
--- /dev/null
+++ b/ragel/csgoto.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOTOCODEGEN_H
+#define _GOTOCODEGEN_H
+
+#include <iostream>
+#include "cscodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+struct GenStateCond;
+
+/*
+ * Goto driven fsm.
+ */
+class CSharpGotoCodeGen : virtual public CSharpFsmCodeGen, public CSharpCodeGen
+{
+public:
+ CSharpGotoCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpCodeGen(out) {}
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &STATE_GOTOS();
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual unsigned int TO_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int EOF_ACTION( RedStateAp *state );
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+ void COND_TRANSLATE( GenStateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+ void emitSingleSwitch( RedStateAp *state );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state );
+ virtual void STATE_GOTO_ERROR();
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/csipgoto.cpp b/ragel/csipgoto.cpp
new file mode 100644
index 0000000..0e3168a
--- /dev/null
+++ b/ragel/csipgoto.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "csipgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+bool CSharpIpGotoCodeGen::useAgainLabel()
+{
+ return redFsm->anyRegActionRets() ||
+ redFsm->anyRegActionByValControl() ||
+ redFsm->anyRegNextStmt();
+}
+
+void CSharpIpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CTRL_FLOW() << "goto st" << gotoDest << ";}";
+}
+
+void CSharpIpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState <<
+ "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpIpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpIpGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpIpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpIpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void CSharpIpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void CSharpIpGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void CSharpIpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << targState;
+}
+
+void CSharpIpGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ /* FIXME: If this code generator is made active then BREAK generation
+ * needs to check csForced. */
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << vCS() << " = " << targState <<
+ "; " << CTRL_FLOW() << "goto _out;}";
+}
+
+bool CSharpIpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
+{
+ bool anyWritten = false;
+
+ /* Emit any transitions that have actions and that go to this state. */
+ for ( int it = 0; it < state->numInTrans; it++ ) {
+ RedTransAp *trans = state->inTrans[it];
+ if ( trans->action != 0 && trans->labelNeeded ) {
+ /* Remember that we wrote an action so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write the label for the transition so it can be jumped to. */
+ out << "tr" << trans->id << ":\n";
+
+ /* If the action contains a next, then we must preload the current
+ * state since the action may or may not set it. */
+ if ( trans->action->anyNextStmt() )
+ out << " " << vCS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ )
+ ACTION( out, item->value, trans->targ->id, false );
+
+ /* If the action contains a next then we need to reload, otherwise
+ * jump directly to the target state. */
+ if ( trans->action->anyNextStmt() )
+ out << "\tgoto _again;\n";
+ else
+ out << "\tgoto st" << trans->targ->id << ";\n";
+ }
+ }
+
+ return anyWritten;
+}
+
+/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
+ * state. */
+void CSharpIpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _test_eof" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+void CSharpIpGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* In the error state we need to emit some stuff that usually goes into
+ * the header. */
+ RedStateAp *state = redFsm->errState;
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ /* No case label needed since we don't switch on the error state. */
+ if ( anyWritten )
+ genLineDirective( out );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ /* Break out here. */
+ outLabelUsed = true;
+ out << vCS() << " = " << state->id << ";\n";
+ out << " goto _out;\n";
+}
+
+
+/* Emit the goto to take for a given transition. */
+std::ostream &CSharpIpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ return out;
+}
+
+std::ostream &CSharpIpGotoCodeGen::EXIT_STATES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->outNeeded ) {
+ testEofUsed = true;
+ out << " _test_eof" << st->id << ": " << vCS() << " = " <<
+ st->id << "; goto _test_eof; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &CSharpIpGotoCodeGen::AGAIN_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ out <<
+ " case " << st->id << ": goto st" << st->id << ";\n";
+ }
+ return out;
+}
+
+std::ostream &CSharpIpGotoCodeGen::FINISH_CASES()
+{
+ bool anyWritten = false;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofAction != 0 ) {
+ if ( st->eofAction->eofRefs == 0 )
+ st->eofAction->eofRefs = new IntSet;
+ st->eofAction->eofRefs->insert( st->id );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
+ }
+
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ if ( act->eofRefs != 0 ) {
+ for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
+ out << " case " << *pst << ": \n";
+
+ /* Remember that we wrote a trans so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write each action in the eof action list. */
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
+ ACTION( out, item->value, STATE_ERR_STATE, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+ return out;
+}
+
+void CSharpIpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call: {
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( item->children );
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void CSharpIpGotoCodeGen::setLabelsNeeded()
+{
+ /* If we use the _again label, then we the _again switch, which uses all
+ * labels. */
+ if ( useAgainLabel() ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = true;
+ }
+ else {
+ /* Do not use all labels by default, init all labelNeeded vars to false. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = false;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->targ->labelNeeded = true;
+
+ /* Need labels for states that have goto or calls in action code
+ * invoked on characters (ie, not from out action code). */
+ if ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( act->value->inlineList );
+ }
+ }
+ }
+ }
+
+ if ( !noEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st != redFsm->errState )
+ st->outNeeded = st->labelNeeded;
+ }
+ }
+}
+
+void CSharpIpGotoCodeGen::writeData()
+{
+ STATE_IDS();
+}
+
+void CSharpIpGotoCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << vCS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " )\n {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ EXIT_STATES() <<
+ "\n";
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n"
+ " switch ( " << vCS() << " ) {\n";
+ FINISH_CASES();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+}
diff --git a/ragel/csipgoto.h b/ragel/csipgoto.h
new file mode 100644
index 0000000..4aeb47d
--- /dev/null
+++ b/ragel/csipgoto.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _IPGCODEGEN_H
+#define _IPGCODEGEN_H
+
+#include <iostream>
+#include "csgoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * class CSharpIpGotoCodeGen
+ */
+class CSharpIpGotoCodeGen : public CSharpGotoCodeGen
+{
+public:
+ CSharpIpGotoCodeGen( ostream &out ) : CSharpFsmCodeGen(out),
+ CSharpGotoCodeGen(out) {}
+
+ std::ostream &EXIT_STATES();
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ std::ostream &FINISH_CASES();
+ std::ostream &AGAIN_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void BREAK( ostream &ret, int targState );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ bool useAgainLabel();
+
+ /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for
+ * each state. */
+ bool IN_TRANS_ACTIONS( RedStateAp *state );
+ void GOTO_HEADER( RedStateAp *state );
+ void STATE_GOTO_ERROR();
+
+ /* Set up labelNeeded flag for each state. */
+ void setLabelsNeeded( GenInlineList *inlineList );
+ void setLabelsNeeded();
+};
+
+#endif
diff --git a/ragel/cssplit.cpp b/ragel/cssplit.cpp
new file mode 100644
index 0000000..8c7464f
--- /dev/null
+++ b/ragel/cssplit.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2006 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 "ragel.h"
+#include "cssplit.h"
+#include "gendata.h"
+#include <assert.h>
+
+using std::ostream;
+using std::ios;
+using std::endl;
+
+/* Emit the goto to take for a given transition. */
+std::ostream &CSharpSplitCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->targ->partition == currentPartition ) {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ }
+ else {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto ptr" << trans->id << ";";
+ trans->partitionBoundary = true;
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto pst" << trans->targ->id << ";";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+ return out;
+}
+
+/* Called from before writing the gotos for each state. */
+void CSharpSplitCodeGen::GOTO_HEADER( RedStateAp *state, bool stateInPartition )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+std::ostream &CSharpSplitCodeGen::STATE_GOTOS( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* We call into the base of the goto which calls back into us
+ * using virtual functions. Set the current partition rather
+ * than coding parameter passing throughout. */
+ currentPartition = partition;
+
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st, st->partition == partition );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ }
+ return out;
+}
+
+
+std::ostream &CSharpSplitCodeGen::PART_TRANS( int partition )
+{
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ if ( trans->partitionBoundary ) {
+ out <<
+ "ptr" << trans->id << ":\n";
+
+ if ( trans->action != 0 ) {
+ /* If the action contains a next, then we must preload the current
+ * state since the action may or may not set it. */
+ if ( trans->action->anyNextStmt() )
+ out << " " << vCS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ )
+ ACTION( out, item->value, trans->targ->id, false );
+ }
+
+ out <<
+ " goto pst" << trans->targ->id << ";\n";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partitionBoundary ) {
+ out <<
+ " pst" << st->id << ":\n"
+ " " << vCS() << " = " << st->id << ";\n";
+
+ if ( st->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, st->id, false );
+ genLineDirective( out );
+ }
+
+ ptOutLabelUsed = true;
+ out << " goto _pt_out; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &CSharpSplitCodeGen::EXIT_STATES( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition && st->outNeeded ) {
+ outLabelUsed = true;
+ out << " _out" << st->id << ": " << vCS() << " = " <<
+ st->id << "; goto _out; \n";
+ }
+ }
+ return out;
+}
+
+
+std::ostream &CSharpSplitCodeGen::PARTITION( int partition )
+{
+ outLabelUsed = false;
+ ptOutLabelUsed = false;
+
+ /* Initialize the partition boundaries, which get set during the writing
+ * of states. After the state writing we will */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ trans->partitionBoundary = false;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->partitionBoundary = false;
+
+ out << " " << ALPH_TYPE() << " *p = *_pp, *pe = *_ppe;\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << vCS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+
+ if ( !noEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out <<
+ "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << vCS() << " )\n {\n";
+ STATE_GOTOS( partition );
+ SWITCH_DEFAULT() <<
+ " }\n";
+ PART_TRANS( partition );
+ EXIT_STATES( partition );
+
+ if ( outLabelUsed ) {
+ out <<
+ "\n"
+ " _out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 0;\n";
+ }
+
+ if ( ptOutLabelUsed ) {
+ out <<
+ "\n"
+ " _pt_out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 1;\n";
+ }
+
+ return out;
+}
+
+std::ostream &CSharpSplitCodeGen::PART_MAP()
+{
+ int *partMap = new int[redFsm->stateList.length()];
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ partMap[st->id] = st->partition;
+
+ out << "\t";
+ int totalItem = 0;
+ for ( int i = 0; i < redFsm->stateList.length(); i++ ) {
+ out << partMap[i];
+ if ( i != redFsm->stateList.length() - 1 ) {
+ out << ", ";
+ if ( ++totalItem % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ delete[] partMap;
+ return out;
+}
+
+void CSharpSplitCodeGen::writeData()
+{
+ out <<
+ "const int " << START() << " = " << START_STATE_ID() << ";\n"
+ "\n";
+
+ if ( !noFinal ) {
+ out <<
+ "const int " << FIRST_FINAL() << " = " << FIRST_FINAL_STATE() << ";\n"
+ "\n";
+ }
+
+ if ( !noError ) {
+ out <<
+ "const int " << ERROR() << " = " << ERROR_STATE() << ";\n"
+ "\n";
+ }
+
+
+ OPEN_ARRAY( ARRAY_TYPE(numSplitPartitions), PM() );
+ PART_MAP();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out << "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm );\n";
+ }
+ out << "\n";
+}
+
+std::ostream &CSharpSplitCodeGen::ALL_PARTITIONS()
+{
+ /* compute the format string. */
+ int width = 0, high = redFsm->nParts - 1;
+ while ( high > 0 ) {
+ width++;
+ high /= 10;
+ }
+ assert( width <= 8 );
+ char suffFormat[] = "_%6.6d.c";
+ suffFormat[2] = suffFormat[4] = ( '0' + width );
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ char suffix[10];
+ sprintf( suffix, suffFormat, p );
+ const char *fn = fileNameFromStem( sourceFileName, suffix );
+ const char *include = fileNameFromStem( sourceFileName, ".h" );
+
+ /* Create the filter on the output and open it. */
+ output_filter *partFilter = new output_filter( fn );
+ partFilter->open( fn, ios::out|ios::trunc );
+ if ( !partFilter->is_open() ) {
+ error() << "error opening " << fn << " for writing" << endl;
+ exit(1);
+ }
+
+ /* Attach the new file to the output stream. */
+ std::streambuf *prev_rdbuf = out.rdbuf( partFilter );
+
+ out <<
+ "#include \"" << include << "\"\n"
+ "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm )\n"
+ "{\n";
+ PARTITION( p ) <<
+ "}\n\n";
+ out.flush();
+
+ /* Fix the output stream. */
+ out.rdbuf( prev_rdbuf );
+ }
+ return out;
+}
+
+
+void CSharpSplitCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ out <<
+ " {\n"
+ " int _stat = 0;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << " goto _resume;\n";
+
+ /* In this reentry, to-state actions have already been executed on the
+ * partition-switch exit from the last partition. */
+ out << "_reenter:\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+
+ out <<
+ " switch ( " << PM() << "[" << vCS() << "] ) {\n";
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out <<
+ " case " << p << ":\n"
+ " _stat = partition" << p << "( &p, &pe, fsm );\n"
+ " break;\n";
+ }
+ out <<
+ " }\n"
+ " if ( _stat )\n"
+ " goto _reenter;\n";
+
+ if ( !noEnd )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+
+ ALL_PARTITIONS();
+}
+
+void CSharpSplitCodeGen::setLabelsNeeded( RedStateAp *fromState, GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call: {
+ /* In split code gen we only need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == item->targState->partition ){
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( fromState, item->children );
+ }
+}
+
+void CSharpSplitCodeGen::setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans )
+{
+ /* In the split code gen we don't need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == trans->targ->partition ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ trans->labelNeeded = true;
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->targ->labelNeeded = true;
+ }
+
+ /* Need labels for states that have goto or calls in action code
+ * invoked on characters (ie, not from out action code). */
+ if ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( fromState, act->value->inlineList );
+ }
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void CSharpSplitCodeGen::setLabelsNeeded()
+{
+ /* If we use the _again label, then we the _again switch, which uses all
+ * labels. */
+ if ( useAgainLabel() ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = true;
+ }
+ else {
+ /* Do not use all labels by default, init all labelNeeded vars to false. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = false;
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ trans->labelNeeded = false;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ for ( RedTransList::Iter tel = st->outSingle; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ if ( st->defTrans != 0 )
+ setLabelsNeeded( st, st->defTrans );
+ }
+ }
+
+ if ( !noEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->outNeeded = st->labelNeeded;
+ }
+ else {
+ if ( redFsm->errState != 0 )
+ redFsm->errState->outNeeded = true;
+
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Any state with a transition in that has a break will need an
+ * out label. */
+ if ( trans->action != 0 && trans->action->anyBreakStmt() )
+ trans->targ->outNeeded = true;
+ }
+ }
+}
+
diff --git a/ragel/cssplit.h b/ragel/cssplit.h
new file mode 100644
index 0000000..9ff2d8f
--- /dev/null
+++ b/ragel/cssplit.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2006 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
+ */
+
+#ifndef _SPLITCODEGEN_H
+#define _SPLITCODEGEN_H
+
+#include "csipgoto.h"
+
+class CSharpSplitCodeGen : public CSharpIpGotoCodeGen
+{
+public:
+ CSharpSplitCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpIpGotoCodeGen(out) {}
+
+ bool ptOutLabelUsed;
+
+ std::ostream &PART_MAP();
+ std::ostream &EXIT_STATES( int partition );
+ std::ostream &PART_TRANS( int partition );
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ void GOTO_HEADER( RedStateAp *state, bool stateInPartition );
+ std::ostream &STATE_GOTOS( int partition );
+ std::ostream &PARTITION( int partition );
+ std::ostream &ALL_PARTITIONS();
+ void writeData();
+ void writeExec();
+ void writeParts();
+
+ void setLabelsNeeded( RedStateAp *fromState, GenInlineList *inlineList );
+ void setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans );
+ void setLabelsNeeded();
+
+ int currentPartition;
+};
+
+#endif
diff --git a/ragel/cstable.cpp b/ragel/cstable.cpp
new file mode 100644
index 0000000..72df0a6
--- /dev/null
+++ b/ragel/cstable.cpp
@@ -0,0 +1,1123 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "cstable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void CSharpTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &CSharpTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::COND_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::KEY_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::INDEX_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::COND_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->stateCondList.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::SINGLE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->outSingle.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::RANGE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ out << st->outRange.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ out << ALPHA_KEY( sc->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << ALPHA_KEY( sc->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ if ( keyOps->alphType->isChar )
+ out << "(char) " << 0 << "\n";
+ else
+ out << 0 << "\n";
+
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::COND_SPACES()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ out << sc->condSpace->condSpaceId << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << ALPHA_KEY( stel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ out << ALPHA_KEY( rtel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << ALPHA_KEY( rtel->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ if ( keyOps->alphType->isChar )
+ out << "(char) " << 0 << "\n";
+ else
+ out << 0 << "\n";
+
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << stel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ out << rtel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::TRANS_ACTIONS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &CSharpTabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &CSharpTabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void CSharpTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpTabCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void CSharpTabCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void CSharpTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void CSharpTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void CSharpTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void CSharpTabCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" <<
+ TOP() << "]; ";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void CSharpTabCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
+}
+
+void CSharpTabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void CSharpTabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << KO() + "[" + vCS() + "]" << ";\n"
+ " _trans = " << CAST(transType) << IO() << "[" << vCS() << "];\n"
+ "\n"
+ " _klen = " << SL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << signedKeysType << " _lower = _keys;\n"
+ " " << signedKeysType << " _mid;\n"
+ " " << signedKeysType << " _upper = " << CAST(signedKeysType) <<
+ " (_keys + _klen - 1);\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = " << CAST(signedKeysType) <<
+ " (_lower + ((_upper-_lower) >> 1));\n"
+ " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+ " _upper = " << CAST(signedKeysType) << " (_mid - 1);\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
+ " _lower = " << CAST(signedKeysType) << " (_mid + 1);\n"
+ " else {\n"
+ " _trans += " << CAST(transType) << " (_mid - _keys);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _keys += " << CAST(keysType) << " _klen;\n"
+ " _trans += " << CAST(transType) << " _klen;\n"
+ " }\n"
+ "\n"
+ " _klen = " << RL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << signedKeysType << " _lower = _keys;\n"
+ " " << signedKeysType << " _mid;\n"
+ " " << signedKeysType << " _upper = " << CAST(signedKeysType) <<
+ " (_keys + (_klen<<1) - 2);\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = " << CAST(signedKeysType) <<
+ " (_lower + (((_upper-_lower) >> 1) & ~1));\n"
+ " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+ " _upper = " << CAST(signedKeysType) << " (_mid - 2);\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
+ " _lower = " << CAST(signedKeysType) << " (_mid + 2);\n"
+ " else {\n"
+ " _trans += " << CAST(transType) << "((_mid - _keys)>>1);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _trans += " << CAST(transType) << " _klen;\n"
+ " }\n"
+ "\n";
+}
+
+void CSharpTabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n"
+ " _klen = " << CL() << "[" << vCS() << "];\n"
+ " _keys = " << CAST(keysType) << " ("<< CO() << "[" << vCS() << "]*2);\n"
+ " if ( _klen > 0 ) {\n"
+ " " << signedKeysType << " _lower = _keys;\n"
+ " " << signedKeysType << " _mid;\n"
+ " " << signedKeysType << " _upper = " << CAST(signedKeysType) <<
+ " (_keys + (_klen<<1) - 2);\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = " << CAST(signedKeysType) <<
+ " (_lower + (((_upper-_lower) >> 1) & ~1));\n"
+ " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
+ " _upper = " << CAST(signedKeysType) << " (_mid - 2);\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
+ " _lower = " << CAST(signedKeysType) << " (_mid + 2);\n"
+ " else {\n"
+ " switch ( " << C() << "[" << CO() << "[" << vCS() << "]"
+ " + ((_mid - _keys)>>1)] ) {\n";
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out <<
+ " break;\n"
+ " }\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+}
+
+void CSharpTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " {\n"
+ " " << klenType << " _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << transType << " _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " int _acts;\n"
+ " int _nacts;\n";
+ }
+
+ out <<
+ " " << keysType << " _keys;\n"
+ "\n";
+// " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" + vCS() + "]" << ";\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( useIndicies )
+ out << " _trans = " << CAST(transType) << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << TA() << "[_trans]" << ";\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 )\n {\n"
+ " switch ( " << A() << "[_acts++] )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "]" << ";\n"
+ " _nacts = " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << CAST(transType) << " (" << ET() <<
+ "[" << vCS() << "] - 1);\n"
+ " goto _eof_trans;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " int __acts = " <<
+ EA() << "[" << vCS() << "]" << ";\n"
+ " int __nacts = " <<
+ A() << "[__acts++];\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[__acts++] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void CSharpTabCodeGen::initVarTypes()
+{
+ int klenMax = MAX(MAX(redFsm->maxCondLen, redFsm->maxRangeLen),
+ redFsm->maxSingleLen);
+ int keysMax = MAX(MAX(redFsm->maxKeyOffset, klenMax),
+ redFsm->maxCondOffset);
+ int transMax = MAX(MAX(redFsm->maxIndex+1, redFsm->maxIndexOffset), keysMax);
+ transMax = MAX(transMax, klenMax);
+ transType = ARRAY_TYPE(transMax);
+ klenType = ARRAY_TYPE(klenMax);
+ keysType = ARRAY_TYPE(keysMax);
+ signedKeysType = ARRAY_TYPE(keysMax, true);
+}
diff --git a/ragel/cstable.h b/ragel/cstable.h
new file mode 100644
index 0000000..a8206fc
--- /dev/null
+++ b/ragel/cstable.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _TABCODEGEN_H
+#define _TABCODEGEN_H
+
+#include <iostream>
+#include "cscodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * TabCodeGen
+ */
+class CSharpTabCodeGen : virtual public CSharpFsmCodeGen, public CSharpCodeGen
+{
+public:
+ CSharpTabCodeGen( ostream &out ) : CSharpFsmCodeGen(out), CSharpCodeGen(out) {}
+ virtual ~CSharpTabCodeGen() { }
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+
+ void LOCATE_TRANS();
+
+ void COND_TRANSLATE();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void calcIndexSize();
+
+ void initVarTypes();
+ string klenType;
+ string keysType;
+ string signedKeysType;
+ string transType;
+};
+
+#endif
diff --git a/ragel/dotcodegen.cpp b/ragel/dotcodegen.cpp
new file mode 100644
index 0000000..7a83c46
--- /dev/null
+++ b/ragel/dotcodegen.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2001-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 "ragel.h"
+#include "dotcodegen.h"
+#include "gendata.h"
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/* Override this so that write statement processing is ignored */
+bool GraphvizDotGen::writeStatement( InputLoc &, int, char ** )
+{
+ return false;
+}
+
+std::ostream &GraphvizDotGen::KEY( Key key )
+{
+ if ( displayPrintables && key.isPrintable() ) {
+ // Output values as characters, ensuring we escape the quote (") character
+ char cVal = (char) key.getVal();
+ switch ( cVal ) {
+ case '"': case '\\':
+ out << "'\\" << cVal << "'";
+ break;
+ case '\a':
+ out << "'\\\\a'";
+ break;
+ case '\b':
+ out << "'\\\\b'";
+ break;
+ case '\t':
+ out << "'\\\\t'";
+ break;
+ case '\n':
+ out << "'\\\\n'";
+ break;
+ case '\v':
+ out << "'\\\\v'";
+ break;
+ case '\f':
+ out << "'\\\\f'";
+ break;
+ case '\r':
+ out << "'\\\\r'";
+ break;
+ case ' ':
+ out << "SP";
+ break;
+ default:
+ out << "'" << cVal << "'";
+ break;
+ }
+ }
+ else {
+ if ( keyOps->isSigned )
+ out << key.getVal();
+ else
+ out << (unsigned long) key.getVal();
+ }
+
+ return out;
+}
+
+std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
+{
+ int n = 0;
+ RedAction *actions[3];
+
+ if ( fromState->fromStateAction != 0 )
+ actions[n++] = fromState->fromStateAction;
+ if ( trans->action != 0 )
+ actions[n++] = trans->action;
+ if ( trans->targ != 0 && trans->targ->toStateAction != 0 )
+ actions[n++] = trans->targ->toStateAction;
+
+ if ( n > 0 )
+ out << " / ";
+
+ /* Loop the existing actions and write out what's there. */
+ for ( int a = 0; a < n; a++ ) {
+ for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
+ GenAction *action = actIt->value;
+ out << action->nameOrLoc();
+ if ( a < n-1 || !actIt.last() )
+ out << ", ";
+ }
+ }
+ return out;
+}
+
+std::ostream &GraphvizDotGen::ACTION( RedAction *action )
+{
+ /* The action. */
+ out << " / ";
+ for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
+ GenAction *action = actIt->value;
+ if ( action->name != 0 )
+ out << action->name;
+ else
+ out << action->loc.line << ":" << action->loc.col;
+ if ( !actIt.last() )
+ out << ", ";
+ }
+ return out;
+}
+
+std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
+{
+ GenCondSpace *condSpace;
+ if ( lowKey > keyOps->maxKey && (condSpace=findCondSpace(lowKey, highKey) ) ) {
+ Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
+
+ lowKey = keyOps->minKey +
+ (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
+ highKey = keyOps->minKey +
+ (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
+ KEY( lowKey );
+ if ( lowKey != highKey ) {
+ out << "..";
+ KEY( highKey );
+ }
+ out << "(";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ bool set = values & (1 << csi.pos());
+ if ( !set )
+ out << "!";
+ out << (*csi)->nameOrLoc();
+ if ( !csi.last() )
+ out << ", ";
+ }
+ out << ")";
+ }
+ else {
+ /* Output the key. Possibly a range. */
+ KEY( lowKey );
+ if ( highKey != lowKey ) {
+ out << "..";
+ KEY( highKey );
+ }
+ }
+ return out;
+}
+
+void GraphvizDotGen::writeTransList( RedStateAp *state )
+{
+ /* Build the set of unique transitions out of this state. */
+ RedTransSet stTransSet;
+ for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
+ /* If we haven't seen the transitions before, the move forward
+ * emitting all the transitions on the same character. */
+ if ( stTransSet.insert( tel->value ) ) {
+ /* Write out the from and to states. */
+ out << "\t" << state->id << " -> ";
+
+ if ( tel->value->targ == 0 )
+ out << "err_" << state->id;
+ else
+ out << tel->value->targ->id;
+
+ /* Begin the label. */
+ out << " [ label = \"";
+ ONCHAR( tel->lowKey, tel->highKey );
+
+ /* Walk the transition list, finding the same. */
+ for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
+ if ( mtel->value == tel->value ) {
+ out << ", ";
+ ONCHAR( mtel->lowKey, mtel->highKey );
+ }
+ }
+
+ /* Write the action and close the transition. */
+ TRANS_ACTION( state, tel->value );
+ out << "\" ];\n";
+ }
+ }
+
+ /* Write the default transition. */
+ if ( state->defTrans != 0 ) {
+ /* Write out the from and to states. */
+ out << "\t" << state->id << " -> ";
+
+ if ( state->defTrans->targ == 0 )
+ out << "err_" << state->id;
+ else
+ out << state->defTrans->targ->id;
+
+ /* Begin the label. */
+ out << " [ label = \"DEF";
+
+ /* Write the action and close the transition. */
+ TRANS_ACTION( state, state->defTrans );
+ out << "\" ];\n";
+ }
+}
+
+void GraphvizDotGen::writeDotFile( )
+{
+ out <<
+ "digraph " << fsmName << " {\n"
+ " rankdir=LR;\n";
+
+ /* Define the psuedo states. Transitions will be done after the states
+ * have been defined as either final or not final. */
+ out << " node [ shape = point ];\n";
+
+ if ( redFsm->startState != 0 )
+ out << " ENTRY;\n";
+
+ /* Psuedo states for entry points in the entry map. */
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
+ RedStateAp *state = allStates + *en;
+ out << " en_" << state->id << ";\n";
+ }
+
+ /* Psuedo states for final states with eof actions. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
+ out << " eof_" << st->id << ";\n";
+ if ( st->eofAction != 0 )
+ out << " eof_" << st->id << ";\n";
+ }
+
+ out << " node [ shape = circle, height = 0.2 ];\n";
+
+ /* Psuedo states for states whose default actions go to error. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ bool needsErr = false;
+ if ( st->defTrans != 0 && st->defTrans->targ == 0 )
+ needsErr = true;
+ else {
+ for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
+ if ( tel->value->targ == 0 ) {
+ needsErr = true;
+ break;
+ }
+ }
+ }
+
+ if ( needsErr )
+ out << " err_" << st->id << " [ label=\"\"];\n";
+ }
+
+ /* Attributes common to all nodes, plus double circle for final states. */
+ out << " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
+
+ /* List Final states. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->isFinal )
+ out << " " << st->id << ";\n";
+ }
+
+ /* List transitions. */
+ out << " node [ shape = circle ];\n";
+
+ /* Walk the states. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ writeTransList( st );
+
+ /* Transitions into the start state. */
+ if ( redFsm->startState != 0 )
+ out << " ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
+
+ /* Transitions into the entry points. */
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
+ RedStateAp *state = allStates + *en;
+ char *name = entryPointNames[en.pos()];
+ out << " en_" << state->id << " -> " << state->id <<
+ " [ label = \"" << name << "\" ];\n";
+ }
+
+ /* Out action transitions. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
+ out << " " << st->id << " -> eof_" <<
+ st->id << " [ label = \"EOF";
+ ACTION( st->eofTrans->action ) << "\" ];\n";
+ }
+ if ( st->eofAction != 0 ) {
+ out << " " << st->id << " -> eof_" <<
+ st->id << " [ label = \"EOF";
+ ACTION( st->eofAction ) << "\" ];\n";
+ }
+ }
+
+ out <<
+ "}\n";
+}
+
+void GraphvizDotGen::finishRagelDef()
+{
+ /* For dot file generation we want to pick default transitions. */
+ redFsm->chooseDefaultSpan();
+}
diff --git a/ragel/dotcodegen.h b/ragel/dotcodegen.h
new file mode 100644
index 0000000..97dd3af
--- /dev/null
+++ b/ragel/dotcodegen.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-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
+ */
+
+#ifndef _GVDOTGEN_H
+#define _GVDOTGEN_H
+
+#include <iostream>
+#include "gendata.h"
+
+class GraphvizDotGen : public CodeGenData
+{
+public:
+ GraphvizDotGen( ostream &out ) : CodeGenData(out) { }
+
+ /* Print an fsm to out stream. */
+ void writeTransList( RedStateAp *state );
+ void writeDotFile( );
+
+ virtual void finishRagelDef();
+ virtual bool writeStatement( InputLoc &, int, char ** );
+
+private:
+ /* Writing labels and actions. */
+ std::ostream &ONCHAR( Key lowKey, Key highKey );
+ std::ostream &TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans );
+ std::ostream &ACTION( RedAction *action );
+ std::ostream &KEY( Key key );
+};
+
+#endif
diff --git a/ragel/fsmap.cpp b/ragel/fsmap.cpp
new file mode 100644
index 0000000..0a98799
--- /dev/null
+++ b/ragel/fsmap.cpp
@@ -0,0 +1,879 @@
+/*
+ * Copyright 2002-2004 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 "fsmgraph.h"
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+CondData *condData = 0;
+KeyOps *keyOps = 0;
+
+/* Insert an action into an action table. */
+void ActionTable::setAction( int ordering, Action *action )
+{
+ /* Multi-insert in case specific instances of an action appear in a
+ * transition more than once. */
+ insertMulti( ordering, action );
+}
+
+/* Set all the action from another action table in this table. */
+void ActionTable::setActions( const ActionTable &other )
+{
+ for ( ActionTable::Iter action = other; action.lte(); action++ )
+ insertMulti( action->key, action->value );
+}
+
+void ActionTable::setActions( int *orderings, Action **actions, int nActs )
+{
+ for ( int a = 0; a < nActs; a++ )
+ insertMulti( orderings[a], actions[a] );
+}
+
+bool ActionTable::hasAction( Action *action )
+{
+ for ( int a = 0; a < length(); a++ ) {
+ if ( data[a].value == action )
+ return true;
+ }
+ return false;
+}
+
+/* Insert an action into an action table. */
+void LmActionTable::setAction( int ordering, LongestMatchPart *action )
+{
+ /* Multi-insert in case specific instances of an action appear in a
+ * transition more than once. */
+ insertMulti( ordering, action );
+}
+
+/* Set all the action from another action table in this table. */
+void LmActionTable::setActions( const LmActionTable &other )
+{
+ for ( LmActionTable::Iter action = other; action.lte(); action++ )
+ insertMulti( action->key, action->value );
+}
+
+void ErrActionTable::setAction( int ordering, Action *action, int transferPoint )
+{
+ insertMulti( ErrActionTableEl( action, ordering, transferPoint ) );
+}
+
+void ErrActionTable::setActions( const ErrActionTable &other )
+{
+ for ( ErrActionTable::Iter act = other; act.lte(); act++ )
+ insertMulti( ErrActionTableEl( act->action, act->ordering, act->transferPoint ) );
+}
+
+/* Insert a priority into this priority table. Looks out for priorities on
+ * duplicate keys. */
+void PriorTable::setPrior( int ordering, PriorDesc *desc )
+{
+ PriorEl *lastHit = 0;
+ PriorEl *insed = insert( PriorEl(ordering, desc), &lastHit );
+ if ( insed == 0 ) {
+ /* This already has a priority on the same key as desc. Overwrite the
+ * priority if the ordering is larger (later in time). */
+ if ( ordering >= lastHit->ordering )
+ *lastHit = PriorEl( ordering, desc );
+ }
+}
+
+/* Set all the priorities from a priorTable in this table. */
+void PriorTable::setPriors( const PriorTable &other )
+{
+ /* Loop src priorities once to overwrite duplicates. */
+ PriorTable::Iter priorIt = other;
+ for ( ; priorIt.lte(); priorIt++ )
+ setPrior( priorIt->ordering, priorIt->desc );
+}
+
+/* Set the priority of starting transitions. Isolates the start state so it has
+ * no other entry points, then sets the priorities of all the transitions out
+ * of the start state. If the start state is final, then the outPrior of the
+ * start state is also set. The idea is that a machine that accepts the null
+ * string can still specify the starting trans prior for when it accepts the
+ * null word. */
+void FsmAp::startFsmPrior( int ordering, PriorDesc *prior )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+
+ /* Walk all transitions out of the start state. */
+ for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 )
+ trans->priorTable.setPrior( ordering, prior );
+ }
+
+ /* If the new start state is final then set the out priority. This follows
+ * the same convention as setting start action in the out action table of
+ * a final start state. */
+ if ( startState->stateBits & STB_ISFINAL )
+ startState->outPriorTable.setPrior( ordering, prior );
+}
+
+/* Set the priority of all transitions in a graph. Walks all transition lists
+ * and all def transitions. */
+void FsmAp::allTransPrior( int ordering, PriorDesc *prior )
+{
+ /* Walk the list of all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Walk the out list of the state. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 )
+ trans->priorTable.setPrior( ordering, prior );
+ }
+ }
+}
+
+/* Set the priority of all transitions that go into a final state. Note that if
+ * any entry states are final, we will not be setting the priority of any
+ * transitions that may go into those states in the future. The graph does not
+ * support pending in transitions in the same way pending out transitions are
+ * supported. */
+void FsmAp::finishFsmPrior( int ordering, PriorDesc *prior )
+{
+ /* Walk all final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) {
+ /* Walk all in transitions of the final state. */
+ for ( TransInList::Iter trans = (*state)->inList; trans.lte(); trans++ )
+ trans->priorTable.setPrior( ordering, prior );
+ }
+}
+
+/* Set the priority of any future out transitions that may be made going out of
+ * this state machine. */
+void FsmAp::leaveFsmPrior( int ordering, PriorDesc *prior )
+{
+ /* Set priority in all final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->outPriorTable.setPrior( ordering, prior );
+}
+
+
+/* Set actions to execute on starting transitions. Isolates the start state
+ * so it has no other entry points, then adds to the transition functions
+ * of all the transitions out of the start state. If the start state is final,
+ * then the func is also added to the start state's out func list. The idea is
+ * that a machine that accepts the null string can execute a start func when it
+ * matches the null word, which can only be done when leaving the start/final
+ * state. */
+void FsmAp::startFsmAction( int ordering, Action *action )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+
+ /* Walk the start state's transitions, setting functions. */
+ for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 )
+ trans->actionTable.setAction( ordering, action );
+ }
+
+ /* If start state is final then add the action to the out action table.
+ * This means that when the null string is accepted the start action will
+ * not be bypassed. */
+ if ( startState->stateBits & STB_ISFINAL )
+ startState->outActionTable.setAction( ordering, action );
+}
+
+/* Set functions to execute on all transitions. Walks the out lists of all
+ * states. */
+void FsmAp::allTransAction( int ordering, Action *action )
+{
+ /* Walk all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Walk the out list of the state. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 )
+ trans->actionTable.setAction( ordering, action );
+ }
+ }
+}
+
+/* Specify functions to execute upon entering final states. If the start state
+ * is final we can't really specify a function to execute upon entering that
+ * final state the first time. So function really means whenever entering a
+ * final state from within the same fsm. */
+void FsmAp::finishFsmAction( int ordering, Action *action )
+{
+ /* Walk all final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) {
+ /* Walk the final state's in list. */
+ for ( TransInList::Iter trans = (*state)->inList; trans.lte(); trans++ )
+ trans->actionTable.setAction( ordering, action );
+ }
+}
+
+/* Add functions to any future out transitions that may be made going out of
+ * this state machine. */
+void FsmAp::leaveFsmAction( int ordering, Action *action )
+{
+ /* Insert the action in the outActionTable of all final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->outActionTable.setAction( ordering, action );
+}
+
+/* Add functions to the longest match action table for constructing scanners. */
+void FsmAp::longMatchAction( int ordering, LongestMatchPart *lmPart )
+{
+ /* Walk all final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) {
+ /* Walk the final state's in list. */
+ for ( TransInList::Iter trans = (*state)->inList; trans.lte(); trans++ )
+ trans->lmActionTable.setAction( ordering, lmPart );
+ }
+}
+
+void FsmAp::fillGaps( StateAp *state )
+{
+ if ( state->outList.length() == 0 ) {
+ /* Add the range on the lower and upper bound. */
+ attachNewTrans( state, 0, keyOps->minKey, keyOps->maxKey );
+ }
+ else {
+ TransList srcList;
+ srcList.transfer( state->outList );
+
+ /* Check for a gap at the beginning. */
+ TransList::Iter trans = srcList, next;
+ if ( keyOps->minKey < trans->lowKey ) {
+ /* Make the high key and append. */
+ Key highKey = trans->lowKey;
+ highKey.decrement();
+
+ attachNewTrans( state, 0, keyOps->minKey, highKey );
+ }
+
+ /* Write the transition. */
+ next = trans.next();
+ state->outList.append( trans );
+
+ /* Keep the last high end. */
+ Key lastHigh = trans->highKey;
+
+ /* Loop each source range. */
+ for ( trans = next; trans.lte(); trans = next ) {
+ /* Make the next key following the last range. */
+ Key nextKey = lastHigh;
+ nextKey.increment();
+
+ /* Check for a gap from last up to here. */
+ if ( nextKey < trans->lowKey ) {
+ /* Make the high end of the range that fills the gap. */
+ Key highKey = trans->lowKey;
+ highKey.decrement();
+
+ attachNewTrans( state, 0, nextKey, highKey );
+ }
+
+ /* Reduce the transition. If it reduced to anything then add it. */
+ next = trans.next();
+ state->outList.append( trans );
+
+ /* Keep the last high end. */
+ lastHigh = trans->highKey;
+ }
+
+ /* Now check for a gap on the end to fill. */
+ if ( lastHigh < keyOps->maxKey ) {
+ /* Get a copy of the default. */
+ lastHigh.increment();
+
+ attachNewTrans( state, 0, lastHigh, keyOps->maxKey );
+ }
+ }
+}
+
+void FsmAp::setErrorActions( StateAp *state, const ActionTable &other )
+{
+ /* Fill any gaps in the out list with an error transition. */
+ fillGaps( state );
+
+ /* Set error transitions in the transitions that go to error. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState == 0 )
+ trans->actionTable.setActions( other );
+ }
+}
+
+void FsmAp::setErrorAction( StateAp *state, int ordering, Action *action )
+{
+ /* Fill any gaps in the out list with an error transition. */
+ fillGaps( state );
+
+ /* Set error transitions in the transitions that go to error. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState == 0 )
+ trans->actionTable.setAction( ordering, action );
+ }
+}
+
+
+/* Give a target state for error transitions. */
+void FsmAp::setErrorTarget( StateAp *state, StateAp *target, int *orderings,
+ Action **actions, int nActs )
+{
+ /* Fill any gaps in the out list with an error transition. */
+ fillGaps( state );
+
+ /* Set error target in the transitions that go to error. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState == 0 ) {
+ /* The trans goes to error, redirect it. */
+ redirectErrorTrans( trans->fromState, target, trans );
+ trans->actionTable.setActions( orderings, actions, nActs );
+ }
+ }
+}
+
+void FsmAp::transferOutActions( StateAp *state )
+{
+ for ( ActionTable::Iter act = state->outActionTable; act.lte(); act++ )
+ state->eofActionTable.setAction( act->key, act->value );
+ state->outActionTable.empty();
+}
+
+void FsmAp::transferErrorActions( StateAp *state, int transferPoint )
+{
+ for ( int i = 0; i < state->errActionTable.length(); ) {
+ ErrActionTableEl *act = state->errActionTable.data + i;
+ if ( act->transferPoint == transferPoint ) {
+ /* Transfer the error action and remove it. */
+ setErrorAction( state, act->ordering, act->action );
+ if ( ! state->isFinState() )
+ state->eofActionTable.setAction( act->ordering, act->action );
+ state->errActionTable.vremove( i );
+ }
+ else {
+ /* Not transfering and deleting, skip over the item. */
+ i += 1;
+ }
+ }
+}
+
+/* Set error actions in the start state. */
+void FsmAp::startErrorAction( int ordering, Action *action, int transferPoint )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+
+ /* Add the actions. */
+ startState->errActionTable.setAction( ordering, action, transferPoint );
+}
+
+/* Set error actions in all states where there is a transition out. */
+void FsmAp::allErrorAction( int ordering, Action *action, int transferPoint )
+{
+ /* Insert actions in the error action table of all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ state->errActionTable.setAction( ordering, action, transferPoint );
+}
+
+/* Set error actions in final states. */
+void FsmAp::finalErrorAction( int ordering, Action *action, int transferPoint )
+{
+ /* Add the action to the error table of final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->errActionTable.setAction( ordering, action, transferPoint );
+}
+
+void FsmAp::notStartErrorAction( int ordering, Action *action, int transferPoint )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState )
+ state->errActionTable.setAction( ordering, action, transferPoint );
+ }
+}
+
+void FsmAp::notFinalErrorAction( int ordering, Action *action, int transferPoint )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( ! state->isFinState() )
+ state->errActionTable.setAction( ordering, action, transferPoint );
+ }
+}
+
+/* Set error actions in the states that have transitions into a final state. */
+void FsmAp::middleErrorAction( int ordering, Action *action, int transferPoint )
+{
+ /* Isolate the start state in case it is reachable from in inside the
+ * machine, in which case we don't want it set. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState && ! state->isFinState() )
+ state->errActionTable.setAction( ordering, action, transferPoint );
+ }
+}
+
+/* Set EOF actions in the start state. */
+void FsmAp::startEOFAction( int ordering, Action *action )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+
+ /* Add the actions. */
+ startState->eofActionTable.setAction( ordering, action );
+}
+
+/* Set EOF actions in all states where there is a transition out. */
+void FsmAp::allEOFAction( int ordering, Action *action )
+{
+ /* Insert actions in the EOF action table of all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ state->eofActionTable.setAction( ordering, action );
+}
+
+/* Set EOF actions in final states. */
+void FsmAp::finalEOFAction( int ordering, Action *action )
+{
+ /* Add the action to the error table of final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->eofActionTable.setAction( ordering, action );
+}
+
+void FsmAp::notStartEOFAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState )
+ state->eofActionTable.setAction( ordering, action );
+ }
+}
+
+void FsmAp::notFinalEOFAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( ! state->isFinState() )
+ state->eofActionTable.setAction( ordering, action );
+ }
+}
+
+/* Set EOF actions in the states that have transitions into a final state. */
+void FsmAp::middleEOFAction( int ordering, Action *action )
+{
+ /* Set the actions in all states that are not the start state and not final. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState && ! state->isFinState() )
+ state->eofActionTable.setAction( ordering, action );
+ }
+}
+
+/*
+ * Set To State Actions.
+ */
+
+/* Set to state actions in the start state. */
+void FsmAp::startToStateAction( int ordering, Action *action )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+ startState->toStateActionTable.setAction( ordering, action );
+}
+
+/* Set to state actions in all states. */
+void FsmAp::allToStateAction( int ordering, Action *action )
+{
+ /* Insert the action on all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ state->toStateActionTable.setAction( ordering, action );
+}
+
+/* Set to state actions in final states. */
+void FsmAp::finalToStateAction( int ordering, Action *action )
+{
+ /* Add the action to the error table of final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->toStateActionTable.setAction( ordering, action );
+}
+
+void FsmAp::notStartToStateAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState )
+ state->toStateActionTable.setAction( ordering, action );
+ }
+}
+
+void FsmAp::notFinalToStateAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( ! state->isFinState() )
+ state->toStateActionTable.setAction( ordering, action );
+ }
+}
+
+/* Set to state actions in states that are not final and not the start state. */
+void FsmAp::middleToStateAction( int ordering, Action *action )
+{
+ /* Set the action in all states that are not the start state and not final. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState && ! state->isFinState() )
+ state->toStateActionTable.setAction( ordering, action );
+ }
+}
+
+/*
+ * Set From State Actions.
+ */
+
+void FsmAp::startFromStateAction( int ordering, Action *action )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+ startState->fromStateActionTable.setAction( ordering, action );
+}
+
+void FsmAp::allFromStateAction( int ordering, Action *action )
+{
+ /* Insert the action on all states. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ state->fromStateActionTable.setAction( ordering, action );
+}
+
+void FsmAp::finalFromStateAction( int ordering, Action *action )
+{
+ /* Add the action to the error table of final states. */
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->fromStateActionTable.setAction( ordering, action );
+}
+
+void FsmAp::notStartFromStateAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState )
+ state->fromStateActionTable.setAction( ordering, action );
+ }
+}
+
+void FsmAp::notFinalFromStateAction( int ordering, Action *action )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( ! state->isFinState() )
+ state->fromStateActionTable.setAction( ordering, action );
+ }
+}
+
+void FsmAp::middleFromStateAction( int ordering, Action *action )
+{
+ /* Set the action in all states that are not the start state and not final. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ if ( state != startState && ! state->isFinState() )
+ state->fromStateActionTable.setAction( ordering, action );
+ }
+}
+
+/* Shift the function ordering of the start transitions to start
+ * at fromOrder and increase in units of 1. Useful before staring.
+ * Returns the maximum number of order numbers used. */
+int FsmAp::shiftStartActionOrder( int fromOrder )
+{
+ int maxUsed = 0;
+
+ /* Walk the start state's transitions, shifting function ordering. */
+ for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) {
+ /* Walk the function data for the transition and set the keys to
+ * increasing values starting at fromOrder. */
+ int curFromOrder = fromOrder;
+ ActionTable::Iter action = trans->actionTable;
+ for ( ; action.lte(); action++ )
+ action->key = curFromOrder++;
+
+ /* Keep track of the max number of orders used. */
+ if ( curFromOrder - fromOrder > maxUsed )
+ maxUsed = curFromOrder - fromOrder;
+ }
+
+ return maxUsed;
+}
+
+/* Remove all priorities. */
+void FsmAp::clearAllPriorities()
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Clear out priority data. */
+ state->outPriorTable.empty();
+
+ /* Clear transition data from the out transitions. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
+ trans->priorTable.empty();
+ }
+}
+
+/* Zeros out the function ordering keys. This may be called before minimization
+ * when it is known that no more fsm operations are going to be done. This
+ * will achieve greater reduction as states will not be separated on the basis
+ * of function ordering. */
+void FsmAp::nullActionKeys( )
+{
+ /* For each state... */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Walk the transitions for the state. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ /* Walk the action table for the transition. */
+ for ( ActionTable::Iter action = trans->actionTable;
+ action.lte(); action++ )
+ action->key = 0;
+
+ /* Walk the action table for the transition. */
+ for ( LmActionTable::Iter action = trans->lmActionTable;
+ action.lte(); action++ )
+ action->key = 0;
+ }
+
+ /* Null the action keys of the to state action table. */
+ for ( ActionTable::Iter action = state->toStateActionTable;
+ action.lte(); action++ )
+ action->key = 0;
+
+ /* Null the action keys of the from state action table. */
+ for ( ActionTable::Iter action = state->fromStateActionTable;
+ action.lte(); action++ )
+ action->key = 0;
+
+ /* Null the action keys of the out transtions. */
+ for ( ActionTable::Iter action = state->outActionTable;
+ action.lte(); action++ )
+ action->key = 0;
+
+ /* Null the action keys of the error action table. */
+ for ( ErrActionTable::Iter action = state->errActionTable;
+ action.lte(); action++ )
+ action->ordering = 0;
+
+ /* Null the action keys eof action table. */
+ for ( ActionTable::Iter action = state->eofActionTable;
+ action.lte(); action++ )
+ action->key = 0;
+ }
+}
+
+/* Walk the list of states and verify that non final states do not have out
+ * data, that all stateBits are cleared, and that there are no states with
+ * zero foreign in transitions. */
+void FsmAp::verifyStates()
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Non final states should not have leaving data. */
+ if ( ! (state->stateBits & STB_ISFINAL) ) {
+ assert( state->outActionTable.length() == 0 );
+ assert( state->outCondSet.length() == 0 );
+ assert( state->outPriorTable.length() == 0 );
+ }
+
+ /* Data used in algorithms should be cleared. */
+ assert( (state->stateBits & STB_BOTH) == 0 );
+ assert( state->foreignInTrans > 0 );
+ }
+}
+
+/* Compare two transitions according to their relative priority. Since the
+ * base transition has no priority associated with it, the default is to
+ * return equal. */
+int FsmAp::comparePrior( const PriorTable &priorTable1, const PriorTable &priorTable2 )
+{
+ /* Looking for differing priorities on same keys. Need to concurrently
+ * scan the priority lists. */
+ PriorTable::Iter pd1 = priorTable1;
+ PriorTable::Iter pd2 = priorTable2;
+ while ( pd1.lte() && pd2.lte() ) {
+ /* Check keys. */
+ if ( pd1->desc->key < pd2->desc->key )
+ pd1.increment();
+ else if ( pd1->desc->key > pd2->desc->key )
+ pd2.increment();
+ /* Keys are the same, check priorities. */
+ else if ( pd1->desc->priority < pd2->desc->priority )
+ return -1;
+ else if ( pd1->desc->priority > pd2->desc->priority )
+ return 1;
+ else {
+ /* Keys and priorities are equal, advance both. */
+ pd1.increment();
+ pd2.increment();
+ }
+ }
+
+ /* No differing priorities on the same key. */
+ return 0;
+}
+
+/* Compares two transitions according to priority and functions. Pointers
+ * should not be null. Does not consider to state or from state. Compare two
+ * transitions according to the data contained in the transitions. Data means
+ * any properties added to user transitions that may differentiate them. Since
+ * the base transition has no data, the default is to return equal. */
+int FsmAp::compareTransData( TransAp *trans1, TransAp *trans2 )
+{
+ /* Compare the prior table. */
+ int cmpRes = CmpPriorTable::compare( trans1->priorTable,
+ trans2->priorTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Compare longest match action tables. */
+ cmpRes = CmpLmActionTable::compare(trans1->lmActionTable,
+ trans2->lmActionTable);
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Compare action tables. */
+ return CmpActionTable::compare(trans1->actionTable,
+ trans2->actionTable);
+}
+
+/* Callback invoked when another trans (or possibly this) is added into this
+ * transition during the merging process. Draw in any properties of srcTrans
+ * into this transition. AddInTrans is called when a new transitions is made
+ * that will be a duplicate of another transition or a combination of several
+ * other transitions. AddInTrans will be called for each transition that the
+ * new transition is to represent. */
+void FsmAp::addInTrans( TransAp *destTrans, TransAp *srcTrans )
+{
+ /* Protect against adding in from ourselves. */
+ if ( srcTrans == destTrans ) {
+ /* Adding in ourselves, need to make a copy of the source transitions.
+ * The priorities are not copied in as that would have no effect. */
+ destTrans->lmActionTable.setActions( LmActionTable(srcTrans->lmActionTable) );
+ destTrans->actionTable.setActions( ActionTable(srcTrans->actionTable) );
+ }
+ else {
+ /* Not a copy of ourself, get the functions and priorities. */
+ destTrans->lmActionTable.setActions( srcTrans->lmActionTable );
+ destTrans->actionTable.setActions( srcTrans->actionTable );
+ destTrans->priorTable.setPriors( srcTrans->priorTable );
+ }
+}
+
+/* Compare the properties of states that are embedded by users. Compares out
+ * priorities, out transitions, to, from, out, error and eof action tables. */
+int FsmAp::compareStateData( const StateAp *state1, const StateAp *state2 )
+{
+ /* Compare the out priority table. */
+ int cmpRes = CmpPriorTable::
+ compare( state1->outPriorTable, state2->outPriorTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test to state action tables. */
+ cmpRes = CmpActionTable::compare( state1->toStateActionTable,
+ state2->toStateActionTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test from state action tables. */
+ cmpRes = CmpActionTable::compare( state1->fromStateActionTable,
+ state2->fromStateActionTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test out action tables. */
+ cmpRes = CmpActionTable::compare( state1->outActionTable,
+ state2->outActionTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test out condition sets. */
+ cmpRes = CmpOutCondSet::compare( state1->outCondSet,
+ state2->outCondSet );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test out error action tables. */
+ cmpRes = CmpErrActionTable::compare( state1->errActionTable,
+ state2->errActionTable );
+ if ( cmpRes != 0 )
+ return cmpRes;
+
+ /* Test eof action tables. */
+ return CmpActionTable::compare( state1->eofActionTable,
+ state2->eofActionTable );
+}
+
+
+/* Invoked when a state looses its final state status and the leaving
+ * transition embedding data should be deleted. */
+void FsmAp::clearOutData( StateAp *state )
+{
+ /* Kill the out actions and priorities. */
+ state->outActionTable.empty();
+ state->outCondSet.empty();
+ state->outPriorTable.empty();
+}
+
+bool FsmAp::hasOutData( StateAp *state )
+{
+ return ( state->outActionTable.length() > 0 ||
+ state->outCondSet.length() > 0 ||
+ state->outPriorTable.length() > 0 );
+}
+
+/*
+ * Setting Conditions.
+ */
+
+void logNewExpansion( Expansion *exp );
+void logCondSpace( CondSpace *condSpace );
+
+CondSpace *FsmAp::addCondSpace( const CondSet &condSet )
+{
+ CondSpace *condSpace = condData->condSpaceMap.find( condSet );
+ if ( condSpace == 0 ) {
+ /* Do we have enough keyspace left? */
+ Size availableSpace = condData->lastCondKey.availableSpace();
+ Size neededSpace = (1 << condSet.length() ) * keyOps->alphSize();
+ if ( neededSpace > availableSpace )
+ throw FsmConstructFail( FsmConstructFail::CondNoKeySpace );
+
+ Key baseKey = condData->lastCondKey;
+ baseKey.increment();
+ condData->lastCondKey += (1 << condSet.length() ) * keyOps->alphSize();
+
+ condSpace = new CondSpace( condSet );
+ condSpace->baseKey = baseKey;
+ condData->condSpaceMap.insert( condSpace );
+
+ #ifdef LOG_CONDS
+ cerr << "adding new condition space" << endl;
+ cerr << " condition set: ";
+ logCondSpace( condSpace );
+ cerr << endl;
+ cerr << " baseKey: " << baseKey.getVal() << endl;
+ #endif
+ }
+ return condSpace;
+}
+
+void FsmAp::startFsmCondition( Action *condAction, bool sense )
+{
+ /* Make sure the start state has no other entry points. */
+ isolateStartState();
+ embedCondition( startState, condAction, sense );
+}
+
+void FsmAp::allTransCondition( Action *condAction, bool sense )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ embedCondition( state, condAction, sense );
+}
+
+void FsmAp::leaveFsmCondition( Action *condAction, bool sense )
+{
+ for ( StateSet::Iter state = finStateSet; state.lte(); state++ )
+ (*state)->outCondSet.insert( OutCond( condAction, sense ) );
+}
diff --git a/ragel/fsmattach.cpp b/ragel/fsmattach.cpp
new file mode 100644
index 0000000..b0911f3
--- /dev/null
+++ b/ragel/fsmattach.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2001 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 <string.h>
+#include <assert.h>
+#include "fsmgraph.h"
+
+#include <iostream>
+using namespace std;
+
+/* Insert a transition into an inlist. The head must be supplied. */
+void FsmAp::attachToInList( StateAp *from, StateAp *to,
+ TransAp *&head, TransAp *trans )
+{
+ trans->ilnext = head;
+ trans->ilprev = 0;
+
+ /* If in trans list is not empty, set the head->prev to trans. */
+ if ( head != 0 )
+ head->ilprev = trans;
+
+ /* Now insert ourselves at the front of the list. */
+ head = trans;
+
+ /* Keep track of foreign transitions for from and to. */
+ if ( from != to ) {
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions is about to go up to 1 then
+ * move it from the misfit list to the main list. */
+ if ( to->foreignInTrans == 0 )
+ stateList.append( misfitList.detach( to ) );
+ }
+
+ to->foreignInTrans += 1;
+ }
+};
+
+/* Detach a transition from an inlist. The head of the inlist must be supplied. */
+void FsmAp::detachFromInList( StateAp *from, StateAp *to,
+ TransAp *&head, TransAp *trans )
+{
+ /* Detach in the inTransList. */
+ if ( trans->ilprev == 0 )
+ head = trans->ilnext;
+ else
+ trans->ilprev->ilnext = trans->ilnext;
+
+ if ( trans->ilnext != 0 )
+ trans->ilnext->ilprev = trans->ilprev;
+
+ /* Keep track of foreign transitions for from and to. */
+ if ( from != to ) {
+ to->foreignInTrans -= 1;
+
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions goes down to 0 then move it
+ * from the main list to the misfit list. */
+ if ( to->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( to ) );
+ }
+ }
+}
+
+/* Attach states on the default transition, range list or on out/in list key.
+ * First makes a new transition. If there is already a transition out from
+ * fromState on the default, then will assertion fail. */
+TransAp *FsmAp::attachNewTrans( StateAp *from, StateAp *to, Key lowKey, Key highKey )
+{
+ /* Make the new transition. */
+ TransAp *retVal = new TransAp();
+
+ /* The transition is now attached. Remember the parties involved. */
+ retVal->fromState = from;
+ retVal->toState = to;
+
+ /* Make the entry in the out list for the transitions. */
+ from->outList.append( retVal );
+
+ /* Set the the keys of the new trans. */
+ retVal->lowKey = lowKey;
+ retVal->highKey = highKey;
+
+ /* Attach using inList as the head pointer. */
+ if ( to != 0 )
+ attachToInList( from, to, to->inList.head, retVal );
+
+ return retVal;
+}
+
+/* Attach for range lists or for the default transition. This attach should
+ * be used when a transition already is allocated and must be attached to a
+ * target state. Does not handle adding the transition into the out list. */
+void FsmAp::attachTrans( StateAp *from, StateAp *to, TransAp *trans )
+{
+ assert( trans->fromState == 0 && trans->toState == 0 );
+ trans->fromState = from;
+ trans->toState = to;
+
+ if ( to != 0 ) {
+ /* Attach using the inList pointer as the head pointer. */
+ attachToInList( from, to, to->inList.head, trans );
+ }
+}
+
+/* Redirect a transition away from error and towards some state. This is just
+ * like attachTrans except it requires fromState to be set and does not touch
+ * it. */
+void FsmAp::redirectErrorTrans( StateAp *from, StateAp *to, TransAp *trans )
+{
+ assert( trans->fromState != 0 && trans->toState == 0 );
+ trans->toState = to;
+
+ if ( to != 0 ) {
+ /* Attach using the inList pointer as the head pointer. */
+ attachToInList( from, to, to->inList.head, trans );
+ }
+}
+
+/* Detach for out/in lists or for default transition. */
+void FsmAp::detachTrans( StateAp *from, StateAp *to, TransAp *trans )
+{
+ assert( trans->fromState == from && trans->toState == to );
+ trans->fromState = 0;
+ trans->toState = 0;
+
+ if ( to != 0 ) {
+ /* Detach using to's inList pointer as the head. */
+ detachFromInList( from, to, to->inList.head, trans );
+ }
+}
+
+
+/* Detach a state from the graph. Detaches and deletes transitions in and out
+ * of the state. Empties inList and outList. Removes the state from the final
+ * state set. A detached state becomes useless and should be deleted. */
+void FsmAp::detachState( StateAp *state )
+{
+ /* Detach the in transitions from the inList list of transitions. */
+ while ( state->inList.head != 0 ) {
+ /* Get pointers to the trans and the state. */
+ TransAp *trans = state->inList.head;
+ StateAp *fromState = trans->fromState;
+
+ /* Detach the transitions from the source state. */
+ detachTrans( fromState, state, trans );
+
+ /* Ok to delete the transition. */
+ fromState->outList.detach( trans );
+ delete trans;
+ }
+
+ /* Remove the entry points in on the machine. */
+ while ( state->entryIds.length() > 0 )
+ unsetEntry( state->entryIds[0], state );
+
+ /* Detach out range transitions. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); ) {
+ TransList::Iter next = trans.next();
+ detachTrans( state, trans->toState, trans );
+ delete trans;
+ trans = next;
+ }
+
+ /* Delete all of the out range pointers. */
+ state->outList.abandon();
+
+ /* Unset final stateness before detaching from graph. */
+ if ( state->stateBits & STB_ISFINAL )
+ finStateSet.remove( state );
+}
+
+
+/* Duplicate a transition. Makes a new transition that is attached to the same
+ * dest as srcTrans. The new transition has functions and priority taken from
+ * srcTrans. Used for merging a transition in to a free spot. The trans can
+ * just be dropped in. It does not conflict with an existing trans and need
+ * not be crossed. Returns the new transition. */
+TransAp *FsmAp::dupTrans( StateAp *from, TransAp *srcTrans )
+{
+ /* Make a new transition. */
+ TransAp *newTrans = new TransAp();
+
+ /* We can attach the transition, one does not exist. */
+ attachTrans( from, srcTrans->toState, newTrans );
+
+ /* Call the user callback to add in the original source transition. */
+ addInTrans( newTrans, srcTrans );
+
+ return newTrans;
+}
+
+/* In crossing, src trans and dest trans both go to existing states. Make one
+ * state from the sets of states that src and dest trans go to. */
+TransAp *FsmAp::fsmAttachStates( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans )
+{
+ /* The priorities are equal. We must merge the transitions. Does the
+ * existing trans go to the state we are to attach to? ie, are we to
+ * simply double up the transition? */
+ StateAp *toState = srcTrans->toState;
+ StateAp *existingState = destTrans->toState;
+
+ if ( existingState == toState ) {
+ /* The transition is a double up to the same state. Copy the src
+ * trans into itself. We don't need to merge in the from out trans
+ * data, that was done already. */
+ addInTrans( destTrans, srcTrans );
+ }
+ else {
+ /* The trans is not a double up. Dest trans cannot be the same as src
+ * trans. Set up the state set. */
+ StateSet stateSet;
+
+ /* We go to all the states the existing trans goes to, plus... */
+ if ( existingState->stateDictEl == 0 )
+ stateSet.insert( existingState );
+ else
+ stateSet.insert( existingState->stateDictEl->stateSet );
+
+ /* ... all the states that we have been told to go to. */
+ if ( toState->stateDictEl == 0 )
+ stateSet.insert( toState );
+ else
+ stateSet.insert( toState->stateDictEl->stateSet );
+
+ /* Look for the state. If it is not there already, make it. */
+ StateDictEl *lastFound;
+ if ( md.stateDict.insert( stateSet, &lastFound ) ) {
+ /* Make a new state representing the combination of states in
+ * stateSet. It gets added to the fill list. This means that we
+ * need to fill in it's transitions sometime in the future. We
+ * don't do that now (ie, do not recurse). */
+ StateAp *combinState = addState();
+
+ /* Link up the dict element and the state. */
+ lastFound->targState = combinState;
+ combinState->stateDictEl = lastFound;
+
+ /* Add to the fill list. */
+ md.fillListAppend( combinState );
+ }
+
+ /* Get the state insertted/deleted. */
+ StateAp *targ = lastFound->targState;
+
+ /* Detach the state from existing state. */
+ detachTrans( from, existingState, destTrans );
+
+ /* Re-attach to the new target. */
+ attachTrans( from, targ, destTrans );
+
+ /* Add in src trans to the existing transition that we redirected to
+ * the new state. We don't need to merge in the from out trans data,
+ * that was done already. */
+ addInTrans( destTrans, srcTrans );
+ }
+
+ return destTrans;
+}
+
+/* Two transitions are to be crossed, handle the possibility of either going
+ * to the error state. */
+TransAp *FsmAp::mergeTrans( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans )
+{
+ TransAp *retTrans = 0;
+ if ( destTrans->toState == 0 && srcTrans->toState == 0 ) {
+ /* Error added into error. */
+ addInTrans( destTrans, srcTrans );
+ retTrans = destTrans;
+ }
+ else if ( destTrans->toState == 0 && srcTrans->toState != 0 ) {
+ /* Non error added into error we need to detach and reattach, */
+ detachTrans( from, destTrans->toState, destTrans );
+ attachTrans( from, srcTrans->toState, destTrans );
+ addInTrans( destTrans, srcTrans );
+ retTrans = destTrans;
+ }
+ else if ( srcTrans->toState == 0 ) {
+ /* Dest goes somewhere but src doesn't, just add it it in. */
+ addInTrans( destTrans, srcTrans );
+ retTrans = destTrans;
+ }
+ else {
+ /* Both go somewhere, run the actual cross. */
+ retTrans = fsmAttachStates( md, from, destTrans, srcTrans );
+ }
+
+ return retTrans;
+}
+
+/* Find the trans with the higher priority. If src is lower priority then dest then
+ * src is ignored. If src is higher priority than dest, then src overwrites dest. If
+ * the priorities are equal, then they are merged. */
+TransAp *FsmAp::crossTransitions( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans )
+{
+ TransAp *retTrans;
+
+ /* Compare the priority of the dest and src transitions. */
+ int compareRes = comparePrior( destTrans->priorTable, srcTrans->priorTable );
+ if ( compareRes < 0 ) {
+ /* Src trans has a higher priority than dest, src overwrites dest.
+ * Detach dest and return a copy of src. */
+ detachTrans( from, destTrans->toState, destTrans );
+ retTrans = dupTrans( from, srcTrans );
+ }
+ else if ( compareRes > 0 ) {
+ /* The dest trans has a higher priority, use dest. */
+ retTrans = destTrans;
+ }
+ else {
+ /* Src trans and dest trans have the same priority, they must be merged. */
+ retTrans = mergeTrans( md, from, destTrans, srcTrans );
+ }
+
+ /* Return the transition that resulted from the cross. */
+ return retTrans;
+}
+
+/* Copy the transitions in srcList to the outlist of dest. The srcList should
+ * not be the outList of dest, otherwise you would be copying the contents of
+ * srcList into itself as it's iterated: bad news. */
+void FsmAp::outTransCopy( MergeData &md, StateAp *dest, TransAp *srcList )
+{
+ /* The destination list. */
+ TransList destList;
+
+ /* Set up an iterator to stop at breaks. */
+ PairIter<TransAp> outPair( dest->outList.head, srcList );
+ for ( ; !outPair.end(); outPair++ ) {
+ switch ( outPair.userState ) {
+ case RangeInS1: {
+ /* The pair iter is the authority on the keys. It may have needed
+ * to break the dest range. */
+ TransAp *destTrans = outPair.s1Tel.trans;
+ destTrans->lowKey = outPair.s1Tel.lowKey;
+ destTrans->highKey = outPair.s1Tel.highKey;
+ destList.append( destTrans );
+ break;
+ }
+ case RangeInS2: {
+ /* Src range may get crossed with dest's default transition. */
+ TransAp *newTrans = dupTrans( dest, outPair.s2Tel.trans );
+
+ /* Set up the transition's keys and append to the dest list. */
+ newTrans->lowKey = outPair.s2Tel.lowKey;
+ newTrans->highKey = outPair.s2Tel.highKey;
+ destList.append( newTrans );
+ break;
+ }
+ case RangeOverlap: {
+ /* Exact overlap, cross them. */
+ TransAp *newTrans = crossTransitions( md, dest,
+ outPair.s1Tel.trans, outPair.s2Tel.trans );
+
+ /* Set up the transition's keys and append to the dest list. */
+ newTrans->lowKey = outPair.s1Tel.lowKey;
+ newTrans->highKey = outPair.s1Tel.highKey;
+ destList.append( newTrans );
+ break;
+ }
+ case BreakS1: {
+ /* Since we are always writing to the dest trans, the dest needs
+ * to be copied when it is broken. The copy goes into the first
+ * half of the break to "break it off". */
+ outPair.s1Tel.trans = dupTrans( dest, outPair.s1Tel.trans );
+ break;
+ }
+ case BreakS2:
+ break;
+ }
+ }
+
+ /* Abandon the old outList and transfer destList into it. */
+ dest->outList.transfer( destList );
+}
+
+
+/* Move all the transitions that go into src so that they go into dest. */
+void FsmAp::inTransMove( StateAp *dest, StateAp *src )
+{
+ /* Do not try to move in trans to and from the same state. */
+ assert( dest != src );
+
+ /* If src is the start state, dest becomes the start state. */
+ if ( src == startState ) {
+ unsetStartState();
+ setStartState( dest );
+ }
+
+ /* For each entry point into, create an entry point into dest, when the
+ * state is detached, the entry points to src will be removed. */
+ for ( EntryIdSet::Iter enId = src->entryIds; enId.lte(); enId++ )
+ changeEntry( *enId, dest, src );
+
+ /* Move the transitions in inList. */
+ while ( src->inList.head != 0 ) {
+ /* Get trans and from state. */
+ TransAp *trans = src->inList.head;
+ StateAp *fromState = trans->fromState;
+
+ /* Detach from src, reattach to dest. */
+ detachTrans( fromState, src, trans );
+ attachTrans( fromState, dest, trans );
+ }
+}
diff --git a/ragel/fsmbase.cpp b/ragel/fsmbase.cpp
new file mode 100644
index 0000000..87c7f0e
--- /dev/null
+++ b/ragel/fsmbase.cpp
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2001-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 <string.h>
+#include <assert.h>
+#include "fsmgraph.h"
+
+/* Simple singly linked list append routine for the fill list. The new state
+ * goes to the end of the list. */
+void MergeData::fillListAppend( StateAp *state )
+{
+ state->alg.next = 0;
+
+ if ( stfillHead == 0 ) {
+ /* List is empty, state becomes head and tail. */
+ stfillHead = state;
+ stfillTail = state;
+ }
+ else {
+ /* List is not empty, state goes after last element. */
+ stfillTail->alg.next = state;
+ stfillTail = state;
+ }
+}
+
+/* Graph constructor. */
+FsmAp::FsmAp()
+:
+ /* No start state. */
+ startState(0),
+ errState(0),
+
+ /* Misfit accounting is a switch, turned on only at specific times. It
+ * controls what happens when states have no way in from the outside
+ * world.. */
+ misfitAccounting(false)
+{
+}
+
+/* Copy all graph data including transitions. */
+FsmAp::FsmAp( const FsmAp &graph )
+:
+ /* Lists start empty. Will be filled by copy. */
+ stateList(),
+ misfitList(),
+
+ /* Copy in the entry points,
+ * pointers will be resolved later. */
+ entryPoints(graph.entryPoints),
+ startState(graph.startState),
+ errState(0),
+
+ /* Will be filled by copy. */
+ finStateSet(),
+
+ /* Misfit accounting is only on during merging. */
+ misfitAccounting(false)
+{
+ /* Create the states and record their map in the original state. */
+ StateList::Iter origState = graph.stateList;
+ for ( ; origState.lte(); origState++ ) {
+ /* Make the new state. */
+ StateAp *newState = new StateAp( *origState );
+
+ /* Add the state to the list. */
+ stateList.append( newState );
+
+ /* Set the mapsTo item of the old state. */
+ origState->alg.stateMap = newState;
+ }
+
+ /* Derefernce all the state maps. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ /* The points to the original in the src machine. The taget's duplicate
+ * is in the statemap. */
+ StateAp *toState = trans->toState != 0 ? trans->toState->alg.stateMap : 0;
+
+ /* Attach The transition to the duplicate. */
+ trans->toState = 0;
+ attachTrans( state, toState, trans );
+ }
+
+ /* Fix the eofTarg, if set. */
+ if ( state->eofTarget != 0 )
+ state->eofTarget = state->eofTarget->alg.stateMap;
+ }
+
+ /* Fix the state pointers in the entry points array. */
+ EntryMapEl *eel = entryPoints.data;
+ for ( int e = 0; e < entryPoints.length(); e++, eel++ ) {
+ /* Get the duplicate of the state. */
+ eel->value = eel->value->alg.stateMap;
+
+ /* Foreign in transitions must be built up when duping machines so
+ * increment it here. */
+ eel->value->foreignInTrans += 1;
+ }
+
+ /* Fix the start state pointer and the new start state's count of in
+ * transiions. */
+ startState = startState->alg.stateMap;
+ startState->foreignInTrans += 1;
+
+ /* Build the final state set. */
+ StateSet::Iter st = graph.finStateSet;
+ for ( ; st.lte(); st++ )
+ finStateSet.insert((*st)->alg.stateMap);
+}
+
+/* Deletes all transition data then deletes each state. */
+FsmAp::~FsmAp()
+{
+ /* Delete all the transitions. */
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Iterate the out transitions, deleting them. */
+ state->outList.empty();
+ }
+
+ /* Delete all the states. */
+ stateList.empty();
+}
+
+/* Set a state final. The state has its isFinState set to true and the state
+ * is added to the finStateSet. */
+void FsmAp::setFinState( StateAp *state )
+{
+ /* Is it already a fin state. */
+ if ( state->stateBits & STB_ISFINAL )
+ return;
+
+ state->stateBits |= STB_ISFINAL;
+ finStateSet.insert( state );
+}
+
+/* Set a state non-final. The has its isFinState flag set false and the state
+ * is removed from the final state set. */
+void FsmAp::unsetFinState( StateAp *state )
+{
+ /* Is it already a non-final state? */
+ if ( ! (state->stateBits & STB_ISFINAL) )
+ return;
+
+ /* When a state looses its final state status it must relinquish all the
+ * properties that are allowed only for final states. */
+ clearOutData( state );
+
+ state->stateBits &= ~ STB_ISFINAL;
+ finStateSet.remove( state );
+}
+
+/* Set and unset a state as the start state. */
+void FsmAp::setStartState( StateAp *state )
+{
+ /* Sould change from unset to set. */
+ assert( startState == 0 );
+ startState = state;
+
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions is about to go up to 1 then
+ * take it off the misfit list and put it on the head list. */
+ if ( state->foreignInTrans == 0 )
+ stateList.append( misfitList.detach( state ) );
+ }
+
+ /* Up the foreign in transitions to the state. */
+ state->foreignInTrans += 1;
+}
+
+void FsmAp::unsetStartState()
+{
+ /* Should change from set to unset. */
+ assert( startState != 0 );
+
+ /* Decrement the entry's count of foreign entries. */
+ startState->foreignInTrans -= 1;
+
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions just went down to 0 then take
+ * it off the main list and put it on the misfit list. */
+ if ( startState->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( startState ) );
+ }
+
+ startState = 0;
+}
+
+/* Associate an id with a state. Makes the state a named entry point. Has no
+ * effect if the entry point is already mapped to the state. */
+void FsmAp::setEntry( int id, StateAp *state )
+{
+ /* Insert the id into the state. If the state is already labelled with id,
+ * nothing to do. */
+ if ( state->entryIds.insert( id ) ) {
+ /* Insert the entry and assert that it succeeds. */
+ entryPoints.insertMulti( id, state );
+
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions is about to go up to 1 then
+ * take it off the misfit list and put it on the head list. */
+ if ( state->foreignInTrans == 0 )
+ stateList.append( misfitList.detach( state ) );
+ }
+
+ /* Up the foreign in transitions to the state. */
+ state->foreignInTrans += 1;
+ }
+}
+
+/* Remove the association of an id with a state. The state looses it's entry
+ * point status. Assumes that the id is indeed mapped to state. */
+void FsmAp::unsetEntry( int id, StateAp *state )
+{
+ /* Find the entry point in on id. */
+ EntryMapEl *enLow = 0, *enHigh = 0;
+ entryPoints.findMulti( id, enLow, enHigh );
+ while ( enLow->value != state )
+ enLow += 1;
+
+ /* Remove the record from the map. */
+ entryPoints.remove( enLow );
+
+ /* Remove the state's sense of the link. */
+ state->entryIds.remove( id );
+ state->foreignInTrans -= 1;
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions just went down to 0 then take
+ * it off the main list and put it on the misfit list. */
+ if ( state->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( state ) );
+ }
+}
+
+/* Remove all association of an id with states. Assumes that the id is indeed
+ * mapped to a state. */
+void FsmAp::unsetEntry( int id )
+{
+ /* Find the entry point in on id. */
+ EntryMapEl *enLow = 0, *enHigh = 0;
+ entryPoints.findMulti( id, enLow, enHigh );
+ for ( EntryMapEl *mel = enLow; mel <= enHigh; mel++ ) {
+ /* Remove the state's sense of the link. */
+ mel->value->entryIds.remove( id );
+ mel->value->foreignInTrans -= 1;
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions just went down to 0
+ * then take it off the main list and put it on the misfit list. */
+ if ( mel->value->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( mel->value ) );
+ }
+ }
+
+ /* Remove the records from the entry points map. */
+ entryPoints.removeMulti( enLow, enHigh );
+}
+
+
+void FsmAp::changeEntry( int id, StateAp *to, StateAp *from )
+{
+ /* Find the entry in the entry map. */
+ EntryMapEl *enLow = 0, *enHigh = 0;
+ entryPoints.findMulti( id, enLow, enHigh );
+ while ( enLow->value != from )
+ enLow += 1;
+
+ /* Change it to the new target. */
+ enLow->value = to;
+
+ /* Remove from's sense of the link. */
+ from->entryIds.remove( id );
+ from->foreignInTrans -= 1;
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions just went down to 0 then take
+ * it off the main list and put it on the misfit list. */
+ if ( from->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( from ) );
+ }
+
+ /* Add to's sense of the link. */
+ if ( to->entryIds.insert( id ) != 0 ) {
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions is about to go up to 1 then
+ * take it off the misfit list and put it on the head list. */
+ if ( to->foreignInTrans == 0 )
+ stateList.append( misfitList.detach( to ) );
+ }
+
+ /* Up the foreign in transitions to the state. */
+ to->foreignInTrans += 1;
+ }
+}
+
+
+/* Clear all entry points from a machine. */
+void FsmAp::unsetAllEntryPoints()
+{
+ for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) {
+ /* Kill all the state's entry points at once. */
+ if ( en->value->entryIds.length() > 0 ) {
+ en->value->foreignInTrans -= en->value->entryIds.length();
+
+ if ( misfitAccounting ) {
+ /* If the number of foreign in transitions just went down to 0
+ * then take it off the main list and put it on the misfit
+ * list. */
+ if ( en->value->foreignInTrans == 0 )
+ misfitList.append( stateList.detach( en->value ) );
+ }
+
+ /* Clear the set of ids out all at once. */
+ en->value->entryIds.empty();
+ }
+ }
+
+ /* Now clear out the entry map all at once. */
+ entryPoints.empty();
+}
+
+/* Assigning an epsilon transition into final states. */
+void FsmAp::epsilonTrans( int id )
+{
+ for ( StateSet::Iter fs = finStateSet; fs.lte(); fs++ )
+ (*fs)->epsilonTrans.append( id );
+}
+
+/* Mark all states reachable from state. Traverses transitions forward. Used
+ * for removing states that have no path into them. */
+void FsmAp::markReachableFromHere( StateAp *state )
+{
+ /* Base case: return; */
+ if ( state->stateBits & STB_ISMARKED )
+ return;
+
+ /* Set this state as processed. We are going to visit all states that this
+ * state has a transition to. */
+ state->stateBits |= STB_ISMARKED;
+
+ /* Recurse on all out transitions. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 )
+ markReachableFromHere( trans->toState );
+ }
+}
+
+void FsmAp::markReachableFromHereStopFinal( StateAp *state )
+{
+ /* Base case: return; */
+ if ( state->stateBits & STB_ISMARKED )
+ return;
+
+ /* Set this state as processed. We are going to visit all states that this
+ * state has a transition to. */
+ state->stateBits |= STB_ISMARKED;
+
+ /* Recurse on all out transitions. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ StateAp *toState = trans->toState;
+ if ( toState != 0 && !toState->isFinState() )
+ markReachableFromHereStopFinal( toState );
+ }
+}
+
+/* Mark all states reachable from state. Traverse transitions backwards. Used
+ * for removing dead end paths in graphs. */
+void FsmAp::markReachableFromHereReverse( StateAp *state )
+{
+ /* Base case: return; */
+ if ( state->stateBits & STB_ISMARKED )
+ return;
+
+ /* Set this state as processed. We are going to visit all states with
+ * transitions into this state. */
+ state->stateBits |= STB_ISMARKED;
+
+ /* Recurse on all items in transitions. */
+ for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ )
+ markReachableFromHereReverse( trans->fromState );
+}
+
+/* Determine if there are any entry points into a start state other than the
+ * start state. Setting starting transitions requires that the start state be
+ * isolated. In most cases a start state will already be isolated. */
+bool FsmAp::isStartStateIsolated()
+{
+ /* If there are any in transitions then the state is not isolated. */
+ if ( startState->inList.head != 0 )
+ return false;
+
+ /* If there are any entry points then isolated. */
+ if ( startState->entryIds.length() > 0 )
+ return false;
+
+ return true;
+}
+
+/* Bring in other's entry points. Assumes others states are going to be
+ * copied into this machine. */
+void FsmAp::copyInEntryPoints( FsmAp *other )
+{
+ /* Use insert multi because names are not unique. */
+ for ( EntryMap::Iter en = other->entryPoints; en.lte(); en++ )
+ entryPoints.insertMulti( en->key, en->value );
+}
+
+
+void FsmAp::unsetAllFinStates()
+{
+ for ( StateSet::Iter st = finStateSet; st.lte(); st++ )
+ (*st)->stateBits &= ~ STB_ISFINAL;
+ finStateSet.empty();
+}
+
+void FsmAp::setFinBits( int finStateBits )
+{
+ for ( int s = 0; s < finStateSet.length(); s++ )
+ finStateSet.data[s]->stateBits |= finStateBits;
+}
+
+
+/* Tests the integrity of the transition lists and the fromStates. */
+void FsmAp::verifyIntegrity()
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ ) {
+ /* Walk the out transitions and assert fromState is correct. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
+ assert( trans->fromState == state );
+
+ /* Walk the inlist and assert toState is correct. */
+ for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ )
+ assert( trans->toState == state );
+ }
+}
+
+void FsmAp::verifyReachability()
+{
+ /* Mark all the states that can be reached
+ * through the set of entry points. */
+ markReachableFromHere( startState );
+ for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
+ markReachableFromHere( en->value );
+
+ /* Check that everything got marked. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Assert it got marked and then clear the mark. */
+ assert( st->stateBits & STB_ISMARKED );
+ st->stateBits &= ~ STB_ISMARKED;
+ }
+}
+
+void FsmAp::verifyNoDeadEndStates()
+{
+ /* Mark all states that have paths to the final states. */
+ for ( StateSet::Iter pst = finStateSet; pst.lte(); pst++ )
+ markReachableFromHereReverse( *pst );
+
+ /* Start state gets honorary marking. Must be done AFTER recursive call. */
+ startState->stateBits |= STB_ISMARKED;
+
+ /* Make sure everything got marked. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Assert the state got marked and unmark it. */
+ assert( st->stateBits & STB_ISMARKED );
+ st->stateBits &= ~ STB_ISMARKED;
+ }
+}
+
+void FsmAp::depthFirstOrdering( StateAp *state )
+{
+ /* Nothing to do if the state is already on the list. */
+ if ( state->stateBits & STB_ONLIST )
+ return;
+
+ /* Doing depth first, put state on the list. */
+ state->stateBits |= STB_ONLIST;
+ stateList.append( state );
+
+ /* Recurse on everything ranges. */
+ for ( TransList::Iter tel = state->outList; tel.lte(); tel++ ) {
+ if ( tel->toState != 0 )
+ depthFirstOrdering( tel->toState );
+ }
+}
+
+/* Ordering states by transition connections. */
+void FsmAp::depthFirstOrdering()
+{
+ /* Init on state list flags. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ )
+ st->stateBits &= ~STB_ONLIST;
+
+ /* Clear out the state list, we will rebuild it. */
+ int stateListLen = stateList.length();
+ stateList.abandon();
+
+ /* Add back to the state list from the start state and all other entry
+ * points. */
+ if ( errState != 0 )
+ depthFirstOrdering( errState );
+ depthFirstOrdering( startState );
+ for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
+ depthFirstOrdering( en->value );
+
+ /* Make sure we put everything back on. */
+ assert( stateListLen == stateList.length() );
+}
+
+/* Stable sort the states by final state status. */
+void FsmAp::sortStatesByFinal()
+{
+ /* Move forward through the list and throw final states onto the end. */
+ StateAp *state = 0;
+ StateAp *next = stateList.head;
+ StateAp *last = stateList.tail;
+ while ( state != last ) {
+ /* Move forward and load up the next. */
+ state = next;
+ next = state->next;
+
+ /* Throw to the end? */
+ if ( state->isFinState() ) {
+ stateList.detach( state );
+ stateList.append( state );
+ }
+ }
+}
+
+void FsmAp::setStateNumbers( int base )
+{
+ for ( StateList::Iter state = stateList; state.lte(); state++ )
+ state->alg.stateNum = base++;
+}
+
+
+bool FsmAp::checkErrTrans( StateAp *state, TransAp *trans )
+{
+ /* Might go directly to error state. */
+ if ( trans->toState == 0 )
+ return true;
+
+ if ( trans->prev == 0 ) {
+ /* If this is the first transition. */
+ if ( keyOps->minKey < trans->lowKey )
+ return true;
+ }
+ else {
+ /* Not the first transition. Compare against the prev. */
+ TransAp *prev = trans->prev;
+ Key nextKey = prev->highKey;
+ nextKey.increment();
+ if ( nextKey < trans->lowKey )
+ return true;
+ }
+ return false;
+}
+
+bool FsmAp::checkErrTransFinish( StateAp *state )
+{
+ /* Check if there are any ranges already. */
+ if ( state->outList.length() == 0 )
+ return true;
+ else {
+ /* Get the last and check for a gap on the end. */
+ TransAp *last = state->outList.tail;
+ if ( last->highKey < keyOps->maxKey )
+ return true;
+ }
+ return 0;
+}
+
+bool FsmAp::hasErrorTrans()
+{
+ bool result;
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ for ( TransList::Iter tr = st->outList; tr.lte(); tr++ ) {
+ result = checkErrTrans( st, tr );
+ if ( result )
+ return true;
+ }
+ result = checkErrTransFinish( st );
+ if ( result )
+ return true;
+ }
+ return false;
+}
diff --git a/ragel/fsmgraph.cpp b/ragel/fsmgraph.cpp
new file mode 100644
index 0000000..fecc4a5
--- /dev/null
+++ b/ragel/fsmgraph.cpp
@@ -0,0 +1,1434 @@
+/*
+ * Copyright 2001, 2002, 2006 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 <assert.h>
+#include <iostream>
+
+#include "fsmgraph.h"
+#include "mergesort.h"
+#include "parsedata.h"
+
+using std::cerr;
+using std::endl;
+
+/* Make a new state. The new state will be put on the graph's
+ * list of state. The new state can be created final or non final. */
+StateAp *FsmAp::addState()
+{
+ /* Make the new state to return. */
+ StateAp *state = new StateAp();
+
+ if ( misfitAccounting ) {
+ /* Create the new state on the misfit list. All states are created
+ * with no foreign in transitions. */
+ misfitList.append( state );
+ }
+ else {
+ /* Create the new state. */
+ stateList.append( state );
+ }
+
+ return state;
+}
+
+/* Construct an FSM that is the concatenation of an array of characters. A new
+ * machine will be made that has len+1 states with one transition between each
+ * state for each integer in str. IsSigned determines if the integers are to
+ * be considered as signed or unsigned ints. */
+void FsmAp::concatFsm( Key *str, int len )
+{
+ /* Make the first state and set it as the start state. */
+ StateAp *last = addState();
+ setStartState( last );
+
+ /* Attach subsequent states. */
+ for ( int i = 0; i < len; i++ ) {
+ StateAp *newState = addState();
+ attachNewTrans( last, newState, str[i], str[i] );
+ last = newState;
+ }
+
+ /* Make the last state the final state. */
+ setFinState( last );
+}
+
+/* Case insensitive version of concatFsm. */
+void FsmAp::concatFsmCI( Key *str, int len )
+{
+ /* Make the first state and set it as the start state. */
+ StateAp *last = addState();
+ setStartState( last );
+
+ /* Attach subsequent states. */
+ for ( int i = 0; i < len; i++ ) {
+ StateAp *newState = addState();
+
+ KeySet keySet;
+ if ( str[i].isLower() )
+ keySet.insert( str[i].toUpper() );
+ if ( str[i].isUpper() )
+ keySet.insert( str[i].toLower() );
+ keySet.insert( str[i] );
+
+ for ( int i = 0; i < keySet.length(); i++ )
+ attachNewTrans( last, newState, keySet[i], keySet[i] );
+
+ last = newState;
+ }
+
+ /* Make the last state the final state. */
+ setFinState( last );
+}
+
+/* Construct a machine that matches one character. A new machine will be made
+ * that has two states with a single transition between the states. IsSigned
+ * determines if the integers are to be considered as signed or unsigned ints. */
+void FsmAp::concatFsm( Key chr )
+{
+ /* Two states first start, second final. */
+ setStartState( addState() );
+
+ StateAp *end = addState();
+ setFinState( end );
+
+ /* Attach on the character. */
+ attachNewTrans( startState, end, chr, chr );
+}
+
+/* Construct a machine that matches any character in set. A new machine will
+ * be made that has two states and len transitions between the them. The set
+ * should be ordered correctly accroding to KeyOps and should not contain
+ * any duplicates. */
+void FsmAp::orFsm( Key *set, int len )
+{
+ /* Two states first start, second final. */
+ setStartState( addState() );
+
+ StateAp *end = addState();
+ setFinState( end );
+
+ for ( int i = 1; i < len; i++ )
+ assert( set[i-1] < set[i] );
+
+ /* Attach on all the integers in the given string of ints. */
+ for ( int i = 0; i < len; i++ )
+ attachNewTrans( startState, end, set[i], set[i] );
+}
+
+/* Construct a machine that matches a range of characters. A new machine will
+ * be made with two states and a range transition between them. The range will
+ * match any characters from low to high inclusive. Low should be less than or
+ * equal to high otherwise undefined behaviour results. IsSigned determines
+ * if the integers are to be considered as signed or unsigned ints. */
+void FsmAp::rangeFsm( Key low, Key high )
+{
+ /* Two states first start, second final. */
+ setStartState( addState() );
+
+ StateAp *end = addState();
+ setFinState( end );
+
+ /* Attach using the range of characters. */
+ attachNewTrans( startState, end, low, high );
+}
+
+/* Construct a machine that a repeated range of characters. */
+void FsmAp::rangeStarFsm( Key low, Key high)
+{
+ /* One state which is final and is the start state. */
+ setStartState( addState() );
+ setFinState( startState );
+
+ /* Attach start to start using range of characters. */
+ attachNewTrans( startState, startState, low, high );
+}
+
+/* Construct a machine that matches the empty string. A new machine will be
+ * made with only one state. The new state will be both a start and final
+ * state. IsSigned determines if the machine has a signed or unsigned
+ * alphabet. Fsm operations must be done on machines with the same alphabet
+ * signedness. */
+void FsmAp::lambdaFsm( )
+{
+ /* Give it one state with no transitions making it
+ * the start state and final state. */
+ setStartState( addState() );
+ setFinState( startState );
+}
+
+/* Construct a machine that matches nothing at all. A new machine will be
+ * made with only one state. It will not be final. */
+void FsmAp::emptyFsm( )
+{
+ /* Give it one state with no transitions making it
+ * the start state and final state. */
+ setStartState( addState() );
+}
+
+void FsmAp::transferOutData( StateAp *destState, StateAp *srcState )
+{
+ for ( TransList::Iter trans = destState->outList; trans.lte(); trans++ ) {
+ if ( trans->toState != 0 ) {
+ /* Get the actions data from the outActionTable. */
+ trans->actionTable.setActions( srcState->outActionTable );
+
+ /* Get the priorities from the outPriorTable. */
+ trans->priorTable.setPriors( srcState->outPriorTable );
+ }
+ }
+}
+
+/* Kleene star operator. Makes this machine the kleene star of itself. Any
+ * transitions made going out of the machine and back into itself will be
+ * notified that they are leaving transitions by having the leavingFromState
+ * callback invoked. */
+void FsmAp::starOp( )
+{
+ /* For the merging process. */
+ MergeData md;
+
+ /* Turn on misfit accounting to possibly catch the old start state. */
+ setMisfitAccounting( true );
+
+ /* Create the new new start state. It will be set final after the merging
+ * of the final states with the start state is complete. */
+ StateAp *prevStartState = startState;
+ unsetStartState();
+ setStartState( addState() );
+
+ /* Merge the new start state with the old one to isolate it. */
+ mergeStates( md, startState, prevStartState );
+
+ /* Merge the start state into all final states. Except the start state on
+ * the first pass. If the start state is set final we will be doubling up
+ * its transitions, which will get transfered to any final states that
+ * follow it in the final state set. This will be determined by the order
+ * of items in the final state set. To prevent this we just merge with the
+ * start on a second pass. */
+ for ( StateSet::Iter st = finStateSet; st.lte(); st++ ) {
+ if ( *st != startState )
+ mergeStatesLeaving( md, *st, startState );
+ }
+
+ /* Now it is safe to merge the start state with itself (provided it
+ * is set final). */
+ if ( startState->isFinState() )
+ mergeStatesLeaving( md, startState, startState );
+
+ /* Now ensure the new start state is a final state. */
+ setFinState( startState );
+
+ /* Fill in any states that were newed up as combinations of others. */
+ fillInStates( md );
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+void FsmAp::repeatOp( int times )
+{
+ /* Must be 1 and up. 0 produces null machine and requires deleting this. */
+ assert( times > 0 );
+
+ /* A repeat of one does absolutely nothing. */
+ if ( times == 1 )
+ return;
+
+ /* Make a machine to make copies from. */
+ FsmAp *copyFrom = new FsmAp( *this );
+
+ /* Concatentate duplicates onto the end up until before the last. */
+ for ( int i = 1; i < times-1; i++ ) {
+ FsmAp *dup = new FsmAp( *copyFrom );
+ doConcat( dup, 0, false );
+ }
+
+ /* Now use the copyFrom on the end. */
+ doConcat( copyFrom, 0, false );
+}
+
+void FsmAp::optionalRepeatOp( int times )
+{
+ /* Must be 1 and up. 0 produces null machine and requires deleting this. */
+ assert( times > 0 );
+
+ /* A repeat of one optional merely allows zero string. */
+ if ( times == 1 ) {
+ setFinState( startState );
+ return;
+ }
+
+ /* Make a machine to make copies from. */
+ FsmAp *copyFrom = new FsmAp( *this );
+
+ /* The state set used in the from end of the concatentation. Starts with
+ * the initial final state set, then after each concatenation, gets set to
+ * the the final states that come from the the duplicate. */
+ StateSet lastFinSet( finStateSet );
+
+ /* Set the initial state to zero to allow zero copies. */
+ setFinState( startState );
+
+ /* Concatentate duplicates onto the end up until before the last. */
+ for ( int i = 1; i < times-1; i++ ) {
+ /* Make a duplicate for concating and set the fin bits to graph 2 so we
+ * can pick out it's final states after the optional style concat. */
+ FsmAp *dup = new FsmAp( *copyFrom );
+ dup->setFinBits( STB_GRAPH2 );
+ doConcat( dup, &lastFinSet, true );
+
+ /* Clear the last final state set and make the new one by taking only
+ * the final states that come from graph 2.*/
+ lastFinSet.empty();
+ for ( int i = 0; i < finStateSet.length(); i++ ) {
+ /* If the state came from graph 2, add it to the last set and clear
+ * the bits. */
+ StateAp *fs = finStateSet[i];
+ if ( fs->stateBits & STB_GRAPH2 ) {
+ lastFinSet.insert( fs );
+ fs->stateBits &= ~STB_GRAPH2;
+ }
+ }
+ }
+
+ /* Now use the copyFrom on the end, no bits set, no bits to clear. */
+ doConcat( copyFrom, &lastFinSet, true );
+}
+
+
+/* Fsm concatentation worker. Supports treating the concatentation as optional,
+ * which essentially leaves the final states of machine one as final. */
+void FsmAp::doConcat( FsmAp *other, StateSet *fromStates, bool optional )
+{
+ /* For the merging process. */
+ StateSet finStateSetCopy, startStateSet;
+ MergeData md;
+
+ /* Turn on misfit accounting for both graphs. */
+ setMisfitAccounting( true );
+ other->setMisfitAccounting( true );
+
+ /* Get the other's start state. */
+ StateAp *otherStartState = other->startState;
+
+ /* Unset other's start state before bringing in the entry points. */
+ other->unsetStartState();
+
+ /* Bring in the rest of other's entry points. */
+ copyInEntryPoints( other );
+ other->entryPoints.empty();
+
+ /* Bring in other's states into our state lists. */
+ stateList.append( other->stateList );
+ misfitList.append( other->misfitList );
+
+ /* If from states is not set, then get a copy of our final state set before
+ * we clobber it and use it instead. */
+ if ( fromStates == 0 ) {
+ finStateSetCopy = finStateSet;
+ fromStates = &finStateSetCopy;
+ }
+
+ /* Unset all of our final states and get the final states from other. */
+ if ( !optional )
+ unsetAllFinStates();
+ finStateSet.insert( other->finStateSet );
+
+ /* Since other's lists are empty, we can delete the fsm without
+ * affecting any states. */
+ delete other;
+
+ /* Merge our former final states with the start state of other. */
+ for ( int i = 0; i < fromStates->length(); i++ ) {
+ StateAp *state = fromStates->data[i];
+
+ /* Merge the former final state with other's start state. */
+ mergeStatesLeaving( md, state, otherStartState );
+
+ /* If the former final state was not reset final then we must clear
+ * the state's out trans data. If it got reset final then it gets to
+ * keep its out trans data. This must be done before fillInStates gets
+ * called to prevent the data from being sourced. */
+ if ( ! state->isFinState() )
+ clearOutData( state );
+ }
+
+ /* Fill in any new states made from merging. */
+ fillInStates( md );
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+/* Concatenates other to the end of this machine. Other is deleted. Any
+ * transitions made leaving this machine and entering into other are notified
+ * that they are leaving transitions by having the leavingFromState callback
+ * invoked. */
+void FsmAp::concatOp( FsmAp *other )
+{
+ /* Assert same signedness and return graph concatenation op. */
+ doConcat( other, 0, false );
+}
+
+
+void FsmAp::doOr( FsmAp *other )
+{
+ /* For the merging process. */
+ MergeData md;
+
+ /* Build a state set consisting of both start states */
+ StateSet startStateSet;
+ startStateSet.insert( startState );
+ startStateSet.insert( other->startState );
+
+ /* Both of the original start states loose their start state status. */
+ unsetStartState();
+ other->unsetStartState();
+
+ /* Bring in the rest of other's entry points. */
+ copyInEntryPoints( other );
+ other->entryPoints.empty();
+
+ /* Merge the lists. This will move all the states from other
+ * into this. No states will be deleted. */
+ stateList.append( other->stateList );
+ misfitList.append( other->misfitList );
+
+ /* Move the final set data from other into this. */
+ finStateSet.insert(other->finStateSet);
+ other->finStateSet.empty();
+
+ /* Since other's list is empty, we can delete the fsm without
+ * affecting any states. */
+ delete other;
+
+ /* Create a new start state. */
+ setStartState( addState() );
+
+ /* Merge the start states. */
+ mergeStates( md, startState, startStateSet.data, startStateSet.length() );
+
+ /* Fill in any new states made from merging. */
+ fillInStates( md );
+}
+
+/* Unions other with this machine. Other is deleted. */
+void FsmAp::unionOp( FsmAp *other )
+{
+ /* Turn on misfit accounting for both graphs. */
+ setMisfitAccounting( true );
+ other->setMisfitAccounting( true );
+
+ /* Call Worker routine. */
+ doOr( other );
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+/* Intersects other with this machine. Other is deleted. */
+void FsmAp::intersectOp( FsmAp *other )
+{
+ /* Turn on misfit accounting for both graphs. */
+ setMisfitAccounting( true );
+ other->setMisfitAccounting( true );
+
+ /* Set the fin bits on this and other to want each other. */
+ setFinBits( STB_GRAPH1 );
+ other->setFinBits( STB_GRAPH2 );
+
+ /* Call worker Or routine. */
+ doOr( other );
+
+ /* Unset any final states that are no longer to
+ * be final due to final bits. */
+ unsetIncompleteFinals();
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+
+ /* Remove states that have no path to a final state. */
+ removeDeadEndStates();
+}
+
+/* Set subtracts other machine from this machine. Other is deleted. */
+void FsmAp::subtractOp( FsmAp *other )
+{
+ /* Turn on misfit accounting for both graphs. */
+ setMisfitAccounting( true );
+ other->setMisfitAccounting( true );
+
+ /* Set the fin bits of other to be killers. */
+ other->setFinBits( STB_GRAPH1 );
+
+ /* Call worker Or routine. */
+ doOr( other );
+
+ /* Unset any final states that are no longer to
+ * be final due to final bits. */
+ unsetKilledFinals();
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+
+ /* Remove states that have no path to a final state. */
+ removeDeadEndStates();
+}
+
+bool FsmAp::inEptVect( EptVect *eptVect, StateAp *state )
+{
+ if ( eptVect != 0 ) {
+ /* Vect is there, walk it looking for state. */
+ for ( int i = 0; i < eptVect->length(); i++ ) {
+ if ( eptVect->data[i].targ == state )
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Fill epsilon vectors in a root state from a given starting point. Epmploys
+ * a depth first search through the graph of epsilon transitions. */
+void FsmAp::epsilonFillEptVectFrom( StateAp *root, StateAp *from, bool parentLeaving )
+{
+ /* Walk the epsilon transitions out of the state. */
+ for ( EpsilonTrans::Iter ep = from->epsilonTrans; ep.lte(); ep++ ) {
+ /* Find the entry point, if the it does not resove, ignore it. */
+ EntryMapEl *enLow, *enHigh;
+ if ( entryPoints.findMulti( *ep, enLow, enHigh ) ) {
+ /* Loop the targets. */
+ for ( EntryMapEl *en = enLow; en <= enHigh; en++ ) {
+ /* Do not add the root or states already in eptVect. */
+ StateAp *targ = en->value;
+ if ( targ != from && !inEptVect(root->eptVect, targ) ) {
+ /* Maybe need to create the eptVect. */
+ if ( root->eptVect == 0 )
+ root->eptVect = new EptVect();
+
+ /* If moving to a different graph or if any parent is
+ * leaving then we are leaving. */
+ bool leaving = parentLeaving ||
+ root->owningGraph != targ->owningGraph;
+
+ /* All ok, add the target epsilon and recurse. */
+ root->eptVect->append( EptVectEl(targ, leaving) );
+ epsilonFillEptVectFrom( root, targ, leaving );
+ }
+ }
+ }
+ }
+}
+
+void FsmAp::shadowReadWriteStates( MergeData &md )
+{
+ /* Init isolatedShadow algorithm data. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ )
+ st->isolatedShadow = 0;
+
+ /* Any states that may be both read from and written to must
+ * be shadowed. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Find such states by looping through stateVect lists, which give us
+ * the states that will be read from. May cause us to visit the states
+ * that we are interested in more than once. */
+ if ( st->eptVect != 0 ) {
+ /* For all states that will be read from. */
+ for ( EptVect::Iter ept = *st->eptVect; ept.lte(); ept++ ) {
+ /* Check for read and write to the same state. */
+ StateAp *targ = ept->targ;
+ if ( targ->eptVect != 0 ) {
+ /* State is to be written to, if the shadow is not already
+ * there, create it. */
+ if ( targ->isolatedShadow == 0 ) {
+ StateAp *shadow = addState();
+ mergeStates( md, shadow, targ );
+ targ->isolatedShadow = shadow;
+ }
+
+ /* Write shadow into the state vector so that it is the
+ * state that the epsilon transition will read from. */
+ ept->targ = targ->isolatedShadow;
+ }
+ }
+ }
+ }
+}
+
+void FsmAp::resolveEpsilonTrans( MergeData &md )
+{
+ /* Walk the state list and invoke recursive worker on each state. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ )
+ epsilonFillEptVectFrom( st, st, false );
+
+ /* Prevent reading from and writing to of the same state. */
+ shadowReadWriteStates( md );
+
+ /* For all states that have epsilon transitions out, draw the transitions,
+ * clear the epsilon transitions. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ /* If there is a state vector, then create the pre-merge state. */
+ if ( st->eptVect != 0 ) {
+ /* Merge all the epsilon targets into the state. */
+ for ( EptVect::Iter ept = *st->eptVect; ept.lte(); ept++ ) {
+ if ( ept->leaving )
+ mergeStatesLeaving( md, st, ept->targ );
+ else
+ mergeStates( md, st, ept->targ );
+ }
+
+ /* Clean up the target list. */
+ delete st->eptVect;
+ st->eptVect = 0;
+ }
+
+ /* Clear the epsilon transitions vector. */
+ st->epsilonTrans.empty();
+ }
+}
+
+void FsmAp::epsilonOp()
+{
+ /* For merging process. */
+ MergeData md;
+
+ setMisfitAccounting( true );
+
+ for ( StateList::Iter st = stateList; st.lte(); st++ )
+ st->owningGraph = 0;
+
+ /* Perform merges. */
+ resolveEpsilonTrans( md );
+
+ /* Epsilons can caused merges which leave behind unreachable states. */
+ fillInStates( md );
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+/* Make a new maching by joining together a bunch of machines without making
+ * any transitions between them. A negative finalId results in there being no
+ * final id. */
+void FsmAp::joinOp( int startId, int finalId, FsmAp **others, int numOthers )
+{
+ /* For the merging process. */
+ MergeData md;
+
+ /* Set the owning machines. Start at one. Zero is reserved for the start
+ * and final states. */
+ for ( StateList::Iter st = stateList; st.lte(); st++ )
+ st->owningGraph = 1;
+ for ( int m = 0; m < numOthers; m++ ) {
+ for ( StateList::Iter st = others[m]->stateList; st.lte(); st++ )
+ st->owningGraph = 2+m;
+ }
+
+ /* All machines loose start state status. */
+ unsetStartState();
+ for ( int m = 0; m < numOthers; m++ )
+ others[m]->unsetStartState();
+
+ /* Bring the other machines into this. */
+ for ( int m = 0; m < numOthers; m++ ) {
+ /* Bring in the rest of other's entry points. */
+ copyInEntryPoints( others[m] );
+ others[m]->entryPoints.empty();
+
+ /* Merge the lists. This will move all the states from other into
+ * this. No states will be deleted. */
+ stateList.append( others[m]->stateList );
+ assert( others[m]->misfitList.length() == 0 );
+
+ /* Move the final set data from other into this. */
+ finStateSet.insert( others[m]->finStateSet );
+ others[m]->finStateSet.empty();
+
+ /* Since other's list is empty, we can delete the fsm without
+ * affecting any states. */
+ delete others[m];
+ }
+
+ /* Look up the start entry point. */
+ EntryMapEl *enLow = 0, *enHigh = 0;
+ bool findRes = entryPoints.findMulti( startId, enLow, enHigh );
+ if ( ! findRes ) {
+ /* No start state. Set a default one and proceed with the join. Note
+ * that the result of the join will be a very uninteresting machine. */
+ setStartState( addState() );
+ }
+ else {
+ /* There is at least one start state, create a state that will become
+ * the new start state. */
+ StateAp *newStart = addState();
+ setStartState( newStart );
+
+ /* The start state is in an owning machine class all it's own. */
+ newStart->owningGraph = 0;
+
+ /* Create the set of states to merge from. */
+ StateSet stateSet;
+ for ( EntryMapEl *en = enLow; en <= enHigh; en++ )
+ stateSet.insert( en->value );
+
+ /* Merge in the set of start states into the new start state. */
+ mergeStates( md, newStart, stateSet.data, stateSet.length() );
+ }
+
+ /* Take a copy of the final state set, before unsetting them all. This
+ * will allow us to call clearOutData on the states that don't get
+ * final state status back back. */
+ StateSet finStateSetCopy = finStateSet;
+
+ /* Now all final states are unset. */
+ unsetAllFinStates();
+
+ if ( finalId >= 0 ) {
+ /* Create the implicit final state. */
+ StateAp *finState = addState();
+ setFinState( finState );
+
+ /* Assign an entry into the final state on the final state entry id. Note
+ * that there may already be an entry on this id. That's ok. Also set the
+ * final state owning machine id. It's in a class all it's own. */
+ setEntry( finalId, finState );
+ finState->owningGraph = 0;
+ }
+
+ /* Hand over to workers for resolving epsilon trans. This will merge states
+ * with the targets of their epsilon transitions. */
+ resolveEpsilonTrans( md );
+
+ /* Invoke the relinquish final callback on any states that did not get
+ * final state status back. */
+ for ( StateSet::Iter st = finStateSetCopy; st.lte(); st++ ) {
+ if ( !((*st)->stateBits & STB_ISFINAL) )
+ clearOutData( *st );
+ }
+
+ /* Fill in any new states made from merging. */
+ fillInStates( md );
+
+ /* Joining can be messy. Instead of having misfit accounting on (which is
+ * tricky here) do a full cleaning. */
+ removeUnreachableStates();
+}
+
+void FsmAp::globOp( FsmAp **others, int numOthers )
+{
+ /* All other machines loose start states status. */
+ for ( int m = 0; m < numOthers; m++ )
+ others[m]->unsetStartState();
+
+ /* Bring the other machines into this. */
+ for ( int m = 0; m < numOthers; m++ ) {
+ /* Bring in the rest of other's entry points. */
+ copyInEntryPoints( others[m] );
+ others[m]->entryPoints.empty();
+
+ /* Merge the lists. This will move all the states from other into
+ * this. No states will be deleted. */
+ stateList.append( others[m]->stateList );
+ assert( others[m]->misfitList.length() == 0 );
+
+ /* Move the final set data from other into this. */
+ finStateSet.insert( others[m]->finStateSet );
+ others[m]->finStateSet.empty();
+
+ /* Since other's list is empty, we can delete the fsm without
+ * affecting any states. */
+ delete others[m];
+ }
+}
+
+void FsmAp::deterministicEntry()
+{
+ /* For the merging process. */
+ MergeData md;
+
+ /* States may loose their entry points, turn on misfit accounting. */
+ setMisfitAccounting( true );
+
+ /* Get a copy of the entry map then clear all the entry points. As we
+ * iterate the old entry map finding duplicates we will add the entry
+ * points for the new states that we create. */
+ EntryMap prevEntry = entryPoints;
+ unsetAllEntryPoints();
+
+ for ( int enId = 0; enId < prevEntry.length(); ) {
+ /* Count the number of states on this entry key. */
+ int highId = enId;
+ while ( highId < prevEntry.length() && prevEntry[enId].key == prevEntry[highId].key )
+ highId += 1;
+
+ int numIds = highId - enId;
+ if ( numIds == 1 ) {
+ /* Only a single entry point, just set the entry. */
+ setEntry( prevEntry[enId].key, prevEntry[enId].value );
+ }
+ else {
+ /* Multiple entry points, need to create a new state and merge in
+ * all the targets of entry points. */
+ StateAp *newEntry = addState();
+ for ( int en = enId; en < highId; en++ )
+ mergeStates( md, newEntry, prevEntry[en].value );
+
+ /* Add the new state as the single entry point. */
+ setEntry( prevEntry[enId].key, newEntry );
+ }
+
+ enId += numIds;
+ }
+
+ /* The old start state may be unreachable. Remove the misfits and turn off
+ * misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+/* Unset any final states that are no longer to be final due to final bits. */
+void FsmAp::unsetKilledFinals()
+{
+ /* Duplicate the final state set before we begin modifying it. */
+ StateSet fin( finStateSet );
+
+ for ( int s = 0; s < fin.length(); s++ ) {
+ /* Check for killing bit. */
+ StateAp *state = fin.data[s];
+ if ( state->stateBits & STB_GRAPH1 ) {
+ /* One final state is a killer, set to non-final. */
+ unsetFinState( state );
+ }
+
+ /* Clear all killing bits. Non final states should never have had those
+ * state bits set in the first place. */
+ state->stateBits &= ~STB_GRAPH1;
+ }
+}
+
+/* Unset any final states that are no longer to be final due to final bits. */
+void FsmAp::unsetIncompleteFinals()
+{
+ /* Duplicate the final state set before we begin modifying it. */
+ StateSet fin( finStateSet );
+
+ for ( int s = 0; s < fin.length(); s++ ) {
+ /* Check for one set but not the other. */
+ StateAp *state = fin.data[s];
+ if ( state->stateBits & STB_BOTH &&
+ (state->stateBits & STB_BOTH) != STB_BOTH )
+ {
+ /* One state wants the other but it is not there. */
+ unsetFinState( state );
+ }
+
+ /* Clear wanting bits. Non final states should never have had those
+ * state bits set in the first place. */
+ state->stateBits &= ~STB_BOTH;
+ }
+}
+
+/* Ensure that the start state is free of entry points (aside from the fact
+ * that it is the start state). If the start state has entry points then Make a
+ * new start state by merging with the old one. Useful before modifying start
+ * transitions. If the existing start state has any entry points other than the
+ * start state entry then modifying its transitions changes more than the start
+ * transitions. So isolate the start state by separating it out such that it
+ * only has start stateness as it's entry point. */
+void FsmAp::isolateStartState( )
+{
+ /* For the merging process. */
+ MergeData md;
+
+ /* Bail out if the start state is already isolated. */
+ if ( isStartStateIsolated() )
+ return;
+
+ /* Turn on misfit accounting to possibly catch the old start state. */
+ setMisfitAccounting( true );
+
+ /* This will be the new start state. The existing start
+ * state is merged with it. */
+ StateAp *prevStartState = startState;
+ unsetStartState();
+ setStartState( addState() );
+
+ /* Merge the new start state with the old one to isolate it. */
+ mergeStates( md, startState, prevStartState );
+
+ /* Stfil and stateDict will be empty because the merging of the old start
+ * state into the new one will not have any conflicting transitions. */
+ assert( md.stateDict.treeSize == 0 );
+ assert( md.stfillHead == 0 );
+
+ /* The old start state may be unreachable. Remove the misfits and turn off
+ * misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+#ifdef LOG_CONDS
+void logCondSpace( CondSpace *condSpace )
+{
+ if ( condSpace == 0 )
+ cerr << "<empty>";
+ else {
+ for ( CondSet::Iter csi = condSpace->condSet.last(); csi.gtb(); csi-- ) {
+ if ( ! csi.last() )
+ cerr << ',';
+ (*csi)->actionName( cerr );
+ }
+ }
+}
+
+void logNewExpansion( Expansion *exp )
+{
+ cerr << "created expansion:" << endl;
+ cerr << " range: " << exp->lowKey.getVal() << " .. " <<
+ exp->highKey.getVal() << endl;
+
+ cerr << " fromCondSpace: ";
+ logCondSpace( exp->fromCondSpace );
+ cerr << endl;
+ cerr << " fromVals: " << exp->fromVals << endl;
+
+ cerr << " toCondSpace: ";
+ logCondSpace( exp->toCondSpace );
+ cerr << endl;
+ cerr << " toValsList: ";
+ for ( LongVect::Iter to = exp->toValsList; to.lte(); to++ )
+ cerr << " " << *to;
+ cerr << endl;
+}
+#endif
+
+
+void FsmAp::findTransExpansions( ExpansionList &expansionList,
+ StateAp *destState, StateAp *srcState )
+{
+ PairIter<TransAp, StateCond> transCond( destState->outList.head,
+ srcState->stateCondList.head );
+ for ( ; !transCond.end(); transCond++ ) {
+ if ( transCond.userState == RangeOverlap ) {
+ Expansion *expansion = new Expansion( transCond.s1Tel.lowKey,
+ transCond.s1Tel.highKey );
+ expansion->fromTrans = new TransAp(*transCond.s1Tel.trans);
+ expansion->fromTrans->fromState = 0;
+ expansion->fromTrans->toState = transCond.s1Tel.trans->toState;
+ expansion->fromCondSpace = 0;
+ expansion->fromVals = 0;
+ CondSpace *srcCS = transCond.s2Tel.trans->condSpace;
+ expansion->toCondSpace = srcCS;
+
+ long numTargVals = (1 << srcCS->condSet.length());
+ for ( long targVals = 0; targVals < numTargVals; targVals++ )
+ expansion->toValsList.append( targVals );
+
+ #ifdef LOG_CONDS
+ logNewExpansion( expansion );
+ #endif
+ expansionList.append( expansion );
+ }
+ }
+}
+
+void FsmAp::findCondExpInTrans( ExpansionList &expansionList, StateAp *state,
+ Key lowKey, Key highKey, CondSpace *fromCondSpace, CondSpace *toCondSpace,
+ long fromVals, LongVect &toValsList )
+{
+ /* Make condition-space low and high keys for searching. */
+ TransAp searchTrans;
+ searchTrans.lowKey = fromCondSpace->baseKey + fromVals * keyOps->alphSize() +
+ (lowKey - keyOps->minKey);
+ searchTrans.highKey = fromCondSpace->baseKey + fromVals * keyOps->alphSize() +
+ (highKey - keyOps->minKey);
+ searchTrans.prev = searchTrans.next = 0;
+
+ PairIter<TransAp> pairIter( state->outList.head, &searchTrans );
+ for ( ; !pairIter.end(); pairIter++ ) {
+ if ( pairIter.userState == RangeOverlap ) {
+ /* Need to make character-space low and high keys from the range
+ * overlap for the expansion object. */
+ Key expLowKey = pairIter.s1Tel.lowKey - fromCondSpace->baseKey - fromVals *
+ keyOps->alphSize() + keyOps->minKey;
+ Key expHighKey = pairIter.s1Tel.highKey - fromCondSpace->baseKey - fromVals *
+ keyOps->alphSize() + keyOps->minKey;
+
+ Expansion *expansion = new Expansion( expLowKey, expHighKey );
+ expansion->fromTrans = new TransAp(*pairIter.s1Tel.trans);
+ expansion->fromTrans->fromState = 0;
+ expansion->fromTrans->toState = pairIter.s1Tel.trans->toState;
+ expansion->fromCondSpace = fromCondSpace;
+ expansion->fromVals = fromVals;
+ expansion->toCondSpace = toCondSpace;
+ expansion->toValsList = toValsList;
+
+ expansionList.append( expansion );
+ #ifdef LOG_CONDS
+ logNewExpansion( expansion );
+ #endif
+ }
+ }
+}
+
+void FsmAp::findCondExpansions( ExpansionList &expansionList,
+ StateAp *destState, StateAp *srcState )
+{
+ PairIter<StateCond, StateCond> condCond( destState->stateCondList.head,
+ srcState->stateCondList.head );
+ for ( ; !condCond.end(); condCond++ ) {
+ if ( condCond.userState == RangeOverlap ) {
+ /* Loop over all existing condVals . */
+ CondSet &destCS = condCond.s1Tel.trans->condSpace->condSet;
+ long destLen = destCS.length();
+
+ /* Find the items in src cond set that are not in dest
+ * cond set. These are the items that we must expand. */
+ CondSet srcOnlyCS = condCond.s2Tel.trans->condSpace->condSet;
+ for ( CondSet::Iter dcsi = destCS; dcsi.lte(); dcsi++ )
+ srcOnlyCS.remove( *dcsi );
+ long srcOnlyLen = srcOnlyCS.length();
+
+ if ( srcOnlyCS.length() > 0 ) {
+ #ifdef LOG_CONDS
+ cerr << "there are " << srcOnlyCS.length() << " item(s) that are "
+ "only in the srcCS" << endl;
+ #endif
+
+ CondSet mergedCS = destCS;
+ mergedCS.insert( condCond.s2Tel.trans->condSpace->condSet );
+
+ CondSpace *fromCondSpace = addCondSpace( destCS );
+ CondSpace *toCondSpace = addCondSpace( mergedCS );
+
+ /* Loop all values in the dest space. */
+ for ( long destVals = 0; destVals < (1 << destLen); destVals++ ) {
+ long basicVals = 0;
+ for ( CondSet::Iter csi = destCS; csi.lte(); csi++ ) {
+ if ( destVals & (1 << csi.pos()) ) {
+ Action **cim = mergedCS.find( *csi );
+ long bitPos = (cim - mergedCS.data);
+ basicVals |= 1 << bitPos;
+ }
+ }
+
+ /* Loop all new values. */
+ LongVect expandToVals;
+ for ( long soVals = 0; soVals < (1 << srcOnlyLen); soVals++ ) {
+ long targVals = basicVals;
+ for ( CondSet::Iter csi = srcOnlyCS; csi.lte(); csi++ ) {
+ if ( soVals & (1 << csi.pos()) ) {
+ Action **cim = mergedCS.find( *csi );
+ long bitPos = (cim - mergedCS.data);
+ targVals |= 1 << bitPos;
+ }
+ }
+ expandToVals.append( targVals );
+ }
+
+ findCondExpInTrans( expansionList, destState,
+ condCond.s1Tel.lowKey, condCond.s1Tel.highKey,
+ fromCondSpace, toCondSpace, destVals, expandToVals );
+ }
+ }
+ }
+ }
+}
+
+void FsmAp::doExpand( MergeData &md, StateAp *destState, ExpansionList &expList1 )
+{
+ for ( ExpansionList::Iter exp = expList1; exp.lte(); exp++ ) {
+ for ( LongVect::Iter to = exp->toValsList; to.lte(); to++ ) {
+ long targVals = *to;
+
+ /* We will use the copy of the transition that was made when the
+ * expansion was created. It will get used multiple times. Each
+ * time we must set up the keys, everything else is constant and
+ * and already prepared. */
+ TransAp *srcTrans = exp->fromTrans;
+
+ srcTrans->lowKey = exp->toCondSpace->baseKey +
+ targVals * keyOps->alphSize() + (exp->lowKey - keyOps->minKey);
+ srcTrans->highKey = exp->toCondSpace->baseKey +
+ targVals * keyOps->alphSize() + (exp->highKey - keyOps->minKey);
+
+ TransList srcList;
+ srcList.append( srcTrans );
+ outTransCopy( md, destState, srcList.head );
+ srcList.abandon();
+ }
+ }
+}
+
+
+void FsmAp::doRemove( MergeData &md, StateAp *destState, ExpansionList &expList1 )
+{
+ for ( ExpansionList::Iter exp = expList1; exp.lte(); exp++ ) {
+ Removal removal;
+ if ( exp->fromCondSpace == 0 ) {
+ removal.lowKey = exp->lowKey;
+ removal.highKey = exp->highKey;
+ }
+ else {
+ removal.lowKey = exp->fromCondSpace->baseKey +
+ exp->fromVals * keyOps->alphSize() + (exp->lowKey - keyOps->minKey);
+ removal.highKey = exp->fromCondSpace->baseKey +
+ exp->fromVals * keyOps->alphSize() + (exp->highKey - keyOps->minKey);
+ }
+ removal.next = 0;
+
+ TransList destList;
+ PairIter<TransAp, Removal> pairIter( destState->outList.head, &removal );
+ for ( ; !pairIter.end(); pairIter++ ) {
+ switch ( pairIter.userState ) {
+ case RangeInS1: {
+ TransAp *destTrans = pairIter.s1Tel.trans;
+ destTrans->lowKey = pairIter.s1Tel.lowKey;
+ destTrans->highKey = pairIter.s1Tel.highKey;
+ destList.append( destTrans );
+ break;
+ }
+ case RangeInS2:
+ break;
+ case RangeOverlap: {
+ TransAp *trans = pairIter.s1Tel.trans;
+ detachTrans( trans->fromState, trans->toState, trans );
+ delete trans;
+ break;
+ }
+ case BreakS1: {
+ pairIter.s1Tel.trans = dupTrans( destState,
+ pairIter.s1Tel.trans );
+ break;
+ }
+ case BreakS2:
+ break;
+ }
+ }
+ destState->outList.transfer( destList );
+ }
+}
+
+void FsmAp::mergeStateConds( StateAp *destState, StateAp *srcState )
+{
+ StateCondList destList;
+ PairIter<StateCond> pairIter( destState->stateCondList.head,
+ srcState->stateCondList.head );
+ for ( ; !pairIter.end(); pairIter++ ) {
+ switch ( pairIter.userState ) {
+ case RangeInS1: {
+ StateCond *destCond = pairIter.s1Tel.trans;
+ destCond->lowKey = pairIter.s1Tel.lowKey;
+ destCond->highKey = pairIter.s1Tel.highKey;
+ destList.append( destCond );
+ break;
+ }
+ case RangeInS2: {
+ StateCond *newCond = new StateCond( *pairIter.s2Tel.trans );
+ newCond->lowKey = pairIter.s2Tel.lowKey;
+ newCond->highKey = pairIter.s2Tel.highKey;
+ destList.append( newCond );
+ break;
+ }
+ case RangeOverlap: {
+ StateCond *destCond = pairIter.s1Tel.trans;
+ StateCond *srcCond = pairIter.s2Tel.trans;
+ CondSet mergedCondSet;
+ mergedCondSet.insert( destCond->condSpace->condSet );
+ mergedCondSet.insert( srcCond->condSpace->condSet );
+ destCond->condSpace = addCondSpace( mergedCondSet );
+
+ destCond->lowKey = pairIter.s1Tel.lowKey;
+ destCond->highKey = pairIter.s1Tel.highKey;
+ destList.append( destCond );
+ break;
+ }
+ case BreakS1:
+ pairIter.s1Tel.trans = new StateCond( *pairIter.s1Tel.trans );
+ break;
+
+ case BreakS2:
+ break;
+ }
+ }
+ destState->stateCondList.transfer( destList );
+}
+
+/* A state merge which represents the drawing in of leaving transitions. If
+ * there is any out data then we duplicate the source state, transfer the out
+ * data, then merge in the state. The new state will be reaped because it will
+ * not be given any in transitions. */
+void FsmAp::mergeStatesLeaving( MergeData &md, StateAp *destState, StateAp *srcState )
+{
+ if ( !hasOutData( destState ) )
+ mergeStates( md, destState, srcState );
+ else {
+ StateAp *ssMutable = addState();
+ mergeStates( md, ssMutable, srcState );
+ transferOutData( ssMutable, destState );
+
+ for ( OutCondSet::Iter cond = destState->outCondSet; cond.lte(); cond++ )
+ embedCondition( md, ssMutable, cond->action, cond->sense );
+
+ mergeStates( md, destState, ssMutable );
+ }
+}
+
+void FsmAp::mergeStates( MergeData &md, StateAp *destState,
+ StateAp **srcStates, int numSrc )
+{
+ for ( int s = 0; s < numSrc; s++ )
+ mergeStates( md, destState, srcStates[s] );
+}
+
+void FsmAp::mergeStates( MergeData &md, StateAp *destState, StateAp *srcState )
+{
+ ExpansionList expList1;
+ ExpansionList expList2;
+
+ findTransExpansions( expList1, destState, srcState );
+ findCondExpansions( expList1, destState, srcState );
+ findTransExpansions( expList2, srcState, destState );
+ findCondExpansions( expList2, srcState, destState );
+
+ mergeStateConds( destState, srcState );
+
+ outTransCopy( md, destState, srcState->outList.head );
+
+ doExpand( md, destState, expList1 );
+ doExpand( md, destState, expList2 );
+
+ doRemove( md, destState, expList1 );
+ doRemove( md, destState, expList2 );
+
+ expList1.empty();
+ expList2.empty();
+
+ /* Get its bits and final state status. */
+ destState->stateBits |= ( srcState->stateBits & ~STB_ISFINAL );
+ if ( srcState->isFinState() )
+ setFinState( destState );
+
+ /* Draw in any properties of srcState into destState. */
+ if ( srcState == destState ) {
+ /* Duplicate the list to protect against write to source. The
+ * priorities sets are not copied in because that would have no
+ * effect. */
+ destState->epsilonTrans.append( EpsilonTrans( srcState->epsilonTrans ) );
+
+ /* Get all actions, duplicating to protect against write to source. */
+ destState->toStateActionTable.setActions(
+ ActionTable( srcState->toStateActionTable ) );
+ destState->fromStateActionTable.setActions(
+ ActionTable( srcState->fromStateActionTable ) );
+ destState->outActionTable.setActions( ActionTable( srcState->outActionTable ) );
+ destState->outCondSet.insert( OutCondSet( srcState->outCondSet ) );
+ destState->errActionTable.setActions( ErrActionTable( srcState->errActionTable ) );
+ destState->eofActionTable.setActions( ActionTable( srcState->eofActionTable ) );
+ }
+ else {
+ /* Get the epsilons, out priorities. */
+ destState->epsilonTrans.append( srcState->epsilonTrans );
+ destState->outPriorTable.setPriors( srcState->outPriorTable );
+
+ /* Get all actions. */
+ destState->toStateActionTable.setActions( srcState->toStateActionTable );
+ destState->fromStateActionTable.setActions( srcState->fromStateActionTable );
+ destState->outActionTable.setActions( srcState->outActionTable );
+ destState->outCondSet.insert( srcState->outCondSet );
+ destState->errActionTable.setActions( srcState->errActionTable );
+ destState->eofActionTable.setActions( srcState->eofActionTable );
+ }
+}
+
+void FsmAp::fillInStates( MergeData &md )
+{
+ /* Merge any states that are awaiting merging. This will likey cause
+ * other states to be added to the stfil list. */
+ StateAp *state = md.stfillHead;
+ while ( state != 0 ) {
+ StateSet *stateSet = &state->stateDictEl->stateSet;
+ mergeStates( md, state, stateSet->data, stateSet->length() );
+ state = state->alg.next;
+ }
+
+ /* Delete the state sets of all states that are on the fill list. */
+ state = md.stfillHead;
+ while ( state != 0 ) {
+ /* Delete and reset the state set. */
+ delete state->stateDictEl;
+ state->stateDictEl = 0;
+
+ /* Next state in the stfill list. */
+ state = state->alg.next;
+ }
+
+ /* StateDict will still have its ptrs/size set but all of it's element
+ * will be deleted so we don't need to clean it up. */
+}
+
+void FsmAp::findEmbedExpansions( ExpansionList &expansionList,
+ StateAp *destState, Action *condAction, bool sense )
+{
+ StateCondList destList;
+ PairIter<TransAp, StateCond> transCond( destState->outList.head,
+ destState->stateCondList.head );
+ for ( ; !transCond.end(); transCond++ ) {
+ switch ( transCond.userState ) {
+ case RangeInS1: {
+ if ( transCond.s1Tel.lowKey <= keyOps->maxKey ) {
+ assert( transCond.s1Tel.highKey <= keyOps->maxKey );
+
+ /* Make a new state cond. */
+ StateCond *newStateCond = new StateCond( transCond.s1Tel.lowKey,
+ transCond.s1Tel.highKey );
+ newStateCond->condSpace = addCondSpace( CondSet( condAction ) );
+ destList.append( newStateCond );
+
+ /* Create the expansion. */
+ Expansion *expansion = new Expansion( transCond.s1Tel.lowKey,
+ transCond.s1Tel.highKey );
+ expansion->fromTrans = new TransAp(*transCond.s1Tel.trans);
+ expansion->fromTrans->fromState = 0;
+ expansion->fromTrans->toState = transCond.s1Tel.trans->toState;
+ expansion->fromCondSpace = 0;
+ expansion->fromVals = 0;
+ expansion->toCondSpace = newStateCond->condSpace;
+ expansion->toValsList.append( sense?1:0 );
+ #ifdef LOG_CONDS
+ logNewExpansion( expansion );
+ #endif
+ expansionList.append( expansion );
+ }
+ break;
+ }
+ case RangeInS2: {
+ /* Enhance state cond and find the expansion. */
+ StateCond *stateCond = transCond.s2Tel.trans;
+ stateCond->lowKey = transCond.s2Tel.lowKey;
+ stateCond->highKey = transCond.s2Tel.highKey;
+
+ CondSet &destCS = stateCond->condSpace->condSet;
+ long destLen = destCS.length();
+ CondSpace *fromCondSpace = stateCond->condSpace;
+
+ CondSet mergedCS = destCS;
+ mergedCS.insert( condAction );
+ CondSpace *toCondSpace = addCondSpace( mergedCS );
+ stateCond->condSpace = toCondSpace;
+ destList.append( stateCond );
+
+ /* Loop all values in the dest space. */
+ for ( long destVals = 0; destVals < (1 << destLen); destVals++ ) {
+ long basicVals = 0;
+ for ( CondSet::Iter csi = destCS; csi.lte(); csi++ ) {
+ if ( destVals & (1 << csi.pos()) ) {
+ Action **cim = mergedCS.find( *csi );
+ long bitPos = (cim - mergedCS.data);
+ basicVals |= 1 << bitPos;
+ }
+ }
+
+ long targVals = basicVals;
+ Action **cim = mergedCS.find( condAction );
+ long bitPos = (cim - mergedCS.data);
+ targVals |= (sense?1:0) << bitPos;
+
+ LongVect expandToVals( targVals );
+ findCondExpInTrans( expansionList, destState,
+ transCond.s2Tel.lowKey, transCond.s2Tel.highKey,
+ fromCondSpace, toCondSpace, destVals, expandToVals );
+ }
+ break;
+ }
+
+
+ case RangeOverlap:
+ case BreakS1:
+ case BreakS2:
+ assert( false );
+ break;
+ }
+ }
+
+ destState->stateCondList.transfer( destList );
+}
+
+void FsmAp::embedCondition( StateAp *state, Action *condAction, bool sense )
+{
+ MergeData md;
+ ExpansionList expList;
+
+ /* Turn on misfit accounting to possibly catch the old start state. */
+ setMisfitAccounting( true );
+
+ /* Worker. */
+ embedCondition( md, state, condAction, sense );
+
+ /* Fill in any states that were newed up as combinations of others. */
+ fillInStates( md );
+
+ /* Remove the misfits and turn off misfit accounting. */
+ removeMisfits();
+ setMisfitAccounting( false );
+}
+
+void FsmAp::embedCondition( MergeData &md, StateAp *state, Action *condAction, bool sense )
+{
+ ExpansionList expList;
+
+ findEmbedExpansions( expList, state, condAction, sense );
+ doExpand( md, state, expList );
+ doRemove( md, state, expList );
+ expList.empty();
+}
+
+/* Check if a machine defines a single character. This is useful in validating
+ * ranges and machines to export. */
+bool FsmAp::checkSingleCharMachine()
+{
+ /* Must have two states. */
+ if ( stateList.length() != 2 )
+ return false;
+ /* The start state cannot be final. */
+ if ( startState->isFinState() )
+ return false;
+ /* There should be only one final state. */
+ if ( finStateSet.length() != 1 )
+ return false;
+ /* The final state cannot have any transitions out. */
+ if ( finStateSet[0]->outList.length() != 0 )
+ return false;
+ /* The start state should have only one transition out. */
+ if ( startState->outList.length() != 1 )
+ return false;
+ /* The singe transition out of the start state should not be a range. */
+ TransAp *startTrans = startState->outList.head;
+ if ( startTrans->lowKey != startTrans->highKey )
+ return false;
+ return true;
+}
+
diff --git a/ragel/fsmgraph.h b/ragel/fsmgraph.h
new file mode 100644
index 0000000..1b7d6f5
--- /dev/null
+++ b/ragel/fsmgraph.h
@@ -0,0 +1,1531 @@
+/*
+ * Copyright 2001-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
+ */
+
+#ifndef _FSMGRAPH_H
+#define _FSMGRAPH_H
+
+#include "config.h"
+#include <assert.h>
+#include <iostream>
+#include <string>
+#include "common.h"
+#include "vector.h"
+#include "bstset.h"
+#include "compare.h"
+#include "avltree.h"
+#include "dlist.h"
+#include "bstmap.h"
+#include "sbstmap.h"
+#include "sbstset.h"
+#include "sbsttable.h"
+#include "avlset.h"
+#include "avlmap.h"
+#include "ragel.h"
+
+//#define LOG_CONDS
+
+/* Flags that control merging. */
+#define STB_GRAPH1 0x01
+#define STB_GRAPH2 0x02
+#define STB_BOTH 0x03
+#define STB_ISFINAL 0x04
+#define STB_ISMARKED 0x08
+#define STB_ONLIST 0x10
+
+using std::ostream;
+
+struct TransAp;
+struct StateAp;
+struct FsmAp;
+struct Action;
+struct LongestMatchPart;
+struct LengthDef;
+
+/* State list element for unambiguous access to list element. */
+struct FsmListEl
+{
+ StateAp *prev, *next;
+};
+
+/* This is the marked index for a state pair. Used in minimization. It keeps
+ * track of whether or not the state pair is marked. */
+struct MarkIndex
+{
+ MarkIndex(int states);
+ ~MarkIndex();
+
+ void markPair(int state1, int state2);
+ bool isPairMarked(int state1, int state2);
+
+private:
+ int numStates;
+ bool *array;
+};
+
+extern KeyOps *keyOps;
+
+/* Transistion Action Element. */
+typedef SBstMapEl< int, Action* > ActionTableEl;
+
+/* Nodes in the tree that use this action. */
+struct NameInst;
+struct InlineList;
+typedef Vector<NameInst*> ActionRefs;
+
+/* Element in list of actions. Contains the string for the code to exectute. */
+struct Action
+:
+ public DListEl<Action>,
+ public AvlTreeEl<Action>
+{
+public:
+
+ Action( const InputLoc &loc, const char *name, InlineList *inlineList, int condId )
+ :
+ loc(loc),
+ name(name),
+ inlineList(inlineList),
+ actionId(-1),
+ numTransRefs(0),
+ numToStateRefs(0),
+ numFromStateRefs(0),
+ numEofRefs(0),
+ numCondRefs(0),
+ anyCall(false),
+ isLmAction(false),
+ condId(condId)
+ {
+ }
+
+ /* Key for action dictionary. */
+ const char *getKey() const { return name; }
+
+ /* Data collected during parse. */
+ InputLoc loc;
+ const char *name;
+ InlineList *inlineList;
+ int actionId;
+
+ void actionName( ostream &out )
+ {
+ if ( name != 0 )
+ out << name;
+ else
+ out << loc.line << ":" << loc.col;
+ }
+
+ /* Places in the input text that reference the action. */
+ ActionRefs actionRefs;
+
+ /* Number of references in the final machine. */
+ int numRefs()
+ { return numTransRefs + numToStateRefs + numFromStateRefs + numEofRefs; }
+ int numTransRefs;
+ int numToStateRefs;
+ int numFromStateRefs;
+ int numEofRefs;
+ int numCondRefs;
+ bool anyCall;
+
+ bool isLmAction;
+ int condId;
+};
+
+struct CmpCondId
+{
+ static inline int compare( const Action *cond1, const Action *cond2 )
+ {
+ if ( cond1->condId < cond2->condId )
+ return -1;
+ else if ( cond1->condId > cond2->condId )
+ return 1;
+ return 0;
+ }
+};
+
+/* A list of actions. */
+typedef DList<Action> ActionList;
+typedef AvlTree<Action, char *, CmpStr> ActionDict;
+
+/* Structure for reverse action mapping. */
+struct RevActionMapEl
+{
+ char *name;
+ InputLoc location;
+};
+
+
+/* Transition Action Table. */
+struct ActionTable
+ : public SBstMap< int, Action*, CmpOrd<int> >
+{
+ void setAction( int ordering, Action *action );
+ void setActions( int *orderings, Action **actions, int nActs );
+ void setActions( const ActionTable &other );
+
+ bool hasAction( Action *action );
+};
+
+typedef SBstSet< Action*, CmpOrd<Action*> > ActionSet;
+typedef CmpSTable< Action*, CmpOrd<Action*> > CmpActionSet;
+
+/* Transistion Action Element. */
+typedef SBstMapEl< int, LongestMatchPart* > LmActionTableEl;
+
+/* Transition Action Table. */
+struct LmActionTable
+ : public SBstMap< int, LongestMatchPart*, CmpOrd<int> >
+{
+ void setAction( int ordering, LongestMatchPart *action );
+ void setActions( const LmActionTable &other );
+};
+
+/* Compare of a whole action table element (key & value). */
+struct CmpActionTableEl
+{
+ static int compare( const ActionTableEl &action1,
+ const ActionTableEl &action2 )
+ {
+ if ( action1.key < action2.key )
+ return -1;
+ else if ( action1.key > action2.key )
+ return 1;
+ else if ( action1.value < action2.value )
+ return -1;
+ else if ( action1.value > action2.value )
+ return 1;
+ return 0;
+ }
+};
+
+/* Compare for ActionTable. */
+typedef CmpSTable< ActionTableEl, CmpActionTableEl > CmpActionTable;
+
+/* Compare of a whole lm action table element (key & value). */
+struct CmpLmActionTableEl
+{
+ static int compare( const LmActionTableEl &lmAction1,
+ const LmActionTableEl &lmAction2 )
+ {
+ if ( lmAction1.key < lmAction2.key )
+ return -1;
+ else if ( lmAction1.key > lmAction2.key )
+ return 1;
+ else if ( lmAction1.value < lmAction2.value )
+ return -1;
+ else if ( lmAction1.value > lmAction2.value )
+ return 1;
+ return 0;
+ }
+};
+
+/* Compare for ActionTable. */
+typedef CmpSTable< LmActionTableEl, CmpLmActionTableEl > CmpLmActionTable;
+
+/* Action table element for error action tables. Adds the encoding of transfer
+ * point. */
+struct ErrActionTableEl
+{
+ ErrActionTableEl( Action *action, int ordering, int transferPoint )
+ : ordering(ordering), action(action), transferPoint(transferPoint) { }
+
+ /* Ordering and id of the action embedding. */
+ int ordering;
+ Action *action;
+
+ /* Id of point of transfere from Error action table to transtions and
+ * eofActionTable. */
+ int transferPoint;
+
+ int getKey() const { return ordering; }
+};
+
+struct ErrActionTable
+ : public SBstTable< ErrActionTableEl, int, CmpOrd<int> >
+{
+ void setAction( int ordering, Action *action, int transferPoint );
+ void setActions( const ErrActionTable &other );
+};
+
+/* Compare of an error action table element (key & value). */
+struct CmpErrActionTableEl
+{
+ static int compare( const ErrActionTableEl &action1,
+ const ErrActionTableEl &action2 )
+ {
+ if ( action1.ordering < action2.ordering )
+ return -1;
+ else if ( action1.ordering > action2.ordering )
+ return 1;
+ else if ( action1.action < action2.action )
+ return -1;
+ else if ( action1.action > action2.action )
+ return 1;
+ else if ( action1.transferPoint < action2.transferPoint )
+ return -1;
+ else if ( action1.transferPoint > action2.transferPoint )
+ return 1;
+ return 0;
+ }
+};
+
+/* Compare for ErrActionTable. */
+typedef CmpSTable< ErrActionTableEl, CmpErrActionTableEl > CmpErrActionTable;
+
+
+/* Descibe a priority, shared among PriorEls.
+ * Has key and whether or not used. */
+struct PriorDesc
+{
+ int key;
+ int priority;
+};
+
+/* Element in the arrays of priorities for transitions and arrays. Ordering is
+ * unique among instantiations of machines, desc is shared. */
+struct PriorEl
+{
+ PriorEl( int ordering, PriorDesc *desc )
+ : ordering(ordering), desc(desc) { }
+
+ int ordering;
+ PriorDesc *desc;
+};
+
+/* Compare priority elements, which are ordered by the priority descriptor
+ * key. */
+struct PriorElCmp
+{
+ static inline int compare( const PriorEl &pel1, const PriorEl &pel2 )
+ {
+ if ( pel1.desc->key < pel2.desc->key )
+ return -1;
+ else if ( pel1.desc->key > pel2.desc->key )
+ return 1;
+ else
+ return 0;
+ }
+};
+
+
+/* Priority Table. */
+struct PriorTable
+ : public SBstSet< PriorEl, PriorElCmp >
+{
+ void setPrior( int ordering, PriorDesc *desc );
+ void setPriors( const PriorTable &other );
+};
+
+/* Compare of prior table elements for distinguising state data. */
+struct CmpPriorEl
+{
+ static inline int compare( const PriorEl &pel1, const PriorEl &pel2 )
+ {
+ if ( pel1.desc < pel2.desc )
+ return -1;
+ else if ( pel1.desc > pel2.desc )
+ return 1;
+ else if ( pel1.ordering < pel2.ordering )
+ return -1;
+ else if ( pel1.ordering > pel2.ordering )
+ return 1;
+ return 0;
+ }
+};
+
+/* Compare of PriorTable distinguising state data. Using a compare of the
+ * pointers is a little more strict than it needs be. It requires that
+ * prioritiy tables have the exact same set of priority assignment operators
+ * (from the input lang) to be considered equal.
+ *
+ * Really only key-value pairs need be tested and ordering be merged. However
+ * this would require that in the fuseing of states, priority descriptors be
+ * chosen for the new fused state based on priority. Since the out transition
+ * lists and ranges aren't necessarily going to line up, this is more work for
+ * little gain. Final compression resets all priorities first, so this would
+ * only be useful for compression at every operator, which is only an
+ * undocumented test feature.
+ */
+typedef CmpSTable<PriorEl, CmpPriorEl> CmpPriorTable;
+
+/* Plain action list that imposes no ordering. */
+typedef Vector<int> TransFuncList;
+
+/* Comparison for TransFuncList. */
+typedef CmpTable< int, CmpOrd<int> > TransFuncListCompare;
+
+/* Transition class that implements actions and priorities. */
+struct TransAp
+{
+ TransAp() : fromState(0), toState(0) {}
+ TransAp( const TransAp &other ) :
+ lowKey(other.lowKey),
+ highKey(other.highKey),
+ fromState(0), toState(0),
+ actionTable(other.actionTable),
+ priorTable(other.priorTable),
+ lmActionTable(other.lmActionTable) {}
+
+ Key lowKey, highKey;
+ StateAp *fromState;
+ StateAp *toState;
+
+ /* Pointers for outlist. */
+ TransAp *prev, *next;
+
+ /* Pointers for in-list. */
+ TransAp *ilprev, *ilnext;
+
+ /* The function table and priority for the transition. */
+ ActionTable actionTable;
+ PriorTable priorTable;
+
+ LmActionTable lmActionTable;
+};
+
+/* In transition list. Like DList except only has head pointers, which is all
+ * that is required. Insertion and deletion is handled by the graph. This
+ * class provides the iterator of a single list. */
+struct TransInList
+{
+ TransInList() : head(0) { }
+
+ TransAp *head;
+
+ struct Iter
+ {
+ /* Default construct. */
+ Iter() : ptr(0) { }
+
+ /* Construct, assign from a list. */
+ Iter( const TransInList &il ) : ptr(il.head) { }
+ Iter &operator=( const TransInList &dl ) { ptr = dl.head; return *this; }
+
+ /* At the end */
+ bool lte() const { return ptr != 0; }
+ bool end() const { return ptr == 0; }
+
+ /* At the first, last element. */
+ bool first() const { return ptr && ptr->ilprev == 0; }
+ bool last() const { return ptr && ptr->ilnext == 0; }
+
+ /* Cast, dereference, arrow ops. */
+ operator TransAp*() const { return ptr; }
+ TransAp &operator *() const { return *ptr; }
+ TransAp *operator->() const { return ptr; }
+
+ /* Increment, decrement. */
+ inline void operator++(int) { ptr = ptr->ilnext; }
+ inline void operator--(int) { ptr = ptr->ilprev; }
+
+ /* The iterator is simply a pointer. */
+ TransAp *ptr;
+ };
+};
+
+typedef DList<TransAp> TransList;
+
+/* Set of states, list of states. */
+typedef BstSet<StateAp*> StateSet;
+typedef DList<StateAp> StateList;
+
+/* A element in a state dict. */
+struct StateDictEl
+:
+ public AvlTreeEl<StateDictEl>
+{
+ StateDictEl(const StateSet &stateSet)
+ : stateSet(stateSet) { }
+
+ const StateSet &getKey() { return stateSet; }
+ StateSet stateSet;
+ StateAp *targState;
+};
+
+/* Dictionary mapping a set of states to a target state. */
+typedef AvlTree< StateDictEl, StateSet, CmpTable<StateAp*> > StateDict;
+
+/* Data needed for a merge operation. */
+struct MergeData
+{
+ MergeData()
+ : stfillHead(0), stfillTail(0) { }
+
+ StateDict stateDict;
+
+ StateAp *stfillHead;
+ StateAp *stfillTail;
+
+ void fillListAppend( StateAp *state );
+};
+
+struct TransEl
+{
+ /* Constructors. */
+ TransEl() { }
+ TransEl( Key lowKey, Key highKey )
+ : lowKey(lowKey), highKey(highKey) { }
+ TransEl( Key lowKey, Key highKey, TransAp *value )
+ : lowKey(lowKey), highKey(highKey), value(value) { }
+
+ Key lowKey, highKey;
+ TransAp *value;
+};
+
+struct CmpKey
+{
+ static int compare( const Key key1, const Key key2 )
+ {
+ if ( key1 < key2 )
+ return -1;
+ else if ( key1 > key2 )
+ return 1;
+ else
+ return 0;
+ }
+};
+
+/* Vector based set of key items. */
+typedef BstSet<Key, CmpKey> KeySet;
+
+struct MinPartition
+{
+ MinPartition() : active(false) { }
+
+ StateList list;
+ bool active;
+
+ MinPartition *prev, *next;
+};
+
+/* Epsilon transition stored in a state. Specifies the target */
+typedef Vector<int> EpsilonTrans;
+
+/* List of states that are to be drawn into this. */
+struct EptVectEl
+{
+ EptVectEl( StateAp *targ, bool leaving )
+ : targ(targ), leaving(leaving) { }
+
+ StateAp *targ;
+ bool leaving;
+};
+typedef Vector<EptVectEl> EptVect;
+
+/* Set of entry ids that go into this state. */
+typedef BstSet<int> EntryIdSet;
+
+/* Set of longest match items that may be active in a given state. */
+typedef BstSet<LongestMatchPart*> LmItemSet;
+
+/* A Conditions which is to be
+ * transfered on pending out transitions. */
+struct OutCond
+{
+ OutCond( Action *action, bool sense )
+ : action(action), sense(sense) {}
+
+ Action *action;
+ bool sense;
+};
+
+struct CmpOutCond
+{
+ static int compare( const OutCond &outCond1, const OutCond &outCond2 )
+ {
+ if ( outCond1.action < outCond2.action )
+ return -1;
+ else if ( outCond1.action > outCond2.action )
+ return 1;
+ else if ( outCond1.sense < outCond2.sense )
+ return -1;
+ else if ( outCond1.sense > outCond2.sense )
+ return 1;
+ return 0;
+ }
+};
+
+/* Set of conditions to be transfered to on pending out transitions. */
+typedef SBstSet< OutCond, CmpOutCond > OutCondSet;
+typedef CmpSTable< OutCond, CmpOutCond > CmpOutCondSet;
+
+/* Conditions. */
+typedef BstSet< Action*, CmpCondId > CondSet;
+typedef CmpTable< Action*, CmpCondId > CmpCondSet;
+
+struct CondSpace
+ : public AvlTreeEl<CondSpace>
+{
+ CondSpace( const CondSet &condSet )
+ : condSet(condSet) {}
+
+ const CondSet &getKey() { return condSet; }
+
+ CondSet condSet;
+ Key baseKey;
+ long condSpaceId;
+};
+
+typedef Vector<CondSpace*> CondSpaceVect;
+
+typedef AvlTree<CondSpace, CondSet, CmpCondSet> CondSpaceMap;
+
+struct StateCond
+{
+ StateCond( Key lowKey, Key highKey ) :
+ lowKey(lowKey), highKey(highKey) {}
+
+ Key lowKey;
+ Key highKey;
+ CondSpace *condSpace;
+
+ StateCond *prev, *next;
+};
+
+typedef DList<StateCond> StateCondList;
+typedef Vector<long> LongVect;
+
+struct Expansion
+{
+ Expansion( Key lowKey, Key highKey ) :
+ lowKey(lowKey), highKey(highKey),
+ fromTrans(0), fromCondSpace(0),
+ toCondSpace(0) {}
+
+ ~Expansion()
+ {
+ if ( fromTrans != 0 )
+ delete fromTrans;
+ }
+
+ Key lowKey;
+ Key highKey;
+
+ TransAp *fromTrans;
+ CondSpace *fromCondSpace;
+ long fromVals;
+
+ CondSpace *toCondSpace;
+ LongVect toValsList;
+
+ Expansion *prev, *next;
+};
+
+typedef DList<Expansion> ExpansionList;
+
+struct Removal
+{
+ Key lowKey;
+ Key highKey;
+
+ Removal *next;
+};
+
+struct CondData
+{
+ CondData() : lastCondKey(0) {}
+
+ /* Condition info. */
+ Key lastCondKey;
+
+ CondSpaceMap condSpaceMap;
+};
+
+extern CondData *condData;
+
+struct FsmConstructFail
+{
+ enum Reason
+ {
+ CondNoKeySpace
+ };
+
+ FsmConstructFail( Reason reason )
+ : reason(reason) {}
+ Reason reason;
+};
+
+/* State class that implements actions and priorities. */
+struct StateAp
+{
+ StateAp();
+ StateAp(const StateAp &other);
+ ~StateAp();
+
+ /* Is the state final? */
+ bool isFinState() { return stateBits & STB_ISFINAL; }
+
+ /* Out transition list and the pointer for the default out trans. */
+ TransList outList;
+
+ /* In transition Lists. */
+ TransInList inList;
+
+ /* Set only during scanner construction when actions are added. NFA to DFA
+ * code can ignore this. */
+ StateAp *eofTarget;
+
+ /* Entry points into the state. */
+ EntryIdSet entryIds;
+
+ /* Epsilon transitions. */
+ EpsilonTrans epsilonTrans;
+
+ /* Condition info. */
+ StateCondList stateCondList;
+
+ /* Number of in transitions from states other than ourselves. */
+ int foreignInTrans;
+
+ /* Temporary data for various algorithms. */
+ union {
+ /* When duplicating the fsm we need to map each
+ * state to the new state representing it. */
+ StateAp *stateMap;
+
+ /* When minimizing machines by partitioning, this maps to the group
+ * the state is in. */
+ MinPartition *partition;
+
+ /* When merging states (state machine operations) this next pointer is
+ * used for the list of states that need to be filled in. */
+ StateAp *next;
+
+ /* Identification for printing and stable minimization. */
+ int stateNum;
+
+ } alg;
+
+ /* Data used in epsilon operation, maybe fit into alg? */
+ StateAp *isolatedShadow;
+ int owningGraph;
+
+ /* A pointer to a dict element that contains the set of states this state
+ * represents. This cannot go into alg, because alg.next is used during
+ * the merging process. */
+ StateDictEl *stateDictEl;
+
+ /* When drawing epsilon transitions, holds the list of states to merge
+ * with. */
+ EptVect *eptVect;
+
+ /* Bits controlling the behaviour of the state during collapsing to dfa. */
+ int stateBits;
+
+ /* State list elements. */
+ StateAp *next, *prev;
+
+ /*
+ * Priority and Action data.
+ */
+
+ /* Out priorities transfered to out transitions. */
+ PriorTable outPriorTable;
+
+ /* The following two action tables are distinguished by the fact that when
+ * toState actions are executed immediatly after transition actions of
+ * incoming transitions and the current character will be the same as the
+ * one available then. The fromState actions are executed immediately
+ * before the transition actions of outgoing transitions and the current
+ * character is same as the one available then. */
+
+ /* Actions to execute upon entering into a state. */
+ ActionTable toStateActionTable;
+
+ /* Actions to execute when going from the state to the transition. */
+ ActionTable fromStateActionTable;
+
+ /* Actions to add to any future transitions that leave via this state. */
+ ActionTable outActionTable;
+
+ /* Conditions to add to any future transiions that leave via this sttate. */
+ OutCondSet outCondSet;
+
+ /* Error action tables. */
+ ErrActionTable errActionTable;
+
+ /* Actions to execute on eof. */
+ ActionTable eofActionTable;
+
+ /* Set of longest match items that may be active in this state. */
+ LmItemSet lmItemSet;
+};
+
+template <class ListItem> struct NextTrans
+{
+ Key lowKey, highKey;
+ ListItem *trans;
+ ListItem *next;
+
+ void load() {
+ if ( trans == 0 )
+ next = 0;
+ else {
+ next = trans->next;
+ lowKey = trans->lowKey;
+ highKey = trans->highKey;
+ }
+ }
+
+ void set( ListItem *t ) {
+ trans = t;
+ load();
+ }
+
+ void increment() {
+ trans = next;
+ load();
+ }
+};
+
+
+/* Encodes the different states that are meaningful to the of the iterator. */
+enum PairIterUserState
+{
+ RangeInS1, RangeInS2,
+ RangeOverlap,
+ BreakS1, BreakS2
+};
+
+template <class ListItem1, class ListItem2 = ListItem1> struct PairIter
+{
+ /* Encodes the different states that an fsm iterator can be in. */
+ enum IterState {
+ Begin,
+ ConsumeS1Range, ConsumeS2Range,
+ OnlyInS1Range, OnlyInS2Range,
+ S1SticksOut, S1SticksOutBreak,
+ S2SticksOut, S2SticksOutBreak,
+ S1DragsBehind, S1DragsBehindBreak,
+ S2DragsBehind, S2DragsBehindBreak,
+ ExactOverlap, End
+ };
+
+ PairIter( ListItem1 *list1, ListItem2 *list2 );
+
+ /* Query iterator. */
+ bool lte() { return itState != End; }
+ bool end() { return itState == End; }
+ void operator++(int) { findNext(); }
+ void operator++() { findNext(); }
+
+ /* Iterator state. */
+ ListItem1 *list1;
+ ListItem2 *list2;
+ IterState itState;
+ PairIterUserState userState;
+
+ NextTrans<ListItem1> s1Tel;
+ NextTrans<ListItem2> s2Tel;
+ Key bottomLow, bottomHigh;
+ ListItem1 *bottomTrans1;
+ ListItem2 *bottomTrans2;
+
+private:
+ void findNext();
+};
+
+/* Init the iterator by advancing to the first item. */
+template <class ListItem1, class ListItem2> PairIter<ListItem1, ListItem2>::PairIter(
+ ListItem1 *list1, ListItem2 *list2 )
+:
+ list1(list1),
+ list2(list2),
+ itState(Begin)
+{
+ findNext();
+}
+
+/* Return and re-entry for the co-routine iterators. This should ALWAYS be
+ * used inside of a block. */
+#define CO_RETURN(label) \
+ itState = label; \
+ return; \
+ entry##label: backIn = true
+
+/* Return and re-entry for the co-routine iterators. This should ALWAYS be
+ * used inside of a block. */
+#define CO_RETURN2(label, uState) \
+ itState = label; \
+ userState = uState; \
+ return; \
+ entry##label: backIn = true
+
+/* Advance to the next transition. When returns, trans points to the next
+ * transition, unless there are no more, in which case end() returns true. */
+template <class ListItem1, class ListItem2> void PairIter<ListItem1, ListItem2>::findNext()
+{
+ /* This variable is used in dummy statements that follow the entry
+ * goto labels. The compiler needs some statement to follow the label. */
+ bool backIn;
+
+ /* Jump into the iterator routine base on the iterator state. */
+ switch ( itState ) {
+ case Begin: goto entryBegin;
+ case ConsumeS1Range: goto entryConsumeS1Range;
+ case ConsumeS2Range: goto entryConsumeS2Range;
+ case OnlyInS1Range: goto entryOnlyInS1Range;
+ case OnlyInS2Range: goto entryOnlyInS2Range;
+ case S1SticksOut: goto entryS1SticksOut;
+ case S1SticksOutBreak: goto entryS1SticksOutBreak;
+ case S2SticksOut: goto entryS2SticksOut;
+ case S2SticksOutBreak: goto entryS2SticksOutBreak;
+ case S1DragsBehind: goto entryS1DragsBehind;
+ case S1DragsBehindBreak: goto entryS1DragsBehindBreak;
+ case S2DragsBehind: goto entryS2DragsBehind;
+ case S2DragsBehindBreak: goto entryS2DragsBehindBreak;
+ case ExactOverlap: goto entryExactOverlap;
+ case End: goto entryEnd;
+ }
+
+entryBegin:
+ /* Set up the next structs at the head of the transition lists. */
+ s1Tel.set( list1 );
+ s2Tel.set( list2 );
+
+ /* Concurrently scan both out ranges. */
+ while ( true ) {
+ if ( s1Tel.trans == 0 ) {
+ /* We are at the end of state1's ranges. Process the rest of
+ * state2's ranges. */
+ while ( s2Tel.trans != 0 ) {
+ /* Range is only in s2. */
+ CO_RETURN2( ConsumeS2Range, RangeInS2 );
+ s2Tel.increment();
+ }
+ break;
+ }
+ else if ( s2Tel.trans == 0 ) {
+ /* We are at the end of state2's ranges. Process the rest of
+ * state1's ranges. */
+ while ( s1Tel.trans != 0 ) {
+ /* Range is only in s1. */
+ CO_RETURN2( ConsumeS1Range, RangeInS1 );
+ s1Tel.increment();
+ }
+ break;
+ }
+ /* Both state1's and state2's transition elements are good.
+ * The signiture of no overlap is a back key being in front of a
+ * front key. */
+ else if ( s1Tel.highKey < s2Tel.lowKey ) {
+ /* A range exists in state1 that does not overlap with state2. */
+ CO_RETURN2( OnlyInS1Range, RangeInS1 );
+ s1Tel.increment();
+ }
+ else if ( s2Tel.highKey < s1Tel.lowKey ) {
+ /* A range exists in state2 that does not overlap with state1. */
+ CO_RETURN2( OnlyInS2Range, RangeInS2 );
+ s2Tel.increment();
+ }
+ /* There is overlap, must mix the ranges in some way. */
+ else if ( s1Tel.lowKey < s2Tel.lowKey ) {
+ /* Range from state1 sticks out front. Must break it into
+ * non-overlaping and overlaping segments. */
+ bottomLow = s2Tel.lowKey;
+ bottomHigh = s1Tel.highKey;
+ s1Tel.highKey = s2Tel.lowKey;
+ s1Tel.highKey.decrement();
+ bottomTrans1 = s1Tel.trans;
+
+ /* Notify the caller that we are breaking s1. This gives them a
+ * chance to duplicate s1Tel[0,1].value. */
+ CO_RETURN2( S1SticksOutBreak, BreakS1 );
+
+ /* Broken off range is only in s1. */
+ CO_RETURN2( S1SticksOut, RangeInS1 );
+
+ /* Advance over the part sticking out front. */
+ s1Tel.lowKey = bottomLow;
+ s1Tel.highKey = bottomHigh;
+ s1Tel.trans = bottomTrans1;
+ }
+ else if ( s2Tel.lowKey < s1Tel.lowKey ) {
+ /* Range from state2 sticks out front. Must break it into
+ * non-overlaping and overlaping segments. */
+ bottomLow = s1Tel.lowKey;
+ bottomHigh = s2Tel.highKey;
+ s2Tel.highKey = s1Tel.lowKey;
+ s2Tel.highKey.decrement();
+ bottomTrans2 = s2Tel.trans;
+
+ /* Notify the caller that we are breaking s2. This gives them a
+ * chance to duplicate s2Tel[0,1].value. */
+ CO_RETURN2( S2SticksOutBreak, BreakS2 );
+
+ /* Broken off range is only in s2. */
+ CO_RETURN2( S2SticksOut, RangeInS2 );
+
+ /* Advance over the part sticking out front. */
+ s2Tel.lowKey = bottomLow;
+ s2Tel.highKey = bottomHigh;
+ s2Tel.trans = bottomTrans2;
+ }
+ /* Low ends are even. Are the high ends even? */
+ else if ( s1Tel.highKey < s2Tel.highKey ) {
+ /* Range from state2 goes longer than the range from state1. We
+ * must break the range from state2 into an evenly overlaping
+ * segment. */
+ bottomLow = s1Tel.highKey;
+ bottomLow.increment();
+ bottomHigh = s2Tel.highKey;
+ s2Tel.highKey = s1Tel.highKey;
+ bottomTrans2 = s2Tel.trans;
+
+ /* Notify the caller that we are breaking s2. This gives them a
+ * chance to duplicate s2Tel[0,1].value. */
+ CO_RETURN2( S2DragsBehindBreak, BreakS2 );
+
+ /* Breaking s2 produces exact overlap. */
+ CO_RETURN2( S2DragsBehind, RangeOverlap );
+
+ /* Advance over the front we just broke off of range 2. */
+ s2Tel.lowKey = bottomLow;
+ s2Tel.highKey = bottomHigh;
+ s2Tel.trans = bottomTrans2;
+
+ /* Advance over the entire s1Tel. We have consumed it. */
+ s1Tel.increment();
+ }
+ else if ( s2Tel.highKey < s1Tel.highKey ) {
+ /* Range from state1 goes longer than the range from state2. We
+ * must break the range from state1 into an evenly overlaping
+ * segment. */
+ bottomLow = s2Tel.highKey;
+ bottomLow.increment();
+ bottomHigh = s1Tel.highKey;
+ s1Tel.highKey = s2Tel.highKey;
+ bottomTrans1 = s1Tel.trans;
+
+ /* Notify the caller that we are breaking s1. This gives them a
+ * chance to duplicate s2Tel[0,1].value. */
+ CO_RETURN2( S1DragsBehindBreak, BreakS1 );
+
+ /* Breaking s1 produces exact overlap. */
+ CO_RETURN2( S1DragsBehind, RangeOverlap );
+
+ /* Advance over the front we just broke off of range 1. */
+ s1Tel.lowKey = bottomLow;
+ s1Tel.highKey = bottomHigh;
+ s1Tel.trans = bottomTrans1;
+
+ /* Advance over the entire s2Tel. We have consumed it. */
+ s2Tel.increment();
+ }
+ else {
+ /* There is an exact overlap. */
+ CO_RETURN2( ExactOverlap, RangeOverlap );
+
+ s1Tel.increment();
+ s2Tel.increment();
+ }
+ }
+
+ /* Done, go into end state. */
+ CO_RETURN( End );
+}
+
+
+/* Compare lists of epsilon transitions. Entries are name ids of targets. */
+typedef CmpTable< int, CmpOrd<int> > CmpEpsilonTrans;
+
+/* Compare class for the Approximate minimization. */
+class ApproxCompare
+{
+public:
+ ApproxCompare() { }
+ int compare( const StateAp *pState1, const StateAp *pState2 );
+};
+
+/* Compare class for the initial partitioning of a partition minimization. */
+class InitPartitionCompare
+{
+public:
+ InitPartitionCompare() { }
+ int compare( const StateAp *pState1, const StateAp *pState2 );
+};
+
+/* Compare class for the regular partitioning of a partition minimization. */
+class PartitionCompare
+{
+public:
+ PartitionCompare() { }
+ int compare( const StateAp *pState1, const StateAp *pState2 );
+};
+
+/* Compare class for a minimization that marks pairs. Provides the shouldMark
+ * routine. */
+class MarkCompare
+{
+public:
+ MarkCompare() { }
+ bool shouldMark( MarkIndex &markIndex, const StateAp *pState1,
+ const StateAp *pState2 );
+};
+
+/* List of partitions. */
+typedef DList< MinPartition > PartitionList;
+
+/* List of transtions out of a state. */
+typedef Vector<TransEl> TransListVect;
+
+/* Entry point map used for keeping track of entry points in a machine. */
+typedef BstSet< int > EntryIdSet;
+typedef BstMapEl< int, StateAp* > EntryMapEl;
+typedef BstMap< int, StateAp* > EntryMap;
+typedef Vector<EntryMapEl> EntryMapBase;
+
+/* Graph class that implements actions and priorities. */
+struct FsmAp
+{
+ /* Constructors/Destructors. */
+ FsmAp( );
+ FsmAp( const FsmAp &graph );
+ ~FsmAp();
+
+ /* The list of states. */
+ StateList stateList;
+ StateList misfitList;
+
+ /* The map of entry points. */
+ EntryMap entryPoints;
+
+ /* The start state. */
+ StateAp *startState;
+
+ /* Error state, possibly created only when the final machine has been
+ * created and the XML machine is about to be written. No transitions
+ * point to this state. */
+ StateAp *errState;
+
+ /* The set of final states. */
+ StateSet finStateSet;
+
+ /* Misfit Accounting. Are misfits put on a separate list. */
+ bool misfitAccounting;
+
+ /*
+ * Transition actions and priorities.
+ */
+
+ /* Set priorities on transtions. */
+ void startFsmPrior( int ordering, PriorDesc *prior );
+ void allTransPrior( int ordering, PriorDesc *prior );
+ void finishFsmPrior( int ordering, PriorDesc *prior );
+ void leaveFsmPrior( int ordering, PriorDesc *prior );
+
+ /* Action setting support. */
+ void transferOutActions( StateAp *state );
+ void transferErrorActions( StateAp *state, int transferPoint );
+ void setErrorActions( StateAp *state, const ActionTable &other );
+ void setErrorAction( StateAp *state, int ordering, Action *action );
+
+ /* Fill all spaces in a transition list with an error transition. */
+ void fillGaps( StateAp *state );
+
+ /* Similar to setErrorAction, instead gives a state to go to on error. */
+ void setErrorTarget( StateAp *state, StateAp *target, int *orderings,
+ Action **actions, int nActs );
+
+ /* Set actions to execute. */
+ void startFsmAction( int ordering, Action *action );
+ void allTransAction( int ordering, Action *action );
+ void finishFsmAction( int ordering, Action *action );
+ void leaveFsmAction( int ordering, Action *action );
+ void longMatchAction( int ordering, LongestMatchPart *lmPart );
+
+ /* Set conditions. */
+ CondSpace *addCondSpace( const CondSet &condSet );
+
+ void findEmbedExpansions( ExpansionList &expansionList,
+ StateAp *destState, Action *condAction, bool sense );
+ void embedCondition( MergeData &md, StateAp *state, Action *condAction, bool sense );
+ void embedCondition( StateAp *state, Action *condAction, bool sense );
+
+ void startFsmCondition( Action *condAction, bool sense );
+ void allTransCondition( Action *condAction, bool sense );
+ void leaveFsmCondition( Action *condAction, bool sense );
+
+ /* Set error actions to execute. */
+ void startErrorAction( int ordering, Action *action, int transferPoint );
+ void allErrorAction( int ordering, Action *action, int transferPoint );
+ void finalErrorAction( int ordering, Action *action, int transferPoint );
+ void notStartErrorAction( int ordering, Action *action, int transferPoint );
+ void notFinalErrorAction( int ordering, Action *action, int transferPoint );
+ void middleErrorAction( int ordering, Action *action, int transferPoint );
+
+ /* Set EOF actions. */
+ void startEOFAction( int ordering, Action *action );
+ void allEOFAction( int ordering, Action *action );
+ void finalEOFAction( int ordering, Action *action );
+ void notStartEOFAction( int ordering, Action *action );
+ void notFinalEOFAction( int ordering, Action *action );
+ void middleEOFAction( int ordering, Action *action );
+
+ /* Set To State actions. */
+ void startToStateAction( int ordering, Action *action );
+ void allToStateAction( int ordering, Action *action );
+ void finalToStateAction( int ordering, Action *action );
+ void notStartToStateAction( int ordering, Action *action );
+ void notFinalToStateAction( int ordering, Action *action );
+ void middleToStateAction( int ordering, Action *action );
+
+ /* Set From State actions. */
+ void startFromStateAction( int ordering, Action *action );
+ void allFromStateAction( int ordering, Action *action );
+ void finalFromStateAction( int ordering, Action *action );
+ void notStartFromStateAction( int ordering, Action *action );
+ void notFinalFromStateAction( int ordering, Action *action );
+ void middleFromStateAction( int ordering, Action *action );
+
+ /* Shift the action ordering of the start transitions to start at
+ * fromOrder and increase in units of 1. Useful before kleene star
+ * operation. */
+ int shiftStartActionOrder( int fromOrder );
+
+ /* Clear all priorities from the fsm to so they won't affcet minimization
+ * of the final fsm. */
+ void clearAllPriorities();
+
+ /* Zero out all the function keys. */
+ void nullActionKeys();
+
+ /* Walk the list of states and verify state properties. */
+ void verifyStates();
+
+ /* Misfit Accounting. Are misfits put on a separate list. */
+ void setMisfitAccounting( bool val )
+ { misfitAccounting = val; }
+
+ /* Set and Unset a state as final. */
+ void setFinState( StateAp *state );
+ void unsetFinState( StateAp *state );
+
+ void setStartState( StateAp *state );
+ void unsetStartState( );
+
+ /* Set and unset a state as an entry point. */
+ void setEntry( int id, StateAp *state );
+ void changeEntry( int id, StateAp *to, StateAp *from );
+ void unsetEntry( int id, StateAp *state );
+ void unsetEntry( int id );
+ void unsetAllEntryPoints();
+
+ /* Epsilon transitions. */
+ void epsilonTrans( int id );
+ void shadowReadWriteStates( MergeData &md );
+
+ /*
+ * Basic attaching and detaching.
+ */
+
+ /* Common to attaching/detaching list and default. */
+ void attachToInList( StateAp *from, StateAp *to, TransAp *&head, TransAp *trans );
+ void detachFromInList( StateAp *from, StateAp *to, TransAp *&head, TransAp *trans );
+
+ /* Attach with a new transition. */
+ TransAp *attachNewTrans( StateAp *from, StateAp *to,
+ Key onChar1, Key onChar2 );
+
+ /* Attach with an existing transition that already in an out list. */
+ void attachTrans( StateAp *from, StateAp *to, TransAp *trans );
+
+ /* Redirect a transition away from error and towards some state. */
+ void redirectErrorTrans( StateAp *from, StateAp *to, TransAp *trans );
+
+ /* Detach a transition from a target state. */
+ void detachTrans( StateAp *from, StateAp *to, TransAp *trans );
+
+ /* Detach a state from the graph. */
+ void detachState( StateAp *state );
+
+ /*
+ * NFA to DFA conversion routines.
+ */
+
+ /* Duplicate a transition that will dropin to a free spot. */
+ TransAp *dupTrans( StateAp *from, TransAp *srcTrans );
+
+ /* In crossing, two transitions both go to real states. */
+ TransAp *fsmAttachStates( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans );
+
+ /* Two transitions are to be crossed, handle the possibility of either
+ * going to the error state. */
+ TransAp *mergeTrans( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans );
+
+ /* Compare deterimne relative priorities of two transition tables. */
+ int comparePrior( const PriorTable &priorTable1, const PriorTable &priorTable2 );
+
+ /* Cross a src transition with one that is already occupying a spot. */
+ TransAp *crossTransitions( MergeData &md, StateAp *from,
+ TransAp *destTrans, TransAp *srcTrans );
+
+ void outTransCopy( MergeData &md, StateAp *dest, TransAp *srcList );
+
+ void doRemove( MergeData &md, StateAp *destState, ExpansionList &expList1 );
+ void doExpand( MergeData &md, StateAp *destState, ExpansionList &expList1 );
+ void findCondExpInTrans( ExpansionList &expansionList, StateAp *state,
+ Key lowKey, Key highKey, CondSpace *fromCondSpace, CondSpace *toCondSpace,
+ long destVals, LongVect &toValsList );
+ void findTransExpansions( ExpansionList &expansionList,
+ StateAp *destState, StateAp *srcState );
+ void findCondExpansions( ExpansionList &expansionList,
+ StateAp *destState, StateAp *srcState );
+ void mergeStateConds( StateAp *destState, StateAp *srcState );
+
+ /* Merge a set of states into newState. */
+ void mergeStates( MergeData &md, StateAp *destState,
+ StateAp **srcStates, int numSrc );
+ void mergeStatesLeaving( MergeData &md, StateAp *destState, StateAp *srcState );
+ void mergeStates( MergeData &md, StateAp *destState, StateAp *srcState );
+
+ /* Make all states that are combinations of other states and that
+ * have not yet had their out transitions filled in. This will
+ * empty out stateDict and stFil. */
+ void fillInStates( MergeData &md );
+
+ /*
+ * Transition Comparison.
+ */
+
+ /* Compare transition data. Either of the pointers may be null. */
+ static inline int compareDataPtr( TransAp *trans1, TransAp *trans2 );
+
+ /* Compare target state and transition data. Either pointer may be null. */
+ static inline int compareFullPtr( TransAp *trans1, TransAp *trans2 );
+
+ /* Compare target partitions. Either pointer may be null. */
+ static inline int comparePartPtr( TransAp *trans1, TransAp *trans2 );
+
+ /* Check marked status of target states. Either pointer may be null. */
+ static inline bool shouldMarkPtr( MarkIndex &markIndex,
+ TransAp *trans1, TransAp *trans2 );
+
+ /*
+ * Callbacks.
+ */
+
+ /* Compare priority and function table of transitions. */
+ static int compareTransData( TransAp *trans1, TransAp *trans2 );
+
+ /* Add in the properties of srcTrans into this. */
+ void addInTrans( TransAp *destTrans, TransAp *srcTrans );
+
+ /* Compare states on data stored in the states. */
+ static int compareStateData( const StateAp *state1, const StateAp *state2 );
+
+ /* Out transition data. */
+ void clearOutData( StateAp *state );
+ bool hasOutData( StateAp *state );
+ void transferOutData( StateAp *destState, StateAp *srcState );
+
+ /*
+ * Allocation.
+ */
+
+ /* New up a state and add it to the graph. */
+ StateAp *addState();
+
+ /*
+ * Building basic machines
+ */
+
+ void concatFsm( Key c );
+ void concatFsm( Key *str, int len );
+ void concatFsmCI( Key *str, int len );
+ void orFsm( Key *set, int len );
+ void rangeFsm( Key low, Key high );
+ void rangeStarFsm( Key low, Key high );
+ void emptyFsm( );
+ void lambdaFsm( );
+
+ /*
+ * Fsm operators.
+ */
+
+ void starOp( );
+ void repeatOp( int times );
+ void optionalRepeatOp( int times );
+ void concatOp( FsmAp *other );
+ void unionOp( FsmAp *other );
+ void intersectOp( FsmAp *other );
+ void subtractOp( FsmAp *other );
+ void epsilonOp();
+ void joinOp( int startId, int finalId, FsmAp **others, int numOthers );
+ void globOp( FsmAp **others, int numOthers );
+ void deterministicEntry();
+
+ /*
+ * Operator workers
+ */
+
+ /* Determine if there are any entry points into a start state other than
+ * the start state. */
+ bool isStartStateIsolated();
+
+ /* Make a new start state that has no entry points. Will not change the
+ * identity of the fsm. */
+ void isolateStartState();
+
+ /* Workers for resolving epsilon transitions. */
+ bool inEptVect( EptVect *eptVect, StateAp *targ );
+ void epsilonFillEptVectFrom( StateAp *root, StateAp *from, bool parentLeaving );
+ void resolveEpsilonTrans( MergeData &md );
+
+ /* Workers for concatenation and union. */
+ void doConcat( FsmAp *other, StateSet *fromStates, bool optional );
+ void doOr( FsmAp *other );
+
+ /*
+ * Final states
+ */
+
+ /* Unset any final states that are no longer to be final
+ * due to final bits. */
+ void unsetIncompleteFinals();
+ void unsetKilledFinals();
+
+ /* Bring in other's entry points. Assumes others states are going to be
+ * copied into this machine. */
+ void copyInEntryPoints( FsmAp *other );
+
+ /* Ordering states. */
+ void depthFirstOrdering( StateAp *state );
+ void depthFirstOrdering();
+ void sortStatesByFinal();
+
+ /* Set sqequential state numbers starting at 0. */
+ void setStateNumbers( int base );
+
+ /* Unset all final states. */
+ void unsetAllFinStates();
+
+ /* Set the bits of final states and clear the bits of non final states. */
+ void setFinBits( int finStateBits );
+
+ /*
+ * Self-consistency checks.
+ */
+
+ /* Run a sanity check on the machine. */
+ void verifyIntegrity();
+
+ /* Verify that there are no unreachable states, or dead end states. */
+ void verifyReachability();
+ void verifyNoDeadEndStates();
+
+ /*
+ * Path pruning
+ */
+
+ /* Mark all states reachable from state. */
+ void markReachableFromHereReverse( StateAp *state );
+
+ /* Mark all states reachable from state. */
+ void markReachableFromHere( StateAp *state );
+ void markReachableFromHereStopFinal( StateAp *state );
+
+ /* Removes states that cannot be reached by any path in the fsm and are
+ * thus wasted silicon. */
+ void removeDeadEndStates();
+
+ /* Removes states that cannot be reached by any path in the fsm and are
+ * thus wasted silicon. */
+ void removeUnreachableStates();
+
+ /* Remove error actions from states on which the error transition will
+ * never be taken. */
+ bool outListCovers( StateAp *state );
+ bool anyErrorRange( StateAp *state );
+
+ /* Remove states that are on the misfit list. */
+ void removeMisfits();
+
+ /*
+ * FSM Minimization
+ */
+
+ /* Minimization by partitioning. */
+ void minimizePartition1();
+ void minimizePartition2();
+
+ /* Minimize the final state Machine. The result is the minimal fsm. Slow
+ * but stable, correct minimization. Uses n^2 space (lookout) and average
+ * n^2 time. Worst case n^3 time, but a that is a very rare case. */
+ void minimizeStable();
+
+ /* Minimize the final state machine. Does not find the minimal fsm, but a
+ * pretty good approximation. Does not use any extra space. Average n^2
+ * time. Worst case n^3 time, but a that is a very rare case. */
+ void minimizeApproximate();
+
+ /* This is the worker for the minimize approximate solution. It merges
+ * states that have identical out transitions. */
+ bool minimizeRound( );
+
+ /* Given an intial partioning of states, split partitions that have out trans
+ * to differing partitions. */
+ int partitionRound( StateAp **statePtrs, MinPartition *parts, int numParts );
+
+ /* Split partitions that have a transition to a previously split partition, until
+ * there are no more partitions to split. */
+ int splitCandidates( StateAp **statePtrs, MinPartition *parts, int numParts );
+
+ /* Fuse together states in the same partition. */
+ void fusePartitions( MinPartition *parts, int numParts );
+
+ /* Mark pairs where out final stateness differs, out trans data differs,
+ * trans pairs go to a marked pair or trans data differs. Should get
+ * alot of pairs. */
+ void initialMarkRound( MarkIndex &markIndex );
+
+ /* One marking round on all state pairs. Considers if trans pairs go
+ * to a marked state only. Returns whether or not a pair was marked. */
+ bool markRound( MarkIndex &markIndex );
+
+ /* Move the in trans into src into dest. */
+ void inTransMove(StateAp *dest, StateAp *src);
+
+ /* Make state src and dest the same state. */
+ void fuseEquivStates(StateAp *dest, StateAp *src);
+
+ /* Find any states that didn't get marked by the marking algorithm and
+ * merge them into the primary states of their equivalence class. */
+ void fuseUnmarkedPairs( MarkIndex &markIndex );
+
+ /* Merge neighboring transitions go to the same state and have the same
+ * transitions data. */
+ void compressTransitions();
+
+ /* Returns true if there is a transtion (either explicit or by a gap) to
+ * the error state. */
+ bool checkErrTrans( StateAp *state, TransAp *trans );
+ bool checkErrTransFinish( StateAp *state );
+ bool hasErrorTrans();
+
+ /* Check if a machine defines a single character. This is useful in
+ * validating ranges and machines to export. */
+ bool checkSingleCharMachine( );
+};
+
+#endif
diff --git a/ragel/fsmmin.cpp b/ragel/fsmmin.cpp
new file mode 100644
index 0000000..42ebfaa
--- /dev/null
+++ b/ragel/fsmmin.cpp
@@ -0,0 +1,732 @@
+/*
+ * Copyright 2002 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 "fsmgraph.h"
+#include "mergesort.h"
+
+int FsmAp::partitionRound( StateAp **statePtrs, MinPartition *parts, int numParts )
+{
+ /* Need a mergesort object and a single partition compare. */
+ MergeSort<StateAp*, PartitionCompare> mergeSort;
+ PartitionCompare partCompare;
+
+ /* For each partition. */
+ for ( int p = 0; p < numParts; p++ ) {
+ /* Fill the pointer array with the states in the partition. */
+ StateList::Iter state = parts[p].list;
+ for ( int s = 0; state.lte(); state++, s++ )
+ statePtrs[s] = state;
+
+ /* Sort the states using the partitioning compare. */
+ int numStates = parts[p].list.length();
+ mergeSort.sort( statePtrs, numStates );
+
+ /* Assign the states into partitions based on the results of the sort. */
+ int destPart = p, firstNewPart = numParts;
+ for ( int s = 1; s < numStates; s++ ) {
+ /* If this state differs from the last then move to the next partition. */
+ if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
+ /* The new partition is the next avail spot. */
+ destPart = numParts;
+ numParts += 1;
+ }
+
+ /* If the state is not staying in the first partition, then
+ * transfer it to its destination partition. */
+ if ( destPart != p ) {
+ StateAp *state = parts[p].list.detach( statePtrs[s] );
+ parts[destPart].list.append( state );
+ }
+ }
+
+ /* Fix the partition pointer for all the states that got moved to a new
+ * partition. This must be done after the states are transfered so the
+ * result of the sort is not altered. */
+ for ( int newPart = firstNewPart; newPart < numParts; newPart++ ) {
+ StateList::Iter state = parts[newPart].list;
+ for ( ; state.lte(); state++ )
+ state->alg.partition = &parts[newPart];
+ }
+ }
+
+ return numParts;
+}
+
+/**
+ * \brief Minimize by partitioning version 1.
+ *
+ * Repeatedly tries to split partitions until all partitions are unsplittable.
+ * Produces the most minimal FSM possible.
+ */
+void FsmAp::minimizePartition1()
+{
+ /* Need one mergesort object and partition compares. */
+ MergeSort<StateAp*, InitPartitionCompare> mergeSort;
+ InitPartitionCompare initPartCompare;
+
+ /* Nothing to do if there are no states. */
+ if ( stateList.length() == 0 )
+ return;
+
+ /*
+ * First thing is to partition the states by final state status and
+ * transition functions. This gives us an initial partitioning to work
+ * with.
+ */
+
+ /* Make a array of pointers to states. */
+ int numStates = stateList.length();
+ StateAp** statePtrs = new StateAp*[numStates];
+
+ /* Fill up an array of pointers to the states for easy sorting. */
+ StateList::Iter state = stateList;
+ for ( int s = 0; state.lte(); state++, s++ )
+ statePtrs[s] = state;
+
+ /* Sort the states using the array of states. */
+ mergeSort.sort( statePtrs, numStates );
+
+ /* An array of lists of states is used to partition the states. */
+ MinPartition *parts = new MinPartition[numStates];
+
+ /* Assign the states into partitions. */
+ int destPart = 0;
+ for ( int s = 0; s < numStates; s++ ) {
+ /* If this state differs from the last then move to the next partition. */
+ if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
+ /* Move to the next partition. */
+ destPart += 1;
+ }
+
+ /* Put the state into its partition. */
+ statePtrs[s]->alg.partition = &parts[destPart];
+ parts[destPart].list.append( statePtrs[s] );
+ }
+
+ /* We just moved all the states from the main list into partitions without
+ * taking them off the main list. So clean up the main list now. */
+ stateList.abandon();
+
+ /* Split partitions. */
+ int numParts = destPart + 1;
+ while ( true ) {
+ /* Test all partitions for splitting. */
+ int newNum = partitionRound( statePtrs, parts, numParts );
+
+ /* When no partitions can be split, stop. */
+ if ( newNum == numParts )
+ break;
+
+ numParts = newNum;
+ }
+
+ /* Fuse states in the same partition. The states will end up back on the
+ * main list. */
+ fusePartitions( parts, numParts );
+
+ /* Cleanup. */
+ delete[] statePtrs;
+ delete[] parts;
+}
+
+/* Split partitions that need splittting, decide which partitions might need
+ * to be split as a result, continue until there are no more that might need
+ * to be split. */
+int FsmAp::splitCandidates( StateAp **statePtrs, MinPartition *parts, int numParts )
+{
+ /* Need a mergesort and a partition compare. */
+ MergeSort<StateAp*, PartitionCompare> mergeSort;
+ PartitionCompare partCompare;
+
+ /* The lists of unsplitable (partList) and splitable partitions.
+ * Only partitions in the splitable list are check for needing splitting. */
+ PartitionList partList, splittable;
+
+ /* Initially, all partitions are born from a split (the initial
+ * partitioning) and can cause other partitions to be split. So any
+ * partition with a state with a transition out to another partition is a
+ * candidate for splitting. This will make every partition except possibly
+ * partitions of final states split candidates. */
+ for ( int p = 0; p < numParts; p++ ) {
+ /* Assume not active. */
+ parts[p].active = false;
+
+ /* Look for a trans out of any state in the partition. */
+ for ( StateList::Iter state = parts[p].list; state.lte(); state++ ) {
+ /* If there is at least one transition out to another state then
+ * the partition becomes splittable. */
+ if ( state->outList.length() > 0 ) {
+ parts[p].active = true;
+ break;
+ }
+ }
+
+ /* If it was found active then it goes on the splittable list. */
+ if ( parts[p].active )
+ splittable.append( &parts[p] );
+ else
+ partList.append( &parts[p] );
+ }
+
+ /* While there are partitions that are splittable, pull one off and try
+ * to split it. If it splits, determine which partitions may now be split
+ * as a result of the newly split partition. */
+ while ( splittable.length() > 0 ) {
+ MinPartition *partition = splittable.detachFirst();
+
+ /* Fill the pointer array with the states in the partition. */
+ StateList::Iter state = partition->list;
+ for ( int s = 0; state.lte(); state++, s++ )
+ statePtrs[s] = state;
+
+ /* Sort the states using the partitioning compare. */
+ int numStates = partition->list.length();
+ mergeSort.sort( statePtrs, numStates );
+
+ /* Assign the states into partitions based on the results of the sort. */
+ MinPartition *destPart = partition;
+ int firstNewPart = numParts;
+ for ( int s = 1; s < numStates; s++ ) {
+ /* If this state differs from the last then move to the next partition. */
+ if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
+ /* The new partition is the next avail spot. */
+ destPart = &parts[numParts];
+ numParts += 1;
+ }
+
+ /* If the state is not staying in the first partition, then
+ * transfer it to its destination partition. */
+ if ( destPart != partition ) {
+ StateAp *state = partition->list.detach( statePtrs[s] );
+ destPart->list.append( state );
+ }
+ }
+
+ /* Fix the partition pointer for all the states that got moved to a new
+ * partition. This must be done after the states are transfered so the
+ * result of the sort is not altered. */
+ int newPart;
+ for ( newPart = firstNewPart; newPart < numParts; newPart++ ) {
+ StateList::Iter state = parts[newPart].list;
+ for ( ; state.lte(); state++ )
+ state->alg.partition = &parts[newPart];
+ }
+
+ /* Put the partition we just split and any new partitions that came out
+ * of the split onto the inactive list. */
+ partition->active = false;
+ partList.append( partition );
+ for ( newPart = firstNewPart; newPart < numParts; newPart++ ) {
+ parts[newPart].active = false;
+ partList.append( &parts[newPart] );
+ }
+
+ if ( destPart == partition )
+ continue;
+
+ /* Now determine which partitions are splittable as a result of
+ * splitting partition by walking the in lists of the states in
+ * partitions that got split. Partition is the faked first item in the
+ * loop. */
+ MinPartition *causalPart = partition;
+ newPart = firstNewPart - 1;
+ while ( newPart < numParts ) {
+ /* Loop all states in the causal partition. */
+ StateList::Iter state = causalPart->list;
+ for ( ; state.lte(); state++ ) {
+ /* Walk all transition into the state and put the partition
+ * that the from state is in onto the splittable list. */
+ for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ ) {
+ MinPartition *fromPart = trans->fromState->alg.partition;
+ if ( ! fromPart->active ) {
+ fromPart->active = true;
+ partList.detach( fromPart );
+ splittable.append( fromPart );
+ }
+ }
+ }
+
+ newPart += 1;
+ causalPart = &parts[newPart];
+ }
+ }
+ return numParts;
+}
+
+
+/**
+ * \brief Minimize by partitioning version 2 (best alg).
+ *
+ * Repeatedly tries to split partitions that may splittable until there are no
+ * more partitions that might possibly need splitting. Runs faster than
+ * version 1. Produces the most minimal fsm possible.
+ */
+void FsmAp::minimizePartition2()
+{
+ /* Need a mergesort and an initial partition compare. */
+ MergeSort<StateAp*, InitPartitionCompare> mergeSort;
+ InitPartitionCompare initPartCompare;
+
+ /* Nothing to do if there are no states. */
+ if ( stateList.length() == 0 )
+ return;
+
+ /*
+ * First thing is to partition the states by final state status and
+ * transition functions. This gives us an initial partitioning to work
+ * with.
+ */
+
+ /* Make a array of pointers to states. */
+ int numStates = stateList.length();
+ StateAp** statePtrs = new StateAp*[numStates];
+
+ /* Fill up an array of pointers to the states for easy sorting. */
+ StateList::Iter state = stateList;
+ for ( int s = 0; state.lte(); state++, s++ )
+ statePtrs[s] = state;
+
+ /* Sort the states using the array of states. */
+ mergeSort.sort( statePtrs, numStates );
+
+ /* An array of lists of states is used to partition the states. */
+ MinPartition *parts = new MinPartition[numStates];
+
+ /* Assign the states into partitions. */
+ int destPart = 0;
+ for ( int s = 0; s < numStates; s++ ) {
+ /* If this state differs from the last then move to the next partition. */
+ if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) {
+ /* Move to the next partition. */
+ destPart += 1;
+ }
+
+ /* Put the state into its partition. */
+ statePtrs[s]->alg.partition = &parts[destPart];
+ parts[destPart].list.append( statePtrs[s] );
+ }
+
+ /* We just moved all the states from the main list into partitions without
+ * taking them off the main list. So clean up the main list now. */
+ stateList.abandon();
+
+ /* Split partitions. */
+ int numParts = splitCandidates( statePtrs, parts, destPart+1 );
+
+ /* Fuse states in the same partition. The states will end up back on the
+ * main list. */
+ fusePartitions( parts, numParts );
+
+ /* Cleanup. */
+ delete[] statePtrs;
+ delete[] parts;
+}
+
+void FsmAp::initialMarkRound( MarkIndex &markIndex )
+{
+ /* P and q for walking pairs. */
+ StateAp *p = stateList.head, *q;
+
+ /* Need an initial partition compare. */
+ InitPartitionCompare initPartCompare;
+
+ /* Walk all unordered pairs of (p, q) where p != q.
+ * The second depth of the walk stops before reaching p. This
+ * gives us all unordered pairs of states (p, q) where p != q. */
+ while ( p != 0 ) {
+ q = stateList.head;
+ while ( q != p ) {
+ /* If the states differ on final state status, out transitions or
+ * any transition data then they should be separated on the initial
+ * round. */
+ if ( initPartCompare.compare( p, q ) != 0 )
+ markIndex.markPair( p->alg.stateNum, q->alg.stateNum );
+
+ q = q->next;
+ }
+ p = p->next;
+ }
+}
+
+bool FsmAp::markRound( MarkIndex &markIndex )
+{
+ /* P an q for walking pairs. Take note if any pair gets marked. */
+ StateAp *p = stateList.head, *q;
+ bool pairWasMarked = false;
+
+ /* Need a mark comparison. */
+ MarkCompare markCompare;
+
+ /* Walk all unordered pairs of (p, q) where p != q.
+ * The second depth of the walk stops before reaching p. This
+ * gives us all unordered pairs of states (p, q) where p != q. */
+ while ( p != 0 ) {
+ q = stateList.head;
+ while ( q != p ) {
+ /* Should we mark the pair? */
+ if ( !markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) {
+ if ( markCompare.shouldMark( markIndex, p, q ) ) {
+ markIndex.markPair( p->alg.stateNum, q->alg.stateNum );
+ pairWasMarked = true;
+ }
+ }
+ q = q->next;
+ }
+ p = p->next;
+ }
+
+ return pairWasMarked;
+}
+
+
+/**
+ * \brief Minimize by pair marking.
+ *
+ * Decides if each pair of states is distinct or not. Uses O(n^2) memory and
+ * should only be used on small graphs. Produces the most minmimal FSM
+ * possible.
+ */
+void FsmAp::minimizeStable()
+{
+ /* Set the state numbers. */
+ setStateNumbers( 0 );
+
+ /* This keeps track of which pairs have been marked. */
+ MarkIndex markIndex( stateList.length() );
+
+ /* Mark pairs where final stateness, out trans, or trans data differ. */
+ initialMarkRound( markIndex );
+
+ /* While the last round of marking succeeded in marking a state
+ * continue to do another round. */
+ int modified = markRound( markIndex );
+ while (modified)
+ modified = markRound( markIndex );
+
+ /* Merge pairs that are unmarked. */
+ fuseUnmarkedPairs( markIndex );
+}
+
+bool FsmAp::minimizeRound()
+{
+ /* Nothing to do if there are no states. */
+ if ( stateList.length() == 0 )
+ return false;
+
+ /* Need a mergesort on approx compare and an approx compare. */
+ MergeSort<StateAp*, ApproxCompare> mergeSort;
+ ApproxCompare approxCompare;
+
+ /* Fill up an array of pointers to the states. */
+ StateAp **statePtrs = new StateAp*[stateList.length()];
+ StateList::Iter state = stateList;
+ for ( int s = 0; state.lte(); state++, s++ )
+ statePtrs[s] = state;
+
+ bool modified = false;
+
+ /* Sort The list. */
+ mergeSort.sort( statePtrs, stateList.length() );
+
+ /* Walk the list looking for duplicates next to each other,
+ * merge in any duplicates. */
+ StateAp **pLast = statePtrs;
+ StateAp **pState = statePtrs + 1;
+ for ( int i = 1; i < stateList.length(); i++, pState++ ) {
+ if ( approxCompare.compare( *pLast, *pState ) == 0 ) {
+ /* Last and pState are the same, so fuse together. Move forward
+ * with pState but not with pLast. If any more are identical, we
+ * must */
+ fuseEquivStates( *pLast, *pState );
+ modified = true;
+ }
+ else {
+ /* Last and this are different, do not set to merge them. Move
+ * pLast to the current (it may be way behind from merging many
+ * states) and pState forward one to consider the next pair. */
+ pLast = pState;
+ }
+ }
+ delete[] statePtrs;
+ return modified;
+}
+
+/**
+ * \brief Minmimize by an approximation.
+ *
+ * Repeatedly tries to find states with transitions out to the same set of
+ * states on the same set of keys until no more identical states can be found.
+ * Does not produce the most minimial FSM possible.
+ */
+void FsmAp::minimizeApproximate()
+{
+ /* While the last minimization round succeeded in compacting states,
+ * continue to try to compact states. */
+ while ( true ) {
+ bool modified = minimizeRound();
+ if ( ! modified )
+ break;
+ }
+}
+
+
+/* Remove states that have no path to them from the start state. Recursively
+ * traverses the graph marking states that have paths into them. Then removes
+ * all states that did not get marked. */
+void FsmAp::removeUnreachableStates()
+{
+ /* Misfit accounting should be off and there should be no states on the
+ * misfit list. */
+ assert( !misfitAccounting && misfitList.length() == 0 );
+
+ /* Mark all the states that can be reached
+ * through the existing set of entry points. */
+ markReachableFromHere( startState );
+ for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
+ markReachableFromHere( en->value );
+
+ /* Delete all states that are not marked
+ * and unmark the ones that are marked. */
+ StateAp *state = stateList.head;
+ while ( state ) {
+ StateAp *next = state->next;
+
+ if ( state->stateBits & STB_ISMARKED )
+ state->stateBits &= ~ STB_ISMARKED;
+ else {
+ detachState( state );
+ stateList.detach( state );
+ delete state;
+ }
+
+ state = next;
+ }
+}
+
+bool FsmAp::outListCovers( StateAp *state )
+{
+ /* Must be at least one range to cover. */
+ if ( state->outList.length() == 0 )
+ return false;
+
+ /* The first must start at the lower bound. */
+ TransList::Iter trans = state->outList.first();
+ if ( keyOps->minKey < trans->lowKey )
+ return false;
+
+ /* Loop starts at second el. */
+ trans.increment();
+
+ /* Loop checks lower against prev upper. */
+ for ( ; trans.lte(); trans++ ) {
+ /* Lower end of the trans must be one greater than the
+ * previous' high end. */
+ Key lowKey = trans->lowKey;
+ lowKey.decrement();
+ if ( trans->prev->highKey < lowKey )
+ return false;
+ }
+
+ /* Require that the last range extends to the upper bound. */
+ trans = state->outList.last();
+ if ( trans->highKey < keyOps->maxKey )
+ return false;
+
+ return true;
+}
+
+/* Remove states that that do not lead to a final states. Works recursivly traversing
+ * the graph in reverse (starting from all final states) and marking seen states. Then
+ * removes states that did not get marked. */
+void FsmAp::removeDeadEndStates()
+{
+ /* Misfit accounting should be off and there should be no states on the
+ * misfit list. */
+ assert( !misfitAccounting && misfitList.length() == 0 );
+
+ /* Mark all states that have paths to the final states. */
+ StateAp **st = finStateSet.data;
+ int nst = finStateSet.length();
+ for ( int i = 0; i < nst; i++, st++ )
+ markReachableFromHereReverse( *st );
+
+ /* Start state gets honorary marking. If the machine accepts nothing we
+ * still want the start state to hang around. This must be done after the
+ * recursive call on all the final states so that it does not cause the
+ * start state in transitions to be skipped when the start state is
+ * visited by the traversal. */
+ startState->stateBits |= STB_ISMARKED;
+
+ /* Delete all states that are not marked
+ * and unmark the ones that are marked. */
+ StateAp *state = stateList.head;
+ while ( state != 0 ) {
+ StateAp *next = state->next;
+
+ if ( state->stateBits & STB_ISMARKED )
+ state->stateBits &= ~ STB_ISMARKED;
+ else {
+ detachState( state );
+ stateList.detach( state );
+ delete state;
+ }
+
+ state = next;
+ }
+}
+
+/* Remove states on the misfit list. To work properly misfit accounting should
+ * be on when this is called. The detaching of a state will likely cause
+ * another misfit to be collected and it can then be removed. */
+void FsmAp::removeMisfits()
+{
+ while ( misfitList.length() > 0 ) {
+ /* Get the first state. */
+ StateAp *state = misfitList.head;
+
+ /* Detach and delete. */
+ detachState( state );
+
+ /* The state was previously on the misfit list and detaching can only
+ * remove in transitions so the state must still be on the misfit
+ * list. */
+ misfitList.detach( state );
+ delete state;
+ }
+}
+
+/* Fuse src into dest because they have been deemed equivalent states.
+ * Involves moving transitions into src to go into dest and invoking
+ * callbacks. Src is deleted detached from the graph and deleted. */
+void FsmAp::fuseEquivStates( StateAp *dest, StateAp *src )
+{
+ /* This would get ugly. */
+ assert( dest != src );
+
+ /* Cur is a duplicate. We can merge it with trail. */
+ inTransMove( dest, src );
+
+ detachState( src );
+ stateList.detach( src );
+ delete src;
+}
+
+void FsmAp::fuseUnmarkedPairs( MarkIndex &markIndex )
+{
+ StateAp *p = stateList.head, *nextP, *q;
+
+ /* Definition: The primary state of an equivalence class is the first state
+ * encounterd that belongs to the equivalence class. All equivalence
+ * classes have primary state including equivalence classes with one state
+ * in it. */
+
+ /* For each unmarked pair merge p into q and delete p. q is always the
+ * primary state of it's equivalence class. We wouldn't have landed on it
+ * here if it were not, because it would have been deleted.
+ *
+ * Proof that q is the primaray state of it's equivalence class: Assume q
+ * is not the primary state of it's equivalence class, then it would be
+ * merged into some state that came before it and thus p would be
+ * equivalent to that state. But q is the first state that p is equivalent
+ * to so we have a contradiction. */
+
+ /* Walk all unordered pairs of (p, q) where p != q.
+ * The second depth of the walk stops before reaching p. This
+ * gives us all unordered pairs of states (p, q) where p != q. */
+ while ( p != 0 ) {
+ nextP = p->next;
+
+ q = stateList.head;
+ while ( q != p ) {
+ /* If one of p or q is a final state then mark. */
+ if ( ! markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) {
+ fuseEquivStates( q, p );
+ break;
+ }
+ q = q->next;
+ }
+ p = nextP;
+ }
+}
+
+void FsmAp::fusePartitions( MinPartition *parts, int numParts )
+{
+ /* For each partition, fuse state 2, 3, ... into state 1. */
+ for ( int p = 0; p < numParts; p++ ) {
+ /* Assume that there will always be at least one state. */
+ StateAp *first = parts[p].list.head, *toFuse = first->next;
+
+ /* Put the first state back onto the main state list. Don't bother
+ * removing it from the partition list first. */
+ stateList.append( first );
+
+ /* Fuse the rest of the state into the first. */
+ while ( toFuse != 0 ) {
+ /* Save the next. We will trash it before it is needed. */
+ StateAp *next = toFuse->next;
+
+ /* Put the state to be fused in to the first back onto the main
+ * list before it is fuse. the graph. The state needs to be on
+ * the main list for the detach from the graph to work. Don't
+ * bother removing the state from the partition list first. We
+ * need not maintain it. */
+ stateList.append( toFuse );
+
+ /* Now fuse to the first. */
+ fuseEquivStates( first, toFuse );
+
+ /* Go to the next that we saved before trashing the next pointer. */
+ toFuse = next;
+ }
+
+ /* We transfered the states from the partition list into the main list without
+ * removing the states from the partition list first. Clean it up. */
+ parts[p].list.abandon();
+ }
+}
+
+
+/* Merge neighboring transitions go to the same state and have the same
+ * transitions data. */
+void FsmAp::compressTransitions()
+{
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ if ( st->outList.length() > 1 ) {
+ for ( TransList::Iter trans = st->outList, next = trans.next(); next.lte(); ) {
+ Key nextLow = next->lowKey;
+ nextLow.decrement();
+ if ( trans->highKey == nextLow && trans->toState == next->toState &&
+ CmpActionTable::compare( trans->actionTable, next->actionTable ) == 0 )
+ {
+ trans->highKey = next->highKey;
+ st->outList.detach( next );
+ detachTrans( next->fromState, next->toState, next );
+ delete next;
+ next = trans.next();
+ }
+ else {
+ trans.increment();
+ next.increment();
+ }
+ }
+ }
+ }
+}
diff --git a/ragel/fsmstate.cpp b/ragel/fsmstate.cpp
new file mode 100644
index 0000000..63c48e9
--- /dev/null
+++ b/ragel/fsmstate.cpp
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2002 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 <string.h>
+#include <assert.h>
+#include "fsmgraph.h"
+
+#include <iostream>
+using namespace std;
+
+/* Construct a mark index for a specified number of states. Must new up
+ * an array that is states^2 in size. */
+MarkIndex::MarkIndex( int states ) : numStates(states)
+{
+ /* Total pairs is states^2. Actually only use half of these, but we allocate
+ * them all to make indexing into the array easier. */
+ int total = states * states;
+
+ /* New up chars so that individual DListEl constructors are
+ * not called. Zero out the mem manually. */
+ array = new bool[total];
+ memset( array, 0, sizeof(bool) * total );
+}
+
+/* Free the array used to store state pairs. */
+MarkIndex::~MarkIndex()
+{
+ delete[] array;
+}
+
+/* Mark a pair of states. States are specified by their number. The
+ * marked states are moved from the unmarked list to the marked list. */
+void MarkIndex::markPair(int state1, int state2)
+{
+ int pos = ( state1 >= state2 ) ?
+ ( state1 * numStates ) + state2 :
+ ( state2 * numStates ) + state1;
+
+ array[pos] = true;
+}
+
+/* Returns true if the pair of states are marked. Returns false otherwise.
+ * Ordering of states given does not matter. */
+bool MarkIndex::isPairMarked(int state1, int state2)
+{
+ int pos = ( state1 >= state2 ) ?
+ ( state1 * numStates ) + state2 :
+ ( state2 * numStates ) + state1;
+
+ return array[pos];
+}
+
+/* Create a new fsm state. State has not out transitions or in transitions, not
+ * out out transition data and not number. */
+StateAp::StateAp()
+:
+ /* No out or in transitions. */
+ outList(),
+ inList(),
+
+ /* No EOF target. */
+ eofTarget(0),
+
+ /* No entry points, or epsilon trans. */
+ entryIds(),
+ epsilonTrans(),
+
+ /* Conditions. */
+ stateCondList(),
+
+ /* No transitions in from other states. */
+ foreignInTrans(0),
+
+ /* Only used during merging. Normally null. */
+ stateDictEl(0),
+ eptVect(0),
+
+ /* No state identification bits. */
+ stateBits(0),
+
+ /* No Priority data. */
+ outPriorTable(),
+
+ /* No Action data. */
+ toStateActionTable(),
+ fromStateActionTable(),
+ outActionTable(),
+ outCondSet(),
+ errActionTable(),
+ eofActionTable()
+{
+}
+
+/* Copy everything except actual the transitions. That is left up to the
+ * FsmAp copy constructor. */
+StateAp::StateAp(const StateAp &other)
+:
+ /* All lists are cleared. They will be filled in when the
+ * individual transitions are duplicated and attached. */
+ outList(),
+ inList(),
+
+ /* Set this using the original state's eofTarget. It will get mapped back
+ * to the new machine in the Fsm copy constructor. */
+ eofTarget(other.eofTarget),
+
+ /* Duplicate the entry id set and epsilon transitions. These
+ * are sets of integers and as such need no fixing. */
+ entryIds(other.entryIds),
+ epsilonTrans(other.epsilonTrans),
+
+ /* Copy in the elements of the conditions. */
+ stateCondList( other.stateCondList ),
+
+ /* No transitions in from other states. */
+ foreignInTrans(0),
+
+ /* This is only used during merging. Normally null. */
+ stateDictEl(0),
+ eptVect(0),
+
+ /* Fsm state data. */
+ stateBits(other.stateBits),
+
+ /* Copy in priority data. */
+ outPriorTable(other.outPriorTable),
+
+ /* Copy in action data. */
+ toStateActionTable(other.toStateActionTable),
+ fromStateActionTable(other.fromStateActionTable),
+ outActionTable(other.outActionTable),
+ outCondSet(other.outCondSet),
+ errActionTable(other.errActionTable),
+ eofActionTable(other.eofActionTable)
+{
+ /* Duplicate all the transitions. */
+ for ( TransList::Iter trans = other.outList; trans.lte(); trans++ ) {
+ /* Dupicate and store the orginal target in the transition. This will
+ * be corrected once all the states have been created. */
+ TransAp *newTrans = new TransAp(*trans);
+ assert( trans->lmActionTable.length() == 0 );
+ newTrans->toState = trans->toState;
+ outList.append( newTrans );
+ }
+}
+
+/* If there is a state dict element, then delete it. Everything else is left
+ * up to the FsmGraph destructor. */
+StateAp::~StateAp()
+{
+ if ( stateDictEl != 0 )
+ delete stateDictEl;
+}
+
+/* Compare two states using pointers to the states. With the approximate
+ * compare, the idea is that if the compare finds them the same, they can
+ * immediately be merged. */
+int ApproxCompare::compare( const StateAp *state1, const StateAp *state2 )
+{
+ int compareRes;
+
+ /* Test final state status. */
+ if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) )
+ return -1;
+ else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) )
+ return 1;
+
+ /* Test epsilon transition sets. */
+ compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans,
+ state2->epsilonTrans );
+ if ( compareRes != 0 )
+ return compareRes;
+
+ /* Compare the out transitions. */
+ compareRes = FsmAp::compareStateData( state1, state2 );
+ if ( compareRes != 0 )
+ return compareRes;
+
+ /* Use a pair iterator to get the transition pairs. */
+ PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
+ for ( ; !outPair.end(); outPair++ ) {
+ switch ( outPair.userState ) {
+
+ case RangeInS1:
+ compareRes = FsmAp::compareFullPtr( outPair.s1Tel.trans, 0 );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeInS2:
+ compareRes = FsmAp::compareFullPtr( 0, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeOverlap:
+ compareRes = FsmAp::compareFullPtr(
+ outPair.s1Tel.trans, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case BreakS1:
+ case BreakS2:
+ break;
+ }
+ }
+
+ /* Check EOF targets. */
+ if ( state1->eofTarget < state2->eofTarget )
+ return -1;
+ else if ( state1->eofTarget > state2->eofTarget )
+ return 1;
+
+ /* Got through the entire state comparison, deem them equal. */
+ return 0;
+}
+
+/* Compare class used in the initial partition. */
+int InitPartitionCompare::compare( const StateAp *state1 , const StateAp *state2 )
+{
+ int compareRes;
+
+ /* Test final state status. */
+ if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) )
+ return -1;
+ else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) )
+ return 1;
+
+ /* Test epsilon transition sets. */
+ compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans,
+ state2->epsilonTrans );
+ if ( compareRes != 0 )
+ return compareRes;
+
+ /* Compare the out transitions. */
+ compareRes = FsmAp::compareStateData( state1, state2 );
+ if ( compareRes != 0 )
+ return compareRes;
+
+ /* Use a pair iterator to test the condition pairs. */
+ PairIter<StateCond> condPair( state1->stateCondList.head, state2->stateCondList.head );
+ for ( ; !condPair.end(); condPair++ ) {
+ switch ( condPair.userState ) {
+ case RangeInS1:
+ return 1;
+ case RangeInS2:
+ return -1;
+
+ case RangeOverlap: {
+ CondSpace *condSpace1 = condPair.s1Tel.trans->condSpace;
+ CondSpace *condSpace2 = condPair.s2Tel.trans->condSpace;
+ if ( condSpace1 < condSpace2 )
+ return -1;
+ else if ( condSpace1 > condSpace2 )
+ return 1;
+ break;
+ }
+ case BreakS1:
+ case BreakS2:
+ break;
+ }
+ }
+
+ /* Use a pair iterator to test the transition pairs. */
+ PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
+ for ( ; !outPair.end(); outPair++ ) {
+ switch ( outPair.userState ) {
+
+ case RangeInS1:
+ compareRes = FsmAp::compareDataPtr( outPair.s1Tel.trans, 0 );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeInS2:
+ compareRes = FsmAp::compareDataPtr( 0, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeOverlap:
+ compareRes = FsmAp::compareDataPtr(
+ outPair.s1Tel.trans, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case BreakS1:
+ case BreakS2:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* Compare class for the sort that does the partitioning. */
+int PartitionCompare::compare( const StateAp *state1, const StateAp *state2 )
+{
+ int compareRes;
+
+ /* Use a pair iterator to get the transition pairs. */
+ PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
+ for ( ; !outPair.end(); outPair++ ) {
+ switch ( outPair.userState ) {
+
+ case RangeInS1:
+ compareRes = FsmAp::comparePartPtr( outPair.s1Tel.trans, 0 );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeInS2:
+ compareRes = FsmAp::comparePartPtr( 0, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case RangeOverlap:
+ compareRes = FsmAp::comparePartPtr(
+ outPair.s1Tel.trans, outPair.s2Tel.trans );
+ if ( compareRes != 0 )
+ return compareRes;
+ break;
+
+ case BreakS1:
+ case BreakS2:
+ break;
+ }
+ }
+
+ /* Test eof targets. */
+ if ( state1->eofTarget == 0 && state2->eofTarget != 0 )
+ return -1;
+ else if ( state1->eofTarget != 0 && state2->eofTarget == 0 )
+ return 1;
+ else if ( state1->eofTarget != 0 ) {
+ /* Both eof targets are set. */
+ compareRes = CmpOrd< MinPartition* >::compare(
+ state1->eofTarget->alg.partition, state2->eofTarget->alg.partition );
+ if ( compareRes != 0 )
+ return compareRes;
+ }
+
+ return 0;
+}
+
+/* Compare class for the sort that does the partitioning. */
+bool MarkCompare::shouldMark( MarkIndex &markIndex, const StateAp *state1,
+ const StateAp *state2 )
+{
+ /* Use a pair iterator to get the transition pairs. */
+ PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
+ for ( ; !outPair.end(); outPair++ ) {
+ switch ( outPair.userState ) {
+
+ case RangeInS1:
+ if ( FsmAp::shouldMarkPtr( markIndex, outPair.s1Tel.trans, 0 ) )
+ return true;
+ break;
+
+ case RangeInS2:
+ if ( FsmAp::shouldMarkPtr( markIndex, 0, outPair.s2Tel.trans ) )
+ return true;
+ break;
+
+ case RangeOverlap:
+ if ( FsmAp::shouldMarkPtr( markIndex,
+ outPair.s1Tel.trans, outPair.s2Tel.trans ) )
+ return true;
+ break;
+
+ case BreakS1:
+ case BreakS2:
+ break;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Transition Comparison.
+ */
+
+/* Compare target partitions. Either pointer may be null. */
+int FsmAp::comparePartPtr( TransAp *trans1, TransAp *trans2 )
+{
+ if ( trans1 != 0 ) {
+ /* If trans1 is set then so should trans2. The initial partitioning
+ * guarantees this for us. */
+ if ( trans1->toState == 0 && trans2->toState != 0 )
+ return -1;
+ else if ( trans1->toState != 0 && trans2->toState == 0 )
+ return 1;
+ else if ( trans1->toState != 0 ) {
+ /* Both of targets are set. */
+ return CmpOrd< MinPartition* >::compare(
+ trans1->toState->alg.partition, trans2->toState->alg.partition );
+ }
+ }
+ return 0;
+}
+
+
+/* Compares two transition pointers according to priority and functions.
+ * Either pointer may be null. Does not consider to state or from state. */
+int FsmAp::compareDataPtr( TransAp *trans1, TransAp *trans2 )
+{
+ if ( trans1 == 0 && trans2 != 0 )
+ return -1;
+ else if ( trans1 != 0 && trans2 == 0 )
+ return 1;
+ else if ( trans1 != 0 ) {
+ /* Both of the transition pointers are set. */
+ int compareRes = compareTransData( trans1, trans2 );
+ if ( compareRes != 0 )
+ return compareRes;
+ }
+ return 0;
+}
+
+/* Compares two transitions according to target state, priority and functions.
+ * Does not consider from state. Either of the pointers may be null. */
+int FsmAp::compareFullPtr( TransAp *trans1, TransAp *trans2 )
+{
+ if ( (trans1 != 0) ^ (trans2 != 0) ) {
+ /* Exactly one of the transitions is set. */
+ if ( trans1 != 0 )
+ return -1;
+ else
+ return 1;
+ }
+ else if ( trans1 != 0 ) {
+ /* Both of the transition pointers are set. Test target state,
+ * priority and funcs. */
+ if ( trans1->toState < trans2->toState )
+ return -1;
+ else if ( trans1->toState > trans2->toState )
+ return 1;
+ else if ( trans1->toState != 0 ) {
+ /* Test transition data. */
+ int compareRes = compareTransData( trans1, trans2 );
+ if ( compareRes != 0 )
+ return compareRes;
+ }
+ }
+ return 0;
+}
+
+
+bool FsmAp::shouldMarkPtr( MarkIndex &markIndex, TransAp *trans1,
+ TransAp *trans2 )
+{
+ if ( (trans1 != 0) ^ (trans2 != 0) ) {
+ /* Exactly one of the transitions is set. The initial mark round
+ * should rule out this case. */
+ assert( false );
+ }
+ else if ( trans1 != 0 ) {
+ /* Both of the transitions are set. If the target pair is marked, then
+ * the pair we are considering gets marked. */
+ return markIndex.isPairMarked( trans1->toState->alg.stateNum,
+ trans2->toState->alg.stateNum );
+ }
+
+ /* Neither of the transitiosn are set. */
+ return false;
+}
+
+
diff --git a/ragel/gendata.cpp b/ragel/gendata.cpp
new file mode 100644
index 0000000..65f0b52
--- /dev/null
+++ b/ragel/gendata.cpp
@@ -0,0 +1,1159 @@
+/*
+ * Copyright 2005-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 "gendata.h"
+#include "ragel.h"
+#include <iostream>
+
+/*
+ * Code generators.
+ */
+
+#include "cstable.h"
+#include "csftable.h"
+#include "csflat.h"
+#include "csfflat.h"
+#include "csgoto.h"
+#include "csfgoto.h"
+#include "csipgoto.h"
+#include "cssplit.h"
+
+#include "cdtable.h"
+#include "cdftable.h"
+#include "cdflat.h"
+#include "cdfflat.h"
+#include "cdgoto.h"
+#include "cdfgoto.h"
+#include "cdipgoto.h"
+#include "cdsplit.h"
+
+#include "dotcodegen.h"
+
+#include "javacodegen.h"
+
+#include "gocodegen.h"
+#include "gotable.h"
+#include "goftable.h"
+#include "goflat.h"
+#include "gofflat.h"
+#include "gogoto.h"
+#include "gofgoto.h"
+#include "goipgoto.h"
+
+#include "mltable.h"
+#include "mlftable.h"
+#include "mlflat.h"
+#include "mlfflat.h"
+#include "mlgoto.h"
+#include "mlfgoto.h"
+
+#include "rubytable.h"
+#include "rubyftable.h"
+#include "rubyflat.h"
+#include "rubyfflat.h"
+#include "rbxgoto.h"
+
+string itoa( int i )
+{
+ char buf[16];
+ sprintf( buf, "%i", i );
+ return buf;
+}
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *dotMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = new GraphvizDotGen(out);
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ /* For normal code generation we want a transition on every character so we never
+ * end up in an undefined state. For graphviz this just clutters the
+ * drawing so we turn it off. */
+ codeGen->wantComplete = false;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *cdMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = 0;
+ switch ( hostLang->lang ) {
+ case HostLang::C:
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new CTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new CFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new CFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new CFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new CGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new CFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new CIpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new CSplitCodeGen(out);
+ break;
+ }
+ break;
+
+ case HostLang::D:
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new DTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new DFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new DFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new DFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new DGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new DFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new DIpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new DSplitCodeGen(out);
+ break;
+ }
+ break;
+
+ case HostLang::D2:
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new D2TabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new D2FTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new D2FlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new D2FFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new D2GotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new D2FGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new D2IpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new D2SplitCodeGen(out);
+ break;
+ }
+ break;
+
+ default: break;
+ }
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = new JavaTabCodeGen(out);
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *goMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = 0;
+
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new GoTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new GoFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new GoFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new GoFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new GoGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new GoFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new GoIpGotoCodeGen(out);
+ break;
+ default:
+ cerr << "Invalid output style, only -T0, -T1, -F0, -F1, -G0, -G1 and -G2 are supported for Go.\n";
+ exit(1);
+ }
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *rubyMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = 0;
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new RubyTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new RubyFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new RubyFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new RubyFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ if ( rubyImpl == Rubinius ) {
+ codeGen = new RbxGotoCodeGen(out);
+ } else {
+ cerr << "Goto style is still _very_ experimental "
+ "and only supported using Rubinius.\n"
+ "You may want to enable the --rbx flag "
+ " to give it a try.\n";
+ exit(1);
+ }
+ break;
+ default:
+ cout << "Invalid code style\n";
+ exit(1);
+ break;
+ }
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *csharpMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = 0;
+
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new CSharpTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new CSharpFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new CSharpFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new CSharpFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new CSharpGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new CSharpFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new CSharpIpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new CSharpSplitCodeGen(out);
+ break;
+ }
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *ocamlMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *codeGen = 0;
+
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new OCamlTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new OCamlFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new OCamlFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new OCamlFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new OCamlGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new OCamlFGotoCodeGen(out);
+ break;
+ default:
+ cerr << "I only support the -T0 -T1 -F0 -F1 -G0 and -G1 output styles for OCaml.\n";
+ exit(1);
+ }
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+
+ return codeGen;
+}
+
+
+CodeGenData *makeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
+{
+ CodeGenData *cgd = 0;
+ if ( generateDot )
+ cgd = dotMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangC )
+ cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangD )
+ cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangD2 )
+ cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangGo )
+ cgd = goMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangJava )
+ cgd = javaMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangRuby )
+ cgd = rubyMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangCSharp )
+ cgd = csharpMakeCodeGen( sourceFileName, fsmName, out );
+ else if ( hostLang == &hostLangOCaml )
+ cgd = ocamlMakeCodeGen( sourceFileName, fsmName, out );
+ return cgd;
+}
+
+void lineDirective( ostream &out, const char *fileName, int line )
+{
+ if ( !generateDot ) {
+ if ( hostLang == &hostLangC )
+ cdLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangD )
+ cdLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangD2 )
+ cdLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangGo )
+ goLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangJava )
+ javaLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangRuby )
+ rubyLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangCSharp )
+ csharpLineDirective( out, fileName, line );
+ else if ( hostLang == &hostLangOCaml )
+ ocamlLineDirective( out, fileName, line );
+ }
+}
+
+void genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ lineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+
+/* Total error count. */
+/* int gblErrorCount = 0; */
+
+CodeGenData::CodeGenData( ostream &out )
+:
+ sourceFileName(0),
+ fsmName(0),
+ out(out),
+ redFsm(0),
+ allActions(0),
+ allActionTables(0),
+ allConditions(0),
+ allCondSpaces(0),
+ allStates(0),
+ nameIndex(0),
+ startState(-1),
+ errState(-1),
+ getKeyExpr(0),
+ accessExpr(0),
+ prePushExpr(0),
+ postPopExpr(0),
+ pExpr(0),
+ peExpr(0),
+ eofExpr(0),
+ csExpr(0),
+ topExpr(0),
+ stackExpr(0),
+ actExpr(0),
+ tokstartExpr(0),
+ tokendExpr(0),
+ dataExpr(0),
+ wantComplete(true),
+ hasLongestMatch(false),
+ noEnd(false),
+ noPrefix(false),
+ noFinal(false),
+ noError(false),
+ noCS(false)
+{}
+
+
+void CodeGenData::createMachine()
+{
+ redFsm = new RedFsmAp();
+}
+
+void CodeGenData::initActionList( unsigned long length )
+{
+ allActions = new GenAction[length];
+ for ( unsigned long a = 0; a < length; a++ )
+ actionList.append( allActions+a );
+}
+
+void CodeGenData::newAction( int anum, const char *name,
+ const InputLoc &loc, GenInlineList *inlineList )
+{
+ allActions[anum].actionId = anum;
+ allActions[anum].name = name;
+ allActions[anum].loc = loc;
+ allActions[anum].inlineList = inlineList;
+}
+
+void CodeGenData::initActionTableList( unsigned long length )
+{
+ allActionTables = new RedAction[length];
+}
+
+void CodeGenData::initStateList( unsigned long length )
+{
+ allStates = new RedStateAp[length];
+ for ( unsigned long s = 0; s < length; s++ )
+ redFsm->stateList.append( allStates+s );
+
+ /* We get the start state as an offset, set the pointer now. */
+ if ( startState >= 0 )
+ redFsm->startState = allStates + startState;
+ if ( errState >= 0 )
+ redFsm->errState = allStates + errState;
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
+ redFsm->entryPoints.insert( allStates + *en );
+
+ /* The nextStateId is no longer used to assign state ids (they come in set
+ * from the frontend now), however generation code still depends on it.
+ * Should eventually remove this variable. */
+ redFsm->nextStateId = redFsm->stateList.length();
+}
+
+void CodeGenData::setStartState( unsigned long startState )
+{
+ this->startState = startState;
+}
+
+void CodeGenData::setErrorState( unsigned long errState )
+{
+ this->errState = errState;
+}
+
+void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
+{
+ entryPointIds.append( entryState );
+ entryPointNames.append( name );
+}
+
+void CodeGenData::initTransList( int snum, unsigned long length )
+{
+ /* Could preallocate the out range to save time growing it. For now do
+ * nothing. */
+}
+
+void CodeGenData::newTrans( int snum, int tnum, Key lowKey,
+ Key highKey, long targ, long action )
+{
+ /* Get the current state and range. */
+ RedStateAp *curState = allStates + snum;
+ RedTransList &destRange = curState->outRange;
+
+ if ( curState == redFsm->errState )
+ return;
+
+ /* Make the new transitions. */
+ RedStateAp *targState = targ >= 0 ? (allStates + targ) :
+ wantComplete ? redFsm->getErrorState() : 0;
+ RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
+ RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
+ RedTransEl transEl( lowKey, highKey, trans );
+
+ if ( wantComplete ) {
+ /* If the machine is to be complete then we need to fill any gaps with
+ * the error transitions. */
+ if ( destRange.length() == 0 ) {
+ /* Range is currently empty. */
+ if ( keyOps->minKey < lowKey ) {
+ /* The first range doesn't start at the low end. */
+ Key fillHighKey = lowKey;
+ fillHighKey.decrement();
+
+ /* Create the filler with the state's error transition. */
+ RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
+ destRange.append( newTel );
+ }
+ }
+ else {
+ /* The range list is not empty, get the the last range. */
+ RedTransEl *last = &destRange[destRange.length()-1];
+ Key nextKey = last->highKey;
+ nextKey.increment();
+ if ( nextKey < lowKey ) {
+ /* There is a gap to fill. Make the high key. */
+ Key fillHighKey = lowKey;
+ fillHighKey.decrement();
+
+ /* Create the filler with the state's error transtion. */
+ RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
+ destRange.append( newTel );
+ }
+ }
+ }
+
+ /* Filler taken care of. Append the range. */
+ destRange.append( RedTransEl( lowKey, highKey, trans ) );
+}
+
+void CodeGenData::finishTransList( int snum )
+{
+ /* Get the current state and range. */
+ RedStateAp *curState = allStates + snum;
+ RedTransList &destRange = curState->outRange;
+
+ if ( curState == redFsm->errState )
+ return;
+
+ /* If building a complete machine we may need filler on the end. */
+ if ( wantComplete ) {
+ /* Check if there are any ranges already. */
+ if ( destRange.length() == 0 ) {
+ /* Fill with the whole alphabet. */
+ /* Add the range on the lower and upper bound. */
+ RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
+ destRange.append( newTel );
+ }
+ else {
+ /* Get the last and check for a gap on the end. */
+ RedTransEl *last = &destRange[destRange.length()-1];
+ if ( last->highKey < keyOps->maxKey ) {
+ /* Make the high key. */
+ Key fillLowKey = last->highKey;
+ fillLowKey.increment();
+
+ /* Create the new range with the error trans and append it. */
+ RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
+ destRange.append( newTel );
+ }
+ }
+ }
+}
+
+void CodeGenData::setId( int snum, int id )
+{
+ RedStateAp *curState = allStates + snum;
+ curState->id = id;
+}
+
+void CodeGenData::setFinal( int snum )
+{
+ RedStateAp *curState = allStates + snum;
+ curState->isFinal = true;
+}
+
+
+void CodeGenData::setStateActions( int snum, long toStateAction,
+ long fromStateAction, long eofAction )
+{
+ RedStateAp *curState = allStates + snum;
+ if ( toStateAction >= 0 )
+ curState->toStateAction = allActionTables + toStateAction;
+ if ( fromStateAction >= 0 )
+ curState->fromStateAction = allActionTables + fromStateAction;
+ if ( eofAction >= 0 )
+ curState->eofAction = allActionTables + eofAction;
+}
+
+void CodeGenData::setEofTrans( int snum, long eofTarget, long actId )
+{
+ RedStateAp *curState = allStates + snum;
+ RedStateAp *targState = allStates + eofTarget;
+ RedAction *eofAct = allActionTables + actId;
+ curState->eofTrans = redFsm->allocateTrans( targState, eofAct );
+}
+
+void CodeGenData::resolveTargetStates( GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call:
+ case GenInlineItem::Next: case GenInlineItem::Entry:
+ item->targState = allStates + item->targId;
+ break;
+ default:
+ break;
+ }
+
+ if ( item->children != 0 )
+ resolveTargetStates( item->children );
+ }
+}
+
+void CodeGenData::closeMachine()
+{
+ for ( GenActionList::Iter a = actionList; a.lte(); a++ )
+ resolveTargetStates( a->inlineList );
+
+ /* Note that even if we want a complete graph we do not give the error
+ * state a default transition. All machines break out of the processing
+ * loop when in the error state. */
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
+ st->stateCondVect.append( sci );
+ }
+}
+
+
+bool CodeGenData::setAlphType( const char *data )
+{
+ HostType *alphType = findAlphTypeInternal( data );
+ if ( alphType == 0 )
+ return false;
+
+ thisKeyOps.setAlphType( alphType );
+ return true;
+}
+
+void CodeGenData::initCondSpaceList( ulong length )
+{
+ allCondSpaces = new GenCondSpace[length];
+ for ( ulong c = 0; c < length; c++ )
+ condSpaceList.append( allCondSpaces + c );
+}
+
+void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
+{
+ GenCondSpace *cond = allCondSpaces + cnum;
+ cond->condSpaceId = condSpaceId;
+ cond->baseKey = baseKey;
+}
+
+void CodeGenData::condSpaceItem( int cnum, long condActionId )
+{
+ GenCondSpace *cond = allCondSpaces + cnum;
+ cond->condSet.append( allActions + condActionId );
+}
+
+void CodeGenData::initStateCondList( int snum, ulong length )
+{
+ /* Could preallocate these, as we could with transitions. */
+}
+
+void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
+{
+ RedStateAp *curState = allStates + snum;
+
+ /* Create the new state condition. */
+ GenStateCond *stateCond = new GenStateCond;
+ stateCond->lowKey = lowKey;
+ stateCond->highKey = highKey;
+
+ /* Assign it a cond space. */
+ GenCondSpace *condSpace = allCondSpaces + condNum;
+ stateCond->condSpace = condSpace;
+
+ curState->stateCondList.append( stateCond );
+}
+
+
+GenCondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
+{
+ for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
+ Key csHighKey = cs->baseKey;
+ csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
+
+ if ( lowKey >= cs->baseKey && highKey <= csHighKey )
+ return cs;
+ }
+ return 0;
+}
+
+Condition *CodeGenData::findCondition( Key key )
+{
+ for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
+ Key upperKey = cond->baseKey + (1 << cond->condSet.length());
+ if ( cond->baseKey <= key && key <= upperKey )
+ return cond;
+ }
+ return 0;
+}
+
+Key CodeGenData::findMaxKey()
+{
+ Key maxKey = keyOps->maxKey;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ assert( st->outSingle.length() == 0 );
+ assert( st->defTrans == 0 );
+
+ long rangeLen = st->outRange.length();
+ if ( rangeLen > 0 ) {
+ Key highKey = st->outRange[rangeLen-1].highKey;
+ if ( highKey > maxKey )
+ maxKey = highKey;
+ }
+ }
+ return maxKey;
+}
+
+void CodeGenData::findFinalActionRefs()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Rerence count out of single transitions. */
+ for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
+ if ( rtel->value->action != 0 ) {
+ rtel->value->action->numTransRefs += 1;
+ for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
+ item->value->numTransRefs += 1;
+ }
+ }
+
+ /* Reference count out of range transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ if ( rtel->value->action != 0 ) {
+ rtel->value->action->numTransRefs += 1;
+ for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
+ item->value->numTransRefs += 1;
+ }
+ }
+
+ /* Reference count default transition. */
+ if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
+ st->defTrans->action->numTransRefs += 1;
+ for ( GenActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
+ item->value->numTransRefs += 1;
+ }
+
+ /* Reference count eof transitions. */
+ if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
+ st->eofTrans->action->numTransRefs += 1;
+ for ( GenActionTable::Iter item = st->eofTrans->action->key; item.lte(); item++ )
+ item->value->numTransRefs += 1;
+ }
+
+ /* Reference count to state actions. */
+ if ( st->toStateAction != 0 ) {
+ st->toStateAction->numToStateRefs += 1;
+ for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
+ item->value->numToStateRefs += 1;
+ }
+
+ /* Reference count from state actions. */
+ if ( st->fromStateAction != 0 ) {
+ st->fromStateAction->numFromStateRefs += 1;
+ for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
+ item->value->numFromStateRefs += 1;
+ }
+
+ /* Reference count EOF actions. */
+ if ( st->eofAction != 0 ) {
+ st->eofAction->numEofRefs += 1;
+ for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
+ item->value->numEofRefs += 1;
+ }
+ }
+}
+
+void CodeGenData::analyzeAction( GenAction *act, GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ /* Only consider actions that are referenced. */
+ if ( act->numRefs() > 0 ) {
+ if ( item->type == GenInlineItem::Goto || item->type == GenInlineItem::GotoExpr )
+ redFsm->bAnyActionGotos = true;
+ else if ( item->type == GenInlineItem::Call || item->type == GenInlineItem::CallExpr )
+ redFsm->bAnyActionCalls = true;
+ else if ( item->type == GenInlineItem::Ret )
+ redFsm->bAnyActionRets = true;
+ }
+
+ /* Check for various things in regular actions. */
+ if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
+ /* Any returns in regular actions? */
+ if ( item->type == GenInlineItem::Ret )
+ redFsm->bAnyRegActionRets = true;
+
+ /* Any next statements in the regular actions? */
+ if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
+ redFsm->bAnyRegNextStmt = true;
+
+ /* Any by value control in regular actions? */
+ if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr )
+ redFsm->bAnyRegActionByValControl = true;
+
+ /* Any references to the current state in regular actions? */
+ if ( item->type == GenInlineItem::Curs )
+ redFsm->bAnyRegCurStateRef = true;
+
+ if ( item->type == GenInlineItem::Break )
+ redFsm->bAnyRegBreak = true;
+ }
+
+ if ( item->children != 0 )
+ analyzeAction( act, item->children );
+ }
+}
+
+void CodeGenData::analyzeActionList( RedAction *redAct, GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ /* Any next statements in the action table? */
+ if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
+ redAct->bAnyNextStmt = true;
+
+ /* Any references to the current state. */
+ if ( item->type == GenInlineItem::Curs )
+ redAct->bAnyCurStateRef = true;
+
+ if ( item->type == GenInlineItem::Break )
+ redAct->bAnyBreakStmt = true;
+
+ if ( item->children != 0 )
+ analyzeActionList( redAct, item->children );
+ }
+}
+
+/* Assign ids to referenced actions. */
+void CodeGenData::assignActionIds()
+{
+ int nextActionId = 0;
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Only ever interested in referenced actions. */
+ if ( act->numRefs() > 0 )
+ act->actionId = nextActionId++;
+ }
+}
+
+void CodeGenData::setValueLimits()
+{
+ redFsm->maxSingleLen = 0;
+ redFsm->maxRangeLen = 0;
+ redFsm->maxKeyOffset = 0;
+ redFsm->maxIndexOffset = 0;
+ redFsm->maxActListId = 0;
+ redFsm->maxActionLoc = 0;
+ redFsm->maxActArrItem = 0;
+ redFsm->maxSpan = 0;
+ redFsm->maxCondSpan = 0;
+ redFsm->maxFlatIndexOffset = 0;
+ redFsm->maxCondOffset = 0;
+ redFsm->maxCondLen = 0;
+ redFsm->maxCondSpaceId = 0;
+ redFsm->maxCondIndexOffset = 0;
+
+ /* In both of these cases the 0 index is reserved for no value, so the max
+ * is one more than it would be if they started at 0. */
+ redFsm->maxIndex = redFsm->transSet.length();
+ redFsm->maxCond = condSpaceList.length();
+
+ /* The nextStateId - 1 is the last state id assigned. */
+ redFsm->maxState = redFsm->nextStateId - 1;
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ if ( csi->condSpaceId > redFsm->maxCondSpaceId )
+ redFsm->maxCondSpaceId = csi->condSpaceId;
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Maximum cond length. */
+ if ( st->stateCondList.length() > redFsm->maxCondLen )
+ redFsm->maxCondLen = st->stateCondList.length();
+
+ /* Maximum single length. */
+ if ( st->outSingle.length() > redFsm->maxSingleLen )
+ redFsm->maxSingleLen = st->outSingle.length();
+
+ /* Maximum range length. */
+ if ( st->outRange.length() > redFsm->maxRangeLen )
+ redFsm->maxRangeLen = st->outRange.length();
+
+ /* The key offset index offset for the state after last is not used, skip it.. */
+ if ( ! st.last() ) {
+ redFsm->maxCondOffset += st->stateCondList.length();
+ redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 2;
+ }
+
+ /* Max cond span. */
+ if ( st->condList != 0 ) {
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ if ( span > redFsm->maxCondSpan )
+ redFsm->maxCondSpan = span;
+ }
+
+ /* Max key span. */
+ if ( st->transList != 0 ) {
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ if ( span > redFsm->maxSpan )
+ redFsm->maxSpan = span;
+ }
+
+ /* Max cond index offset. */
+ if ( ! st.last() ) {
+ if ( st->condList != 0 )
+ redFsm->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+
+ /* Max flat index offset. */
+ if ( ! st.last() ) {
+ if ( st->transList != 0 )
+ redFsm->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
+ redFsm->maxFlatIndexOffset += 1;
+ }
+ }
+
+ for ( GenActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
+ /* Maximum id of action lists. */
+ if ( at->actListId+1 > redFsm->maxActListId )
+ redFsm->maxActListId = at->actListId+1;
+
+ /* Maximum location of items in action array. */
+ if ( at->location+1 > redFsm->maxActionLoc )
+ redFsm->maxActionLoc = at->location+1;
+
+ /* Maximum values going into the action array. */
+ if ( at->key.length() > redFsm->maxActArrItem )
+ redFsm->maxActArrItem = at->key.length();
+ for ( GenActionTable::Iter item = at->key; item.lte(); item++ ) {
+ if ( item->value->actionId > redFsm->maxActArrItem )
+ redFsm->maxActArrItem = item->value->actionId;
+ }
+ }
+}
+
+
+
+/* Gather various info on the machine. */
+void CodeGenData::analyzeMachine()
+{
+ /* Find the true count of action references. */
+ findFinalActionRefs();
+
+ /* Check if there are any calls in action code. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Record the occurrence of various kinds of actions. */
+ if ( act->numToStateRefs > 0 )
+ redFsm->bAnyToStateActions = true;
+ if ( act->numFromStateRefs > 0 )
+ redFsm->bAnyFromStateActions = true;
+ if ( act->numEofRefs > 0 )
+ redFsm->bAnyEofActions = true;
+ if ( act->numTransRefs > 0 )
+ redFsm->bAnyRegActions = true;
+
+ /* Recurse through the action's parse tree looking for various things. */
+ analyzeAction( act, act->inlineList );
+ }
+
+ /* Analyze reduced action lists. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ for ( GenActionTable::Iter act = redAct->key; act.lte(); act++ )
+ analyzeActionList( redAct, act->value->inlineList );
+ }
+
+ /* Find states that have transitions with actions that have next
+ * statements. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Check any actions out of outSinge. */
+ for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
+ if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
+ st->bAnyRegCurStateRef = true;
+ }
+
+ /* Check any actions out of outRange. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
+ st->bAnyRegCurStateRef = true;
+ }
+
+ /* Check any action out of default. */
+ if ( st->defTrans != 0 && st->defTrans->action != 0 &&
+ st->defTrans->action->anyCurStateRef() )
+ st->bAnyRegCurStateRef = true;
+
+ if ( st->stateCondList.length() > 0 )
+ redFsm->bAnyConditions = true;
+
+ if ( st->eofTrans != 0 )
+ redFsm->bAnyEofTrans = true;
+ }
+
+ /* Assign ids to actions that are referenced. */
+ assignActionIds();
+
+ /* Set the maximums of various values used for deciding types. */
+ setValueLimits();
+}
+
+void CodeGenData::write_option_error( InputLoc &loc, char *arg )
+{
+ source_warning(loc) << "unrecognized write option \"" << arg << "\"" << endl;
+}
+
+/* returns true if the following section should generate line directives. */
+bool CodeGenData::writeStatement( InputLoc &loc, int nargs, char **args )
+{
+ bool followLineDirective = false;
+
+ if ( strcmp( args[0], "data" ) == 0 ) {
+ out << '\n';
+ genLineDirective( out );
+ followLineDirective = true;
+
+ for ( int i = 1; i < nargs; i++ ) {
+ if ( strcmp( args[i], "noerror" ) == 0 )
+ noError = true;
+ else if ( strcmp( args[i], "noprefix" ) == 0 )
+ noPrefix = true;
+ else if ( strcmp( args[i], "nofinal" ) == 0 )
+ noFinal = true;
+ else
+ write_option_error( loc, args[i] );
+ }
+ writeData();
+ }
+ else if ( strcmp( args[0], "init" ) == 0 ) {
+ out << '\n';
+ genLineDirective( out );
+ followLineDirective = true;
+
+ for ( int i = 1; i < nargs; i++ ) {
+ if ( strcmp( args[i], "nocs" ) == 0 )
+ noCS = true;
+ else
+ write_option_error( loc, args[i] );
+ }
+ writeInit();
+ }
+ else if ( strcmp( args[0], "exec" ) == 0 ) {
+ out << '\n';
+ genLineDirective( out );
+ followLineDirective = true;
+
+ for ( int i = 1; i < nargs; i++ ) {
+ if ( strcmp( args[i], "noend" ) == 0 )
+ noEnd = true;
+ else
+ write_option_error( loc, args[i] );
+ }
+ writeExec();
+ }
+ else if ( strcmp( args[0], "exports" ) == 0 ) {
+ out << '\n';
+ genLineDirective( out );
+ followLineDirective = true;
+
+ for ( int i = 1; i < nargs; i++ )
+ write_option_error( loc, args[i] );
+ writeExports();
+ }
+ else if ( strcmp( args[0], "start" ) == 0 ) {
+ for ( int i = 1; i < nargs; i++ )
+ write_option_error( loc, args[i] );
+ writeStart();
+ }
+ else if ( strcmp( args[0], "first_final" ) == 0 ) {
+ for ( int i = 1; i < nargs; i++ )
+ write_option_error( loc, args[i] );
+ writeFirstFinal();
+ }
+ else if ( strcmp( args[0], "error" ) == 0 ) {
+ for ( int i = 1; i < nargs; i++ )
+ write_option_error( loc, args[i] );
+ writeError();
+ }
+ else {
+ /* EMIT An error here. */
+ source_error(loc) << "unrecognized write command \"" <<
+ args[0] << "\"" << endl;
+ }
+ return followLineDirective;
+}
+
+ostream &CodeGenData::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &CodeGenData::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
+
diff --git a/ragel/gendata.h b/ragel/gendata.h
new file mode 100644
index 0000000..071c601
--- /dev/null
+++ b/ragel/gendata.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2005-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
+ */
+
+#ifndef _GENDATA_H
+#define _GENDATA_H
+
+#include <iostream>
+#include "config.h"
+#include "redfsm.h"
+#include "common.h"
+
+using std::ostream;
+
+extern bool generateDot;
+
+struct NameInst;
+typedef DList<GenAction> GenActionList;
+
+typedef unsigned long ulong;
+
+extern int gblErrorCount;
+
+struct CodeGenData;
+
+typedef AvlMap<char *, CodeGenData*, CmpStr> CodeGenMap;
+typedef AvlMapEl<char *, CodeGenData*> CodeGenMapEl;
+
+void cdLineDirective( ostream &out, const char *fileName, int line );
+void javaLineDirective( ostream &out, const char *fileName, int line );
+void goLineDirective( ostream &out, const char *fileName, int line );
+void rubyLineDirective( ostream &out, const char *fileName, int line );
+void csharpLineDirective( ostream &out, const char *fileName, int line );
+void ocamlLineDirective( ostream &out, const char *fileName, int line );
+void genLineDirective( ostream &out );
+void lineDirective( ostream &out, const char *fileName, int line );
+
+string itoa( int i );
+
+/*********************************/
+
+struct CodeGenData
+{
+ /*
+ * The interface to the code generator.
+ */
+ virtual void finishRagelDef() {}
+
+ /* These are invoked by the corresponding write statements. */
+ virtual void writeData() {};
+ virtual void writeInit() {};
+ virtual void writeExec() {};
+ virtual void writeExports() {};
+ virtual void writeStart() {};
+ virtual void writeFirstFinal() {};
+ virtual void writeError() {};
+
+ /* This can also be overwridden to modify the processing of write
+ * statements. */
+ virtual bool writeStatement( InputLoc &loc, int nargs, char **args );
+
+ /********************/
+
+ CodeGenData( ostream &out );
+ virtual ~CodeGenData() {}
+
+ /*
+ * Collecting the machine.
+ */
+
+ const char *sourceFileName;
+ const char *fsmName;
+ ostream &out;
+ RedFsmAp *redFsm;
+ GenAction *allActions;
+ RedAction *allActionTables;
+ Condition *allConditions;
+ GenCondSpace *allCondSpaces;
+ RedStateAp *allStates;
+ NameInst **nameIndex;
+ int startState;
+ int errState;
+ GenActionList actionList;
+ ConditionList conditionList;
+ CondSpaceList condSpaceList;
+ GenInlineList *getKeyExpr;
+ GenInlineList *accessExpr;
+ GenInlineList *prePushExpr;
+ GenInlineList *postPopExpr;
+
+ /* Overriding variables. */
+ GenInlineList *pExpr;
+ GenInlineList *peExpr;
+ GenInlineList *eofExpr;
+ GenInlineList *csExpr;
+ GenInlineList *topExpr;
+ GenInlineList *stackExpr;
+ GenInlineList *actExpr;
+ GenInlineList *tokstartExpr;
+ GenInlineList *tokendExpr;
+ GenInlineList *dataExpr;
+
+ KeyOps thisKeyOps;
+ bool wantComplete;
+ EntryIdVect entryPointIds;
+ EntryNameVect entryPointNames;
+ bool hasLongestMatch;
+ ExportList exportList;
+
+ /* Write options. */
+ bool noEnd;
+ bool noPrefix;
+ bool noFinal;
+ bool noError;
+ bool noCS;
+
+ void createMachine();
+ void initActionList( unsigned long length );
+ void newAction( int anum, const char *name, const InputLoc &loc, GenInlineList *inlineList );
+ void initActionTableList( unsigned long length );
+ void initStateList( unsigned long length );
+ void setStartState( unsigned long startState );
+ void setErrorState( unsigned long errState );
+ void addEntryPoint( char *name, unsigned long entryState );
+ void setId( int snum, int id );
+ void setFinal( int snum );
+ void initTransList( int snum, unsigned long length );
+ void newTrans( int snum, int tnum, Key lowKey, Key highKey,
+ long targ, long act );
+ void finishTransList( int snum );
+ void setStateActions( int snum, long toStateAction,
+ long fromStateAction, long eofAction );
+ void setEofTrans( int snum, long targ, long eofAction );
+ void setForcedErrorState()
+ { redFsm->forcedErrorState = true; }
+
+
+ void initCondSpaceList( ulong length );
+ void condSpaceItem( int cnum, long condActionId );
+ void newCondSpace( int cnum, int condSpaceId, Key baseKey );
+
+ void initStateCondList( int snum, ulong length );
+ void addStateCond( int snum, Key lowKey, Key highKey, long condNum );
+
+ GenCondSpace *findCondSpace( Key lowKey, Key highKey );
+ Condition *findCondition( Key key );
+
+ bool setAlphType( const char *data );
+
+ void resolveTargetStates( GenInlineList *inlineList );
+ Key findMaxKey();
+
+ /* Gather various info on the machine. */
+ void analyzeActionList( RedAction *redAct, GenInlineList *inlineList );
+ void analyzeAction( GenAction *act, GenInlineList *inlineList );
+ void findFinalActionRefs();
+ void analyzeMachine();
+
+ void closeMachine();
+ void setValueLimits();
+ void assignActionIds();
+
+ ostream &source_warning( const InputLoc &loc );
+ ostream &source_error( const InputLoc &loc );
+ void write_option_error( InputLoc &loc, char *arg );
+};
+
+CodeGenData *makeCodeGen( const char *sourceFileName,
+ const char *fsmName, ostream &out );
+
+#endif
diff --git a/ragel/gocodegen.cpp b/ragel/gocodegen.cpp
new file mode 100644
index 0000000..5ff44c1
--- /dev/null
+++ b/ragel/gocodegen.cpp
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "gocodegen.h"
+#include "ragel.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <sstream>
+#include <string>
+#include <assert.h>
+
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/*
+ * Go Specific
+ */
+
+void goLineDirective( ostream &out, const char *fileName, int line )
+{
+ out << "//line " << fileName << ":" << line << endl;
+}
+
+void GoCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ goLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+unsigned int GoCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string GoCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+
+/* Write out the fsm name. */
+string GoCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string GoCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &GoCodeGen::ACTIONS_ARRAY()
+{
+ out << " 0, ";
+ int totalActions = 1;
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ out << act->key.length() << ", ";
+ if ( totalActions++ % IALL == 0 )
+ out << endl << " ";
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
+ out << item->value->actionId << ", ";
+ if ( ! (act.last() && item.last()) ) {
+ if ( totalActions++ % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ }
+ out << endl;
+ return out;
+}
+
+
+string GoCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false, false );
+ return ret.str();
+}
+
+
+string GoCodeGen::P()
+{
+ ostringstream ret;
+ if ( pExpr == 0 )
+ ret << "p";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, pExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::PE()
+{
+ ostringstream ret;
+ if ( peExpr == 0 )
+ ret << "pe";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, peExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::vEOF()
+{
+ ostringstream ret;
+ if ( eofExpr == 0 )
+ ret << "eof";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, eofExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::vCS()
+{
+ ostringstream ret;
+ if ( csExpr == 0 )
+ ret << ACCESS() << "cs";
+ else {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, csExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::TOP()
+{
+ ostringstream ret;
+ if ( topExpr == 0 )
+ ret << ACCESS() + "top";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, topExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::STACK()
+{
+ ostringstream ret;
+ if ( stackExpr == 0 )
+ ret << ACCESS() + "stack";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, stackExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::ACT()
+{
+ ostringstream ret;
+ if ( actExpr == 0 )
+ ret << ACCESS() + "act";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, actExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::TOKSTART()
+{
+ ostringstream ret;
+ if ( tokstartExpr == 0 )
+ ret << ACCESS() + "ts";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokstartExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::TOKEND()
+{
+ ostringstream ret;
+ if ( tokendExpr == 0 )
+ ret << ACCESS() + "te";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokendExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string GoCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string GoCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << DATA() << "[" << P() << "]";
+ }
+ return ret.str();
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string GoCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+/* Write out a key from the fsm code gen. Depends on wether or not the key is
+ * signed. */
+string GoCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+}
+
+bool GoCodeGen::isAlphTypeSigned()
+{
+ return keyOps->isSigned;
+}
+
+bool GoCodeGen::isWideAlphTypeSigned()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ return isAlphTypeSigned();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ return wideType->isSigned;
+ }
+}
+
+string GoCodeGen::WIDE_KEY( RedStateAp *state, Key key )
+{
+ if ( state->stateCondList.length() > 0 ) {
+ ostringstream ret;
+ if ( isWideAlphTypeSigned() )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+ }
+ else {
+ return KEY( key );
+ }
+}
+
+
+
+void GoCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+ /* The parser gives fexec two children. The double brackets are for D
+ * code. If the inline list is a single word it will get interpreted as a
+ * C-style cast by the D compiler. */
+ ret << P() << " = (";
+ INLINE_LIST( ret, item->children, targState, inFinish, false );
+ ret << ") - 1" << endl;
+}
+
+void GoCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish, bool csForced )
+{
+ ret <<
+ " switch " << ACT() << " {" << endl;
+
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 ) {
+ ret << " default:" << endl;
+ }
+ else
+ ret << " case " << lma->lmId << ":" << endl;
+
+ /* Write the block and close it off. */
+ ret << " {";
+ INLINE_LIST( ret, lma->children, targState, inFinish, csForced );
+ ret << "}" << endl;
+ }
+
+ ret <<
+ " }" << endl <<
+ " ";
+}
+
+void GoCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void GoCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << endl;
+}
+
+void GoCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void GoCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << endl;
+}
+
+void GoCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = 0" << endl;
+}
+
+void GoCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << endl;
+}
+
+void GoCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{";
+ INLINE_LIST( ret, item->children, targState, inFinish, csForced );
+ ret << "}";
+ }
+}
+
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void GoCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish, bool csForced )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << "--" << endl;
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ CURS( ret, inFinish );
+ break;
+ case GenInlineItem::Targs:
+ TARGS( ret, inFinish, targState );
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish, csForced );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish, csForced );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState, csForced );
+ break;
+ }
+ }
+}
+/* Write out paths in line directives. Escapes any special characters. */
+string GoCodeGen::LDIR_PATH( char *path )
+{
+ ostringstream ret;
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ ret << "\\\\";
+ else
+ ret << *pc;
+ }
+ return ret.str();
+}
+
+void GoCodeGen::ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ goLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced );
+ ret << endl;
+}
+
+void GoCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ INLINE_LIST( ret, condition->inlineList, 0, false, false );
+}
+
+string GoCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string GoCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void GoCodeGen::writeInit()
+{
+ out << " {" << endl;
+
+ if ( !noCS )
+ out << " " << vCS() << " = " << START() << endl;
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << " " << TOP() << " = 0" << endl;
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << endl <<
+ " " << TOKEND() << " = " << NULL_ITEM() << endl <<
+ " " << ACT() << " = 0" << endl;
+ }
+ out << " }" << endl;
+}
+
+string GoCodeGen::DATA()
+{
+ ostringstream ret;
+ if ( dataExpr == 0 )
+ ret << ACCESS() + "data";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, dataExpr, 0, false, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string GoCodeGen::DATA_PREFIX()
+{
+ if ( !noPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string GoCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string GoCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+void GoCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ CONST( "int", START() ) << " = " << START_STATE_ID() << endl;
+
+ if ( !noFinal )
+ CONST( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << endl;
+
+ if ( !noError )
+ CONST( "int", ERROR() ) << " = " << ERROR_STATE() << endl;
+
+ out << endl;
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ CONST( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << endl;
+ }
+ out << endl;
+ }
+}
+
+void GoCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void GoCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void GoCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+void GoCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &GoCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &GoCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
+
+/*
+ * Go implementation.
+ *
+ */
+
+std::ostream &GoCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "var " << name << " []" << type << " = []" << type << "{" << endl;
+ return out;
+}
+
+std::ostream &GoCodeGen::CLOSE_ARRAY()
+{
+ return out << "}" << endl;
+}
+
+std::ostream &GoCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "var " << name << " " << type;
+ return out;
+}
+
+std::ostream &GoCodeGen::CONST( string type, string name )
+{
+ out << "const " << name << " " << type;
+ return out;
+}
+
+string GoCodeGen::UINT( )
+{
+ return "uint";
+}
+
+string GoCodeGen::INT()
+{
+ return "int";
+}
+
+string GoCodeGen::CAST( string type, string expr )
+{
+ return type + "(" + expr + ")";
+}
+
+string GoCodeGen::NULL_ITEM()
+{
+ return "0";
+}
+
+void GoCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "const " << DATA_PREFIX() << "ex_" << ex->name << " = " <<
+ KEY(ex->key) << endl;
+ }
+ out << endl;
+ }
+}
diff --git a/ragel/gocodegen.h b/ragel/gocodegen.h
new file mode 100644
index 0000000..50e8804
--- /dev/null
+++ b/ragel/gocodegen.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOCODEGEN_H
+#define _GOCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/* Integer array line length. */
+#define IALL 8
+
+/* Forwards. */
+struct RedFsmAp;
+struct RedStateAp;
+struct CodeGenData;
+struct GenAction;
+struct NameInst;
+struct GenInlineItem;
+struct GenInlineList;
+struct RedAction;
+struct LongestMatch;
+struct LongestMatchPart;
+
+class GoCodeGen : public CodeGenData
+{
+public:
+ GoCodeGen( ostream &out )
+ : CodeGenData(out) {}
+
+ virtual ~GoCodeGen() {}
+
+ virtual void finishRagelDef();
+ virtual void writeInit();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+ virtual void writeExports();
+protected:
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string WIDE_KEY( RedStateAp *state, Key key );
+ string LDIR_PATH( char *path );
+ virtual void ACTION( ostream &ret, GenAction *action, int targState,
+ bool inFinish, bool csForced );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+
+ bool isAlphTypeSigned();
+ bool isWideAlphTypeSigned();
+
+ virtual string CAST( string type, string expr );
+ virtual string UINT();
+ virtual string INT();
+ virtual string NULL_ITEM();
+ virtual string GET_KEY();
+
+ string P();
+ string PE();
+ string vEOF();
+
+ string ACCESS();
+ string vCS();
+ string STACK();
+ string TOP();
+ string TOKSTART();
+ string TOKEND();
+ string ACT();
+ string DATA();
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish, bool csForced );
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem,
+ int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+ virtual void BREAK( ostream &ret, int targState, bool csForced ) = 0;
+ virtual void CURS( ostream &ret, bool inFinish ) = 0;
+ virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0;
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState,
+ int inFinish, bool csForced );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ virtual void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish, bool csForced );
+ void STATE_IDS();
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual ostream &CONST( string type, string name );
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool testEofUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+ void genLineDirective( ostream &out );
+
+public:
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize() {}
+};
+
+#endif
diff --git a/ragel/gofflat.cpp b/ragel/gofflat.cpp
new file mode 100644
index 0000000..59e729c
--- /dev/null
+++ b/ragel/gofflat.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "gofflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::endl;
+
+std::ostream &GoFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+/* Write out the function for a transition. */
+std::ostream &GoFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFFlatCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoFFlatCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFFlatCodeGen::ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void GoFFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoFFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {" << endl <<
+ " var _slen " << INT() << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << endl;
+
+ out << " var _trans " << INT() << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _cond " << INT() << endl;
+
+ out <<
+ " var _keys " << INT() << endl <<
+ " var _inds " << INT() << endl;
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " var _conds " << INT() << endl <<
+ " var _widec " << WIDE_ALPH_TYPE() << endl;
+ }
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch " << FSA() << "[" << vCS() << "] {" << endl;
+ FROM_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << endl;
+
+ out <<
+ " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl <<
+ endl;
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] == 0 {" << endl <<
+ " goto _again" << endl <<
+ " }" << endl <<
+ endl <<
+ " switch " << TA() << "[_trans] {" << endl;
+ ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch " << TSA() << "[" << vCS() << "] {" << endl;
+ TO_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << "++; " << P() << " != " << PE() << " {"
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
+ " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
+ " goto _eof_trans" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch " << EA() << "[" << vCS() << "] {" << endl;
+ EOF_ACTION_SWITCH(2);
+ out <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/gofflat.h b/ragel/gofflat.h
new file mode 100644
index 0000000..bd3bde4
--- /dev/null
+++ b/ragel/gofflat.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOFFLAT_H
+#define _GOFFLAT_H
+
+#include <iostream>
+#include "goflat.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * FFlatCodeGen
+ */
+class GoFFlatCodeGen
+ : public GoFlatCodeGen
+{
+public:
+ GoFFlatCodeGen( ostream &out )
+ : GoFlatCodeGen(out) {}
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ std::ostream &ACTION_SWITCH( int level );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/gofgoto.cpp b/ragel/gofgoto.cpp
new file mode 100644
index 0000000..4f6ce36
--- /dev/null
+++ b/ragel/gofgoto.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "gofgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+using std::endl;
+
+std::ostream &GoFGotoCodeGen::EXEC_ACTIONS()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* We are at the start of a glob, write the case. */
+ out << "f" << redAct->actListId << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << TABS(1) << "goto _again" << endl;
+ }
+ }
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFGotoCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoFGotoCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &GoFGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << TABS(2) << "case " << st->id << ":" << endl;
+
+ /* Jump to the func. */
+ out << TABS(3) << "goto f" << st->eofAction->actListId << endl;
+ }
+ }
+
+ return out;
+}
+
+unsigned int GoFGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+unsigned int GoFGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+unsigned int GoFGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+void GoFGotoCodeGen::writeData()
+{
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoFGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << " = 0" << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _widec " << WIDE_ALPH_TYPE() << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch " << FSA() << "[" << vCS() << "] {" << endl;
+ FROM_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ out <<
+ " switch " << vCS() << " {" << endl;
+ STATE_GOTOS(1);
+ out <<
+ " }" << endl <<
+ endl;
+ TRANSITIONS() <<
+ endl;
+
+ if ( redFsm->anyRegActions() )
+ EXEC_ACTIONS() << endl;
+
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch " << TSA() << "[" << vCS() << "] {" << endl;
+ TO_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch " << vCS() << " {" << endl;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out <<
+ " case " << st->id << ":" << endl <<
+ " goto tr" << st->eofTrans->id << endl;
+ }
+
+ out <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch " << EA() << "[" << vCS() << "] {" << endl;
+ EOF_ACTION_SWITCH(2);
+ out <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/gofgoto.h b/ragel/gofgoto.h
new file mode 100644
index 0000000..c53e450
--- /dev/null
+++ b/ragel/gofgoto.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOFGOTO_H
+#define _GOFGOTO_H
+
+#include <iostream>
+#include "gogoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+class GoFGotoCodeGen
+ : public GoGotoCodeGen
+{
+public:
+ GoFGotoCodeGen( ostream &out )
+ : GoGotoCodeGen(out) {}
+
+ std::ostream &EXEC_ACTIONS();
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &FINISH_CASES();
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ unsigned int TO_STATE_ACTION( RedStateAp *state );
+ unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ unsigned int EOF_ACTION( RedStateAp *state );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/goflat.cpp b/ragel/goflat.cpp
new file mode 100644
index 0000000..bc7f51c
--- /dev/null
+++ b/ragel/goflat.cpp
@@ -0,0 +1,764 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "goflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::endl;
+
+std::ostream &GoFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, true, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &GoFlatCodeGen::ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &GoFlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ out << " ";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::KEY_SPANS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ out << span << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::TO_STATE_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::FROM_STATE_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::EOF_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::EOF_TRANS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans << ", ";
+
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoFlatCodeGen::COND_KEYS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ out << KEY( st->condLowKey ) << ", ";
+ out << KEY( st->condHighKey ) << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::COND_KEY_SPANS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ out << span << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::CONDS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ out << st->condList[pos]->condSpaceId + 1 << ", ";
+ else
+ out << "0, ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::COND_INDEX_OFFSET()
+{
+ out << " ";
+ int totalStateNum = 0;
+ int curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoFlatCodeGen::KEYS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ out << KEY( st->lowKey ) << ", ";
+ out << KEY( st->highKey ) << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::INDICIES()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ out << st->transList[pos]->id << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoFlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << " ";
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Save the position. Needed for eofTargs. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id << ", ";
+ if ( t < redFsm->transSet.length()-1 ) {
+ if ( ++totalStates % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &GoFlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << " ";
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ out << ", ";
+ if ( t < redFsm->transSet.length()-1 ) {
+ if ( ++totalAct % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] transPtrs;
+ return out;
+}
+
+void GoFlatCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << CAST(INT(), vCS() + " << 1") << endl <<
+ " _inds = " << CAST(INT(), IO() + "[" + vCS() + "]") << endl <<
+ endl <<
+ " _slen = " << CAST(INT(), SP() + "[" + vCS() + "]") << endl <<
+ " if _slen > 0 && " << K() << "[_keys] <= " << GET_WIDE_KEY() << " && " <<
+ GET_WIDE_KEY() << " <= " << K() << "[_keys + 1]" << " {" << endl <<
+ " _trans = " << CAST(INT(), I() + "[_inds + " + CAST(INT(), GET_WIDE_KEY() + " - " + K() + "[_keys]") + "]") << endl <<
+ " } else {" << endl <<
+ " _trans = " << CAST(INT(), I() + "[_inds + _slen]") << endl <<
+ " }" << endl <<
+ endl;
+}
+
+void GoFlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoFlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl;
+
+ out <<
+ " _keys = " << CAST(INT(), vCS() + " << 1") << endl <<
+ " _conds = " << CAST(INT(), CO() + "[" + vCS() + "]") << endl <<
+ endl <<
+ " _slen = " << CAST(INT(), CSP() + "[" + vCS() + "]") << endl <<
+ " if _slen > 0 && " << CK() << "[_keys]" << " <= " << GET_WIDE_KEY() << " && " <<
+ GET_WIDE_KEY() << " <= " << CK() << "[_keys + 1] {" << endl <<
+ " _cond = " << CAST(INT(), C() + "[_conds + " + CAST(INT(), GET_WIDE_KEY() + " - " + CK() + "[_keys]") + "]") << endl <<
+ " } else {" << endl <<
+ " _cond = 0" << endl <<
+ " }" << endl <<
+ endl;
+
+ out <<
+ " switch _cond {" << endl;
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId + 1 << ":" << endl;
+ out << TABS(2) << "_widec = " <<
+ KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) <<
+ " - " << KEY(keyOps->minKey) << ")" << endl;
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " {" << endl <<
+ " _widec += " << condValOffset << endl <<
+ " }" << endl;
+ }
+ }
+
+ out <<
+ " }" << endl;
+}
+
+void GoFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {" << endl <<
+ " var _slen " << INT() << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << endl;
+
+ out <<
+ " var _trans " << INT() << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _cond " << INT() << endl;
+
+ if ( redFsm->anyToStateActions() ||
+ redFsm->anyRegActions() || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " var _acts " << INT() << endl <<
+ " var _nacts " << UINT() << endl;
+ }
+
+ out <<
+ " var _keys " << INT() << endl <<
+ " var _inds " << INT() << endl;
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " var _conds " << INT() << endl <<
+ " var _widec " << WIDE_ALPH_TYPE() << endl;
+ }
+
+ out << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ FROM_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << endl;
+
+ out <<
+ " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl <<
+ endl;
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] == 0 {" << endl <<
+ " goto _again" << endl <<
+ " }" << endl <<
+ endl <<
+ " _acts = " << CAST(INT(), TA() + "[_trans]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ TO_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
+ " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
+ " goto _eof_trans" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " __acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl <<
+ " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl <<
+ " for ; __nacts > 0; __nacts-- {" << endl <<
+ " __acts++" << endl <<
+ " switch " << A() << "[__acts - 1]" << " {" << endl;
+ EOF_ACTION_SWITCH(3);
+ out <<
+ " }" << endl <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/goflat.h b/ragel/goflat.h
new file mode 100644
index 0000000..5216e85
--- /dev/null
+++ b/ragel/goflat.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOFLAT_H
+#define _GOFLAT_H
+
+#include <iostream>
+#include "gotablish.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * GoFlatCodeGen
+ */
+class GoFlatCodeGen
+ : public GoTablishCodeGen
+{
+public:
+ GoFlatCodeGen( ostream &out )
+ : GoTablishCodeGen(out) {}
+
+ virtual ~GoFlatCodeGen() { }
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ std::ostream &ACTION_SWITCH( int level );
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/goftable.cpp b/ragel/goftable.cpp
new file mode 100644
index 0000000..318f878
--- /dev/null
+++ b/ragel/goftable.cpp
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "goftable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::endl;
+
+/* Determine if we should use indicies or not. */
+void GoFTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &GoFTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoFTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+
+/* Write out the function for a transition. */
+std::ostream &GoFTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFTabCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << endl;
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFTabCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << endl;
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoFTabCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true, false );
+
+ out << endl;
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &GoFTabCodeGen::ACTION_SWITCH( int level )
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false, false );
+
+ out << endl;
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void GoFTabCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoFTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {" << endl <<
+ " var _klen " << INT() << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << endl;
+
+ out <<
+ " var _keys " << INT() << endl <<
+ " var _trans " << INT() << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _widec " << WIDE_ALPH_TYPE() << endl;
+
+ out << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch " << FSA() << "[" << vCS() << "] {" << endl;
+ FROM_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:" << endl;
+
+ if ( useIndicies )
+ out << " _trans = " << CAST(INT(), I() + "[_trans]") << endl;
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << endl;
+
+ out <<
+ " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl <<
+ endl;
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] == 0 {" << endl <<
+ " goto _again" << endl <<
+ " }" << endl <<
+ endl <<
+ " switch " << TA() << "[_trans] {" << endl;
+ ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch " << TSA() << "[" << vCS() << "] {" << endl;
+ TO_STATE_ACTION_SWITCH(1);
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
+ " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
+ " goto _eof_trans" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " switch " << EA() << "[" << vCS() << "] {" << endl;
+ EOF_ACTION_SWITCH(2);
+ out <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/goftable.h b/ragel/goftable.h
new file mode 100644
index 0000000..524b6a2
--- /dev/null
+++ b/ragel/goftable.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOFTABLE_H
+#define _GOFTABLE_H
+
+#include <iostream>
+#include "gotable.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * GoFTabCode
+ */
+class GoFTabCodeGen
+ : public GoTabCodeGen
+{
+public:
+ GoFTabCodeGen( ostream &out )
+ : GoTabCodeGen(out) {}
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ std::ostream &ACTION_SWITCH( int level );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+ virtual void calcIndexSize();
+};
+
+#endif
diff --git a/ragel/gogoto.cpp b/ragel/gogoto.cpp
new file mode 100644
index 0000000..757308a
--- /dev/null
+++ b/ragel/gogoto.cpp
@@ -0,0 +1,734 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "gogoto.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+using std::endl;
+
+/* Emit the goto to take for a given transition. */
+std::ostream &GoGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ return out;
+}
+
+int GoGotoCodeGen::TRANS_NR( RedTransAp *trans )
+{
+ return trans->id;
+}
+
+std::ostream &GoGotoCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, true, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void GoGotoCodeGen::GOTO_HEADER( RedStateAp *state, int level )
+{
+ /* Label the state. */
+ out << TABS(level) << "case " << state->id << ":" << endl;
+}
+
+void GoGotoCodeGen::emitSingleSwitch( RedStateAp *state, int level )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " == " <<
+ WIDE_KEY(state, data[0].lowKey) << " {" << endl;
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, level + 1) << endl;
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << TABS(level) << "switch " << GET_WIDE_KEY(state) << " {" << endl;
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << TABS(level) << "case " << WIDE_KEY(state, data[j].lowKey) << ":" << endl;
+ TRANS_GOTO(data[j].value, level + 1) << endl;
+ }
+
+ /* Close off the transition switch. */
+ out << TABS(level) << "}" << endl;
+ }
+}
+
+void GoGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ RedTransEl *data = state->outRange.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " < " <<
+ WIDE_KEY(state, data[mid].lowKey) << ":" << endl;
+ emitRangeBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " > " <<
+ WIDE_KEY(state, data[mid].highKey) << ":" << endl;
+ emitRangeBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "default:" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " < " <<
+ WIDE_KEY(state, data[mid].lowKey) << ":" << endl;
+ emitRangeBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "default:" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ }
+ else {
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << ":" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ }
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " > " <<
+ WIDE_KEY(state, data[mid].highKey) << ":" << endl;
+ emitRangeBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "default:" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ }
+ else {
+ out << TABS(level) << "case " << GET_WIDE_KEY(state) << " >= " <<
+ WIDE_KEY(state, data[mid].lowKey) << ":" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ }
+ out << TABS(level) << "}" << endl;
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << WIDE_KEY(state, data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << " {" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " <<
+ WIDE_KEY(state, data[mid].highKey) << " {" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if " << WIDE_KEY(state, data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " {" << endl;
+ TRANS_GOTO(data[mid].value, level+1) << endl;
+ out << TABS(level) << "}" << endl;
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level) << endl;
+ }
+ }
+}
+
+void GoGotoCodeGen::STATE_GOTO_ERROR( int level )
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << TABS(level) << "case " << state->id << ":" << endl;
+ out << TABS(level + 1) << "goto _out" << endl;
+}
+
+void GoGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
+{
+ GenCondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " <<
+ KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) <<
+ " - " << KEY(keyOps->minKey) << ")" << endl;
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " {" << endl;
+ out << TABS(level + 1) << "_widec += " << condValOffset << endl;
+ out << TABS(level) << "}" << endl;
+ }
+}
+
+void GoGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ GenStateCond **data = state->stateCondVect.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << ":" << endl;
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "case " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << ":" << endl;
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "default:" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << ":" << endl;
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "default:" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ else {
+ out << TABS(level) << "case " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << ":" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "switch {" << endl;
+ out << TABS(level) << "case " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << ":" << endl;
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "default:" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ else {
+ out << TABS(level) << "case " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << ":" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ out << TABS(level) << "}" << endl;
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " {" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " {" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}" << endl;
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " {" << endl;
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}" << endl;
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &GoGotoCodeGen::STATE_GOTOS( int level )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR(level);
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st, level );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << TABS(level + 1) << "_widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl;
+ emitCondBSearch( st, level + 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st, level + 1 );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, level + 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, level + 1 ) << endl;
+ }
+ }
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ out << " tr" << trans->id << ": ";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << vCS() << ";";
+ out << vCS() << " = " << trans->targ->id << "; ";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ out << "goto f" << trans->action->actListId << endl;
+ }
+ else {
+ /* No code to execute, just loop around. */
+ out << "goto _again" << endl;
+ }
+ }
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ out << " f" << redAct->actListId << ": " <<
+ "_acts = " << (redAct->location + 1) << ";"
+ " goto execFuncs" << endl;
+ }
+ }
+
+ out <<
+ endl <<
+ "execFuncs:" << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ " goto _again" << endl;
+ return out;
+}
+
+unsigned int GoGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+unsigned int GoGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+unsigned int GoGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &GoGotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << " ";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st] << ", ";
+ if ( st < numStates-1 ) {
+ if ( (st+1) % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << " ";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st] << ", ";
+ if ( st < numStates-1 ) {
+ if ( (st+1) % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << " ";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st] << ", ";
+ if ( st < numStates-1 ) {
+ if ( (st+1) % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GoGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << TABS(2) << "case " << st->id << ":" << endl;
+
+ /* Write the goto func. */
+ out << TABS(3) << "goto f" << st->eofAction->actListId << endl;
+ }
+ }
+
+ return out;
+}
+
+void GoGotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << " = 0" << endl;
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " var _acts " << INT() << endl <<
+ " var _nacts " << UINT() << endl;
+ }
+
+ if ( redFsm->anyConditions() )
+ out << " var _widec " << WIDE_ALPH_TYPE() << endl;
+
+ out << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ FROM_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ out <<
+ " switch " << vCS() << " {" << endl;
+ STATE_GOTOS(1);
+ out <<
+ " }" << endl <<
+ endl;
+ TRANSITIONS() <<
+ endl;
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << endl;
+
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ TO_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " switch " << vCS() << " {" << endl;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out <<
+ " case " << st->id << ":" << endl <<
+ " goto tr" << st->eofTrans->id << endl;
+ }
+
+ out <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " __acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl <<
+ " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl <<
+ " for ; __nacts > 0; __nacts-- {" << endl <<
+ " __acts++" << endl <<
+ " switch " << A() << "[__acts - 1]" << " {" << endl;
+ EOF_ACTION_SWITCH(3);
+ out <<
+ " }" << endl <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/gogoto.h b/ragel/gogoto.h
new file mode 100644
index 0000000..18d058e
--- /dev/null
+++ b/ragel/gogoto.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOGOTO_H
+#define _GOGOTO_H
+
+#include <iostream>
+#include "gotablish.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+struct GenStateCond;
+
+/*
+ * Goto driven fsm.
+ */
+class GoGotoCodeGen
+ : public GoTablishCodeGen
+{
+public:
+ GoGotoCodeGen( ostream &out )
+ : GoTablishCodeGen(out) {}
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ std::ostream &ACTION_SWITCH( int level );
+ std::ostream &STATE_GOTOS( int level );
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ virtual unsigned int TO_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int EOF_ACTION( RedStateAp *state );
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+ void COND_TRANSLATE( GenStateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ virtual int TRANS_NR( RedTransAp *trans );
+
+ void emitSingleSwitch( RedStateAp *state, int level );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state, int level );
+ virtual void STATE_GOTO_ERROR( int level );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/goipgoto.cpp b/ragel/goipgoto.cpp
new file mode 100644
index 0000000..153197e
--- /dev/null
+++ b/ragel/goipgoto.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "goipgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+using std::endl;
+
+bool GoIpGotoCodeGen::useAgainLabel()
+{
+ return redFsm->anyRegActionRets() ||
+ redFsm->anyRegActionByValControl() ||
+ redFsm->anyRegNextStmt();
+}
+
+void GoIpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << "goto st" << gotoDest << " }";
+}
+
+void GoIpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "] = " << targState <<
+ "; " << TOP() << "++; " << "goto st" << callDest << " }";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void GoIpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "] = " << targState << "; " << TOP() << "++; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << "goto _again }";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void GoIpGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << TOP() << "--; " << vCS() << " = " << STACK() << "[" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << "}";
+ }
+
+ ret << "goto _again }";
+}
+
+void GoIpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << "); " << "goto _again }";
+}
+
+void GoIpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void GoIpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ");";
+}
+
+void GoIpGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void GoIpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << targState;
+}
+
+void GoIpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << "{" << P() << "++; ";
+ if ( !csForced )
+ ret << vCS() << " = " << targState << "; ";
+ ret << "goto _out }";
+}
+
+bool GoIpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
+{
+ bool anyWritten = false;
+
+ /* Emit any transitions that have actions and that go to this state. */
+ for ( int it = 0; it < state->numInTrans; it++ ) {
+ RedTransAp *trans = state->inTrans[it];
+ if ( trans->action != 0 && trans->labelNeeded ) {
+ /* Remember that we wrote an action so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write the label for the transition so it can be jumped to. */
+ out << "tr" << trans->id << ":" << endl;
+
+ /* If the action contains a next, then we must preload the current
+ * state since the action may or may not set it. */
+ if ( trans->action->anyNextStmt() )
+ out << " " << vCS() << " = " << trans->targ->id << endl;
+
+ /* Write each action in the list. */
+ for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
+ ACTION( out, item->value, trans->targ->id, false,
+ trans->action->anyNextStmt() );
+ }
+
+ /* If the action contains a next then we need to reload, otherwise
+ * jump directly to the target state. */
+ if ( trans->action->anyNextStmt() )
+ out << " goto _again" << endl;
+ else
+ out << " goto st" << trans->targ->id << endl;
+ }
+ }
+
+ return anyWritten;
+}
+
+std::ostream &GoIpGotoCodeGen::STATE_GOTOS_SWITCH( int level )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ out << TABS(level) << "case " << st->id << ":" << endl;
+ out << TABS(level + 1) << "goto st_case_" << st->id << endl;
+ }
+ return out;
+}
+
+/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
+ * state. */
+void GoIpGotoCodeGen::GOTO_HEADER( RedStateAp *state, int level )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << TABS(level) << "st" << state->id << ":" << endl;
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->toStateAction->anyNextStmt() );
+ }
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( !noEnd ) {
+ out <<
+ TABS(level + 1) << "if " << P() << "++; " << P() << " == " << PE() << " {" << endl <<
+ TABS(level + 2) << "goto _test_eof" << state->id << endl <<
+ TABS(level + 1) << "}" << endl;
+ }
+ else {
+ out <<
+ TABS(level + 1) << P() << "++" << endl;
+ }
+ }
+
+ /* Give the state a label. */
+ out << TABS(level) << "st_case_" << state->id << ":" << endl;
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
+ ACTION( out, item->value, state->id, false,
+ state->fromStateAction->anyNextStmt() );
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << TABS(level + 1) << "_ps = " << state->id << endl;
+}
+
+void GoIpGotoCodeGen::STATE_GOTO_ERROR( int level )
+{
+ /* In the error state we need to emit some stuff that usually goes into
+ * the header. */
+ RedStateAp *state = redFsm->errState;
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ /* No case label needed since we don't switch on the error state. */
+ if ( anyWritten )
+ genLineDirective( out );
+
+ out << "st_case_" << state->id << ":" << endl;
+ if ( state->labelNeeded )
+ out << TABS(level) << "st" << state->id << ":" << endl;
+
+ /* Break out here. */
+ outLabelUsed = true;
+ out << TABS(level + 1) << vCS() << " = " << state->id << endl;
+ out << TABS(level + 1) << "goto _out" << endl;
+}
+
+
+/* Emit the goto to take for a given transition. */
+std::ostream &GoIpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id;
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id;
+ }
+ return out;
+}
+
+int GoIpGotoCodeGen::TRANS_NR( RedTransAp *trans )
+{
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ return trans->id + redFsm->stateList.length();
+ }
+ else {
+ /* Go directly to the target state. */
+ return trans->targ->id;
+ }
+}
+
+std::ostream &GoIpGotoCodeGen::EXIT_STATES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->outNeeded ) {
+ testEofUsed = true;
+ out << " _test_eof" << st->id << ": " << vCS() << " = " <<
+ st->id << "; goto _test_eof" << endl;
+ }
+ }
+ return out;
+}
+
+std::ostream &GoIpGotoCodeGen::AGAIN_CASES( int level )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ out <<
+ TABS(level) << "case " << st->id << ":" << endl <<
+ TABS(level + 1) << "goto st" << st->id << endl;
+ }
+ return out;
+}
+
+std::ostream &GoIpGotoCodeGen::FINISH_CASES( int level )
+{
+ bool anyWritten = false;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofAction != 0 ) {
+ if ( st->eofAction->eofRefs == 0 )
+ st->eofAction->eofRefs = new IntSet;
+ st->eofAction->eofRefs->insert( st->id );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << TABS(level) << "case " << st->id << ":" << endl <<
+ TABS(level + 1) << "goto tr" << st->eofTrans->id << endl;
+ }
+
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ if ( act->eofRefs != 0 ) {
+ out << TABS(level) << "case ";
+ for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ ) {
+ out << *pst;
+ if ( !pst.last() )
+ out << ", ";
+ }
+ out << ":" << endl;
+
+ /* Remember that we wrote a trans so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write each action in the eof action list. */
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
+ ACTION( out, item->value, STATE_ERR_STATE, true, false );
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+ return out;
+}
+
+void GoIpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Goto: case GenInlineItem::Call: {
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( item->children );
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void GoIpGotoCodeGen::setLabelsNeeded()
+{
+ /* If we use the _again label, then we the _again switch, which uses all
+ * labels. */
+ if ( useAgainLabel() ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = true;
+ }
+ else {
+ /* Do not use all labels by default, init all labelNeeded vars to false. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->labelNeeded = false;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->targ->labelNeeded = true;
+
+ /* Need labels for states that have goto or calls in action code
+ * invoked on characters (ie, not from out action code). */
+ if ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( act->value->inlineList );
+ }
+ }
+ }
+ }
+
+ if ( !noEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st != redFsm->errState )
+ st->outNeeded = st->labelNeeded;
+ }
+ }
+}
+
+void GoIpGotoCodeGen::writeData()
+{
+ STATE_IDS();
+}
+
+void GoIpGotoCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " {" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << " = 0" << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _widec " << WIDE_ALPH_TYPE() << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume" << endl <<
+ endl <<
+ "_again:" << endl <<
+ " switch " << vCS() << " {" << endl;
+ AGAIN_CASES(1) <<
+ " }" << endl <<
+ endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << "++; " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl;
+ }
+ out << "_resume:" << endl;
+ }
+
+ out <<
+ " switch " << vCS() << " {" << endl;
+ STATE_GOTOS_SWITCH(1);
+ out <<
+ " }" << endl;
+ out << " goto st_out" << endl;
+ STATE_GOTOS(1);
+ out << " st_out:" << endl;
+ EXIT_STATES() <<
+ endl;
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl <<
+ " switch " << vCS() << " {" << endl;
+ FINISH_CASES(2);
+ out <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out <<
+ " }" << endl;
+}
diff --git a/ragel/goipgoto.h b/ragel/goipgoto.h
new file mode 100644
index 0000000..cceaee0
--- /dev/null
+++ b/ragel/goipgoto.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOIPGOTO_H
+#define _GOIPGOTO_H
+
+#include <iostream>
+#include "gogoto.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+class GoIpGotoCodeGen
+ : public GoGotoCodeGen
+{
+public:
+ GoIpGotoCodeGen( ostream &out )
+ : GoGotoCodeGen(out) {}
+
+ std::ostream &EXIT_STATES();
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ int TRANS_NR( RedTransAp *trans );
+ std::ostream &FINISH_CASES( int level );
+ std::ostream &AGAIN_CASES( int level );
+ std::ostream &STATE_GOTOS_SWITCH( int level );
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void BREAK( ostream &ret, int targState, bool csForced );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ bool useAgainLabel();
+
+ /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for
+ * each state. */
+ bool IN_TRANS_ACTIONS( RedStateAp *state );
+ void GOTO_HEADER( RedStateAp *state, int level );
+ void STATE_GOTO_ERROR( int level );
+
+ /* Set up labelNeeded flag for each state. */
+ void setLabelsNeeded( GenInlineList *inlineList );
+ void setLabelsNeeded();
+};
+
+#endif
diff --git a/ragel/gotable.cpp b/ragel/gotable.cpp
new file mode 100644
index 0000000..01152d3
--- /dev/null
+++ b/ragel/gotable.cpp
@@ -0,0 +1,977 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 <sstream>
+#include "ragel.h"
+#include "gotable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::endl;
+
+/* Determine if we should use indicies or not. */
+void GoTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &GoTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::TO_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoTabCodeGen::FROM_STATE_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GoTabCodeGen::EOF_ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, true, false );
+ }
+ }
+
+ genLineDirective(out);
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::ACTION_SWITCH( int level )
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << TABS(level) << "case " << act->actionId << ":" << endl;
+ ACTION( out, act, 0, false, false );
+ }
+ }
+
+ genLineDirective(out);
+ return out;
+}
+
+std::ostream &GoTabCodeGen::COND_OFFSETS()
+{
+ out << " ";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::KEY_OFFSETS()
+{
+ out << " ";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::INDEX_OFFSETS()
+{
+ out << " ";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::COND_LENS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->stateCondList.length();
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::SINGLE_LENS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->outSingle.length();
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::RANGE_LENS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ out << st->outRange.length();
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::TO_STATE_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::FROM_STATE_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::EOF_ACTIONS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::EOF_TRANS()
+{
+ out << " ";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ out << ", ";
+ if ( !st.last() ) {
+ if ( ++totalStateNum % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::COND_KEYS()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ out << KEY( sc->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+
+ /* Upper key. */
+ out << KEY( sc->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::COND_SPACES()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ out << sc->condSpace->condSpaceId << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::KEYS()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << KEY( stel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ out << KEY( rtel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+
+ /* Upper key. */
+ out << KEY( rtel->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::INDICIES()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << stel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ out << rtel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::TRANS_TARGS()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ /* Add any eof transitions that have not yet been written out above. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+
+ out << endl;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::TRANS_ACTIONS()
+{
+ out << " ";
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ /* Add any eof transitions that have not yet been written out above. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+
+ out << endl;
+ return out;
+}
+
+std::ostream &GoTabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << " ";
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id << ", ";
+ if ( t < redFsm->transSet.length()-1 ) {
+ if ( ++totalStates % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &GoTabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << " ";
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ out << ", ";
+ if ( t < redFsm->transSet.length()-1 ) {
+ if ( ++totalAct % IALL == 0 )
+ out << endl << " ";
+ }
+ }
+ out << endl;
+ delete[] transPtrs;
+ return out;
+}
+
+void GoTabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() << endl;
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() << endl;
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() << endl;
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() << endl;
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() << endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() << endl;
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() << endl;
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() << endl;
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() << endl;
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() << endl;
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() << endl;
+ }
+
+ STATE_IDS();
+}
+
+void GoTabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << CAST(INT(), KO() + "[" + vCS() + "]") << endl <<
+ " _trans = " << CAST(INT(), IO() + "[" + vCS() + "]") << endl <<
+ endl <<
+ " _klen = " << CAST(INT(), SL() + "[" + vCS() + "]") << endl <<
+ " if _klen > 0 {" << endl <<
+ " _lower := " << CAST(INT(), "_keys") << endl <<
+ " var _mid " << INT() << endl <<
+ " _upper := " << CAST(INT(), "_keys + _klen - 1") << endl <<
+ " for {" << endl <<
+ " if _upper < _lower {" << endl <<
+ " break" << endl <<
+ " }" << endl <<
+ endl <<
+ " _mid = _lower + ((_upper - _lower) >> 1)" << endl <<
+ " switch {" << endl <<
+ " case " << GET_WIDE_KEY() << " < " << K() << "[_mid]" << ":" << endl <<
+ " _upper = _mid - 1" << endl <<
+ " case " << GET_WIDE_KEY() << " > " << K() << "[_mid]" << ":" << endl <<
+ " _lower = _mid + 1" << endl <<
+ " default:" << endl <<
+ " _trans += " << CAST(INT(), "_mid - " + CAST(INT(), "_keys")) << endl <<
+ " goto _match" << endl <<
+ " }" << endl <<
+ " }" << endl <<
+ " _keys += _klen" << endl <<
+ " _trans += _klen" << endl <<
+ " }" << endl <<
+ endl <<
+ " _klen = " << CAST(INT(), RL() + "[" + vCS() + "]") << endl <<
+ " if _klen > 0 {" << endl <<
+ " _lower := " << CAST(INT(), "_keys") << endl <<
+ " var _mid " << INT() << endl <<
+ " _upper := " << CAST(INT(), "_keys + (_klen << 1) - 2") << endl <<
+ " for {" << endl <<
+ " if _upper < _lower {" << endl <<
+ " break" << endl <<
+ " }" << endl <<
+ endl <<
+ " _mid = _lower + (((_upper - _lower) >> 1) & ^1)" << endl <<
+ " switch {" << endl <<
+ " case " << GET_WIDE_KEY() << " < " << K() << "[_mid]" << ":" << endl <<
+ " _upper = _mid - 2" << endl <<
+ " case " << GET_WIDE_KEY() << " > " << K() << "[_mid + 1]" << ":" << endl <<
+ " _lower = _mid + 2" << endl <<
+ " default:" << endl <<
+ " _trans += " << CAST(INT(), "(_mid - " + CAST(INT(), "_keys") + ") >> 1") << endl <<
+ " goto _match" << endl <<
+ " }" << endl <<
+ " }" << endl <<
+ " _trans += _klen" << endl <<
+ " }" << endl <<
+ endl;
+}
+
+void GoTabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl <<
+ " _klen = " << CAST(INT(), CL() + "[" + vCS() + "]") << endl <<
+ " _keys = " << CAST(INT(), CO() + "[" + vCS() + "] * 2") << endl <<
+ " if _klen > 0 {" << endl <<
+ " _lower := " << CAST(INT(), "_keys") << endl <<
+ " var _mid " << INT() << endl <<
+ " _upper := " << CAST(INT(), "_keys + (_klen << 1) - 2") << endl <<
+ " COND_LOOP:" << endl <<
+ " for {" << endl <<
+ " if _upper < _lower {" << endl <<
+ " break" << endl <<
+ " }" << endl <<
+ endl <<
+ " _mid = _lower + (((_upper - _lower) >> 1) & ^1)" << endl <<
+ " switch {" << endl <<
+ " case " << GET_WIDE_KEY() << " < " << CAST(WIDE_ALPH_TYPE(), CK() + "[_mid]") << ":" << endl <<
+ " _upper = _mid - 2" << endl <<
+ " case " << GET_WIDE_KEY() << " > " << CAST(WIDE_ALPH_TYPE(), CK() + "[_mid + 1]") << ":" << endl <<
+ " _lower = _mid + 2" << endl <<
+ " default:" << endl <<
+ " switch " << C() << "[" << CAST(INT(), CO() + "[" + vCS() + "]") <<
+ " + ((_mid - _keys)>>1)] {" << endl;
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << TABS(4) << "case " << condSpace->condSpaceId << ":" << endl;
+ out << TABS(5) << "_widec = " << KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) <<
+ " - " << KEY(keyOps->minKey) << ")" << endl;
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(5) << "if ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " {" << endl << TABS(6) << "_widec += " << condValOffset << endl << TABS(5) << "}" << endl;
+ }
+ }
+
+ out <<
+ " }" << endl <<
+ " break COND_LOOP" << endl <<
+ " }" << endl <<
+ " }" << endl <<
+ " }" << endl <<
+ endl;
+}
+
+void GoTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out <<
+ " {" << endl <<
+ " var _klen " << INT() << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " var _ps " << INT() << endl;
+
+ out <<
+ " var _trans " << INT() << endl;
+
+ if ( redFsm->anyConditions() )
+ out << " var _widec " << WIDE_ALPH_TYPE() << endl;
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " var _acts " << INT() << endl <<
+ " var _nacts " << UINT() << endl;
+ }
+
+ out <<
+ " var _keys " << INT() << endl;
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " == " << PE() << " {" << endl <<
+ " goto _test_eof" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ out << "_resume:" << endl;
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts - 1]" << " {" << endl;
+ FROM_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl << endl;
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:" << endl;
+
+ if ( useIndicies )
+ out << " _trans = " << CAST(INT(), I() + "[_trans]") << endl;
+
+ if ( redFsm->anyEofTrans() )
+ out << "_eof_trans:" << endl;
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << endl;
+
+ out <<
+ " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl << endl;
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] == 0 {" << endl <<
+ " goto _again" << endl <<
+ " }" << endl <<
+ endl <<
+ " _acts = " << CAST(INT(), TA() + "[_trans]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts-1]" << " {" << endl;
+ ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl << endl;
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:" << endl;
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl <<
+ " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
+ " for ; _nacts > 0; _nacts-- {" << endl <<
+ " _acts++" << endl <<
+ " switch " << A() << "[_acts-1] {" << endl;
+ TO_STATE_ACTION_SWITCH(2);
+ out <<
+ " }" << endl <<
+ " }" << endl << endl;
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
+ " goto _out" << endl <<
+ " }" << endl;
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " " << P() << "++" << endl <<
+ " if " << P() << " != " << PE() << " {" << endl <<
+ " goto _resume" << endl <<
+ " }" << endl;
+ }
+ else {
+ out <<
+ " " << P() << "++" << endl <<
+ " goto _resume" << endl;
+ }
+
+ if ( testEofUsed )
+ out << " _test_eof: {}" << endl;
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << " {" << endl;
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
+ " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
+ " goto _eof_trans" << endl <<
+ " }" << endl;
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " __acts := " << EA() << "[" << vCS() << "]" << endl <<
+ " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl <<
+ " for ; __nacts > 0; __nacts-- {" << endl <<
+ " __acts++" << endl <<
+ " switch " << A() << "[__acts-1] {" << endl;
+ EOF_ACTION_SWITCH(3);
+ out <<
+ " }" << endl <<
+ " }" << endl;
+ }
+
+ out <<
+ " }" << endl << endl;
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}" << endl;
+
+ out << " }" << endl;
+}
diff --git a/ragel/gotable.h b/ragel/gotable.h
new file mode 100644
index 0000000..a62b8a0
--- /dev/null
+++ b/ragel/gotable.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOTABLE_H
+#define _GOTABLE_H
+
+#include <iostream>
+#include "gotablish.h"
+
+class GoTabCodeGen
+ : public GoTablishCodeGen
+{
+public:
+ GoTabCodeGen( ostream &out )
+ : GoTablishCodeGen(out) {}
+
+ virtual ~GoTabCodeGen() { }
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH( int level );
+ std::ostream &FROM_STATE_ACTION_SWITCH( int level );
+ std::ostream &EOF_ACTION_SWITCH( int level );
+ std::ostream &ACTION_SWITCH( int level );
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+ void LOCATE_TRANS();
+
+ void COND_TRANSLATE();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void calcIndexSize();
+};
+
+#endif
diff --git a/ragel/gotablish.cpp b/ragel/gotablish.cpp
new file mode 100644
index 0000000..218ab47
--- /dev/null
+++ b/ragel/gotablish.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "gotablish.h"
+
+using std::endl;
+
+void GoTablishCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << vCS() << " = " << gotoDest << endl <<
+ "goto _again" << endl;
+}
+
+void GoTablishCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ")" << endl << "goto _again" << endl;
+}
+
+void GoTablishCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void GoTablishCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void GoTablishCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << endl;
+}
+
+void GoTablishCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
+ ret << ")" << endl;
+}
+
+void GoTablishCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{ ";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << "++; " <<
+ vCS() << " = " << callDest << "; " << "goto _again" << endl;
+
+ if ( prePushExpr != 0 )
+ ret << " }";
+}
+
+void GoTablishCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false, false );
+ }
+
+ ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << "++; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
+ ret << "); " << "goto _again" << endl;
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void GoTablishCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << TOP() << "--; " << vCS() << " = " << STACK() << "[" <<
+ TOP() << "]" << endl;
+
+ if ( postPopExpr != 0 ) {
+ ret << "{ ";
+ INLINE_LIST( ret, postPopExpr, 0, false, false );
+ ret << " }" << endl;
+ }
+
+ ret << "goto _again" << endl;
+}
+
+void GoTablishCodeGen::BREAK( ostream &ret, int targState, bool csForced )
+{
+ outLabelUsed = true;
+ ret << P() << "++; " << "goto _out" << endl;
+}
diff --git a/ragel/gotablish.h b/ragel/gotablish.h
new file mode 100644
index 0000000..9e79b11
--- /dev/null
+++ b/ragel/gotablish.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _GOTABLISH_H
+#define _GOTABLISH_H
+
+#include "gocodegen.h"
+
+class GoTablishCodeGen
+ : public GoCodeGen
+{
+public:
+ GoTablishCodeGen( ostream &out )
+ : GoCodeGen(out) {}
+protected:
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish );
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ virtual void CURS( ostream &ret, bool inFinish );
+ virtual void TARGS( ostream &ret, bool inFinish, int targState );
+ virtual void RET( ostream &ret, bool inFinish );
+ virtual void BREAK( ostream &ret, int targState, bool csForced );
+};
+
+#endif
diff --git a/ragel/inputdata.cpp b/ragel/inputdata.cpp
new file mode 100644
index 0000000..7d8322f
--- /dev/null
+++ b/ragel/inputdata.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2008 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 "ragel.h"
+#include "common.h"
+#include "inputdata.h"
+#include "parsedata.h"
+#include "rlparse.h"
+#include <iostream>
+#include "dotcodegen.h"
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ios;
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::cdDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 ) {
+ const char *ext = findFileExtension( inputFile );
+ if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".h" );
+ else {
+ const char *defExtension = 0;
+ switch ( hostLang->lang ) {
+ case HostLang::C: defExtension = ".c"; break;
+ case HostLang::D: defExtension = ".d"; break;
+ case HostLang::D2: defExtension = ".d"; break;
+ default: break;
+ }
+ outputFileName = fileNameFromStem( inputFile, defExtension );
+ }
+ }
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::goDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".go" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::javaDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".java" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::rubyDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".rb" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::csharpDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 ) {
+ const char *ext = findFileExtension( inputFile );
+ if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".h" );
+ else
+ outputFileName = fileNameFromStem( inputFile, ".cs" );
+ }
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::ocamlDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".ml" );
+}
+
+void InputData::makeOutputStream()
+{
+ if ( ! generateDot && ! generateXML ) {
+ switch ( hostLang->lang ) {
+ case HostLang::C:
+ case HostLang::D:
+ case HostLang::D2:
+ cdDefaultFileName( inputFileName );
+ break;
+ case HostLang::Java:
+ javaDefaultFileName( inputFileName );
+ break;
+ case HostLang::Go:
+ goDefaultFileName( inputFileName );
+ break;
+ case HostLang::Ruby:
+ rubyDefaultFileName( inputFileName );
+ break;
+ case HostLang::CSharp:
+ csharpDefaultFileName( inputFileName );
+ break;
+ case HostLang::OCaml:
+ ocamlDefaultFileName( inputFileName );
+ break;
+ }
+ }
+
+ /* Make sure we are not writing to the same file as the input file. */
+ if ( outputFileName != 0 ) {
+ if ( strcmp( inputFileName, outputFileName ) == 0 ) {
+ error() << "output file \"" << outputFileName <<
+ "\" is the same as the input file" << endl;
+ }
+
+ /* Create the filter on the output and open it. */
+ outFilter = new output_filter( outputFileName );
+
+ /* Open the output stream, attaching it to the filter. */
+ outStream = new ostream( outFilter );
+ }
+ else {
+ /* Writing out ot std out. */
+ outStream = &cout;
+ }
+}
+
+void InputData::openOutput()
+{
+ if ( outFilter != 0 ) {
+ outFilter->open( outputFileName, ios::out|ios::trunc );
+ if ( !outFilter->is_open() ) {
+ error() << "error opening " << outputFileName << " for writing" << endl;
+ exit(1);
+ }
+ }
+}
+
+void InputData::prepareMachineGen()
+{
+ if ( generateDot ) {
+ /* Locate a machine spec to generate dot output for. We can only emit.
+ * Dot takes one graph at a time. */
+ if ( machineSpec != 0 ) {
+ /* Machine specified. */
+ ParserDictEl *pdEl = parserDict.find( machineSpec );
+ if ( pdEl == 0 )
+ error() << "could not locate machine specified with -S and/or -M" << endp;
+ dotGenParser = pdEl->value;
+ }
+ else {
+ /* No machine spec given, just use the first one. */
+ if ( parserList.length() == 0 )
+ error() << "no machine specification to generate graphviz output" << endp;
+
+ dotGenParser = parserList.head;
+ }
+
+ GraphDictEl *gdEl = 0;
+
+ if ( machineName != 0 ) {
+ gdEl = dotGenParser->pd->graphDict.find( machineName );
+ if ( gdEl == 0 )
+ error() << "machine definition/instantiation not found" << endp;
+ }
+ else {
+ /* We are using the whole machine spec. Need to make sure there
+ * are instances in the spec. */
+ if ( dotGenParser->pd->instanceList.length() == 0 )
+ error() << "no machine instantiations to generate graphviz output" << endp;
+ }
+
+ dotGenParser->pd->prepareMachineGen( gdEl );
+ }
+ else {
+ /* No machine spec or machine name given. Generate everything. */
+ for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
+ ParseData *pd = parser->value->pd;
+ if ( pd->instanceList.length() > 0 )
+ pd->prepareMachineGen( 0 );
+ }
+ }
+}
+
+void InputData::generateReduced()
+{
+ if ( generateDot )
+ dotGenParser->pd->generateReduced( *this );
+ else {
+ for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
+ ParseData *pd = parser->value->pd;
+ if ( pd->instanceList.length() > 0 )
+ pd->generateReduced( *this );
+ }
+ }
+}
+
+/* Send eof to all parsers. */
+void InputData::terminateAllParsers( )
+{
+ /* FIXME: a proper token is needed here. Suppose we should use the
+ * location of EOF in the last file that the parser was referenced in. */
+ InputLoc loc;
+ loc.fileName = "<EOF>";
+ loc.line = 0;
+ loc.col = 0;
+ for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
+ pdel->value->token( loc, Parser_tk_eof, 0, 0 );
+}
+
+void InputData::verifyWritesHaveData()
+{
+ if ( !generateXML && !generateDot ) {
+ for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
+ if ( ii->type == InputItem::Write ) {
+ if ( ii->pd->cgd == 0 )
+ error( ii->loc ) << "no machine instantiations to write" << endl;
+ }
+ }
+ }
+}
+
+void InputData::writeOutput()
+{
+ if ( generateXML )
+ writeXML( *outStream );
+ else if ( generateDot )
+ static_cast<GraphvizDotGen*>(dotGenParser->pd->cgd)->writeDotFile();
+ else {
+ bool hostLineDirective = true;
+ for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
+ if ( ii->type == InputItem::Write ) {
+ CodeGenData *cgd = ii->pd->cgd;
+ ::keyOps = &cgd->thisKeyOps;
+
+ hostLineDirective = cgd->writeStatement( ii->loc,
+ ii->writeArgs.length()-1, ii->writeArgs.data );
+ }
+ else {
+ if ( hostLineDirective ) {
+ /* Write statements can turn off host line directives for
+ * host sections that follow them. */
+ *outStream << '\n';
+ lineDirective( *outStream, inputFileName, ii->loc.line );
+ }
+ *outStream << ii->data.str();
+ hostLineDirective = true;
+ }
+ }
+ }
+}
+
diff --git a/ragel/inputdata.h b/ragel/inputdata.h
new file mode 100644
index 0000000..09a62c1
--- /dev/null
+++ b/ragel/inputdata.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008 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
+ */
+
+#ifndef _INPUT_DATA
+#define _INPUT_DATA
+
+#include "gendata.h"
+#include <iostream>
+#include <sstream>
+
+struct Parser;
+struct ParseData;
+
+struct InputItem
+{
+ enum Type {
+ HostData,
+ Write,
+ };
+
+ Type type;
+ std::ostringstream data;
+ std::string name;
+ ParseData *pd;
+ Vector<char *> writeArgs;
+
+ InputLoc loc;
+
+ InputItem *prev, *next;
+};
+
+struct Parser;
+
+typedef AvlMap<const char*, Parser*, CmpStr> ParserDict;
+typedef AvlMapEl<const char*, Parser*> ParserDictEl;
+typedef DList<Parser> ParserList;
+typedef DList<InputItem> InputItemList;
+typedef Vector<const char *> ArgsVector;
+
+struct InputData
+{
+ InputData() :
+ inputFileName(0),
+ outputFileName(0),
+ inStream(0),
+ outStream(0),
+ outFilter(0),
+ dotGenParser(0)
+ {}
+
+ /* The name of the root section, this does not change during an include. */
+ const char *inputFileName;
+ const char *outputFileName;
+
+ /* Io globals. */
+ std::istream *inStream;
+ std::ostream *outStream;
+ output_filter *outFilter;
+
+ Parser *dotGenParser;
+
+ ParserDict parserDict;
+ ParserList parserList;
+ InputItemList inputItems;
+
+ ArgsVector includePaths;
+
+ void verifyWritesHaveData();
+
+ void writeOutput();
+ void makeOutputStream();
+ void openOutput();
+ void generateReduced();
+ void prepareMachineGen();
+ void terminateAllParsers();
+
+ void cdDefaultFileName( const char *inputFile );
+ void goDefaultFileName( const char *inputFile );
+ void javaDefaultFileName( const char *inputFile );
+ void rubyDefaultFileName( const char *inputFile );
+ void csharpDefaultFileName( const char *inputFile );
+ void ocamlDefaultFileName( const char *inputFile );
+
+ void writeLanguage( std::ostream &out );
+ void writeXML( std::ostream &out );
+};
+
+#endif
diff --git a/ragel/javacodegen.cpp b/ragel/javacodegen.cpp
new file mode 100644
index 0000000..ff2193c
--- /dev/null
+++ b/ragel/javacodegen.cpp
@@ -0,0 +1,1684 @@
+/*
+ * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
+ * 2007 Colin Fleming <colin.fleming@caverock.com>
+ */
+
+/* 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 "ragel.h"
+#include "javacodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <iomanip>
+#include <sstream>
+
+/* Integer array line length. */
+#define IALL 12
+
+/* Static array initialization item count
+ * (should be multiple of IALL). */
+#define SAIIC 8184
+
+#define _resume 1
+#define _again 2
+#define _eof_trans 3
+#define _test_eof 4
+#define _out 5
+
+using std::setw;
+using std::ios;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::setiosflags;
+
+void javaLineDirective( ostream &out, const char *fileName, int line )
+{
+ /* Write the preprocessor line info for to the input file. */
+ out << "// line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+ out << "\"\n";
+}
+
+void JavaTabCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ javaLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << gotoDest << "; _goto_targ = " << _again << "; " <<
+ CTRL_FLOW() << "continue _goto;}";
+}
+
+void JavaTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
+}
+
+void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void JavaTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ ret << "_goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
+}
+
+void JavaTabCodeGen::BREAK( ostream &ret, int targState )
+{
+ ret << "{ " << P() << " += 1; _goto_targ = " << _out << "; " <<
+ CTRL_FLOW() << " continue _goto;}";
+}
+
+void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void JavaTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void JavaTabCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+ /* The parser gives fexec two children. The double brackets are for D
+ * code. If the inline list is a single word it will get interpreted as a
+ * C-style cast by the D compiler. */
+ ret << "{" << P() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "))-1;}";
+}
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void JavaTabCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << "--;";
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ ret << "(_ps)";
+ break;
+ case GenInlineItem::Targs:
+ ret << "(" << vCS() << ")";
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState );
+ break;
+ }
+ }
+}
+
+string JavaTabCodeGen::DATA_PREFIX()
+{
+ if ( !noPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string JavaTabCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string JavaTabCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+
+
+void JavaTabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n"
+ " _keys = " << CO() << "[" << vCS() << "]*2\n;"
+ " _klen = " << CL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " int _lower = _keys\n;"
+ " int _mid;\n"
+ " int _upper = _keys + (_klen<<1) - 2;\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " switch ( " << C() << "[" << CO() << "[" << vCS() << "]"
+ " + ((_mid - _keys)>>1)] ) {\n"
+ ;
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId << ": {\n";
+ out << TABS(2) << "_widec = " << KEY(condSpace->baseKey) <<
+ " + (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ");\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out <<
+ " break;\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+}
+
+
+void JavaTabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _match: do {\n"
+ " _keys = " << KO() << "[" << vCS() << "]" << ";\n"
+ " _trans = " << IO() << "[" << vCS() << "];\n"
+ " _klen = " << SL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " int _lower = _keys;\n"
+ " int _mid;\n"
+ " int _upper = _keys + _klen - 1;\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + ((_upper-_lower) >> 1);\n"
+ " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+ " _upper = _mid - 1;\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
+ " _lower = _mid + 1;\n"
+ " else {\n"
+ " _trans += (_mid - _keys);\n"
+ " break _match;\n"
+ " }\n"
+ " }\n"
+ " _keys += _klen;\n"
+ " _trans += _klen;\n"
+ " }\n"
+ "\n"
+ " _klen = " << RL() << "[" << vCS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " int _lower = _keys;\n"
+ " int _mid;\n"
+ " int _upper = _keys + (_klen<<1) - 2;\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " _trans += ((_mid - _keys)>>1);\n"
+ " break _match;\n"
+ " }\n"
+ " }\n"
+ " _trans += _klen;\n"
+ " }\n"
+ " } while (false);\n"
+ "\n";
+}
+
+/* Determine if we should use indicies or not. */
+void JavaTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+
+int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ return act;
+}
+
+std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::COND_OFFSETS()
+{
+ int curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ ARRAY_ITEM( INT(curKeyOffset), st.last() );
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::KEY_OFFSETS()
+{
+ int curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ ARRAY_ITEM( INT(curKeyOffset), st.last() );
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
+{
+ int curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ ARRAY_ITEM( INT(curIndOffset), st.last() );
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::COND_LENS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
+ }
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::SINGLE_LENS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::RANGE_LENS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ ARRAY_ITEM( INT(st->outRange.length()), st.last() );
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(TO_STATE_ACTION(st)), st.last() );
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), st.last() );
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::EOF_ACTIONS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::EOF_TRANS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(trans), st.last() );
+ }
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::COND_KEYS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ ARRAY_ITEM( KEY( sc->lowKey ), false );
+ ARRAY_ITEM( KEY( sc->highKey ), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::COND_SPACES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::KEYS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ ARRAY_ITEM( KEY( stel->lowKey ), false );
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ ARRAY_ITEM( KEY( rtel->lowKey ), false );
+
+ /* Upper key. */
+ ARRAY_ITEM( KEY( rtel->highKey ), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::INDICIES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ ARRAY_ITEM( KEY( stel->value->id ), false );
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ ARRAY_ITEM( KEY( rtel->value->id ), false );
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ ARRAY_ITEM( KEY( st->defTrans->id ), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ ARRAY_ITEM( KEY( trans->targ->id ), false );
+ totalTrans++;
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ ARRAY_ITEM( KEY( trans->targ->id ), false );
+ totalTrans++;
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ ARRAY_ITEM( KEY( trans->targ->id ), false );
+ totalTrans++;
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans++;
+ ARRAY_ITEM( KEY( trans->targ->id ), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), true );
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Save the position. Needed for eofTargs. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
+ }
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ( t >= redFsm->transSet.length()-1 ) );
+ }
+ delete[] transPtrs;
+ return out;
+}
+
+void JavaTabCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
+ << " = " << KEY(ex->key) << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+void JavaTabCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void JavaTabCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void JavaTabCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+void JavaTabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
+
+ if ( !noFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
+
+ if ( !noError )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+void JavaTabCodeGen::writeExec()
+{
+ out <<
+ " {\n"
+ " int _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " int _trans = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " int _widec;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions() ||
+ redFsm->anyFromStateActions() )
+ {
+ out <<
+ " int _acts;\n"
+ " int _nacts;\n";
+ }
+
+ out <<
+ " int _keys;\n"
+ " int _goto_targ = 0;\n"
+ "\n";
+
+ out <<
+ " _goto: while (true) {\n"
+ " switch ( _goto_targ ) {\n"
+ " case 0:\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if ( " << P() << " == " << PE() << " ) {\n"
+ " _goto_targ = " << _test_eof << ";\n"
+ " continue _goto;\n"
+ " }\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " ) {\n"
+ " _goto_targ = " << _out << ";\n"
+ " continue _goto;\n"
+ " }\n";
+ }
+
+ out << "case " << _resume << ":\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" << vCS() << "]" << ";\n"
+ " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ FROM_STATE_ACTION_SWITCH() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() )
+ out << "case " << _eof_trans << ":\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] != 0 ) {\n"
+ " _acts = " << TA() << "[_trans]" << ";\n"
+ " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 )\n {\n"
+ " switch ( " << A() << "[_acts++] )\n"
+ " {\n";
+ ACTION_SWITCH() <<
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ out << "case " << _again << ":\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "]" << ";\n"
+ " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[_acts++] ) {\n";
+ TO_STATE_ACTION_SWITCH() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " ) {\n"
+ " _goto_targ = " << _out << ";\n"
+ " continue _goto;\n"
+ " }\n";
+ }
+
+ if ( !noEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " ) {\n"
+ " _goto_targ = " << _resume << ";\n"
+ " continue _goto;\n"
+ " }\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " _goto_targ = " << _resume << ";\n"
+ " continue _goto;\n";
+ }
+
+ out << "case " << _test_eof << ":\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if ( " << P() << " == " << vEOF() << " )\n"
+ " {\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if ( " << ET() << "[" << vCS() << "] > 0 ) {\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " _goto_targ = " << _eof_trans << ";\n"
+ " continue _goto;\n"
+ " }\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " int __acts = " << EA() << "[" << vCS() << "]" << ";\n"
+ " int __nacts = " << CAST("int") << " " << A() << "[__acts++];\n"
+ " while ( __nacts-- > 0 ) {\n"
+ " switch ( " << A() << "[__acts++] ) {\n";
+ EOF_ACTION_SWITCH() <<
+ " }\n"
+ " }\n";
+ }
+
+ out <<
+ " }\n"
+ "\n";
+ }
+
+ out << "case " << _out << ":\n";
+
+ /* The switch and goto loop. */
+ out << " }\n";
+ out << " break; }\n";
+
+ /* The execute block. */
+ out << " }\n";
+}
+
+std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
+{
+ array_type = type;
+ array_name = name;
+ item_count = 0;
+ div_count = 1;
+
+ out << "private static " << type << "[] init_" << name << "_0()\n"
+ "{\n\t"
+ "return new " << type << " [] {\n\t";
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
+{
+ item_count++;
+
+ out << setw(5) << setiosflags(ios::right) << item;
+
+ if ( !last ) {
+ if ( item_count % SAIIC == 0 ) {
+ out << "\n\t};\n};\n"
+ "private static "<< array_type << "[] init_" <<
+ array_name << "_" << div_count << "()\n"
+ "{\n\t"
+ "return new " << array_type << " [] {\n\t";
+ div_count++;
+ } else if (item_count % IALL == 0) {
+ out << ",\n\t";
+ } else {
+ out << ",";
+ }
+ }
+ return out;
+}
+
+std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
+{
+ out << "\n\t};\n}\n\n";
+
+ if (item_count < SAIIC) {
+ out << "private static final " << array_type << " " << array_name <<
+ "[] = init_" << array_name << "_0();\n\n";
+ } else {
+ out << "private static final " << array_type << " [] combine_" << array_name
+ << "() {\n\t"
+ << array_type << " [] combined = new " << array_type <<
+ " [ " << item_count << " ];\n\t";
+ int block = 0;
+ int full_blocks = item_count / SAIIC;
+ for (;block < full_blocks; ++block) {
+ out << "System.arraycopy ( init_" << array_name << "_" << block <<
+ "(), 0, combined, " << SAIIC * block << ", " << SAIIC << " );\n\t";
+ }
+ if ( (item_count % SAIIC) > 0 ) {
+ out << "System.arraycopy ( init_" << array_name << "_" << block <<
+ "(), 0, combined, " << SAIIC * block << ", " <<
+ (item_count % SAIIC) << " );\n\t";
+ }
+ out << "return combined;\n}\n";
+ out << "private static final " << array_type << " [] " << array_name <<
+ " = combine_" << array_name << "();";
+ }
+ return out;
+}
+
+
+std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "static final " << type << " " << name;
+ return out;
+}
+
+string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
+{
+ return ptr + " + " + offset;
+}
+
+string JavaTabCodeGen::CAST( string type )
+{
+ return "(" + type + ")";
+}
+
+string JavaTabCodeGen::NULL_ITEM()
+{
+ /* In java we use integers instead of pointers. */
+ return "-1";
+}
+
+string JavaTabCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << DATA() << "[" << P() << "]";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::CTRL_FLOW()
+{
+ return "if (true) ";
+}
+
+unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+
+/* Write out the fsm name. */
+string JavaTabCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string JavaTabCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
+{
+ ARRAY_ITEM( INT(0), false );
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ ARRAY_ITEM( INT(act->key.length()), false );
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
+ ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
+ }
+ return out;
+}
+
+
+string JavaTabCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false );
+ return ret.str();
+}
+
+string JavaTabCodeGen::P()
+{
+ ostringstream ret;
+ if ( pExpr == 0 )
+ ret << "p";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, pExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::PE()
+{
+ ostringstream ret;
+ if ( peExpr == 0 )
+ ret << "pe";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, peExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::vEOF()
+{
+ ostringstream ret;
+ if ( eofExpr == 0 )
+ ret << "eof";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, eofExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::vCS()
+{
+ ostringstream ret;
+ if ( csExpr == 0 )
+ ret << ACCESS() << "cs";
+ else {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, csExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::TOP()
+{
+ ostringstream ret;
+ if ( topExpr == 0 )
+ ret << ACCESS() + "top";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, topExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::STACK()
+{
+ ostringstream ret;
+ if ( stackExpr == 0 )
+ ret << ACCESS() + "stack";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, stackExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::ACT()
+{
+ ostringstream ret;
+ if ( actExpr == 0 )
+ ret << ACCESS() + "act";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, actExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::TOKSTART()
+{
+ ostringstream ret;
+ if ( tokstartExpr == 0 )
+ ret << ACCESS() + "ts";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokstartExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::TOKEND()
+{
+ ostringstream ret;
+ if ( tokendExpr == 0 )
+ ret << ACCESS() + "te";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, tokendExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string JavaTabCodeGen::DATA()
+{
+ ostringstream ret;
+ if ( dataExpr == 0 )
+ ret << ACCESS() + "data";
+ else {
+ ret << "(";
+ INLINE_LIST( ret, dataExpr, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+
+string JavaTabCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string JavaTabCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+string JavaTabCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal();
+ return ret.str();
+}
+
+string JavaTabCodeGen::INT( int i )
+{
+ ostringstream ret;
+ ret << i;
+ return ret.str();
+}
+
+void JavaTabCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish )
+{
+ ret <<
+ " switch( " << ACT() << " ) {\n";
+
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 )
+ ret << " default:\n";
+ else
+ ret << " case " << lma->lmId << ":\n";
+
+ /* Write the block and close it off. */
+ ret << " {";
+ INLINE_LIST( ret, lma->children, targState, inFinish );
+ ret << "}\n";
+
+ ret << " break;\n";
+ }
+
+ ret <<
+ " }\n"
+ "\t";
+}
+
+void JavaTabCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void JavaTabCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << ";";
+}
+
+void JavaTabCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void JavaTabCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = 0;";
+}
+
+void JavaTabCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << ";";
+}
+
+void JavaTabCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "}";
+ }
+}
+
+void JavaTabCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ javaLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t{";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish );
+ ret << "}\n";
+}
+
+void JavaTabCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ ret << "\n";
+ javaLineDirective( ret, condition->loc.fileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+string JavaTabCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string JavaTabCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void JavaTabCodeGen::writeInit()
+{
+ out << " {\n";
+
+ if ( !noCS )
+ out << "\t" << vCS() << " = " << START() << ";\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\t" << TOP() << " = 0;\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
+ " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
+ " " << ACT() << " = 0;\n";
+ }
+ out << " }\n";
+}
+
+void JavaTabCodeGen::finishRagelDef()
+{
+ /* The frontend will do this for us, but it may be a good idea to force it
+ * if the intermediate file is edited. */
+ redFsm->sortByStateId();
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &JavaTabCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &JavaTabCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
+
diff --git a/ragel/javacodegen.h b/ragel/javacodegen.h
new file mode 100644
index 0000000..06914c9
--- /dev/null
+++ b/ragel/javacodegen.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
+ * 2007 Colin Fleming <colin.fleming@caverock.com>
+ */
+
+/* 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
+ */
+
+#ifndef _JAVACODEGEN_H
+#define _JAVACODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/*
+ * JavaTabCodeGen
+ */
+struct JavaTabCodeGen : public CodeGenData
+{
+ JavaTabCodeGen( ostream &out ) :
+ CodeGenData(out) {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+
+ void BREAK( ostream &ret, int targState );
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+
+ void COND_TRANSLATE();
+ void LOCATE_TRANS();
+
+ virtual void writeExec();
+ virtual void writeData();
+ virtual void writeInit();
+ virtual void writeExports();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+ virtual void finishRagelDef();
+
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+
+ int TO_STATE_ACTION( RedStateAp *state );
+ int FROM_STATE_ACTION( RedStateAp *state );
+ int EOF_ACTION( RedStateAp *state );
+ int TRANS_ACTION( RedTransAp *trans );
+
+ /* Determine if we should use indicies. */
+ void calcIndexSize();
+
+private:
+ string array_type;
+ string array_name;
+ int item_count;
+ int div_count;
+
+public:
+
+ virtual string NULL_ITEM();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &ARRAY_ITEM( string item, bool last );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string GET_KEY();
+ virtual string CTRL_FLOW();
+
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string INT( int i );
+ void ACTION( ostream &ret, GenAction *action, int targState, bool inFinish );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+
+ string ACCESS();
+
+ string P();
+ string PE();
+ string vEOF();
+
+ string vCS();
+ string STACK();
+ string TOP();
+ string TOKSTART();
+ string TOKEND();
+ string ACT();
+ string DATA();
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, GenInlineList *inlineList, int targState, bool inFinish );
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void EXECTE( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish );
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+ void genLineDirective( ostream &out );
+};
+
+#endif
diff --git a/ragel/main.cpp b/ragel/main.cpp
new file mode 100644
index 0000000..f5fbd7b
--- /dev/null
+++ b/ragel/main.cpp
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2001-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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <psapi.h>
+#include <time.h>
+#include <io.h>
+#include <process.h>
+
+#if _MSC_VER
+#define S_IRUSR _S_IREAD
+#define S_IWUSR _S_IWRITE
+#endif
+#endif
+
+/* Parsing. */
+#include "ragel.h"
+#include "rlscan.h"
+
+/* Parameters and output. */
+#include "pcheck.h"
+#include "vector.h"
+#include "version.h"
+#include "common.h"
+#include "inputdata.h"
+
+using std::istream;
+using std::ostream;
+using std::ifstream;
+using std::ofstream;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ios;
+using std::streamsize;
+
+/* Controls minimization. */
+MinimizeLevel minimizeLevel = MinimizePartition2;
+MinimizeOpt minimizeOpt = MinimizeMostOps;
+
+/* Graphviz dot file generation. */
+const char *machineSpec = 0, *machineName = 0;
+bool machineSpecFound = false;
+bool wantDupsRemoved = true;
+
+bool printStatistics = false;
+bool generateXML = false;
+bool generateDot = false;
+
+/* Target language and output style. */
+CodeStyle codeStyle = GenTables;
+
+int numSplitPartitions = 0;
+bool noLineDirectives = false;
+
+bool displayPrintables = false;
+
+/* Target ruby impl */
+RubyImplEnum rubyImpl = MRI;
+
+/* Print a summary of the options. */
+void usage()
+{
+ cout <<
+"usage: ragel [options] file\n"
+"general:\n"
+" -h, -H, -?, --help Print this usage and exit\n"
+" -v, --version Print version information and exit\n"
+" -o <file> Write output to <file>\n"
+" -s Print some statistics on stderr\n"
+" -d Do not remove duplicates from action lists\n"
+" -I <dir> Add <dir> to the list of directories to search\n"
+" for included an imported files\n"
+"error reporting format:\n"
+" --error-format=gnu file:line:column: message (default)\n"
+" --error-format=msvc file(line,column): message\n"
+"fsm minimization:\n"
+" -n Do not perform minimization\n"
+" -m Minimize at the end of the compilation\n"
+" -l Minimize after most operations (default)\n"
+" -e Minimize after every operation\n"
+"visualization:\n"
+" -x Run the frontend only: emit XML intermediate format\n"
+" -V Generate a dot file for Graphviz\n"
+" -p Display printable characters on labels\n"
+" -S <spec> FSM specification to output (for graphviz output)\n"
+" -M <machine> Machine definition/instantiation to output (for graphviz output)\n"
+"host language:\n"
+" -C The host language is C, C++, Obj-C or Obj-C++ (default)\n"
+" -D The host language is D\n"
+" -Z The host language is Go\n"
+" -J The host language is Java\n"
+" -R The host language is Ruby\n"
+" -A The host language is C#\n"
+" -O The host language is OCaml\n"
+"line directives: (C/D/Ruby/C#/OCaml)\n"
+" -L Inhibit writing of #line directives\n"
+"code style: (C/D/Java/Ruby/C#/OCaml)\n"
+" -T0 Table driven FSM (default)\n"
+"code style: (C/D/Ruby/C#/OCaml)\n"
+" -T1 Faster table driven FSM\n"
+" -F0 Flat table driven FSM\n"
+" -F1 Faster flat table-driven FSM\n"
+"code style: (C/D/C#/OCaml)\n"
+" -G0 Goto-driven FSM\n"
+" -G1 Faster goto-driven FSM\n"
+"code style: (C/D)\n"
+" -G2 Really fast goto-driven FSM\n"
+" -P<N> N-Way Split really fast goto-driven FSM\n"
+ ;
+
+ exit(0);
+}
+
+/* Print version information and exit. */
+void version()
+{
+ cout << "Ragel State Machine Compiler version " VERSION << " " PUBDATE << endl <<
+ "Copyright (c) 2001-2009 by Adrian Thurston" << endl;
+ exit(0);
+}
+
+/* Error reporting format. */
+ErrorFormat errorFormat = ErrorFormatGNU;
+
+InputLoc makeInputLoc( const char *fileName, int line, int col)
+{
+ InputLoc loc = { fileName, line, col };
+ return loc;
+}
+
+ostream &operator<<( ostream &out, const InputLoc &loc )
+{
+ assert( loc.fileName != 0 );
+ switch ( errorFormat ) {
+ case ErrorFormatMSVC:
+ out << loc.fileName << "(" << loc.line;
+ if ( loc.col )
+ out << "," << loc.col;
+ out << ")";
+ break;
+
+ default:
+ out << loc.fileName << ":" << loc.line;
+ if ( loc.col )
+ out << ":" << loc.col;
+ break;
+ }
+ return out;
+}
+
+/* Total error count. */
+int gblErrorCount = 0;
+
+/* Print the opening to a warning in the input, then return the error ostream. */
+ostream &warning( const InputLoc &loc )
+{
+ cerr << loc << ": warning: ";
+ return cerr;
+}
+
+/* Print the opening to a program error, then return the error stream. */
+ostream &error()
+{
+ gblErrorCount += 1;
+ cerr << PROGNAME ": ";
+ return cerr;
+}
+
+ostream &error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ cerr << loc << ": ";
+ return cerr;
+}
+
+void escapeLineDirectivePath( std::ostream &out, char *path )
+{
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+}
+
+void processArgs( int argc, const char **argv, InputData &id )
+{
+ ParamCheck pc("xo:dnmleabjkS:M:I:CDEJZRAOvHh?-:sT:F:G:P:LpV", argc, argv);
+
+ /* FIXME: Need to check code styles VS langauge. */
+
+ while ( pc.check() ) {
+ switch ( pc.state ) {
+ case ParamCheck::match:
+ switch ( pc.parameter ) {
+ case 'V':
+ generateDot = true;
+ break;
+
+ case 'x':
+ generateXML = true;
+ break;
+
+ /* Output. */
+ case 'o':
+ if ( *pc.paramArg == 0 )
+ error() << "a zero length output file name was given" << endl;
+ else if ( id.outputFileName != 0 )
+ error() << "more than one output file name was given" << endl;
+ else {
+ /* Ok, remember the output file name. */
+ id.outputFileName = pc.paramArg;
+ }
+ break;
+
+ /* Flag for turning off duplicate action removal. */
+ case 'd':
+ wantDupsRemoved = false;
+ break;
+
+ /* Minimization, mostly hidden options. */
+ case 'n':
+ minimizeOpt = MinimizeNone;
+ break;
+ case 'm':
+ minimizeOpt = MinimizeEnd;
+ break;
+ case 'l':
+ minimizeOpt = MinimizeMostOps;
+ break;
+ case 'e':
+ minimizeOpt = MinimizeEveryOp;
+ break;
+ case 'a':
+ minimizeLevel = MinimizeApprox;
+ break;
+ case 'b':
+ minimizeLevel = MinimizeStable;
+ break;
+ case 'j':
+ minimizeLevel = MinimizePartition1;
+ break;
+ case 'k':
+ minimizeLevel = MinimizePartition2;
+ break;
+
+ /* Machine spec. */
+ case 'S':
+ if ( *pc.paramArg == 0 )
+ error() << "please specify an argument to -S" << endl;
+ else if ( machineSpec != 0 )
+ error() << "more than one -S argument was given" << endl;
+ else {
+ /* Ok, remember the path to the machine to generate. */
+ machineSpec = pc.paramArg;
+ }
+ break;
+
+ /* Machine path. */
+ case 'M':
+ if ( *pc.paramArg == 0 )
+ error() << "please specify an argument to -M" << endl;
+ else if ( machineName != 0 )
+ error() << "more than one -M argument was given" << endl;
+ else {
+ /* Ok, remember the machine name to generate. */
+ machineName = pc.paramArg;
+ }
+ break;
+
+ case 'I':
+ if ( *pc.paramArg == 0 )
+ error() << "please specify an argument to -I" << endl;
+ else {
+ id.includePaths.append( pc.paramArg );
+ }
+ break;
+
+ /* Host language types. */
+ case 'C':
+ hostLang = &hostLangC;
+ break;
+ case 'D':
+ hostLang = &hostLangD;
+ break;
+ case 'E':
+ hostLang = &hostLangD2;
+ break;
+ case 'Z':
+ hostLang = &hostLangGo;
+ break;
+ case 'J':
+ hostLang = &hostLangJava;
+ break;
+ case 'R':
+ hostLang = &hostLangRuby;
+ break;
+ case 'A':
+ hostLang = &hostLangCSharp;
+ break;
+ case 'O':
+ hostLang = &hostLangOCaml;
+ break;
+
+ /* Version and help. */
+ case 'v':
+ version();
+ break;
+ case 'H': case 'h': case '?':
+ usage();
+ break;
+ case 's':
+ printStatistics = true;
+ break;
+ case '-': {
+ char *arg = strdup( pc.paramArg );
+ char *eq = strchr( arg, '=' );
+
+ if ( eq != 0 )
+ *eq++ = 0;
+
+ if ( strcmp( arg, "help" ) == 0 )
+ usage();
+ else if ( strcmp( arg, "version" ) == 0 )
+ version();
+ else if ( strcmp( arg, "error-format" ) == 0 ) {
+ if ( eq == 0 )
+ error() << "expecting '=value' for error-format" << endl;
+ else if ( strcmp( eq, "gnu" ) == 0 )
+ errorFormat = ErrorFormatGNU;
+ else if ( strcmp( eq, "msvc" ) == 0 )
+ errorFormat = ErrorFormatMSVC;
+ else
+ error() << "invalid value for error-format" << endl;
+ }
+ else if ( strcmp( arg, "rbx" ) == 0 )
+ rubyImpl = Rubinius;
+ else {
+ error() << "--" << pc.paramArg <<
+ " is an invalid argument" << endl;
+ }
+ free( arg );
+ break;
+ }
+
+ /* Passthrough args. */
+ case 'T':
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenTables;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFTables;
+ else {
+ error() << "-T" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'F':
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenFlat;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFFlat;
+ else {
+ error() << "-F" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'G':
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenGoto;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFGoto;
+ else if ( pc.paramArg[0] == '2' )
+ codeStyle = GenIpGoto;
+ else {
+ error() << "-G" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'P':
+ codeStyle = GenSplit;
+ numSplitPartitions = atoi( pc.paramArg );
+ break;
+
+ case 'p':
+ displayPrintables = true;
+ break;
+
+ case 'L':
+ noLineDirectives = true;
+ break;
+ }
+ break;
+
+ case ParamCheck::invalid:
+ error() << "-" << pc.parameter << " is an invalid argument" << endl;
+ break;
+
+ case ParamCheck::noparam:
+ /* It is interpreted as an input file. */
+ if ( *pc.curArg == 0 )
+ error() << "a zero length input file name was given" << endl;
+ else if ( id.inputFileName != 0 )
+ error() << "more than one input file name was given" << endl;
+ else {
+ /* OK, Remember the filename. */
+ id.inputFileName = pc.curArg;
+ }
+ break;
+ }
+ }
+}
+
+void process( InputData &id )
+{
+ /* Open the input file for reading. */
+ assert( id.inputFileName != 0 );
+ ifstream *inFile = new ifstream( id.inputFileName );
+ if ( ! inFile->is_open() )
+ error() << "could not open " << id.inputFileName << " for reading" << endp;
+
+ /* Used for just a few things. */
+ std::ostringstream hostData;
+
+ /* Make the first input item. */
+ InputItem *firstInputItem = new InputItem;
+ firstInputItem->type = InputItem::HostData;
+ firstInputItem->loc.fileName = id.inputFileName;
+ firstInputItem->loc.line = 1;
+ firstInputItem->loc.col = 1;
+ id.inputItems.append( firstInputItem );
+
+ Scanner scanner( id, id.inputFileName, *inFile, 0, 0, 0, false );
+ scanner.do_scan();
+
+ /* Finished, final check for errors.. */
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ /* Now send EOF to all parsers. */
+ id.terminateAllParsers();
+
+ /* Bail on above error. */
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ /* Locate the backend program */
+ /* Compiles machines. */
+ id.prepareMachineGen();
+
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ id.makeOutputStream();
+
+ /* Generates the reduced machine, which we use to write output. */
+ if ( !generateXML ) {
+ id.generateReduced();
+
+ if ( gblErrorCount > 0 )
+ exit(1);
+ }
+
+ id.verifyWritesHaveData();
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ /*
+ * From this point on we should not be reporting any errors.
+ */
+
+ id.openOutput();
+ id.writeOutput();
+
+ /* Close the input and the intermediate file. */
+ delete inFile;
+
+ /* If writing to a file, delete the ostream, causing it to flush.
+ * Standard out is flushed automatically. */
+ if ( id.outputFileName != 0 ) {
+ delete id.outStream;
+ delete id.outFilter;
+ }
+
+ assert( gblErrorCount == 0 );
+}
+
+char *makeIntermedTemplate( const char *baseFileName )
+{
+ char *result = 0;
+ const char *templ = "ragel-XXXXXX.xml";
+ const char *lastSlash = strrchr( baseFileName, '/' );
+ if ( lastSlash == 0 ) {
+ result = new char[strlen(templ)+1];
+ strcpy( result, templ );
+ }
+ else {
+ int baseLen = lastSlash - baseFileName + 1;
+ result = new char[baseLen + strlen(templ) + 1];
+ memcpy( result, baseFileName, baseLen );
+ strcpy( result+baseLen, templ );
+ }
+ return result;
+};
+
+/* Main, process args and call yyparse to start scanning input. */
+int main( int argc, const char **argv )
+{
+ InputData id;
+
+ processArgs( argc, argv, id );
+
+ /* Require an input file. If we use standard in then we won't have a file
+ * name on which to base the output. */
+ if ( id.inputFileName == 0 )
+ error() << "no input file given" << endl;
+
+ /* Bail on argument processing errors. */
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ /* Make sure we are not writing to the same file as the input file. */
+ if ( id.inputFileName != 0 && id.outputFileName != 0 &&
+ strcmp( id.inputFileName, id.outputFileName ) == 0 )
+ {
+ error() << "output file \"" << id.outputFileName <<
+ "\" is the same as the input file" << endp;
+ }
+
+ process( id );
+
+ return 0;
+}
diff --git a/ragel/mlcodegen.cpp b/ragel/mlcodegen.cpp
new file mode 100644
index 0000000..f8268d6
--- /dev/null
+++ b/ragel/mlcodegen.cpp
@@ -0,0 +1,744 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mlcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <sstream>
+#include <iomanip>
+#include <string>
+#include <assert.h>
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+void ocamlLineDirective( ostream &out, const char *fileName, int line )
+{
+ if ( noLineDirectives )
+ return;
+
+ /* Write the line info for to the input file. */
+ out << "# " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' || *pc == '"' )
+ out << "\\";
+ out << *pc;
+ }
+ out << "\"\n";
+}
+
+void OCamlCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ ocamlLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+
+/* Init code gen with in parameters. */
+OCamlCodeGen::OCamlCodeGen( ostream &out )
+:
+ CodeGenData(out)
+{
+}
+
+unsigned int OCamlCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string OCamlCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ return ARRAY_TYPE( maxVal, false );
+}
+
+string OCamlCodeGen::ARRAY_TYPE( unsigned long maxVal, bool forceSigned )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType;
+ if (forceSigned)
+ arrayType = keyOps->typeSubsumes(true, maxValLL);
+ else
+ arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+/* Write out the fsm name. */
+string OCamlCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string OCamlCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &OCamlCodeGen::ACTIONS_ARRAY()
+{
+ out << "\t0; ";
+ int totalActions = 1;
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ out << act->key.length() << ARR_SEP();
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
+ out << item->value->actionId;
+ if ( ! (act.last() && item.last()) )
+ out << ARR_SEP();
+
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+/*
+string OCamlCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false );
+ return ret.str();
+}
+*/
+
+string OCamlCodeGen::make_access(char const* name, GenInlineList* x, bool prefix = true)
+{
+ ostringstream ret;
+ if ( x == 0 )
+ {
+ if (prefix && accessExpr != 0)
+ {
+ INLINE_LIST( ret, accessExpr, 0, false);
+ ret << name;
+ }
+ else
+ ret << name << ".contents"; // ref cell
+ }
+ else {
+ ret << "(";
+ INLINE_LIST( ret, x, 0, false );
+ ret << ")";
+ }
+ return ret.str();
+}
+
+string OCamlCodeGen::P() { return make_access("p", pExpr, false); }
+string OCamlCodeGen::PE() { return make_access("pe", peExpr, false); }
+string OCamlCodeGen::vEOF() { return make_access("eof", eofExpr, false); }
+string OCamlCodeGen::vCS() { return make_access("cs", csExpr); }
+string OCamlCodeGen::TOP() { return make_access("top", topExpr); }
+string OCamlCodeGen::STACK() { return make_access("stack", stackExpr); }
+string OCamlCodeGen::ACT() { return make_access("act", actExpr); }
+string OCamlCodeGen::TOKSTART() { return make_access("ts", tokstartExpr); }
+string OCamlCodeGen::TOKEND() { return make_access("te", tokendExpr); }
+
+string OCamlCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ { ostringstream ret; ret << "Char.code " << GET_KEY(); return ret.str(); }
+}
+
+string OCamlCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ { ostringstream ret; ret << "Char.code " << GET_KEY(); return ret.str(); }
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string OCamlCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+/* Write out a key from the fsm code gen. Depends on wether or not the key is
+ * signed. */
+string OCamlCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+}
+
+string OCamlCodeGen::ALPHA_KEY( Key key )
+{
+ ostringstream ret;
+ ret << key.getVal();
+ /*
+ if (key.getVal() > 0xFFFF) {
+ ret << key.getVal();
+ } else {
+ ret << "'\\u" << std::hex << std::setw(4) << std::setfill('0') <<
+ key.getVal() << "'";
+ }
+ */
+ //ret << "(char) " << key.getVal();
+ return ret.str();
+}
+
+void OCamlCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+// The parser gives fexec two children.
+ ret << "begin " << P() << " <- ";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << " - 1 end; ";
+}
+
+void OCamlCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish )
+{
+ bool catch_all = false;
+ ret <<
+ " begin match " << ACT() << " with\n";
+
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 )
+ {
+ catch_all = true;
+ ret << " | _ ->\n";
+ }
+ else
+ ret << " | " << lma->lmId << " ->\n";
+
+ /* Write the block and close it off. */
+ ret << " begin ";
+ INLINE_LIST( ret, lma->children, targState, inFinish );
+ ret << " end\n";
+ }
+
+ if (!catch_all)
+ ret << " | _ -> assert false\n";
+
+ ret <<
+ " end;\n"
+ "\t";
+}
+
+void OCamlCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " <- " << item->lmId << "; ";
+}
+
+void OCamlCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " <- " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << "; ";
+}
+
+void OCamlCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void OCamlCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " <- " << NULL_ITEM() << "; ";
+}
+
+void OCamlCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " <- 0;";
+}
+
+void OCamlCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " <- " << P() << "; ";
+}
+
+void OCamlCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "begin ";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << " end";
+ }
+}
+
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void OCamlCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << " <- " << P() << " - 1; ";
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ CURS( ret, inFinish );
+ break;
+ case GenInlineItem::Targs:
+ TARGS( ret, inFinish, targState );
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState );
+ break;
+ }
+ }
+}
+/* Write out paths in line directives. Escapes any special characters. */
+string OCamlCodeGen::LDIR_PATH( char *path )
+{
+ ostringstream ret;
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ ret << "\\\\";
+ else
+ ret << *pc;
+ }
+ return ret.str();
+}
+
+void OCamlCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ ocamlLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t\tbegin ";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish );
+ ret << " end;\n";
+}
+
+void OCamlCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ ret << "\n";
+ ocamlLineDirective( ret, condition->loc.fileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+string OCamlCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string OCamlCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void OCamlCodeGen::writeInit()
+{
+ out << " begin\n";
+
+ if ( !noCS )
+ out << "\t" << vCS() << " <- " << START() << ";\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\t" << TOP() << " <- 0;\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " <- " << NULL_ITEM() << ";\n"
+ " " << TOKEND() << " <- " << NULL_ITEM() << ";\n"
+ " " << ACT() << " <- 0;\n";
+ }
+ out << " end;\n";
+}
+
+string OCamlCodeGen::PRE_INCR(string val)
+{
+ ostringstream ret;
+ ret << "(" << val << " <- " << val << " + 1; " << val << ")";
+ return ret.str();
+}
+
+string OCamlCodeGen::POST_INCR(string val)
+{
+ ostringstream ret;
+ ret << "(let temp = " << val << " in " << val << " <- " << val << " + 1; temp)";
+ return ret.str();
+}
+
+string OCamlCodeGen::PRE_DECR(string val)
+{
+ ostringstream ret;
+ ret << "(" << val << " <- " << val << " - 1; " << val << ")";
+ return ret.str();
+}
+
+string OCamlCodeGen::POST_DECR(string val)
+{
+ ostringstream ret;
+ ret << "(let temp = " << val << " in " << val << " <- " << val << " - 1; temp)";
+ return ret.str();
+}
+
+string OCamlCodeGen::DATA_PREFIX()
+{
+ if ( data_prefix.empty() ) // init
+ {
+ data_prefix = string(fsmName) + "_";
+ if (data_prefix.size() > 0)
+ data_prefix[0] = ::tolower(data_prefix[0]); // uncapitalize
+ }
+ if ( !noPrefix )
+ return data_prefix;
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string OCamlCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string OCamlCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+void OCamlCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << TOP_SEP ();
+
+ if ( !noFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << TOP_SEP();
+
+ if ( !noError )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << TOP_SEP();
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << TOP_SEP();
+ }
+ out << "\n";
+ }
+}
+
+
+void OCamlCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void OCamlCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void OCamlCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+string OCamlCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << "data.[" << P() << "]";
+ }
+ return ret.str();
+}
+string OCamlCodeGen::NULL_ITEM()
+{
+ return "-1";
+}
+
+string OCamlCodeGen::POINTER()
+{
+ // XXX C# has no pointers
+ // multiple items seperated by commas can also be pointer types.
+ return " ";
+}
+
+string OCamlCodeGen::PTR_CONST()
+{
+ return "";
+}
+
+std::ostream &OCamlCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out << "let " << name << " : " << type << " array = [|" << endl;
+ return out;
+}
+
+std::ostream &OCamlCodeGen::CLOSE_ARRAY()
+{
+ return out << "|]" << TOP_SEP();
+}
+
+string OCamlCodeGen::TOP_SEP()
+{
+ return "\n"; // original syntax
+}
+
+string OCamlCodeGen::ARR_SEP()
+{
+ return "; ";
+}
+
+string OCamlCodeGen::AT(const string& array, const string& index)
+{
+ ostringstream ret;
+ ret << array << ".(" << index << ")";
+ return ret.str();
+}
+
+std::ostream &OCamlCodeGen::STATIC_VAR( string type, string name )
+{
+ out << "let " << name << " : " << type;
+ return out;
+}
+
+string OCamlCodeGen::ARR_OFF( string ptr, string offset )
+{
+ // XXX C# can't do pointer arithmetic
+ return "&" + ptr + "[" + offset + "]";
+}
+
+string OCamlCodeGen::CAST( string type )
+{
+ return "";
+// return "(" + type + ")";
+}
+
+string OCamlCodeGen::UINT( )
+{
+ return "uint";
+}
+
+std::ostream &OCamlCodeGen::SWITCH_DEFAULT()
+{
+ out << " | _ -> ()\n";
+ return out;
+}
+
+string OCamlCodeGen::CTRL_FLOW()
+{
+ return "if true then ";
+}
+
+void OCamlCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &OCamlCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &OCamlCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
diff --git a/ragel/mlcodegen.h b/ragel/mlcodegen.h
new file mode 100644
index 0000000..9ca4916
--- /dev/null
+++ b/ragel/mlcodegen.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLCODEGEN_H
+#define _MLCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/* Forwards. */
+/*
+struct RedFsmAp;
+struct RedStateAp;
+struct CodeGenData;
+struct GenAction;
+struct NameInst;
+struct GenInlineItem;
+struct GenInlineList;
+struct RedAction;
+struct LongestMatch;
+struct LongestMatchPart;
+*/
+
+/* Integer array line length. */
+#define IALL 8
+
+//string itoa( int i );
+
+/*
+ * class OCamlCodeGen
+ */
+class OCamlCodeGen : public CodeGenData
+{
+public:
+ OCamlCodeGen( ostream &out );
+ virtual ~OCamlCodeGen() {}
+
+ virtual void finishRagelDef();
+ virtual void writeInit();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+
+protected:
+ string data_prefix;
+
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string ALPHA_KEY( Key key );
+ string LDIR_PATH( char *path );
+ void ACTION( ostream &ret, GenAction *action, int targState, bool inFinish );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+ string ARRAY_TYPE( unsigned long maxVal, bool forceSigned );
+
+ virtual string ARR_OFF( string ptr, string offset );
+ virtual string CAST( string type );
+ virtual string UINT();
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual string GET_KEY();
+ virtual ostream &SWITCH_DEFAULT();
+
+ string P();
+ string PE();
+ string vEOF();
+
+// string ACCESS();
+ string vCS();
+ string STACK();
+ string TOP();
+ string TOKSTART();
+ string TOKEND();
+ string ACT();
+
+ // ++x
+ string PRE_INCR(string);
+ string PRE_DECR(string);
+
+ // x++
+ string POST_INCR(string);
+ string POST_DECR(string);
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string TYPE_STATE() { return "_" + DATA_PREFIX() + "state"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, GenInlineList *inlineList, int targState, bool inFinish );
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem,
+ int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+ virtual void BREAK( ostream &ret, int targState ) = 0;
+ virtual void CURS( ostream &ret, bool inFinish ) = 0;
+ virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0;
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish );
+ void STATE_IDS();
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ virtual string PTR_CONST();
+ virtual ostream &OPEN_ARRAY( string type, string name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( string type, string name );
+
+ virtual string CTRL_FLOW();
+
+ // toplevel phrase separator
+ string TOP_SEP();
+ // array elements separator
+ string ARR_SEP();
+ // access array
+ string AT(const string& array, const string& index);
+
+ string make_access(char const* name, GenInlineList* x, bool prefix);
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool testEofUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+public:
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize() {}
+
+ void genLineDirective( ostream &out );
+};
+
+#define MAX(a, b) (a > b ? a : b)
+
+#endif
diff --git a/ragel/mlfflat.cpp b/ragel/mlfflat.cpp
new file mode 100644
index 0000000..2e14543
--- /dev/null
+++ b/ragel/mlfflat.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mlfflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &OCamlFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+/* Write out the function for a transition. */
+std::ostream &OCamlFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlFFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFFlatCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void OCamlFFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "type " << TYPE_STATE() << " = { mutable keys : int; mutable trans : int; }"
+ << TOP_SEP();
+
+ out << "exception Goto_match" << TOP_SEP();
+ out << "exception Goto_again" << TOP_SEP();
+ out << "exception Goto_eof_trans" << TOP_SEP();
+}
+
+void OCamlFFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " begin\n";
+// " " << slenType << " _slen";
+
+// if ( redFsm->anyRegCurStateRef() )
+// out << ", _ps";
+
+// out << ";\n";
+// out << " " << transType << " _trans";
+
+// if ( redFsm->anyConditions() )
+// out << ", _cond";
+
+// out << ";\n";
+
+// out <<
+// " " << "int _keys;\n"
+// " " << indsType << " _inds;\n";
+ /*
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";*/
+
+ out <<
+ " let state = { keys = 0; trans = 0; } in\n"
+ " let rec do_start () =\n";
+
+// if ( redFsm->anyConditions() ) {
+// out <<
+// " " << condsType << " _conds;\n"
+// " " << WIDE_ALPH_TYPE() << " _widec;\n";
+// }
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " begin match " << AT( FSA(), vCS() ) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ out << "\tbegin try\n";
+ LOCATE_TRANS();
+ out << "\twith Goto_match -> () end;\n";
+
+ out << "\tdo_eof_trans ()\n";
+
+// if ( redFsm->anyEofTrans() )
+ out << "and do_eof_trans () =\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " let ps = " << vCS() << " in\n";
+
+ out <<
+ " " << vCS() << " <- " << AT( TT() ,"state.trans" ) << ";\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " begin try if " << AT( TA() , "state.trans" ) << " = 0 then\n"
+ " raise Goto_again;\n"
+ "\n"
+ " match " << AT( TA(), "state.trans" ) << " with\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " with Goto_again -> () end;\n"
+ "\n";
+ }
+ out << "\tdo_again ()\n";
+
+// if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+// redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " begin match " << AT( TSA(), vCS() ) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n"
+ "\t| " << redFsm->errState->id << " -> do_out ()\n"
+ "\t| _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin try\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << AT( ET(), vCS() ) << " > 0 then\n"
+ " begin\n"
+ " state.trans <- " << CAST(transType) << "(" << AT( ET(), vCS() ) << " - 1);\n"
+ " raise Goto_eof_trans;\n"
+ " end;\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " begin match " << AT( EA(), vCS() ) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n";
+ }
+
+ out <<
+ " with Goto_again -> do_again ()\n"
+ " | Goto_eof_trans -> do_eof_trans () end\n"
+ "\n";
+ }
+ else
+ {
+ out << "\t()\n";
+ }
+
+ if ( outLabelUsed )
+ out << " and do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
+
diff --git a/ragel/mlfflat.h b/ragel/mlfflat.h
new file mode 100644
index 0000000..242e6b9
--- /dev/null
+++ b/ragel/mlfflat.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLFFLAT_H
+#define _MLFFLAT_H
+
+#include <iostream>
+#include "mlflat.h"
+
+/* Forwards. */
+//struct CodeGenData;
+
+/*
+ * OCamlFFlatCodeGen
+ */
+class OCamlFFlatCodeGen : public OCamlFlatCodeGen
+{
+public:
+ OCamlFFlatCodeGen( ostream &out ) : OCamlFlatCodeGen(out) {}
+private:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/mlfgoto.cpp b/ragel/mlfgoto.cpp
new file mode 100644
index 0000000..b66d66e
--- /dev/null
+++ b/ragel/mlfgoto.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mlfgoto.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+std::ostream &OCamlFGotoCodeGen::EXEC_ACTIONS()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* We are at the start of a glob, write the case. */
+ out << "and f" << redAct->actListId << " () =\n";
+ out << "\tbegin try\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\twith Goto_again -> () end;\n";
+ out << "\tdo_again ()\n";
+ }
+ }
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t|" << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+// out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+// out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlFGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+// out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &OCamlFGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\t| " << st->id << " -> ";
+
+ /* Jump to the func. */
+ out << "f" << st->eofAction->actListId << " ()\n";
+ }
+ }
+
+ return out;
+}
+
+unsigned int OCamlFGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+unsigned int OCamlFGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+unsigned int OCamlFGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+void OCamlFGotoCodeGen::writeData()
+{
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "exception Goto_again" << TOP_SEP();
+}
+
+void OCamlFGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " begin\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " let _ps = ref 0 in\n";
+
+ if ( redFsm->anyConditions() )
+ out << " let _widec : " << WIDE_ALPH_TYPE() << " = ref 0 in\n";
+
+ out << "\n";
+ out << "\tlet rec do_start () =\n";
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " begin match " << AT(FSA(),vCS()) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ out <<
+ " begin match " << vCS() << " with\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_ACTIONS() << "\n";
+
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " begin match " << AT(TSA(), vCS()) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n" <<
+ " | " << redFsm->errState->id << " -> do_out ()\n"
+ " | _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " match " << vCS() << " with\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " | " << st->id << " -> tr" << st->eofTrans->id << " ()\n";
+ }
+
+ SWITCH_DEFAULT() << ";\n"; // fall through
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " try match " << AT(EA(), vCS()) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " \n"
+ " with Goto_again -> do_again () \n";
+ }
+
+ out <<
+ " end\n"
+ "\n";
+ }
+ else
+ out << "\t()\n";
+
+ if ( outLabelUsed )
+ out << "\tand do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
diff --git a/ragel/mlfgoto.h b/ragel/mlfgoto.h
new file mode 100644
index 0000000..bccbd55
--- /dev/null
+++ b/ragel/mlfgoto.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLFGOTO_H
+#define _MLFGOTO_H
+
+#include <iostream>
+#include "mlgoto.h"
+
+/*
+ * class OCamlFGotoCodeGen
+ */
+class OCamlFGotoCodeGen : virtual public OCamlGotoCodeGen
+{
+public:
+ OCamlFGotoCodeGen( ostream &out ) : OCamlCodeGen(out), OCamlGotoCodeGen(out) {}
+
+ std::ostream &EXEC_ACTIONS();
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &FINISH_CASES();
+ std::ostream &EOF_ACTION_SWITCH();
+ unsigned int TO_STATE_ACTION( RedStateAp *state );
+ unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ unsigned int EOF_ACTION( RedStateAp *state );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/mlflat.cpp b/ragel/mlflat.cpp
new file mode 100644
index 0000000..b97aa15
--- /dev/null
+++ b/ragel/mlflat.cpp
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 <sstream>
+#include "ragel.h"
+#include "mlflat.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &OCamlFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, true );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &OCamlFlatCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &OCamlFlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlFlatCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ out << ALPHA_KEY( st->condLowKey ) << ARR_SEP();
+ out << ALPHA_KEY( st->condHighKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << /*"(char) " <<*/ 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::COND_KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::CONDS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ out << st->condList[pos]->condSpaceId + 1 << ARR_SEP();
+ else
+ out << "0" << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::COND_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlFlatCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ out << ALPHA_KEY( st->lowKey ) << ARR_SEP();
+ out << ALPHA_KEY( st->highKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << /*"(char) " <<*/ 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ out << st->transList[pos]->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 )
+ out << st->defTrans->id << ARR_SEP();
+
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlFlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ARR_SEP();
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &OCamlFlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ARR_SEP();
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void OCamlFlatCodeGen::LOCATE_TRANS()
+{
+ std::ostringstream temp;
+ temp << "inds + (\n"
+ " if slen > 0 && " << AT( K(), "keys" ) << " <= " << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << AT( K(), "keys+1" ) << " then\n"
+ " " << GET_WIDE_KEY() << " - " << AT(K(), "keys" ) << " else slen)";
+ out <<
+ " let keys = " << vCS() << " lsl 1 in\n"
+ " let inds = " << AT( IO(), vCS() ) << " in\n"
+ "\n"
+ " let slen = " << AT( SP(), vCS() ) << " in\n"
+ " state.trans <- " << AT( I(), temp.str() ) << ";\n"
+ "\n";
+}
+
+void OCamlFlatCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << gotoDest << "; " <<
+ CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlFlatCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << " raise Goto_again end";
+}
+
+void OCamlFlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void OCamlFlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void OCamlFlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " <- " << nextDest << ";";
+}
+
+void OCamlFlatCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void OCamlFlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT( STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; ";
+ ret << vCS() << " <- " << callDest << "; " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlFlatCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT(STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlFlatCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << AT(STACK(), PRE_DECR(TOP()) ) << "; ";
+
+ if ( postPopExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "end ";
+ }
+
+ ret << CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlFlatCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "begin " << P() << " <- " << P() << " + 1; " << CTRL_FLOW() << "raise Goto_out end";
+}
+
+void OCamlFlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "type " << TYPE_STATE() << " = { mutable trans : int; mutable acts : int; mutable nacts : int; }"
+ << TOP_SEP();
+
+ out << "exception Goto_match" << TOP_SEP();
+ out << "exception Goto_again" << TOP_SEP();
+ out << "exception Goto_eof_trans" << TOP_SEP();
+}
+
+void OCamlFlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n";
+
+ out <<
+ " _keys = " << vCS() << "<<1;\n"
+ " _conds = " << CO() << "[" << vCS() << "];\n"
+// " _keys = " << ARR_OFF( CK(), "(" + vCS() + "<<1)" ) << ";\n"
+// " _conds = " << ARR_OFF( C(), CO() + "[" + vCS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << CSP() << "[" << vCS() << "];\n"
+ " if (_slen > 0 && " << CK() << "[_keys] <="
+ << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << CK() << "[_keys+1])\n"
+ " _cond = " << C() << "[_conds+" << GET_WIDE_KEY() << " - " <<
+ CK() << "[_keys]];\n"
+ " else\n"
+ " _cond = 0;"
+ "\n";
+ /* XXX This version of the code doesn't work because Mono is weird. Works
+ * fine in Microsoft's csc, even though the bug report filed claimed it
+ * didn't.
+ " _slen = " << CSP() << "[" << vCS() << "];\n"
+ " _cond = _slen > 0 && " << CK() << "[_keys] <="
+ << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= " << CK() << "[_keys+1] ?\n"
+ " " << C() << "[_conds+" << GET_WIDE_KEY() << " - " << CK()
+ << "[_keys]] : 0;\n"
+ "\n";
+ */
+ out <<
+ " switch ( _cond ) {\n";
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId + 1 << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out << " }\n";
+ out << " break;\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n";
+}
+
+void OCamlFlatCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " begin\n";
+// " " << slenType << " _slen";
+
+// if ( redFsm->anyRegCurStateRef() )
+// out << ", _ps";
+
+// out <<
+// " " << transType << " _trans";
+
+// if ( redFsm->anyConditions() )
+// out << ", _cond";
+// out << ";\n";
+
+// if ( redFsm->anyToStateActions() ||
+// redFsm->anyRegActions() || redFsm->anyFromStateActions() )
+// {
+// out <<
+// " int _acts;\n"
+// " int _nacts;\n";
+// }
+
+// out <<
+// " " << "int _keys;\n"
+// " " << indsType << " _inds;\n";
+ /*
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";*/
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << condsType << " _conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ out << "\n";
+
+ out <<
+ " let state = { trans = 0; acts = 0; nacts = 0; } in\n"
+ " let rec do_start () =\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " state.acts <- " << AT( FSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+// out << "\tbegin try\n";
+ LOCATE_TRANS();
+// out << "\twith Goto_match -> () end;\n";
+
+ out << "\tdo_eof_trans ()\n";
+
+// if ( redFsm->anyEofTrans() )
+ out << "and do_eof_trans () =\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " let ps = " << vCS() << " in\n";
+
+ out <<
+ " " << vCS() << " <- " << AT( TT() ,"state.trans" ) << ";\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ "\tbegin try\n"
+ " match " << AT( TA(), "state.trans" ) << " with\n"
+ "\t| 0 -> raise Goto_again\n"
+ "\t| _ ->\n"
+ " state.acts <- " << AT( TA(), "state.trans" ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ " done\n"
+ "\twith Goto_again -> () end;\n";
+ }
+ out << "\tdo_again ()\n";
+
+// if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+// redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " state.acts <- " << AT( TSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n"
+ "\t| " << redFsm->errState->id << " -> do_out ()\n"
+ "\t| _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin try\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << AT( ET(), vCS() ) << " > 0 then\n"
+ " begin\n"
+ " state.trans <- " << CAST(transType) << "(" << AT( ET(), vCS() ) << " - 1);\n"
+ " raise Goto_eof_trans;\n"
+ " end;\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " let __acts = ref " << AT( EA(), vCS() ) << " in\n"
+ " let __nacts = ref " << AT( A(), "!__acts" ) << " in\n"
+ " incr __acts;\n"
+ " while !__nacts > 0 do\n"
+ " decr __nacts;\n"
+ " begin match " << AT( A(), POST_INCR("__acts.contents") ) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ " done\n";
+ }
+
+ out <<
+ " with Goto_again -> do_again ()\n"
+ " | Goto_eof_trans -> do_eof_trans () end\n"
+ "\n";
+ }
+ else
+ {
+ out << "\t()\n";
+ }
+
+ if ( outLabelUsed )
+ out << " and do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
+
+void OCamlFlatCodeGen::initVarTypes()
+{
+ slenType = ARRAY_TYPE(MAX(redFsm->maxSpan, redFsm->maxCondSpan));
+ transType = ARRAY_TYPE(redFsm->maxIndex+1);
+ indsType = ARRAY_TYPE(redFsm->maxFlatIndexOffset);
+ condsType = ARRAY_TYPE(redFsm->maxCondIndexOffset);
+}
diff --git a/ragel/mlflat.h b/ragel/mlflat.h
new file mode 100644
index 0000000..6da1819
--- /dev/null
+++ b/ragel/mlflat.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLFLAT_H
+#define _MLFLAT_H
+
+#include <iostream>
+#include "mlcodegen.h"
+
+/* Forwards. */
+//struct CodeGenData;
+//struct NameInst;
+//struct RedTransAp;
+//struct RedStateAp;
+
+/*
+ * OCamlFlatCodeGen
+ */
+class OCamlFlatCodeGen : public OCamlCodeGen
+{
+public:
+ OCamlFlatCodeGen( ostream &out ) : OCamlCodeGen(out) {}
+ virtual ~OCamlFlatCodeGen() { }
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+ void initVarTypes();
+ string slenType, transType, indsType, condsType;
+};
+
+#endif
diff --git a/ragel/mlftable.cpp b/ragel/mlftable.cpp
new file mode 100644
index 0000000..15a9885
--- /dev/null
+++ b/ragel/mlftable.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mlftable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void OCamlFTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &OCamlFTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlFTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+
+/* Write out the function for a transition. */
+std::ostream &OCamlFTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlFTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &OCamlFTabCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\t| " << redAct->actListId+1 << " ->\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void OCamlFTabCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "type " << TYPE_STATE() << " = { mutable keys : int; mutable trans : int; }"
+ << TOP_SEP();
+
+ out << "exception Goto_match" << TOP_SEP();
+ out << "exception Goto_again" << TOP_SEP();
+ out << "exception Goto_eof_trans" << TOP_SEP();
+}
+
+void OCamlFTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " begin\n";
+
+// if ( redFsm->anyRegCurStateRef() )
+// out << klenType ", _ps";
+
+ out <<
+ " let state = { keys = 0; trans = 0; } in\n"
+ " let rec do_start () =\n";
+
+// if ( redFsm->anyConditions() )
+// out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " begin match " << AT( FSA(), vCS() ) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ out << "\tbegin try\n";
+ LOCATE_TRANS();
+ out << "\twith Goto_match -> () end;\n";
+
+ out <<
+ "\tdo_match ()\n";
+
+ out << "and do_match () =\n";
+
+ if ( useIndicies )
+ out << " state.trans <- " << CAST(transType) << AT( I(), "state.trans" ) << ";\n";
+
+ out << "\tdo_eof_trans ()\n";
+
+// if ( redFsm->anyEofTrans() )
+ out << "and do_eof_trans () =\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " let ps = " << vCS() << " in\n";
+
+ out <<
+ " " << vCS() << " <- " << AT( TT() ,"state.trans" ) << ";\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " begin try if " << AT( TA() , "state.trans" ) << " = 0 then\n"
+ " raise Goto_again;\n"
+ "\n"
+ " match " << AT( TA(), "state.trans" ) << " with\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " with Goto_again -> () end;\n"
+ "\n";
+ }
+ out << "\tdo_again ()\n";
+
+// if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+// redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " begin match " << AT( TSA(), vCS() ) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n"
+ "\t| " << redFsm->errState->id << " -> do_out ()\n"
+ "\t| _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin try\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << AT( ET(), vCS() ) << " > 0 then\n"
+ " begin\n"
+ " state.trans <- " << CAST(transType) << "(" << AT( ET(), vCS() ) << " - 1);\n"
+ " raise Goto_eof_trans;\n"
+ " end;\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " begin match " << AT( EA(), vCS() ) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n";
+ }
+
+ out <<
+ " with Goto_again -> do_again ()\n"
+ " | Goto_eof_trans -> do_eof_trans () end\n"
+ "\n";
+ }
+ else
+ {
+ out << "\t()\n";
+ }
+
+ if ( outLabelUsed )
+ out << " and do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
+
diff --git a/ragel/mlftable.h b/ragel/mlftable.h
new file mode 100644
index 0000000..da88e84
--- /dev/null
+++ b/ragel/mlftable.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLFTABLE_H
+#define _MLFTABLE_H
+
+#include <iostream>
+#include "mltable.h"
+
+/* Forwards. */
+//struct CodeGenData;
+
+
+/*
+ * OCamlFTabCodeGen
+ */
+class OCamlFTabCodeGen : public OCamlTabCodeGen
+{
+public:
+ OCamlFTabCodeGen( ostream &out ) : OCamlTabCodeGen(out) {}
+private:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void writeData();
+ virtual void writeExec();
+ virtual void calcIndexSize();
+};
+
+#endif
diff --git a/ragel/mlgoto.cpp b/ragel/mlgoto.cpp
new file mode 100644
index 0000000..65570d8
--- /dev/null
+++ b/ragel/mlgoto.cpp
@@ -0,0 +1,821 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mlgoto.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+/* Emit the goto to take for a given transition. */
+std::ostream &OCamlGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level) << "tr" << trans->id << " ()";
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, true );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ out << "\t()\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void OCamlGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ /* Label the state. */
+ out << "| " << state->id << " ->\n";
+}
+
+
+void OCamlGotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << "\tif " << GET_WIDE_KEY(state) << " = " <<
+ KEY(data[0].lowKey) << " then\n\t\t";
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, 0) << " else\n";
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << "\tmatch " << GET_WIDE_KEY(state) << " with\n";
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << "\t\t| " << ALPHA_KEY(data[j].lowKey) << " -> ";
+ TRANS_GOTO(data[j].value, 0) << "\n";
+ }
+
+ out << "\t\t| _ ->\n";
+ }
+}
+
+void OCamlGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high, RedTransAp* def)
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ RedTransEl *data = state->outRange.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " then begin\n";
+ emitRangeBSearch( state, level+1, low, mid-1, def );
+ out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " then begin\n";
+ emitRangeBSearch( state, level+1, mid+1, high, def );
+ out << TABS(level) << " end else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " then begin\n";
+ emitRangeBSearch( state, level+1, low, mid-1, def );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << " end else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
+ TRANS_GOTO(def, level+1) << "\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " then begin\n";
+ emitRangeBSearch( state, level+1, mid+1, high, def );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << " end else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " >= " <<
+ KEY(data[mid].lowKey) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
+ TRANS_GOTO(def, level+1) << "\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
+ TRANS_GOTO(def, level+1) << "\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
+ TRANS_GOTO(def, level+1) << "\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
+ TRANS_GOTO(def, level+1) << "\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+}
+
+void OCamlGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << "| " << state->id << " ->\n";
+ out << " do_out ()\n";
+}
+
+void OCamlGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
+{
+ GenCondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+}
+
+void OCamlGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ GenStateCond **data = state->stateCondVect.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " )\n {";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &OCamlGotoCodeGen::STATE_GOTOS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st );
+ out << "\tbegin\n";
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1, st->defTrans );
+ else
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+
+ out << "\tend\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ out << " and tr" << trans->id << " () = ";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << vCS() << ";";
+ out << vCS() << " <- " << trans->targ->id << "; ";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ out << "f" << trans->action->actListId << " ()\n";
+ }
+ else {
+ /* No code to execute, just loop around. */
+ out << "do_again ()\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ out << " and f" << redAct->actListId << " () = " <<
+ "state.acts <- " << itoa( redAct->location+1 ) << "; "
+ "execFuncs ()\n";
+ }
+ }
+
+ out <<
+ "\n"
+ "and execFuncs () =\n"
+ " state.nacts <- " << AT( A(), POST_INCR( "state.acts") ) << ";\n"
+ " begin try while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " done with Goto_again -> () end;\n"
+ " do_again ()\n";
+ return out;
+}
+
+unsigned int OCamlGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+unsigned int OCamlGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+unsigned int OCamlGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &OCamlGotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ARR_SEP();
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ARR_SEP();
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ARR_SEP();
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &OCamlGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\t| " << st->id << " -> ";
+
+ /* Write the goto func. */
+ out << "f" << st->eofAction->actListId << " ()\n";
+ }
+ }
+
+ return out;
+}
+
+void OCamlGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << gotoDest << "; " <<
+ CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void OCamlGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void OCamlGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " <- " << nextDest << ";";
+}
+
+void OCamlGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void OCamlGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT( STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; ";
+ ret << vCS() << " <- " << callDest << "; " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT(STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << AT(STACK(), PRE_DECR(TOP()) ) << "; ";
+
+ if ( postPopExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "end ";
+ }
+
+ ret << CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "begin " << P() << " <- " << P() << " + 1; " << CTRL_FLOW() << "raise Goto_out end";
+}
+
+void OCamlGotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "type " << TYPE_STATE() << " = { mutable acts : " << ARRAY_TYPE(redFsm->maxActionLoc) <<
+ " ; mutable nacts : " << ARRAY_TYPE(redFsm->maxActArrItem) << "; }"
+ << TOP_SEP();
+
+ out << "exception Goto_again" << TOP_SEP();
+}
+
+void OCamlGotoCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+
+ out << " begin\n";
+
+// if ( redFsm->anyRegCurStateRef() )
+// out << " int _ps = 0;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out << " let state = { acts = 0; nacts = 0; } in\n";
+ }
+
+// if ( redFsm->anyConditions() )
+// out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+ out << " let rec do_start () =\n";
+
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " state.acts <- " << AT( FSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ out <<
+ " begin match " << vCS() << " with\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << "\n";
+
+// if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+// redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " state.acts <- " << AT( TSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n"
+ "\t| " << redFsm->errState->id << " -> do_out ()\n"
+ "\t| _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " match " << vCS() << " with\n";
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 )
+ out << " | " << st->id << " -> tr" << st->eofTrans->id << " ()\n";
+ }
+
+ out << "\t| _ -> ();\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " let __acts = ref " << AT( EA(), vCS() ) << " in\n"
+ " let __nacts = ref " << AT( A(), "!__acts" ) << " in\n"
+ " incr __acts;\n"
+ " begin try while !__nacts > 0 do\n"
+ " decr __nacts;\n"
+ " begin match " << AT( A(), POST_INCR("__acts.contents") ) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ " done with Goto_again -> do_again () end;\n";
+ }
+
+ out <<
+ " end\n"
+ "\n";
+ }
+ else
+ {
+ out << "\t()\n";
+ }
+
+ if ( outLabelUsed )
+ out << " and do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
diff --git a/ragel/mlgoto.h b/ragel/mlgoto.h
new file mode 100644
index 0000000..50aeb32
--- /dev/null
+++ b/ragel/mlgoto.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _MLGOTO_H
+#define _MLGOTO_H
+
+#include <iostream>
+#include "mlcodegen.h"
+
+/* Forwards. */
+//struct CodeGenData;
+//struct NameInst;
+//struct RedTransAp;
+//struct RedStateAp;
+//struct GenStateCond;
+
+/*
+ * OCamlGotoCodeGen
+ */
+class OCamlGotoCodeGen : virtual public OCamlCodeGen
+{
+public:
+ OCamlGotoCodeGen( ostream &out ) : OCamlCodeGen(out) {}
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &STATE_GOTOS();
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual unsigned int TO_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int EOF_ACTION( RedStateAp *state );
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+ void COND_TRANSLATE( GenStateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+ void emitSingleSwitch( RedStateAp *state );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high, RedTransAp* def );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state );
+ virtual void STATE_GOTO_ERROR();
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+#endif
diff --git a/ragel/mltable.cpp b/ragel/mltable.cpp
new file mode 100644
index 0000000..8f70b7c
--- /dev/null
+++ b/ragel/mltable.cpp
@@ -0,0 +1,1131 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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 "ragel.h"
+#include "mltable.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void OCamlTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &OCamlTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " ->\n";
+ ACTION( out, act, 0, true );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\t| " << act->actionId << " -> \n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::COND_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::KEY_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::INDEX_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::COND_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->stateCondList.length();
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::SINGLE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->outSingle.length();
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::RANGE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ out << st->outRange.length();
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::EOF_TRANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+ out << trans;
+
+ if ( !st.last() ) {
+ out << ARR_SEP();
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ out << ALPHA_KEY( sc->lowKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << ALPHA_KEY( sc->highKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::COND_SPACES()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ out << sc->condSpace->condSpaceId << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << ALPHA_KEY( stel->lowKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ out << ALPHA_KEY( rtel->lowKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << ALPHA_KEY( rtel->highKey ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << stel->value->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ out << rtel->value->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ out << trans->targ->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ out << trans->targ->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ out << trans->targ->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans;
+ out << trans->targ->id << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::TRANS_ACTIONS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ TRANS_ACTION( trans ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ TRANS_ACTION( trans ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ TRANS_ACTION( trans ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ TRANS_ACTION( trans ) << ARR_SEP();
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &OCamlTabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Record the position, need this for eofTrans. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ARR_SEP();
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &OCamlTabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ARR_SEP();
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void OCamlTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << gotoDest << "; " <<
+ CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlTabCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void OCamlTabCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void OCamlTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " <- " << nextDest << ";";
+}
+
+void OCamlTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void OCamlTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT( STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; ";
+ ret << vCS() << " <- " << callDest << "; " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin " << AT(STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; " << vCS() << " <- (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "raise Goto_again end ";
+
+ if ( prePushExpr != 0 )
+ ret << "end";
+}
+
+void OCamlTabCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "begin " << vCS() << " <- " << AT(STACK(), PRE_DECR(TOP()) ) << "; ";
+
+ if ( postPopExpr != 0 ) {
+ ret << "begin ";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "end ";
+ }
+
+ ret << CTRL_FLOW() << "raise Goto_again end";
+}
+
+void OCamlTabCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << "begin " << P() << " <- " << P() << " + 1; " << CTRL_FLOW() << "raise Goto_out end";
+}
+
+void OCamlTabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+
+ out << "type " << TYPE_STATE() << " = { mutable keys : int; mutable trans : int; mutable acts : int; mutable nacts : int; }"
+ << TOP_SEP();
+
+ out << "exception Goto_match" << TOP_SEP();
+ out << "exception Goto_again" << TOP_SEP();
+ out << "exception Goto_eof_trans" << TOP_SEP();
+}
+
+void OCamlTabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " state.keys <- " << AT( KO(), vCS() ) << ";\n"
+ " state.trans <- " << CAST(transType) << AT( IO(), vCS() ) << ";\n"
+ "\n"
+ " let klen = " << AT( SL(), vCS() ) << " in\n"
+ " if klen > 0 then begin\n"
+ " let lower : " << signedKeysType << " ref = ref state.keys in\n"
+ " let upper : " << signedKeysType << " ref = ref " << CAST(signedKeysType) <<
+ "(state.keys + klen - 1) in\n"
+ " while !upper >= !lower do\n"
+ " let mid = " << CAST(signedKeysType) << " (!lower + ((!upper - !lower) / 2)) in\n"
+ " if " << GET_WIDE_KEY() << " < " << AT( K(), "mid" ) << " then\n"
+ " upper := " << CAST(signedKeysType) << " (mid - 1)\n"
+ " else if " << GET_WIDE_KEY() << " > " << AT( K(), "mid" ) << " then\n"
+ " lower := " << CAST(signedKeysType) << " (mid + 1)\n"
+ " else begin\n"
+ " state.trans <- state.trans + " << CAST(transType) << " (mid - state.keys);\n"
+ " raise Goto_match;\n"
+ " end\n"
+ " done;\n"
+ " state.keys <- state.keys + " << CAST(keysType) << " klen;\n"
+ " state.trans <- state.trans + " << CAST(transType) << " klen;\n"
+ " end;\n"
+ "\n"
+ " let klen = " << AT( RL(), vCS() ) << " in\n"
+ " if klen > 0 then begin\n"
+ " let lower : " << signedKeysType << " ref = ref state.keys in\n"
+ " let upper : " << signedKeysType << " ref = ref " << CAST(signedKeysType) <<
+ "(state.keys + (klen * 2) - 2) in\n"
+ " while !upper >= !lower do\n"
+ " let mid = " << CAST(signedKeysType) << " (!lower + (((!upper - !lower) / 2) land (lnot 1))) in\n"
+ " if " << GET_WIDE_KEY() << " < " << AT( K() , "mid" ) << " then\n"
+ " upper := " << CAST(signedKeysType) << " (mid - 2)\n"
+ " else if " << GET_WIDE_KEY() << " > " << AT( K(), "mid+1" ) << " then\n"
+ " lower := " << CAST(signedKeysType) << " (mid + 2)\n"
+ " else begin\n"
+ " state.trans <- state.trans + " << CAST(transType) << "((mid - state.keys) / 2);\n"
+ " raise Goto_match;\n"
+ " end\n"
+ " done;\n"
+ " state.trans <- state.trans + " << CAST(transType) << " klen;\n"
+ " end;\n"
+ "\n";
+}
+
+void OCamlTabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n"
+ " _klen = " << CL() << "[" << vCS() << "];\n"
+ " _keys = " << CAST(keysType) << " ("<< CO() << "[" << vCS() << "]*2);\n"
+ " if ( _klen > 0 ) {\n"
+ " " << signedKeysType << " _lower = _keys;\n"
+ " " << signedKeysType << " _mid;\n"
+ " " << signedKeysType << " _upper = " << CAST(signedKeysType) <<
+ " (_keys + (_klen<<1) - 2);\n"
+ " while (true) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = " << CAST(signedKeysType) <<
+ " (_lower + (((_upper-_lower) >> 1) & ~1));\n"
+ " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
+ " _upper = " << CAST(signedKeysType) << " (_mid - 2);\n"
+ " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
+ " _lower = " << CAST(signedKeysType) << " (_mid + 2);\n"
+ " else {\n"
+ " switch ( " << C() << "[" << CO() << "[" << vCS() << "]"
+ " + ((_mid - _keys)>>1)] ) {\n";
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out <<
+ " break;\n"
+ " }\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+}
+
+void OCamlTabCodeGen::writeExec()
+{
+ testEofUsed = false;
+ outLabelUsed = false;
+ initVarTypes();
+
+ out <<
+ " begin\n";
+// " " << klenType << " _klen";
+
+// if ( redFsm->anyRegCurStateRef() )
+// out << ", _ps";
+
+/*
+ out << " " << transType << " _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " int _acts;\n"
+ " int _nacts;\n";
+ }
+
+ out <<
+ " " << keysType << " _keys;\n"
+ "\n";
+// " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+*/
+
+ out <<
+ " let state = { keys = 0; trans = 0; acts = 0; nacts = 0; } in\n"
+ " let rec do_start () =\n";
+ if ( !noEnd ) {
+ testEofUsed = true;
+ out <<
+ " if " << P() << " = " << PE() << " then\n"
+ " do_test_eof ()\n"
+ "\telse\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if " << vCS() << " = " << redFsm->errState->id << " then\n"
+ " do_out ()\n"
+ "\telse\n";
+ }
+ out << "\tdo_resume ()\n";
+
+ out << "and do_resume () =\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " state.acts <- " << AT( FSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ out << "\tbegin try\n";
+ LOCATE_TRANS();
+ out << "\twith Goto_match -> () end;\n";
+
+ out <<
+ "\tdo_match ()\n";
+
+ out << "and do_match () =\n";
+
+ if ( useIndicies )
+ out << " state.trans <- " << CAST(transType) << AT( I(), "state.trans" ) << ";\n";
+
+ out << "\tdo_eof_trans ()\n";
+
+// if ( redFsm->anyEofTrans() )
+ out << "and do_eof_trans () =\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " let ps = " << vCS() << " in\n";
+
+ out <<
+ " " << vCS() << " <- " << AT( TT() ,"state.trans" ) << ";\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ "\tbegin try\n"
+ " match " << AT( TA(), "state.trans" ) << " with\n"
+ "\t| 0 -> raise Goto_again\n"
+ "\t| _ ->\n"
+ " state.acts <- " << AT( TA(), "state.trans" ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ " done\n"
+ "\twith Goto_again -> () end;\n";
+ }
+ out << "\tdo_again ()\n";
+
+// if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+// redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\tand do_again () =\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " state.acts <- " << AT( TSA(), vCS() ) << ";\n"
+ " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
+ " while " << POST_DECR("state.nacts") << " > 0 do\n"
+ " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end\n"
+ " done;\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " match " << vCS() << " with\n"
+ "\t| " << redFsm->errState->id << " -> do_out ()\n"
+ "\t| _ ->\n";
+ }
+
+ out << "\t" << P() << " <- " << P() << " + 1;\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " <> " << PE() << " then\n"
+ " do_resume ()\n"
+ "\telse do_test_eof ()\n";
+ }
+ else {
+ out <<
+ " do_resume ()\n";
+ }
+
+// if ( testEofUsed )
+ out << "and do_test_eof () =\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " = " << vEOF() << " then\n"
+ " begin try\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << AT( ET(), vCS() ) << " > 0 then\n"
+ " begin\n"
+ " state.trans <- " << CAST(transType) << "(" << AT( ET(), vCS() ) << " - 1);\n"
+ " raise Goto_eof_trans;\n"
+ " end;\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " let __acts = ref " << AT( EA(), vCS() ) << " in\n"
+ " let __nacts = ref " << AT( A(), "!__acts" ) << " in\n"
+ " incr __acts;\n"
+ " while !__nacts > 0 do\n"
+ " decr __nacts;\n"
+ " begin match " << AT( A(), POST_INCR("__acts.contents") ) << " with\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " end;\n"
+ " done\n";
+ }
+
+ out <<
+ " with Goto_again -> do_again ()\n"
+ " | Goto_eof_trans -> do_eof_trans () end\n"
+ "\n";
+ }
+ else
+ {
+ out << "\t()\n";
+ }
+
+ if ( outLabelUsed )
+ out << " and do_out () = ()\n";
+
+ out << "\tin do_start ()\n";
+ out << " end;\n";
+}
+
+void OCamlTabCodeGen::initVarTypes()
+{
+ int klenMax = MAX(MAX(redFsm->maxCondLen, redFsm->maxRangeLen),
+ redFsm->maxSingleLen);
+ int keysMax = MAX(MAX(redFsm->maxKeyOffset, klenMax),
+ redFsm->maxCondOffset);
+ int transMax = MAX(MAX(redFsm->maxIndex+1, redFsm->maxIndexOffset), keysMax);
+ transMax = MAX(transMax, klenMax);
+ transType = ARRAY_TYPE(transMax);
+ klenType = ARRAY_TYPE(klenMax);
+ keysType = ARRAY_TYPE(keysMax);
+ signedKeysType = ARRAY_TYPE(keysMax, true);
+}
diff --git a/ragel/mltable.h b/ragel/mltable.h
new file mode 100644
index 0000000..505d378
--- /dev/null
+++ b/ragel/mltable.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* 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
+ */
+
+#ifndef _OCAMLTABCODEGEN_H
+#define _OCAMLTABCODEGEN_H
+
+#include <iostream>
+#include "mlcodegen.h"
+
+/* Forwards. */
+/*
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+*/
+
+/*
+ * OCamlTabCodeGen
+ */
+class OCamlTabCodeGen : public OCamlCodeGen
+{
+public:
+ OCamlTabCodeGen( ostream &out ) : OCamlCodeGen(out) {}
+ virtual ~OCamlTabCodeGen() { }
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+
+ void LOCATE_TRANS();
+
+ void COND_TRANSLATE();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void calcIndexSize();
+
+ void initVarTypes();
+ string klenType;
+ string keysType;
+ string signedKeysType;
+ string transType;
+};
+
+#endif
diff --git a/ragel/parsedata.cpp b/ragel/parsedata.cpp
new file mode 100644
index 0000000..8ce89db
--- /dev/null
+++ b/ragel/parsedata.cpp
@@ -0,0 +1,1466 @@
+/*
+ * Copyright 2001-2008 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 <iomanip>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "ragel.h"
+#include "rlparse.h"
+#include "parsedata.h"
+#include "parsetree.h"
+#include "mergesort.h"
+#include "xmlcodegen.h"
+#include "version.h"
+#include "inputdata.h"
+
+using namespace std;
+
+char mainMachine[] = "main";
+
+void Token::set( const char *str, int len )
+{
+ length = len;
+ data = new char[len+1];
+ memcpy( data, str, len );
+ data[len] = 0;
+}
+
+void Token::append( const Token &other )
+{
+ int newLength = length + other.length;
+ char *newString = new char[newLength+1];
+ memcpy( newString, data, length );
+ memcpy( newString + length, other.data, other.length );
+ newString[newLength] = 0;
+ data = newString;
+ length = newLength;
+}
+
+/* Perform minimization after an operation according
+ * to the command line args. */
+void afterOpMinimize( FsmAp *fsm, bool lastInSeq )
+{
+ /* Switch on the prefered minimization algorithm. */
+ if ( minimizeOpt == MinimizeEveryOp || ( minimizeOpt == MinimizeMostOps && lastInSeq ) ) {
+ /* First clean up the graph. FsmAp operations may leave these
+ * lying around. There should be no dead end states. The subtract
+ * intersection operators are the only places where they may be
+ * created and those operators clean them up. */
+ fsm->removeUnreachableStates();
+
+ switch ( minimizeLevel ) {
+ case MinimizeApprox:
+ fsm->minimizeApproximate();
+ break;
+ case MinimizePartition1:
+ fsm->minimizePartition1();
+ break;
+ case MinimizePartition2:
+ fsm->minimizePartition2();
+ break;
+ case MinimizeStable:
+ fsm->minimizeStable();
+ break;
+ }
+ }
+}
+
+/* Count the transitions in the fsm by walking the state list. */
+int countTransitions( FsmAp *fsm )
+{
+ int numTrans = 0;
+ StateAp *state = fsm->stateList.head;
+ while ( state != 0 ) {
+ numTrans += state->outList.length();
+ state = state->next;
+ }
+ return numTrans;
+}
+
+Key makeFsmKeyHex( char *str, const InputLoc &loc, ParseData *pd )
+{
+ /* Reset errno so we can check for overflow or underflow. In the event of
+ * an error, sets the return val to the upper or lower bound being tested
+ * against. */
+ errno = 0;
+ unsigned int size = keyOps->alphType->size;
+ bool unusedBits = size < sizeof(unsigned long);
+
+ unsigned long ul = strtoul( str, 0, 16 );
+
+ if ( errno == ERANGE || ( unusedBits && ul >> (size * 8) ) ) {
+ error(loc) << "literal " << str << " overflows the alphabet type" << endl;
+ ul = 1 << (size * 8);
+ }
+
+ if ( unusedBits && keyOps->alphType->isSigned && ul >> (size * 8 - 1) )
+ ul |= ( -1L >> (size*8) ) << (size*8);
+
+ return Key( (long)ul );
+}
+
+Key makeFsmKeyDec( char *str, const InputLoc &loc, ParseData *pd )
+{
+ /* Convert the number to a decimal. First reset errno so we can check
+ * for overflow or underflow. */
+ errno = 0;
+ long long minVal = keyOps->alphType->minVal;
+ long long maxVal = keyOps->alphType->maxVal;
+
+ long long ll = strtoll( str, 0, 10 );
+
+ /* Check for underflow. */
+ if ( ( errno == ERANGE && ll < 0 ) || ll < minVal) {
+ error(loc) << "literal " << str << " underflows the alphabet type" << endl;
+ ll = minVal;
+ }
+ /* Check for overflow. */
+ else if ( ( errno == ERANGE && ll > 0 ) || ll > maxVal ) {
+ error(loc) << "literal " << str << " overflows the alphabet type" << endl;
+ ll = maxVal;
+ }
+
+ if ( keyOps->alphType->isSigned )
+ return Key( (long)ll );
+ else
+ return Key( (unsigned long)ll );
+}
+
+/* Make an fsm key in int format (what the fsm graph uses) from an alphabet
+ * number returned by the parser. Validates that the number doesn't overflow
+ * the alphabet type. */
+Key makeFsmKeyNum( char *str, const InputLoc &loc, ParseData *pd )
+{
+ /* Switch on hex/decimal format. */
+ if ( str[0] == '0' && str[1] == 'x' )
+ return makeFsmKeyHex( str, loc, pd );
+ else
+ return makeFsmKeyDec( str, loc, pd );
+}
+
+/* Make an fsm int format (what the fsm graph uses) from a single character.
+ * Performs proper conversion depending on signed/unsigned property of the
+ * alphabet. */
+Key makeFsmKeyChar( char c, ParseData *pd )
+{
+ if ( keyOps->isSigned ) {
+ /* Copy from a char type. */
+ return Key( c );
+ }
+ else {
+ /* Copy from an unsigned byte type. */
+ return Key( (unsigned char)c );
+ }
+}
+
+/* Make an fsm key array in int format (what the fsm graph uses) from a string
+ * of characters. Performs proper conversion depending on signed/unsigned
+ * property of the alphabet. */
+void makeFsmKeyArray( Key *result, char *data, int len, ParseData *pd )
+{
+ if ( keyOps->isSigned ) {
+ /* Copy from a char star type. */
+ char *src = data;
+ for ( int i = 0; i < len; i++ )
+ result[i] = Key(src[i]);
+ }
+ else {
+ /* Copy from an unsigned byte ptr type. */
+ unsigned char *src = (unsigned char*) data;
+ for ( int i = 0; i < len; i++ )
+ result[i] = Key(src[i]);
+ }
+}
+
+/* Like makeFsmKeyArray except the result has only unique keys. They ordering
+ * will be changed. */
+void makeFsmUniqueKeyArray( KeySet &result, char *data, int len,
+ bool caseInsensitive, ParseData *pd )
+{
+ /* Use a transitions list for getting unique keys. */
+ if ( keyOps->isSigned ) {
+ /* Copy from a char star type. */
+ char *src = data;
+ for ( int si = 0; si < len; si++ ) {
+ Key key( src[si] );
+ result.insert( key );
+ if ( caseInsensitive ) {
+ if ( key.isLower() )
+ result.insert( key.toUpper() );
+ else if ( key.isUpper() )
+ result.insert( key.toLower() );
+ }
+ }
+ }
+ else {
+ /* Copy from an unsigned byte ptr type. */
+ unsigned char *src = (unsigned char*) data;
+ for ( int si = 0; si < len; si++ ) {
+ Key key( src[si] );
+ result.insert( key );
+ if ( caseInsensitive ) {
+ if ( key.isLower() )
+ result.insert( key.toUpper() );
+ else if ( key.isUpper() )
+ result.insert( key.toLower() );
+ }
+ }
+ }
+}
+
+FsmAp *dotFsm( ParseData *pd )
+{
+ FsmAp *retFsm = new FsmAp();
+ retFsm->rangeFsm( keyOps->minKey, keyOps->maxKey );
+ return retFsm;
+}
+
+FsmAp *dotStarFsm( ParseData *pd )
+{
+ FsmAp *retFsm = new FsmAp();
+ retFsm->rangeStarFsm( keyOps->minKey, keyOps->maxKey );
+ return retFsm;
+}
+
+/* Make a builtin type. Depends on the signed nature of the alphabet type. */
+FsmAp *makeBuiltin( BuiltinMachine builtin, ParseData *pd )
+{
+ /* FsmAp created to return. */
+ FsmAp *retFsm = 0;
+ bool isSigned = keyOps->isSigned;
+
+ switch ( builtin ) {
+ case BT_Any: {
+ /* All characters. */
+ retFsm = dotFsm( pd );
+ break;
+ }
+ case BT_Ascii: {
+ /* Ascii characters 0 to 127. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( 0, 127 );
+ break;
+ }
+ case BT_Extend: {
+ /* Ascii extended characters. This is the full byte range. Dependent
+ * on signed, vs no signed. If the alphabet is one byte then just use
+ * dot fsm. */
+ if ( isSigned ) {
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( -128, 127 );
+ }
+ else {
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( 0, 255 );
+ }
+ break;
+ }
+ case BT_Alpha: {
+ /* Alpha [A-Za-z]. */
+ FsmAp *upper = new FsmAp(), *lower = new FsmAp();
+ upper->rangeFsm( 'A', 'Z' );
+ lower->rangeFsm( 'a', 'z' );
+ upper->unionOp( lower );
+ upper->minimizePartition2();
+ retFsm = upper;
+ break;
+ }
+ case BT_Digit: {
+ /* Digits [0-9]. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( '0', '9' );
+ break;
+ }
+ case BT_Alnum: {
+ /* Alpha numerics [0-9A-Za-z]. */
+ FsmAp *digit = new FsmAp(), *lower = new FsmAp();
+ FsmAp *upper = new FsmAp();
+ digit->rangeFsm( '0', '9' );
+ upper->rangeFsm( 'A', 'Z' );
+ lower->rangeFsm( 'a', 'z' );
+ digit->unionOp( upper );
+ digit->unionOp( lower );
+ digit->minimizePartition2();
+ retFsm = digit;
+ break;
+ }
+ case BT_Lower: {
+ /* Lower case characters. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( 'a', 'z' );
+ break;
+ }
+ case BT_Upper: {
+ /* Upper case characters. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( 'A', 'Z' );
+ break;
+ }
+ case BT_Cntrl: {
+ /* Control characters. */
+ FsmAp *cntrl = new FsmAp();
+ FsmAp *highChar = new FsmAp();
+ cntrl->rangeFsm( 0, 31 );
+ highChar->concatFsm( 127 );
+ cntrl->unionOp( highChar );
+ cntrl->minimizePartition2();
+ retFsm = cntrl;
+ break;
+ }
+ case BT_Graph: {
+ /* Graphical ascii characters [!-~]. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( '!', '~' );
+ break;
+ }
+ case BT_Print: {
+ /* Printable characters. Same as graph except includes space. */
+ retFsm = new FsmAp();
+ retFsm->rangeFsm( ' ', '~' );
+ break;
+ }
+ case BT_Punct: {
+ /* Punctuation. */
+ FsmAp *range1 = new FsmAp();
+ FsmAp *range2 = new FsmAp();
+ FsmAp *range3 = new FsmAp();
+ FsmAp *range4 = new FsmAp();
+ range1->rangeFsm( '!', '/' );
+ range2->rangeFsm( ':', '@' );
+ range3->rangeFsm( '[', '`' );
+ range4->rangeFsm( '{', '~' );
+ range1->unionOp( range2 );
+ range1->unionOp( range3 );
+ range1->unionOp( range4 );
+ range1->minimizePartition2();
+ retFsm = range1;
+ break;
+ }
+ case BT_Space: {
+ /* Whitespace: [\t\v\f\n\r ]. */
+ FsmAp *cntrl = new FsmAp();
+ FsmAp *space = new FsmAp();
+ cntrl->rangeFsm( '\t', '\r' );
+ space->concatFsm( ' ' );
+ cntrl->unionOp( space );
+ cntrl->minimizePartition2();
+ retFsm = cntrl;
+ break;
+ }
+ case BT_Xdigit: {
+ /* Hex digits [0-9A-Fa-f]. */
+ FsmAp *digit = new FsmAp();
+ FsmAp *upper = new FsmAp();
+ FsmAp *lower = new FsmAp();
+ digit->rangeFsm( '0', '9' );
+ upper->rangeFsm( 'A', 'F' );
+ lower->rangeFsm( 'a', 'f' );
+ digit->unionOp( upper );
+ digit->unionOp( lower );
+ digit->minimizePartition2();
+ retFsm = digit;
+ break;
+ }
+ case BT_Lambda: {
+ retFsm = new FsmAp();
+ retFsm->lambdaFsm();
+ break;
+ }
+ case BT_Empty: {
+ retFsm = new FsmAp();
+ retFsm->emptyFsm();
+ break;
+ }}
+
+ return retFsm;
+}
+
+/* Check if this name inst or any name inst below is referenced. */
+bool NameInst::anyRefsRec()
+{
+ if ( numRefs > 0 )
+ return true;
+
+ /* Recurse on children until true. */
+ for ( NameVect::Iter ch = childVect; ch.lte(); ch++ ) {
+ if ( (*ch)->anyRefsRec() )
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * ParseData
+ */
+
+/* Initialize the structure that will collect info during the parse of a
+ * machine. */
+ParseData::ParseData( const char *fileName, char *sectionName,
+ const InputLoc &sectionLoc )
+:
+ sectionGraph(0),
+ generatingSectionSubset(false),
+ nextPriorKey(0),
+ /* 0 is reserved for global error actions. */
+ nextLocalErrKey(1),
+ nextNameId(0),
+ nextCondId(0),
+ alphTypeSet(false),
+ getKeyExpr(0),
+ accessExpr(0),
+ prePushExpr(0),
+ postPopExpr(0),
+ pExpr(0),
+ peExpr(0),
+ eofExpr(0),
+ csExpr(0),
+ topExpr(0),
+ stackExpr(0),
+ actExpr(0),
+ tokstartExpr(0),
+ tokendExpr(0),
+ dataExpr(0),
+ lowerNum(0),
+ upperNum(0),
+ fileName(fileName),
+ sectionName(sectionName),
+ sectionLoc(sectionLoc),
+ curActionOrd(0),
+ curPriorOrd(0),
+ rootName(0),
+ exportsRootName(0),
+ nextEpsilonResolvedLink(0),
+ nextLongestMatchId(1),
+ lmRequiresErrorState(false),
+ cgd(0)
+{
+ /* Initialize the dictionary of graphs. This is our symbol table. The
+ * initialization needs to be done on construction which happens at the
+ * beginning of a machine spec so any assignment operators can reference
+ * the builtins. */
+ initGraphDict();
+}
+
+/* Clean up the data collected during a parse. */
+ParseData::~ParseData()
+{
+ /* Delete all the nodes in the action list. Will cause all the
+ * string data that represents the actions to be deallocated. */
+ actionList.empty();
+}
+
+/* Make a name id in the current name instantiation scope if it is not
+ * already there. */
+NameInst *ParseData::addNameInst( const InputLoc &loc, const char *data, bool isLabel )
+{
+ /* Create the name instantitaion object and insert it. */
+ NameInst *newNameInst = new NameInst( loc, curNameInst, data, nextNameId++, isLabel );
+ curNameInst->childVect.append( newNameInst );
+ if ( data != 0 )
+ curNameInst->children.insertMulti( data, newNameInst );
+ return newNameInst;
+}
+
+void ParseData::initNameWalk()
+{
+ curNameInst = rootName;
+ curNameChild = 0;
+}
+
+void ParseData::initExportsNameWalk()
+{
+ curNameInst = exportsRootName;
+ curNameChild = 0;
+}
+
+/* Goes into the next child scope. The number of the child is already set up.
+ * We need this for the syncronous name tree and parse tree walk to work
+ * properly. It is reset on entry into a scope and advanced on poping of a
+ * scope. A call to enterNameScope should be accompanied by a corresponding
+ * popNameScope. */
+NameFrame ParseData::enterNameScope( bool isLocal, int numScopes )
+{
+ /* Save off the current data. */
+ NameFrame retFrame;
+ retFrame.prevNameInst = curNameInst;
+ retFrame.prevNameChild = curNameChild;
+ retFrame.prevLocalScope = localNameScope;
+
+ /* Enter into the new name scope. */
+ for ( int i = 0; i < numScopes; i++ ) {
+ curNameInst = curNameInst->childVect[curNameChild];
+ curNameChild = 0;
+ }
+
+ if ( isLocal )
+ localNameScope = curNameInst;
+
+ return retFrame;
+}
+
+/* Return from a child scope to a parent. The parent info must be specified as
+ * an argument and is obtained from the corresponding call to enterNameScope.
+ * */
+void ParseData::popNameScope( const NameFrame &frame )
+{
+ /* Pop the name scope. */
+ curNameInst = frame.prevNameInst;
+ curNameChild = frame.prevNameChild+1;
+ localNameScope = frame.prevLocalScope;
+}
+
+void ParseData::resetNameScope( const NameFrame &frame )
+{
+ /* Pop the name scope. */
+ curNameInst = frame.prevNameInst;
+ curNameChild = frame.prevNameChild;
+ localNameScope = frame.prevLocalScope;
+}
+
+
+void ParseData::unsetObsoleteEntries( FsmAp *graph )
+{
+ /* Loop the reference names and increment the usage. Names that are no
+ * longer needed will be unset in graph. */
+ for ( NameVect::Iter ref = curNameInst->referencedNames; ref.lte(); ref++ ) {
+ /* Get the name. */
+ NameInst *name = *ref;
+ name->numUses += 1;
+
+ /* If the name is no longer needed unset its corresponding entry. */
+ if ( name->numUses == name->numRefs ) {
+ assert( graph->entryPoints.find( name->id ) != 0 );
+ graph->unsetEntry( name->id );
+ assert( graph->entryPoints.find( name->id ) == 0 );
+ }
+ }
+}
+
+NameSet ParseData::resolvePart( NameInst *refFrom, const char *data, bool recLabelsOnly )
+{
+ /* Queue needed for breadth-first search, load it with the start node. */
+ NameInstList nameQueue;
+ nameQueue.append( refFrom );
+
+ NameSet result;
+ while ( nameQueue.length() > 0 ) {
+ /* Pull the next from location off the queue. */
+ NameInst *from = nameQueue.detachFirst();
+
+ /* Look for the name. */
+ NameMapEl *low, *high;
+ if ( from->children.findMulti( data, low, high ) ) {
+ /* Record all instances of the name. */
+ for ( ; low <= high; low++ )
+ result.insert( low->value );
+ }
+
+ /* Name not there, do breadth-first operation of appending all
+ * childrent to the processing queue. */
+ for ( NameVect::Iter name = from->childVect; name.lte(); name++ ) {
+ if ( !recLabelsOnly || (*name)->isLabel )
+ nameQueue.append( *name );
+ }
+ }
+
+ /* Queue exhausted and name never found. */
+ return result;
+}
+
+void ParseData::resolveFrom( NameSet &result, NameInst *refFrom,
+ const NameRef &nameRef, int namePos )
+{
+ /* Look for the name in the owning scope of the factor with aug. */
+ NameSet partResult = resolvePart( refFrom, nameRef[namePos], false );
+
+ /* If there are more parts to the name then continue on. */
+ if ( ++namePos < nameRef.length() ) {
+ /* There are more components to the name, search using all the part
+ * results as the base. */
+ for ( NameSet::Iter name = partResult; name.lte(); name++ )
+ resolveFrom( result, *name, nameRef, namePos );
+ }
+ else {
+ /* This is the last component, append the part results to the final
+ * results. */
+ result.insert( partResult );
+ }
+}
+
+/* Write out a name reference. */
+ostream &operator<<( ostream &out, const NameRef &nameRef )
+{
+ int pos = 0;
+ if ( nameRef[pos] == 0 ) {
+ out << "::";
+ pos += 1;
+ }
+ out << nameRef[pos++];
+ for ( ; pos < nameRef.length(); pos++ )
+ out << "::" << nameRef[pos];
+ return out;
+}
+
+ostream &operator<<( ostream &out, const NameInst &nameInst )
+{
+ /* Count the number fully qualified name parts. */
+ int numParents = 0;
+ NameInst *curParent = nameInst.parent;
+ while ( curParent != 0 ) {
+ numParents += 1;
+ curParent = curParent->parent;
+ }
+
+ /* Make an array and fill it in. */
+ curParent = nameInst.parent;
+ NameInst **parents = new NameInst*[numParents];
+ for ( int p = numParents-1; p >= 0; p-- ) {
+ parents[p] = curParent;
+ curParent = curParent->parent;
+ }
+
+ /* Write the parents out, skip the root. */
+ for ( int p = 1; p < numParents; p++ )
+ out << "::" << ( parents[p]->name != 0 ? parents[p]->name : "<ANON>" );
+
+ /* Write the name and cleanup. */
+ out << "::" << ( nameInst.name != 0 ? nameInst.name : "<ANON>" );
+ delete[] parents;
+ return out;
+}
+
+struct CmpNameInstLoc
+{
+ static int compare( const NameInst *ni1, const NameInst *ni2 )
+ {
+ if ( ni1->loc.line < ni2->loc.line )
+ return -1;
+ else if ( ni1->loc.line > ni2->loc.line )
+ return 1;
+ else if ( ni1->loc.col < ni2->loc.col )
+ return -1;
+ else if ( ni1->loc.col > ni2->loc.col )
+ return 1;
+ return 0;
+ }
+};
+
+void errorStateLabels( const NameSet &resolved )
+{
+ MergeSort<NameInst*, CmpNameInstLoc> mergeSort;
+ mergeSort.sort( resolved.data, resolved.length() );
+ for ( NameSet::Iter res = resolved; res.lte(); res++ )
+ error((*res)->loc) << " -> " << **res << endl;
+}
+
+
+NameInst *ParseData::resolveStateRef( const NameRef &nameRef, InputLoc &loc, Action *action )
+{
+ NameInst *nameInst = 0;
+
+ /* Do the local search if the name is not strictly a root level name
+ * search. */
+ if ( nameRef[0] != 0 ) {
+ /* If the action is referenced, resolve all of them. */
+ if ( action != 0 && action->actionRefs.length() > 0 ) {
+ /* Look for the name in all referencing scopes. */
+ NameSet resolved;
+ for ( ActionRefs::Iter actRef = action->actionRefs; actRef.lte(); actRef++ )
+ resolveFrom( resolved, *actRef, nameRef, 0 );
+
+ if ( resolved.length() > 0 ) {
+ /* Take the first one. */
+ nameInst = resolved[0];
+ if ( resolved.length() > 1 ) {
+ /* Complain about the multiple references. */
+ error(loc) << "state reference " << nameRef <<
+ " resolves to multiple entry points" << endl;
+ errorStateLabels( resolved );
+ }
+ }
+ }
+ }
+
+ /* If not found in the local scope, look in global. */
+ if ( nameInst == 0 ) {
+ NameSet resolved;
+ int fromPos = nameRef[0] != 0 ? 0 : 1;
+ resolveFrom( resolved, rootName, nameRef, fromPos );
+
+ if ( resolved.length() > 0 ) {
+ /* Take the first. */
+ nameInst = resolved[0];
+ if ( resolved.length() > 1 ) {
+ /* Complain about the multiple references. */
+ error(loc) << "state reference " << nameRef <<
+ " resolves to multiple entry points" << endl;
+ errorStateLabels( resolved );
+ }
+ }
+ }
+
+ if ( nameInst == 0 ) {
+ /* If not found then complain. */
+ error(loc) << "could not resolve state reference " << nameRef << endl;
+ }
+ return nameInst;
+}
+
+void ParseData::resolveNameRefs( InlineList *inlineList, Action *action )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Entry: case InlineItem::Goto:
+ case InlineItem::Call: case InlineItem::Next: {
+ /* Resolve, pass action for local search. */
+ NameInst *target = resolveStateRef( *item->nameRef, item->loc, action );
+
+ /* Name lookup error reporting is handled by resolveStateRef. */
+ if ( target != 0 ) {
+ /* Check if the target goes into a longest match. */
+ NameInst *search = target->parent;
+ while ( search != 0 ) {
+ if ( search->isLongestMatch ) {
+ error(item->loc) << "cannot enter inside a longest "
+ "match construction as an entry point" << endl;
+ break;
+ }
+ search = search->parent;
+ }
+
+ /* Record the reference in the name. This will cause the
+ * entry point to survive to the end of the graph
+ * generating walk. */
+ target->numRefs += 1;
+ }
+
+ item->nameTarg = target;
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Some of the item types may have children. */
+ if ( item->children != 0 )
+ resolveNameRefs( item->children, action );
+ }
+}
+
+/* Resolve references to labels in actions. */
+void ParseData::resolveActionNameRefs()
+{
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Only care about the actions that are referenced. */
+ if ( act->actionRefs.length() > 0 )
+ resolveNameRefs( act->inlineList, act );
+ }
+}
+
+/* Walk a name tree starting at from and fill the name index. */
+void ParseData::fillNameIndex( NameInst *from )
+{
+ /* Fill the value for from in the name index. */
+ nameIndex[from->id] = from;
+
+ /* Recurse on the implicit final state and then all children. */
+ if ( from->final != 0 )
+ fillNameIndex( from->final );
+ for ( NameVect::Iter name = from->childVect; name.lte(); name++ )
+ fillNameIndex( *name );
+}
+
+void ParseData::makeRootNames()
+{
+ /* Create the root name. */
+ rootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
+ exportsRootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
+}
+
+/* Build the name tree and supporting data structures. */
+void ParseData::makeNameTree( GraphDictEl *dictEl )
+{
+ /* Set up curNameInst for the walk. */
+ initNameWalk();
+
+ if ( dictEl != 0 ) {
+ /* A start location has been specified. */
+ dictEl->value->makeNameTree( dictEl->loc, this );
+ }
+ else {
+ /* First make the name tree. */
+ for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
+ /* Recurse on the instance. */
+ glel->value->makeNameTree( glel->loc, this );
+ }
+ }
+
+ /* The number of nodes in the tree can now be given by nextNameId */
+ nameIndex = new NameInst*[nextNameId];
+ memset( nameIndex, 0, sizeof(NameInst*)*nextNameId );
+ fillNameIndex( rootName );
+ fillNameIndex( exportsRootName );
+}
+
+
+void ParseData::createBuiltin( const char *name, BuiltinMachine builtin )
+{
+ Expression *expression = new Expression( builtin );
+ Join *join = new Join( expression );
+ MachineDef *machineDef = new MachineDef( join );
+ VarDef *varDef = new VarDef( name, machineDef );
+ GraphDictEl *graphDictEl = new GraphDictEl( name, varDef );
+ graphDict.insert( graphDictEl );
+}
+
+/* Initialize the graph dict with builtin types. */
+void ParseData::initGraphDict( )
+{
+ createBuiltin( "any", BT_Any );
+ createBuiltin( "ascii", BT_Ascii );
+ createBuiltin( "extend", BT_Extend );
+ createBuiltin( "alpha", BT_Alpha );
+ createBuiltin( "digit", BT_Digit );
+ createBuiltin( "alnum", BT_Alnum );
+ createBuiltin( "lower", BT_Lower );
+ createBuiltin( "upper", BT_Upper );
+ createBuiltin( "cntrl", BT_Cntrl );
+ createBuiltin( "graph", BT_Graph );
+ createBuiltin( "print", BT_Print );
+ createBuiltin( "punct", BT_Punct );
+ createBuiltin( "space", BT_Space );
+ createBuiltin( "xdigit", BT_Xdigit );
+ createBuiltin( "null", BT_Lambda );
+ createBuiltin( "zlen", BT_Lambda );
+ createBuiltin( "empty", BT_Empty );
+}
+
+/* Set the alphabet type. If the types are not valid returns false. */
+bool ParseData::setAlphType( const InputLoc &loc, char *s1, char *s2 )
+{
+ alphTypeLoc = loc;
+ userAlphType = findAlphType( s1, s2 );
+ alphTypeSet = true;
+ return userAlphType != 0;
+}
+
+/* Set the alphabet type. If the types are not valid returns false. */
+bool ParseData::setAlphType( const InputLoc &loc, char *s1 )
+{
+ alphTypeLoc = loc;
+ userAlphType = findAlphType( s1 );
+ alphTypeSet = true;
+ return userAlphType != 0;
+}
+
+bool ParseData::setVariable( char *var, InlineList *inlineList )
+{
+ bool set = true;
+
+ if ( strcmp( var, "p" ) == 0 )
+ pExpr = inlineList;
+ else if ( strcmp( var, "pe" ) == 0 )
+ peExpr = inlineList;
+ else if ( strcmp( var, "eof" ) == 0 )
+ eofExpr = inlineList;
+ else if ( strcmp( var, "cs" ) == 0 )
+ csExpr = inlineList;
+ else if ( strcmp( var, "data" ) == 0 )
+ dataExpr = inlineList;
+ else if ( strcmp( var, "top" ) == 0 )
+ topExpr = inlineList;
+ else if ( strcmp( var, "stack" ) == 0 )
+ stackExpr = inlineList;
+ else if ( strcmp( var, "act" ) == 0 )
+ actExpr = inlineList;
+ else if ( strcmp( var, "ts" ) == 0 )
+ tokstartExpr = inlineList;
+ else if ( strcmp( var, "te" ) == 0 )
+ tokendExpr = inlineList;
+ else
+ set = false;
+
+ return set;
+}
+
+/* Initialize the key operators object that will be referenced by all fsms
+ * created. */
+void ParseData::initKeyOps( )
+{
+ /* Signedness and bounds. */
+ HostType *alphType = alphTypeSet ? userAlphType : hostLang->defaultAlphType;
+ thisKeyOps.setAlphType( alphType );
+
+ if ( lowerNum != 0 ) {
+ /* If ranges are given then interpret the alphabet type. */
+ thisKeyOps.minKey = makeFsmKeyNum( lowerNum, rangeLowLoc, this );
+ thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
+ }
+
+ thisCondData.lastCondKey = thisKeyOps.maxKey;
+}
+
+void ParseData::printNameInst( NameInst *nameInst, int level )
+{
+ for ( int i = 0; i < level; i++ )
+ cerr << " ";
+ cerr << (nameInst->name != 0 ? nameInst->name : "<ANON>") <<
+ " id: " << nameInst->id <<
+ " refs: " << nameInst->numRefs <<
+ " uses: " << nameInst->numUses << endl;
+ for ( NameVect::Iter name = nameInst->childVect; name.lte(); name++ )
+ printNameInst( *name, level+1 );
+}
+
+/* Remove duplicates of unique actions from an action table. */
+void ParseData::removeDups( ActionTable &table )
+{
+ /* Scan through the table looking for unique actions to
+ * remove duplicates of. */
+ for ( int i = 0; i < table.length(); i++ ) {
+ /* Remove any duplicates ahead of i. */
+ for ( int r = i+1; r < table.length(); ) {
+ if ( table[r].value == table[i].value )
+ table.vremove(r);
+ else
+ r += 1;
+ }
+ }
+}
+
+/* Remove duplicates from action lists. This operates only on transition and
+ * eof action lists and so should be called once all actions have been
+ * transfered to their final resting place. */
+void ParseData::removeActionDups( FsmAp *graph )
+{
+ /* Loop all states. */
+ for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
+ /* Loop all transitions. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
+ removeDups( trans->actionTable );
+ removeDups( state->toStateActionTable );
+ removeDups( state->fromStateActionTable );
+ removeDups( state->eofActionTable );
+ }
+}
+
+Action *ParseData::newAction( const char *name, InlineList *inlineList )
+{
+ InputLoc loc;
+ loc.line = 1;
+ loc.col = 1;
+ loc.fileName = "NONE";
+
+ Action *action = new Action( loc, name, inlineList, nextCondId++ );
+ action->actionRefs.append( rootName );
+ actionList.append( action );
+ return action;
+}
+
+void ParseData::initLongestMatchData()
+{
+ if ( lmList.length() > 0 ) {
+ /* The initTokStart action resets the token start. */
+ InlineList *il1 = new InlineList;
+ il1->append( new InlineItem( InputLoc(), InlineItem::LmInitTokStart ) );
+ initTokStart = newAction( "initts", il1 );
+ initTokStart->isLmAction = true;
+
+ /* The initActId action gives act a default value. */
+ InlineList *il4 = new InlineList;
+ il4->append( new InlineItem( InputLoc(), InlineItem::LmInitAct ) );
+ initActId = newAction( "initact", il4 );
+ initActId->isLmAction = true;
+
+ /* The setTokStart action sets tokstart. */
+ InlineList *il5 = new InlineList;
+ il5->append( new InlineItem( InputLoc(), InlineItem::LmSetTokStart ) );
+ setTokStart = newAction( "ts", il5 );
+ setTokStart->isLmAction = true;
+
+ /* The setTokEnd action sets tokend. */
+ InlineList *il3 = new InlineList;
+ il3->append( new InlineItem( InputLoc(), InlineItem::LmSetTokEnd ) );
+ setTokEnd = newAction( "te", il3 );
+ setTokEnd->isLmAction = true;
+
+ /* The action will also need an ordering: ahead of all user action
+ * embeddings. */
+ initTokStartOrd = curActionOrd++;
+ initActIdOrd = curActionOrd++;
+ setTokStartOrd = curActionOrd++;
+ setTokEndOrd = curActionOrd++;
+ }
+}
+
+/* After building the graph, do some extra processing to ensure the runtime
+ * data of the longest mactch operators is consistent. */
+void ParseData::setLongestMatchData( FsmAp *graph )
+{
+ if ( lmList.length() > 0 ) {
+ /* Make sure all entry points (targets of fgoto, fcall, fnext, fentry)
+ * init the tokstart. */
+ for ( EntryMap::Iter en = graph->entryPoints; en.lte(); en++ ) {
+ /* This is run after duplicates are removed, we must guard against
+ * inserting a duplicate. */
+ ActionTable &actionTable = en->value->toStateActionTable;
+ if ( ! actionTable.hasAction( initTokStart ) )
+ actionTable.setAction( initTokStartOrd, initTokStart );
+ }
+
+ /* Find the set of states that are the target of transitions with
+ * actions that have calls. These states will be targeted by fret
+ * statements. */
+ StateSet states;
+ for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ for ( ActionTable::Iter ati = trans->actionTable; ati.lte(); ati++ ) {
+ if ( ati->value->anyCall && trans->toState != 0 )
+ states.insert( trans->toState );
+ }
+ }
+ }
+
+
+ /* Init tokstart upon entering the above collected states. */
+ for ( StateSet::Iter ps = states; ps.lte(); ps++ ) {
+ /* This is run after duplicates are removed, we must guard against
+ * inserting a duplicate. */
+ ActionTable &actionTable = (*ps)->toStateActionTable;
+ if ( ! actionTable.hasAction( initTokStart ) )
+ actionTable.setAction( initTokStartOrd, initTokStart );
+ }
+ }
+}
+
+/* Make the graph from a graph dict node. Does minimization and state sorting. */
+FsmAp *ParseData::makeInstance( GraphDictEl *gdNode )
+{
+ /* Build the graph from a walk of the parse tree. */
+ FsmAp *graph = gdNode->value->walk( this );
+
+ /* Resolve any labels that point to multiple states. Any labels that are
+ * still around are referenced only by gotos and calls and they need to be
+ * made into deterministic entry points. */
+ graph->deterministicEntry();
+
+ /*
+ * All state construction is now complete.
+ */
+
+ /* Transfer actions from the out action tables to eof action tables. */
+ for ( StateSet::Iter state = graph->finStateSet; state.lte(); state++ )
+ graph->transferOutActions( *state );
+
+ /* Transfer global error actions. */
+ for ( StateList::Iter state = graph->stateList; state.lte(); state++ )
+ graph->transferErrorActions( state, 0 );
+
+ if ( ::wantDupsRemoved )
+ removeActionDups( graph );
+
+ /* Remove unreachable states. There should be no dead end states. The
+ * subtract and intersection operators are the only places where they may
+ * be created and those operators clean them up. */
+ graph->removeUnreachableStates();
+
+ /* No more fsm operations are to be done. Action ordering numbers are
+ * no longer of use and will just hinder minimization. Clear them. */
+ graph->nullActionKeys();
+
+ /* Transition priorities are no longer of use. We can clear them
+ * because they will just hinder minimization as well. Clear them. */
+ graph->clearAllPriorities();
+
+ if ( minimizeOpt != MinimizeNone ) {
+ /* Minimize here even if we minimized at every op. Now that function
+ * keys have been cleared we may get a more minimal fsm. */
+ switch ( minimizeLevel ) {
+ case MinimizeApprox:
+ graph->minimizeApproximate();
+ break;
+ case MinimizeStable:
+ graph->minimizeStable();
+ break;
+ case MinimizePartition1:
+ graph->minimizePartition1();
+ break;
+ case MinimizePartition2:
+ graph->minimizePartition2();
+ break;
+ }
+ }
+
+ graph->compressTransitions();
+
+ return graph;
+}
+
+void ParseData::printNameTree()
+{
+ /* Print the name instance map. */
+ for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
+ printNameInst( *name, 0 );
+
+ cerr << "name index:" << endl;
+ /* Show that the name index is correct. */
+ for ( int ni = 0; ni < nextNameId; ni++ ) {
+ cerr << ni << ": ";
+ const char *name = nameIndex[ni]->name;
+ cerr << ( name != 0 ? name : "<ANON>" ) << endl;
+ }
+}
+
+FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
+{
+ /* Build the name tree and supporting data structures. */
+ makeNameTree( gdNode );
+
+ /* Resove name references from gdNode. */
+ initNameWalk();
+ gdNode->value->resolveNameRefs( this );
+
+ /* Do not resolve action references. Since we are not building the entire
+ * graph there's a good chance that many name references will fail. This
+ * is okay since generating part of the graph is usually only done when
+ * inspecting the compiled machine. */
+
+ /* Same story for extern entry point references. */
+
+ /* Flag this case so that the XML code generator is aware that we haven't
+ * looked up name references in actions. It can then avoid segfaulting. */
+ generatingSectionSubset = true;
+
+ /* Just building the specified graph. */
+ initNameWalk();
+ FsmAp *mainGraph = makeInstance( gdNode );
+
+ return mainGraph;
+}
+
+FsmAp *ParseData::makeAll()
+{
+ /* Build the name tree and supporting data structures. */
+ makeNameTree( 0 );
+
+ /* Resove name references in the tree. */
+ initNameWalk();
+ for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
+ glel->value->resolveNameRefs( this );
+
+ /* Resolve action code name references. */
+ resolveActionNameRefs();
+
+ /* Force name references to the top level instantiations. */
+ for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
+ (*inst)->numRefs += 1;
+
+ FsmAp *mainGraph = 0;
+ FsmAp **graphs = new FsmAp*[instanceList.length()];
+ int numOthers = 0;
+
+ /* Make all the instantiations, we know that main exists in this list. */
+ initNameWalk();
+ for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
+ if ( strcmp( glel->key, mainMachine ) == 0 ) {
+ /* Main graph is always instantiated. */
+ mainGraph = makeInstance( glel );
+ }
+ else {
+ /* Instantiate and store in others array. */
+ graphs[numOthers++] = makeInstance( glel );
+ }
+ }
+
+ if ( mainGraph == 0 )
+ mainGraph = graphs[--numOthers];
+
+ if ( numOthers > 0 ) {
+ /* Add all the other graphs into main. */
+ mainGraph->globOp( graphs, numOthers );
+ }
+
+ delete[] graphs;
+ return mainGraph;
+}
+
+void ParseData::analyzeAction( Action *action, InlineList *inlineList )
+{
+ /* FIXME: Actions used as conditions should be very constrained. */
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
+ action->anyCall = true;
+
+ /* Need to recurse into longest match items. */
+ if ( item->type == InlineItem::LmSwitch ) {
+ LongestMatch *lm = item->longestMatch;
+ for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) {
+ if ( lmi->action != 0 )
+ analyzeAction( action, lmi->action->inlineList );
+ }
+ }
+
+ if ( item->type == InlineItem::LmOnLast ||
+ item->type == InlineItem::LmOnNext ||
+ item->type == InlineItem::LmOnLagBehind )
+ {
+ LongestMatchPart *lmi = item->longestMatchPart;
+ if ( lmi->action != 0 )
+ analyzeAction( action, lmi->action->inlineList );
+ }
+
+ if ( item->children != 0 )
+ analyzeAction( action, item->children );
+ }
+}
+
+
+/* Check actions for bad uses of fsm directives. We don't go inside longest
+ * match items in actions created by ragel, since we just want the user
+ * actions. */
+void ParseData::checkInlineList( Action *act, InlineList *inlineList )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ /* EOF checks. */
+ if ( act->numEofRefs > 0 ) {
+ switch ( item->type ) {
+ /* Currently no checks. */
+ default:
+ break;
+ }
+ }
+
+ /* Recurse. */
+ if ( item->children != 0 )
+ checkInlineList( act, item->children );
+ }
+}
+
+void ParseData::checkAction( Action *action )
+{
+ /* Check for actions with calls that are embedded within a longest match
+ * machine. */
+ if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) {
+ for ( ActionRefs::Iter ar = action->actionRefs; ar.lte(); ar++ ) {
+ NameInst *check = *ar;
+ while ( check != 0 ) {
+ if ( check->isLongestMatch ) {
+ error(action->loc) << "within a scanner, fcall is permitted"
+ " only in pattern actions" << endl;
+ break;
+ }
+ check = check->parent;
+ }
+ }
+ }
+
+ checkInlineList( action, action->inlineList );
+}
+
+
+void ParseData::analyzeGraph( FsmAp *graph )
+{
+ for ( ActionList::Iter act = actionList; act.lte(); act++ )
+ analyzeAction( act, act->inlineList );
+
+ for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
+ /* The transition list. */
+ for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
+ for ( ActionTable::Iter at = trans->actionTable; at.lte(); at++ )
+ at->value->numTransRefs += 1;
+ }
+
+ for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
+ at->value->numToStateRefs += 1;
+
+ for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
+ at->value->numFromStateRefs += 1;
+
+ for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
+ at->value->numEofRefs += 1;
+
+ for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ for ( CondSet::Iter sci = sc->condSpace->condSet; sci.lte(); sci++ )
+ (*sci)->numCondRefs += 1;
+ }
+ }
+
+ /* Checks for bad usage of directives in action code. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ )
+ checkAction( act );
+}
+
+void ParseData::makeExportsNameTree()
+{
+ /* Make a name tree for the exports. */
+ initExportsNameWalk();
+
+ /* First make the name tree. */
+ for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
+ if ( gdel->value->isExport ) {
+ /* Recurse on the instance. */
+ gdel->value->makeNameTree( gdel->loc, this );
+ }
+ }
+}
+
+void ParseData::makeExports()
+{
+ makeExportsNameTree();
+
+ /* Resove name references in the tree. */
+ initExportsNameWalk();
+ for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
+ if ( gdel->value->isExport )
+ gdel->value->resolveNameRefs( this );
+ }
+
+ /* Make all the instantiations, we know that main exists in this list. */
+ initExportsNameWalk();
+ for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
+ /* Check if this var def is an export. */
+ if ( gdel->value->isExport ) {
+ /* Build the graph from a walk of the parse tree. */
+ FsmAp *graph = gdel->value->walk( this );
+
+ /* Build the graph from a walk of the parse tree. */
+ if ( !graph->checkSingleCharMachine() ) {
+ error(gdel->loc) << "bad export machine, must define "
+ "a single character" << endl;
+ }
+ else {
+ /* Safe to extract the key and declare the export. */
+ Key exportKey = graph->startState->outList.head->lowKey;
+ exportList.append( new Export( gdel->value->name, exportKey ) );
+ }
+ }
+ }
+
+}
+
+/* Construct the machine and catch failures which can occur during
+ * construction. */
+void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
+{
+ try {
+ /* This machine construction can fail. */
+ prepareMachineGenTBWrapped( graphDictEl );
+ }
+ catch ( FsmConstructFail fail ) {
+ switch ( fail.reason ) {
+ case FsmConstructFail::CondNoKeySpace: {
+ InputLoc &loc = alphTypeSet ? alphTypeLoc : sectionLoc;
+ error(loc) << "sorry, no more characters are "
+ "available in the alphabet space" << endl;
+ error(loc) << " for conditions, please use a "
+ "smaller alphtype or reduce" << endl;
+ error(loc) << " the span of characters on which "
+ "conditions are embedded" << endl;
+ break;
+ }
+ }
+ }
+}
+
+void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
+{
+ beginProcessing();
+ initKeyOps();
+ makeRootNames();
+ initLongestMatchData();
+
+ /* Make the graph, do minimization. */
+ if ( graphDictEl == 0 )
+ sectionGraph = makeAll();
+ else
+ sectionGraph = makeSpecific( graphDictEl );
+
+ /* Compute exports from the export definitions. */
+ makeExports();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ analyzeGraph( sectionGraph );
+
+ /* Depends on the graph analysis. */
+ setLongestMatchData( sectionGraph );
+
+ /* Decide if an error state is necessary.
+ * 1. There is an error transition
+ * 2. There is a gap in the transitions
+ * 3. The longest match operator requires it. */
+ if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
+ sectionGraph->errState = sectionGraph->addState();
+
+ /* State numbers need to be assigned such that all final states have a
+ * larger state id number than all non-final states. This enables the
+ * first_final mechanism to function correctly. We also want states to be
+ * ordered in a predictable fashion. So we first apply a depth-first
+ * search, then do a stable sort by final state status, then assign
+ * numbers. */
+
+ sectionGraph->depthFirstOrdering();
+ sectionGraph->sortStatesByFinal();
+ sectionGraph->setStateNumbers( 0 );
+}
+
+void ParseData::generateReduced( InputData &inputData )
+{
+ beginProcessing();
+
+ cgd = makeCodeGen( inputData.inputFileName, sectionName, *inputData.outStream );
+
+ /* Make the generator. */
+ BackendGen backendGen( sectionName, this, sectionGraph, cgd );
+
+ /* Write out with it. */
+ backendGen.makeBackend();
+
+ if ( printStatistics ) {
+ cerr << "fsm name : " << sectionName << endl;
+ cerr << "num states: " << sectionGraph->stateList.length() << endl;
+ cerr << endl;
+ }
+}
+
+void ParseData::generateXML( ostream &out )
+{
+ beginProcessing();
+
+ /* Make the generator. */
+ XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
+
+ /* Write out with it. */
+ codeGen.writeXML();
+
+ if ( printStatistics ) {
+ cerr << "fsm name : " << sectionName << endl;
+ cerr << "num states: " << sectionGraph->stateList.length() << endl;
+ cerr << endl;
+ }
+}
+
diff --git a/ragel/parsedata.h b/ragel/parsedata.h
new file mode 100644
index 0000000..3e3bfa6
--- /dev/null
+++ b/ragel/parsedata.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2001-2008 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
+ */
+
+#ifndef _PARSEDATA_H
+#define _PARSEDATA_H
+
+#include <iostream>
+#include <limits.h>
+#include <sstream>
+#include "avlmap.h"
+#include "bstmap.h"
+#include "vector.h"
+#include "dlist.h"
+#include "fsmgraph.h"
+#include "compare.h"
+#include "vector.h"
+#include "common.h"
+#include "parsetree.h"
+
+/* Forwards. */
+using std::ostream;
+
+struct VarDef;
+struct Join;
+struct Expression;
+struct Term;
+struct FactorWithAug;
+struct FactorWithLabel;
+struct FactorWithRep;
+struct FactorWithNeg;
+struct Factor;
+struct Literal;
+struct Range;
+struct RegExpr;
+struct ReItem;
+struct ReOrBlock;
+struct ReOrItem;
+struct LongestMatch;
+struct InputData;
+struct CodeGenData;
+typedef DList<LongestMatch> LmList;
+
+
+/* Graph dictionary. */
+struct GraphDictEl
+:
+ public AvlTreeEl<GraphDictEl>,
+ public DListEl<GraphDictEl>
+{
+ GraphDictEl( const char *k )
+ : key(k), value(0), isInstance(false) { }
+ GraphDictEl( const char *k, VarDef *value )
+ : key(k), value(value), isInstance(false) { }
+
+ const char *getKey() { return key; }
+
+ const char *key;
+ VarDef *value;
+ bool isInstance;
+
+ /* Location info of graph definition. Points to variable name of assignment. */
+ InputLoc loc;
+};
+
+typedef AvlTree<GraphDictEl, const char*, CmpStr> GraphDict;
+typedef DList<GraphDictEl> GraphList;
+
+/* Priority name dictionary. */
+typedef AvlMapEl<char*, int> PriorDictEl;
+typedef AvlMap<char*, int, CmpStr> PriorDict;
+
+/* Local error name dictionary. */
+typedef AvlMapEl<const char*, int> LocalErrDictEl;
+typedef AvlMap<const char*, int, CmpStr> LocalErrDict;
+
+/* Tree of instantiated names. */
+typedef BstMapEl<const char*, NameInst*> NameMapEl;
+typedef BstMap<const char*, NameInst*, CmpStr> NameMap;
+typedef Vector<NameInst*> NameVect;
+typedef BstSet<NameInst*> NameSet;
+
+/* Node in the tree of instantiated names. */
+struct NameInst
+{
+ NameInst( const InputLoc &loc, NameInst *parent, const char *name, int id, bool isLabel ) :
+ loc(loc), parent(parent), name(name), id(id), isLabel(isLabel),
+ isLongestMatch(false), numRefs(0), numUses(0), start(0), final(0) {}
+
+ InputLoc loc;
+
+ /* Keep parent pointers in the name tree to retrieve
+ * fully qulified names. */
+ NameInst *parent;
+
+ const char *name;
+ int id;
+ bool isLabel;
+ bool isLongestMatch;
+
+ int numRefs;
+ int numUses;
+
+ /* Names underneath us, excludes anonymous names. */
+ NameMap children;
+
+ /* All names underneath us in order of appearance. */
+ NameVect childVect;
+
+ /* Join scopes need an implicit "final" target. */
+ NameInst *start, *final;
+
+ /* During a fsm generation walk, lists the names that are referenced by
+ * epsilon operations in the current scope. After the link is made by the
+ * epsilon reference and the join operation is complete, the label can
+ * have its refcount decremented. Once there are no more references the
+ * entry point can be removed from the fsm returned. */
+ NameVect referencedNames;
+
+ /* Pointers for the name search queue. */
+ NameInst *prev, *next;
+
+ /* Check if this name inst or any name inst below is referenced. */
+ bool anyRefsRec();
+};
+
+typedef DList<NameInst> NameInstList;
+
+/* Stack frame used in walking the name tree. */
+struct NameFrame
+{
+ NameInst *prevNameInst;
+ int prevNameChild;
+ NameInst *prevLocalScope;
+};
+
+struct LengthDef
+{
+ LengthDef( char *name )
+ : name(name) {}
+
+ char *name;
+ LengthDef *prev, *next;
+};
+
+typedef DList<LengthDef> LengthDefList;
+
+/* Class to collect information about the machine during the
+ * parse of input. */
+struct ParseData
+{
+ /* Create a new parse data object. This is done at the beginning of every
+ * fsm specification. */
+ ParseData( const char *fileName, char *sectionName, const InputLoc &sectionLoc );
+ ~ParseData();
+
+ /*
+ * Setting up the graph dict.
+ */
+
+ /* Initialize a graph dict with the basic fsms. */
+ void initGraphDict();
+ void createBuiltin( const char *name, BuiltinMachine builtin );
+
+ /* Make a name id in the current name instantiation scope if it is not
+ * already there. */
+ NameInst *addNameInst( const InputLoc &loc, const char *data, bool isLabel );
+ void makeRootNames();
+ void makeNameTree( GraphDictEl *gdNode );
+ void makeExportsNameTree();
+ void fillNameIndex( NameInst *from );
+ void printNameTree();
+
+ /* Increments the usage count on entry names. Names that are no longer
+ * needed will have their entry points unset. */
+ void unsetObsoleteEntries( FsmAp *graph );
+
+ /* Resove name references in action code and epsilon transitions. */
+ NameSet resolvePart( NameInst *refFrom, const char *data, bool recLabelsOnly );
+ void resolveFrom( NameSet &result, NameInst *refFrom,
+ const NameRef &nameRef, int namePos );
+ NameInst *resolveStateRef( const NameRef &nameRef, InputLoc &loc, Action *action );
+ void resolveNameRefs( InlineList *inlineList, Action *action );
+ void resolveActionNameRefs();
+
+ /* Set the alphabet type. If type types are not valid returns false. */
+ bool setAlphType( const InputLoc &loc, char *s1, char *s2 );
+ bool setAlphType( const InputLoc &loc, char *s1 );
+
+ /* Override one of the variables ragel uses. */
+ bool setVariable( char *var, InlineList *inlineList );
+
+ /* Unique actions. */
+ void removeDups( ActionTable &actionTable );
+ void removeActionDups( FsmAp *graph );
+
+ /* Dumping the name instantiation tree. */
+ void printNameInst( NameInst *nameInst, int level );
+
+ /* Make the graph from a graph dict node. Does minimization. */
+ FsmAp *makeInstance( GraphDictEl *gdNode );
+ FsmAp *makeSpecific( GraphDictEl *gdNode );
+ FsmAp *makeAll();
+
+ /* Checking the contents of actions. */
+ void checkAction( Action *action );
+ void checkInlineList( Action *act, InlineList *inlineList );
+
+ void analyzeAction( Action *action, InlineList *inlineList );
+ void analyzeGraph( FsmAp *graph );
+ void makeExports();
+
+ void prepareMachineGen( GraphDictEl *graphDictEl );
+ void prepareMachineGenTBWrapped( GraphDictEl *graphDictEl );
+ void generateXML( ostream &out );
+ void generateReduced( InputData &inputData );
+ FsmAp *sectionGraph;
+ bool generatingSectionSubset;
+
+ void initKeyOps();
+
+ /*
+ * Data collected during the parse.
+ */
+
+ /* Dictionary of graphs. Both instances and non-instances go here. */
+ GraphDict graphDict;
+
+ /* The list of instances. */
+ GraphList instanceList;
+
+ /* Dictionary of actions. Lets actions be defined and then referenced. */
+ ActionDict actionDict;
+
+ /* Dictionary of named priorities. */
+ PriorDict priorDict;
+
+ /* Dictionary of named local errors. */
+ LocalErrDict localErrDict;
+
+ /* List of actions. Will be pasted into a switch statement. */
+ ActionList actionList;
+
+ /* The id of the next priority name and label. */
+ int nextPriorKey, nextLocalErrKey, nextNameId, nextCondId;
+
+ /* The default priority number key for a machine. This is active during
+ * the parse of the rhs of a machine assignment. */
+ int curDefPriorKey;
+
+ int curDefLocalErrKey;
+
+ /* Alphabet type. */
+ HostType *userAlphType;
+ bool alphTypeSet;
+ InputLoc alphTypeLoc;
+
+ /* Element type and get key expression. */
+ InlineList *getKeyExpr;
+ InlineList *accessExpr;
+
+ /* Stack management */
+ InlineList *prePushExpr;
+ InlineList *postPopExpr;
+
+ /* Overriding variables. */
+ InlineList *pExpr;
+ InlineList *peExpr;
+ InlineList *eofExpr;
+ InlineList *csExpr;
+ InlineList *topExpr;
+ InlineList *stackExpr;
+ InlineList *actExpr;
+ InlineList *tokstartExpr;
+ InlineList *tokendExpr;
+ InlineList *dataExpr;
+
+ /* The alphabet range. */
+ char *lowerNum, *upperNum;
+ Key lowKey, highKey;
+ InputLoc rangeLowLoc, rangeHighLoc;
+
+ /* The name of the file the fsm is from, and the spec name. */
+ const char *fileName;
+ char *sectionName;
+ InputLoc sectionLoc;
+
+ /* Counting the action and priority ordering. */
+ int curActionOrd;
+ int curPriorOrd;
+
+ /* Root of the name tree. One root is for the instantiated machines. The
+ * other root is for exported definitions. */
+ NameInst *rootName;
+ NameInst *exportsRootName;
+
+ /* Name tree walking. */
+ NameInst *curNameInst;
+ int curNameChild;
+
+ /* The place where resolved epsilon transitions go. These cannot go into
+ * the parse tree because a single epsilon op can resolve more than once
+ * to different nameInsts if the machine it's in is used more than once. */
+ NameVect epsilonResolvedLinks;
+ int nextEpsilonResolvedLink;
+
+ /* Root of the name tree used for doing local name searches. */
+ NameInst *localNameScope;
+
+ void setLmInRetLoc( InlineList *inlineList );
+ void initLongestMatchData();
+ void setLongestMatchData( FsmAp *graph );
+ void initNameWalk();
+ void initExportsNameWalk();
+ NameInst *nextNameScope() { return curNameInst->childVect[curNameChild]; }
+ NameFrame enterNameScope( bool isLocal, int numScopes );
+ void popNameScope( const NameFrame &frame );
+ void resetNameScope( const NameFrame &frame );
+
+ /* Make name ids to name inst pointers. */
+ NameInst **nameIndex;
+
+ /* Counter for assigning ids to longest match items. */
+ int nextLongestMatchId;
+ bool lmRequiresErrorState;
+
+ /* List of all longest match parse tree items. */
+ LmList lmList;
+
+ Action *newAction( const char *name, InlineList *inlineList );
+
+ Action *initTokStart;
+ int initTokStartOrd;
+
+ Action *setTokStart;
+ int setTokStartOrd;
+
+ Action *initActId;
+ int initActIdOrd;
+
+ Action *setTokEnd;
+ int setTokEndOrd;
+
+ void beginProcessing()
+ {
+ ::condData = &thisCondData;
+ ::keyOps = &thisKeyOps;
+ }
+
+ CondData thisCondData;
+ KeyOps thisKeyOps;
+
+ ExportList exportList;
+ LengthDefList lengthDefList;
+
+ CodeGenData *cgd;
+};
+
+void afterOpMinimize( FsmAp *fsm, bool lastInSeq = true );
+Key makeFsmKeyHex( char *str, const InputLoc &loc, ParseData *pd );
+Key makeFsmKeyDec( char *str, const InputLoc &loc, ParseData *pd );
+Key makeFsmKeyNum( char *str, const InputLoc &loc, ParseData *pd );
+Key makeFsmKeyChar( char c, ParseData *pd );
+void makeFsmKeyArray( Key *result, char *data, int len, ParseData *pd );
+void makeFsmUniqueKeyArray( KeySet &result, char *data, int len,
+ bool caseInsensitive, ParseData *pd );
+FsmAp *makeBuiltin( BuiltinMachine builtin, ParseData *pd );
+FsmAp *dotFsm( ParseData *pd );
+FsmAp *dotStarFsm( ParseData *pd );
+
+void errorStateLabels( const NameSet &locations );
+
+
+#endif
diff --git a/ragel/parsetree.cpp b/ragel/parsetree.cpp
new file mode 100644
index 0000000..3245a54
--- /dev/null
+++ b/ragel/parsetree.cpp
@@ -0,0 +1,2141 @@
+/*
+ * Copyright 2001-2006 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 <iomanip>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/* Parsing. */
+#include "ragel.h"
+#include "rlparse.h"
+#include "parsetree.h"
+
+using namespace std;
+ostream &operator<<( ostream &out, const NameRef &nameRef );
+ostream &operator<<( ostream &out, const NameInst &nameInst );
+
+/* Convert the literal string which comes in from the scanner into an array of
+ * characters with escapes and options interpreted. Also null terminates the
+ * string. Though this null termination should not be relied on for
+ * interpreting literals in the parser because the string may contain \0 */
+char *prepareLitString( const InputLoc &loc, const char *data, long length,
+ long &resLen, bool &caseInsensitive )
+{
+ char *resData = new char[length+1];
+ caseInsensitive = false;
+
+ const char *src = data + 1;
+ const char *end = data + length - 1;
+
+ while ( *end != '\'' && *end != '\"' ) {
+ if ( *end == 'i' )
+ caseInsensitive = true;
+ else {
+ error( loc ) << "literal string '" << *end <<
+ "' option not supported" << endl;
+ }
+ end -= 1;
+ }
+
+ char *dest = resData;
+ long len = 0;
+ while ( src != end ) {
+ if ( *src == '\\' ) {
+ switch ( src[1] ) {
+ case '0': dest[len++] = '\0'; break;
+ case 'a': dest[len++] = '\a'; break;
+ case 'b': dest[len++] = '\b'; break;
+ case 't': dest[len++] = '\t'; break;
+ case 'n': dest[len++] = '\n'; break;
+ case 'v': dest[len++] = '\v'; break;
+ case 'f': dest[len++] = '\f'; break;
+ case 'r': dest[len++] = '\r'; break;
+ case '\n': break;
+ default: dest[len++] = src[1]; break;
+ }
+ src += 2;
+ }
+ else {
+ dest[len++] = *src++;
+ }
+ }
+
+ resLen = len;
+ resData[resLen] = 0;
+ return resData;
+}
+
+FsmAp *VarDef::walk( ParseData *pd )
+{
+ /* We enter into a new name scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* Recurse on the expression. */
+ FsmAp *rtnVal = machineDef->walk( pd );
+
+ /* Do the tranfer of local error actions. */
+ LocalErrDictEl *localErrDictEl = pd->localErrDict.find( name );
+ if ( localErrDictEl != 0 ) {
+ for ( StateList::Iter state = rtnVal->stateList; state.lte(); state++ )
+ rtnVal->transferErrorActions( state, localErrDictEl->value );
+ }
+
+ /* If the expression below is a join operation with multiple expressions
+ * then it just had epsilon transisions resolved. If it is a join
+ * with only a single expression then run the epsilon op now. */
+ if ( machineDef->type == MachineDef::JoinType && machineDef->join->exprList.length() == 1 )
+ rtnVal->epsilonOp();
+
+ /* We can now unset entry points that are not longer used. */
+ pd->unsetObsoleteEntries( rtnVal );
+
+ /* If the name of the variable is referenced then add the entry point to
+ * the graph. */
+ if ( pd->curNameInst->numRefs > 0 )
+ rtnVal->setEntry( pd->curNameInst->id, rtnVal->startState );
+
+ /* Pop the name scope. */
+ pd->popNameScope( nameFrame );
+ return rtnVal;
+}
+
+void VarDef::makeNameTree( const InputLoc &loc, ParseData *pd )
+{
+ /* The variable definition enters a new scope. */
+ NameInst *prevNameInst = pd->curNameInst;
+ pd->curNameInst = pd->addNameInst( loc, name, false );
+
+ if ( machineDef->type == MachineDef::LongestMatchType )
+ pd->curNameInst->isLongestMatch = true;
+
+ /* Recurse. */
+ machineDef->makeNameTree( pd );
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->curNameInst = prevNameInst;
+}
+
+void VarDef::resolveNameRefs( ParseData *pd )
+{
+ /* Entering into a new scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* Recurse. */
+ machineDef->resolveNameRefs( pd );
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->popNameScope( nameFrame );
+}
+
+InputLoc LongestMatchPart::getLoc()
+{
+ return action != 0 ? action->loc : semiLoc;
+}
+
+/*
+ * If there are any LMs then all of the following entry points must reset
+ * tokstart:
+ *
+ * 1. fentry(StateRef)
+ * 2. ftoto(StateRef), fcall(StateRef), fnext(StateRef)
+ * 3. targt of any transition that has an fcall (the return loc).
+ * 4. start state of all longest match routines.
+ */
+
+Action *LongestMatch::newAction( ParseData *pd, const InputLoc &loc,
+ const char *name, InlineList *inlineList )
+{
+ Action *action = new Action( loc, name, inlineList, pd->nextCondId++ );
+ action->actionRefs.append( pd->curNameInst );
+ pd->actionList.append( action );
+ action->isLmAction = true;
+ return action;
+}
+
+void LongestMatch::makeActions( ParseData *pd )
+{
+ /* Make actions that set the action id. */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ ) {
+ /* For each part create actions for setting the match type. We need
+ * to do this so that the actions will go into the actionIndex. */
+ InlineList *inlineList = new InlineList;
+ inlineList->append( new InlineItem( lmi->getLoc(), this, lmi,
+ InlineItem::LmSetActId ) );
+ char *actName = new char[50];
+ sprintf( actName, "store%i", lmi->longestMatchId );
+ lmi->setActId = newAction( pd, lmi->getLoc(), actName, inlineList );
+ }
+
+ /* Make actions that execute the user action and restart on the last
+ * character. */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ ) {
+ /* For each part create actions for setting the match type. We need
+ * to do this so that the actions will go into the actionIndex. */
+ InlineList *inlineList = new InlineList;
+ inlineList->append( new InlineItem( lmi->getLoc(), this, lmi,
+ InlineItem::LmOnLast ) );
+ char *actName = new char[50];
+ sprintf( actName, "last%i", lmi->longestMatchId );
+ lmi->actOnLast = newAction( pd, lmi->getLoc(), actName, inlineList );
+ }
+
+ /* Make actions that execute the user action and restart on the next
+ * character. These actions will set tokend themselves (it is the current
+ * char). */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ ) {
+ /* For each part create actions for setting the match type. We need
+ * to do this so that the actions will go into the actionIndex. */
+ InlineList *inlineList = new InlineList;
+ inlineList->append( new InlineItem( lmi->getLoc(), this, lmi,
+ InlineItem::LmOnNext ) );
+ char *actName = new char[50];
+ sprintf( actName, "next%i", lmi->longestMatchId );
+ lmi->actOnNext = newAction( pd, lmi->getLoc(), actName, inlineList );
+ }
+
+ /* Make actions that execute the user action and restart at tokend. These
+ * actions execute some time after matching the last char. */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ ) {
+ /* For each part create actions for setting the match type. We need
+ * to do this so that the actions will go into the actionIndex. */
+ InlineList *inlineList = new InlineList;
+ inlineList->append( new InlineItem( lmi->getLoc(), this, lmi,
+ InlineItem::LmOnLagBehind ) );
+ char *actName = new char[50];
+ sprintf( actName, "lag%i", lmi->longestMatchId );
+ lmi->actLagBehind = newAction( pd, lmi->getLoc(), actName, inlineList );
+ }
+
+ InputLoc loc;
+ loc.line = 1;
+ loc.col = 1;
+ loc.fileName = "NONE";
+
+ /* Create the error action. */
+ InlineList *il6 = new InlineList;
+ il6->append( new InlineItem( loc, this, 0, InlineItem::LmSwitch ) );
+ lmActSelect = newAction( pd, loc, "switch", il6 );
+}
+
+void LongestMatch::findName( ParseData *pd )
+{
+ NameInst *nameInst = pd->curNameInst;
+ while ( nameInst->name == 0 ) {
+ nameInst = nameInst->parent;
+ /* Since every machine must must have a name, we should always find a
+ * name for the longest match. */
+ assert( nameInst != 0 );
+ }
+ name = nameInst->name;
+}
+
+void LongestMatch::makeNameTree( ParseData *pd )
+{
+ /* Create an anonymous scope for the longest match. Will be used for
+ * restarting machine after matching a token. */
+ NameInst *prevNameInst = pd->curNameInst;
+ pd->curNameInst = pd->addNameInst( loc, 0, false );
+
+ /* Recurse into all parts of the longest match operator. */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ )
+ lmi->join->makeNameTree( pd );
+
+ /* Traverse the name tree upwards to find a name for this lm. */
+ findName( pd );
+
+ /* Also make the longest match's actions at this point. */
+ makeActions( pd );
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->curNameInst = prevNameInst;
+}
+
+void LongestMatch::resolveNameRefs( ParseData *pd )
+{
+ /* The longest match gets its own name scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* Take an action reference for each longest match item and recurse. */
+ for ( LmPartList::Iter lmi = *longestMatchList; lmi.lte(); lmi++ ) {
+ /* Record the reference if the item has an action. */
+ if ( lmi->action != 0 )
+ lmi->action->actionRefs.append( pd->localNameScope );
+
+ /* Recurse down the join. */
+ lmi->join->resolveNameRefs( pd );
+ }
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->popNameScope( nameFrame );
+}
+
+void LongestMatch::restart( FsmAp *graph, TransAp *trans )
+{
+ StateAp *fromState = trans->fromState;
+ graph->detachTrans( fromState, trans->toState, trans );
+ graph->attachTrans( fromState, graph->startState, trans );
+}
+
+void LongestMatch::runLongestMatch( ParseData *pd, FsmAp *graph )
+{
+ graph->markReachableFromHereStopFinal( graph->startState );
+ for ( StateList::Iter ms = graph->stateList; ms.lte(); ms++ ) {
+ if ( ms->stateBits & STB_ISMARKED ) {
+ ms->lmItemSet.insert( 0 );
+ ms->stateBits &= ~ STB_ISMARKED;
+ }
+ }
+
+ /* Transfer the first item of non-empty lmAction tables to the item sets
+ * of the states that follow. Exclude states that have no transitions out.
+ * This must happen on a separate pass so that on each iteration of the
+ * next pass we have the item set entries from all lmAction tables. */
+ for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
+ for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
+ if ( trans->lmActionTable.length() > 0 ) {
+ LmActionTableEl *lmAct = trans->lmActionTable.data;
+ StateAp *toState = trans->toState;
+ assert( toState );
+
+ /* Can only optimize this if there are no transitions out.
+ * Note there can be out transitions going nowhere with
+ * actions and they too must inhibit this optimization. */
+ if ( toState->outList.length() > 0 ) {
+ /* Fill the item sets. */
+ graph->markReachableFromHereStopFinal( toState );
+ for ( StateList::Iter ms = graph->stateList; ms.lte(); ms++ ) {
+ if ( ms->stateBits & STB_ISMARKED ) {
+ ms->lmItemSet.insert( lmAct->value );
+ ms->stateBits &= ~ STB_ISMARKED;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* The lmItem sets are now filled, telling us which longest match rules
+ * can succeed in which states. First determine if we need to make sure
+ * act is defaulted to zero. We need to do this if there are any states
+ * with lmItemSet.length() > 1 and NULL is included. That is, that the
+ * switch may get called when in fact nothing has been matched. */
+ int maxItemSetLength = 0;
+ graph->markReachableFromHereStopFinal( graph->startState );
+ for ( StateList::Iter ms = graph->stateList; ms.lte(); ms++ ) {
+ if ( ms->stateBits & STB_ISMARKED ) {
+ if ( ms->lmItemSet.length() > maxItemSetLength )
+ maxItemSetLength = ms->lmItemSet.length();
+ ms->stateBits &= ~ STB_ISMARKED;
+ }
+ }
+
+ /* The actions executed on starting to match a token. */
+ graph->isolateStartState();
+ graph->startState->toStateActionTable.setAction( pd->initTokStartOrd, pd->initTokStart );
+ graph->startState->fromStateActionTable.setAction( pd->setTokStartOrd, pd->setTokStart );
+ if ( maxItemSetLength > 1 ) {
+ /* The longest match action switch may be called when tokens are
+ * matched, in which case act must be initialized, there must be a
+ * case to handle the error, and the generated machine will require an
+ * error state. */
+ lmSwitchHandlesError = true;
+ pd->lmRequiresErrorState = true;
+ graph->startState->toStateActionTable.setAction( pd->initActIdOrd, pd->initActId );
+ }
+
+ /* The place to store transitions to restart. It maybe possible for the
+ * restarting to affect the searching through the graph that follows. For
+ * now take the safe route and save the list of transitions to restart
+ * until after all searching is done. */
+ Vector<TransAp*> restartTrans;
+
+ /* Set actions that do immediate token recognition, set the longest match part
+ * id and set the token ending. */
+ for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
+ for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
+ if ( trans->lmActionTable.length() > 0 ) {
+ LmActionTableEl *lmAct = trans->lmActionTable.data;
+ StateAp *toState = trans->toState;
+ assert( toState );
+
+ /* Can only optimize this if there are no transitions out.
+ * Note there can be out transitions going nowhere with
+ * actions and they too must inhibit this optimization. */
+ if ( toState->outList.length() == 0 ) {
+ /* Can execute the immediate action for the longest match
+ * part. Redirect the action to the start state.
+ *
+ * NOTE: When we need to inhibit on_last due to leaving
+ * actions the above test suffices. If the state has out
+ * actions then it will fail because the out action will
+ * have been transferred to an error transition, which
+ * makes the outlist non-empty. */
+ trans->actionTable.setAction( lmAct->key,
+ lmAct->value->actOnLast );
+ restartTrans.append( trans );
+ }
+ else {
+ /* Look for non final states that have a non-empty item
+ * set. If these are present then we need to record the
+ * end of the token. Also Find the highest item set
+ * length reachable from here (excluding at transtions to
+ * final states). */
+ bool nonFinalNonEmptyItemSet = false;
+ maxItemSetLength = 0;
+ graph->markReachableFromHereStopFinal( toState );
+ for ( StateList::Iter ms = graph->stateList; ms.lte(); ms++ ) {
+ if ( ms->stateBits & STB_ISMARKED ) {
+ if ( ms->lmItemSet.length() > 0 && !ms->isFinState() )
+ nonFinalNonEmptyItemSet = true;
+ if ( ms->lmItemSet.length() > maxItemSetLength )
+ maxItemSetLength = ms->lmItemSet.length();
+ ms->stateBits &= ~ STB_ISMARKED;
+ }
+ }
+
+ /* If there are reachable states that are not final and
+ * have non empty item sets or that have an item set
+ * length greater than one then we need to set tokend
+ * because the error action that matches the token will
+ * require it. */
+ if ( nonFinalNonEmptyItemSet || maxItemSetLength > 1 )
+ trans->actionTable.setAction( pd->setTokEndOrd, pd->setTokEnd );
+
+ /* Some states may not know which longest match item to
+ * execute, must set it. */
+ if ( maxItemSetLength > 1 ) {
+ /* There are transitions out, another match may come. */
+ trans->actionTable.setAction( lmAct->key,
+ lmAct->value->setActId );
+ }
+ }
+ }
+ }
+ }
+
+ /* Now that all graph searching is done it certainly safe set the
+ * restarting. It may be safe above, however this must be verified. */
+ for ( Vector<TransAp*>::Iter pt = restartTrans; pt.lte(); pt++ )
+ restart( graph, *pt );
+
+ int lmErrActionOrd = pd->curActionOrd++;
+
+ /* Embed the error for recognizing a char. */
+ for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
+ if ( st->lmItemSet.length() == 1 && st->lmItemSet[0] != 0 ) {
+ if ( st->isFinState() ) {
+ /* On error execute the onActNext action, which knows that
+ * the last character of the token was one back and restart. */
+ graph->setErrorTarget( st, graph->startState, &lmErrActionOrd,
+ &st->lmItemSet[0]->actOnNext, 1 );
+ st->eofActionTable.setAction( lmErrActionOrd,
+ st->lmItemSet[0]->actOnNext );
+ st->eofTarget = graph->startState;
+ }
+ else {
+ graph->setErrorTarget( st, graph->startState, &lmErrActionOrd,
+ &st->lmItemSet[0]->actLagBehind, 1 );
+ st->eofActionTable.setAction( lmErrActionOrd,
+ st->lmItemSet[0]->actLagBehind );
+ st->eofTarget = graph->startState;
+ }
+ }
+ else if ( st->lmItemSet.length() > 1 ) {
+ /* Need to use the select. Take note of which items the select
+ * is needed for so only the necessary actions are included. */
+ for ( LmItemSet::Iter plmi = st->lmItemSet; plmi.lte(); plmi++ ) {
+ if ( *plmi != 0 )
+ (*plmi)->inLmSelect = true;
+ }
+ /* On error, execute the action select and go to the start state. */
+ graph->setErrorTarget( st, graph->startState, &lmErrActionOrd,
+ &lmActSelect, 1 );
+ st->eofActionTable.setAction( lmErrActionOrd, lmActSelect );
+ st->eofTarget = graph->startState;
+ }
+ }
+
+ /* Finally, the start state should be made final. */
+ graph->setFinState( graph->startState );
+}
+
+void LongestMatch::transferScannerLeavingActions( FsmAp *graph )
+{
+ for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
+ if ( st->outActionTable.length() > 0 )
+ graph->setErrorActions( st, st->outActionTable );
+ }
+}
+
+FsmAp *LongestMatch::walk( ParseData *pd )
+{
+ /* The longest match has it's own name scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* Make each part of the longest match. */
+ FsmAp **parts = new FsmAp*[longestMatchList->length()];
+ LmPartList::Iter lmi = *longestMatchList;
+ for ( int i = 0; lmi.lte(); lmi++, i++ ) {
+ /* Create the machine and embed the setting of the longest match id. */
+ parts[i] = lmi->join->walk( pd );
+ parts[i]->longMatchAction( pd->curActionOrd++, lmi );
+ }
+
+ /* Before we union the patterns we need to deal with leaving actions. They
+ * are transfered to error transitions out of the final states (like local
+ * error actions) and to eof actions. In the scanner we need to forbid
+ * on_last for any final state that has an leaving action. */
+ for ( int i = 0; i < longestMatchList->length(); i++ )
+ transferScannerLeavingActions( parts[i] );
+
+ /* Union machines one and up with machine zero. The grammar dictates that
+ * there will always be at least one part. */
+ FsmAp *rtnVal = parts[0];
+ for ( int i = 1; i < longestMatchList->length(); i++ ) {
+ rtnVal->unionOp( parts[i] );
+ afterOpMinimize( rtnVal );
+ }
+
+ runLongestMatch( pd, rtnVal );
+
+ /* Pop the name scope. */
+ pd->popNameScope( nameFrame );
+
+ delete[] parts;
+ return rtnVal;
+}
+
+FsmAp *MachineDef::walk( ParseData *pd )
+{
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case JoinType:
+ rtnVal = join->walk( pd );
+ break;
+ case LongestMatchType:
+ rtnVal = longestMatch->walk( pd );
+ break;
+ case LengthDefType:
+ condData->lastCondKey.increment();
+ rtnVal = new FsmAp();
+ rtnVal->concatFsm( condData->lastCondKey );
+ break;
+ }
+ return rtnVal;
+}
+
+void MachineDef::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case JoinType:
+ join->makeNameTree( pd );
+ break;
+ case LongestMatchType:
+ longestMatch->makeNameTree( pd );
+ break;
+ case LengthDefType:
+ break;
+ }
+}
+
+void MachineDef::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case JoinType:
+ join->resolveNameRefs( pd );
+ break;
+ case LongestMatchType:
+ longestMatch->resolveNameRefs( pd );
+ break;
+ case LengthDefType:
+ break;
+ }
+}
+
+
+/* Construct with a location and the first expression. */
+Join::Join( const InputLoc &loc, Expression *expr )
+:
+ loc(loc)
+{
+ exprList.append( expr );
+}
+
+/* Construct with a location and the first expression. */
+Join::Join( Expression *expr )
+:
+ loc(loc)
+{
+ exprList.append( expr );
+}
+
+/* Walk an expression node. */
+FsmAp *Join::walk( ParseData *pd )
+{
+ if ( exprList.length() > 1 )
+ return walkJoin( pd );
+ else
+ return exprList.head->walk( pd );
+}
+
+/* There is a list of expressions to join. */
+FsmAp *Join::walkJoin( ParseData *pd )
+{
+ /* We enter into a new name scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* Evaluate the machines. */
+ FsmAp **fsms = new FsmAp*[exprList.length()];
+ ExprList::Iter expr = exprList;
+ for ( int e = 0; e < exprList.length(); e++, expr++ )
+ fsms[e] = expr->walk( pd );
+
+ /* Get the start and final names. Final is
+ * guaranteed to exist, start is not. */
+ NameInst *startName = pd->curNameInst->start;
+ NameInst *finalName = pd->curNameInst->final;
+
+ int startId = -1;
+ if ( startName != 0 ) {
+ /* Take note that there was an implicit link to the start machine. */
+ pd->localNameScope->referencedNames.append( startName );
+ startId = startName->id;
+ }
+
+ /* A final id of -1 indicates there is no epsilon that references the
+ * final state, therefor do not create one or set an entry point to it. */
+ int finalId = -1;
+ if ( finalName->numRefs > 0 )
+ finalId = finalName->id;
+
+ /* Join machines 1 and up onto machine 0. */
+ FsmAp *retFsm = fsms[0];
+ retFsm->joinOp( startId, finalId, fsms+1, exprList.length()-1 );
+
+ /* We can now unset entry points that are not longer used. */
+ pd->unsetObsoleteEntries( retFsm );
+
+ /* Pop the name scope. */
+ pd->popNameScope( nameFrame );
+
+ delete[] fsms;
+ return retFsm;
+}
+
+void Join::makeNameTree( ParseData *pd )
+{
+ if ( exprList.length() > 1 ) {
+ /* Create the new anonymous scope. */
+ NameInst *prevNameInst = pd->curNameInst;
+ pd->curNameInst = pd->addNameInst( loc, 0, false );
+
+ /* Join scopes need an implicit "final" target. */
+ pd->curNameInst->final = new NameInst( InputLoc(), pd->curNameInst, "final",
+ pd->nextNameId++, false );
+
+ /* Recurse into all expressions in the list. */
+ for ( ExprList::Iter expr = exprList; expr.lte(); expr++ )
+ expr->makeNameTree( pd );
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->curNameInst = prevNameInst;
+ }
+ else {
+ /* Recurse into the single expression. */
+ exprList.head->makeNameTree( pd );
+ }
+}
+
+
+void Join::resolveNameRefs( ParseData *pd )
+{
+ /* Branch on whether or not there is to be a join. */
+ if ( exprList.length() > 1 ) {
+ /* The variable definition enters a new scope. */
+ NameFrame nameFrame = pd->enterNameScope( true, 1 );
+
+ /* The join scope must contain a start label. */
+ NameSet resolved = pd->resolvePart( pd->localNameScope, "start", true );
+ if ( resolved.length() > 0 ) {
+ /* Take the first. */
+ pd->curNameInst->start = resolved[0];
+ if ( resolved.length() > 1 ) {
+ /* Complain about the multiple references. */
+ error(loc) << "join operation has multiple start labels" << endl;
+ errorStateLabels( resolved );
+ }
+ }
+
+ /* Make sure there is a start label. */
+ if ( pd->curNameInst->start != 0 ) {
+ /* There is an implicit reference to start name. */
+ pd->curNameInst->start->numRefs += 1;
+ }
+ else {
+ /* No start label. */
+ error(loc) << "join operation has no start label" << endl;
+ }
+
+ /* Recurse into all expressions in the list. */
+ for ( ExprList::Iter expr = exprList; expr.lte(); expr++ )
+ expr->resolveNameRefs( pd );
+
+ /* The name scope ends, pop the name instantiation. */
+ pd->popNameScope( nameFrame );
+ }
+ else {
+ /* Recurse into the single expression. */
+ exprList.head->resolveNameRefs( pd );
+ }
+}
+
+/* Clean up after an expression node. */
+Expression::~Expression()
+{
+ switch ( type ) {
+ case OrType: case IntersectType: case SubtractType:
+ case StrongSubtractType:
+ delete expression;
+ delete term;
+ break;
+ case TermType:
+ delete term;
+ break;
+ case BuiltinType:
+ break;
+ }
+}
+
+/* Evaluate a single expression node. */
+FsmAp *Expression::walk( ParseData *pd, bool lastInSeq )
+{
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case OrType: {
+ /* Evaluate the expression. */
+ rtnVal = expression->walk( pd, false );
+ /* Evaluate the term. */
+ FsmAp *rhs = term->walk( pd );
+ /* Perform union. */
+ rtnVal->unionOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case IntersectType: {
+ /* Evaluate the expression. */
+ rtnVal = expression->walk( pd );
+ /* Evaluate the term. */
+ FsmAp *rhs = term->walk( pd );
+ /* Perform intersection. */
+ rtnVal->intersectOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case SubtractType: {
+ /* Evaluate the expression. */
+ rtnVal = expression->walk( pd );
+ /* Evaluate the term. */
+ FsmAp *rhs = term->walk( pd );
+ /* Perform subtraction. */
+ rtnVal->subtractOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case StrongSubtractType: {
+ /* Evaluate the expression. */
+ rtnVal = expression->walk( pd );
+
+ /* Evaluate the term and pad it with any* machines. */
+ FsmAp *rhs = dotStarFsm( pd );
+ FsmAp *termFsm = term->walk( pd );
+ FsmAp *trailAnyStar = dotStarFsm( pd );
+ rhs->concatOp( termFsm );
+ rhs->concatOp( trailAnyStar );
+
+ /* Perform subtraction. */
+ rtnVal->subtractOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case TermType: {
+ /* Return result of the term. */
+ rtnVal = term->walk( pd );
+ break;
+ }
+ case BuiltinType: {
+ /* Duplicate the builtin. */
+ rtnVal = makeBuiltin( builtin, pd );
+ break;
+ }
+ }
+
+ return rtnVal;
+}
+
+void Expression::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case OrType:
+ case IntersectType:
+ case SubtractType:
+ case StrongSubtractType:
+ expression->makeNameTree( pd );
+ term->makeNameTree( pd );
+ break;
+ case TermType:
+ term->makeNameTree( pd );
+ break;
+ case BuiltinType:
+ break;
+ }
+}
+
+void Expression::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case OrType:
+ case IntersectType:
+ case SubtractType:
+ case StrongSubtractType:
+ expression->resolveNameRefs( pd );
+ term->resolveNameRefs( pd );
+ break;
+ case TermType:
+ term->resolveNameRefs( pd );
+ break;
+ case BuiltinType:
+ break;
+ }
+}
+
+/* Clean up after a term node. */
+Term::~Term()
+{
+ switch ( type ) {
+ case ConcatType:
+ case RightStartType:
+ case RightFinishType:
+ case LeftType:
+ delete term;
+ delete factorWithAug;
+ break;
+ case FactorWithAugType:
+ delete factorWithAug;
+ break;
+ }
+}
+
+/* Evaluate a term node. */
+FsmAp *Term::walk( ParseData *pd, bool lastInSeq )
+{
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case ConcatType: {
+ /* Evaluate the Term. */
+ rtnVal = term->walk( pd, false );
+ /* Evaluate the FactorWithRep. */
+ FsmAp *rhs = factorWithAug->walk( pd );
+ /* Perform concatenation. */
+ rtnVal->concatOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case RightStartType: {
+ /* Evaluate the Term. */
+ rtnVal = term->walk( pd );
+
+ /* Evaluate the FactorWithRep. */
+ FsmAp *rhs = factorWithAug->walk( pd );
+
+ /* Set up the priority descriptors. The left machine gets the
+ * lower priority where as the right get the higher start priority. */
+ priorDescs[0].key = pd->nextPriorKey++;
+ priorDescs[0].priority = 0;
+ rtnVal->allTransPrior( pd->curPriorOrd++, &priorDescs[0] );
+
+ /* The start transitions of the right machine gets the higher
+ * priority. Use the same unique key. */
+ priorDescs[1].key = priorDescs[0].key;
+ priorDescs[1].priority = 1;
+ rhs->startFsmPrior( pd->curPriorOrd++, &priorDescs[1] );
+
+ /* Perform concatenation. */
+ rtnVal->concatOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case RightFinishType: {
+ /* Evaluate the Term. */
+ rtnVal = term->walk( pd );
+
+ /* Evaluate the FactorWithRep. */
+ FsmAp *rhs = factorWithAug->walk( pd );
+
+ /* Set up the priority descriptors. The left machine gets the
+ * lower priority where as the finishing transitions to the right
+ * get the higher priority. */
+ priorDescs[0].key = pd->nextPriorKey++;
+ priorDescs[0].priority = 0;
+ rtnVal->allTransPrior( pd->curPriorOrd++, &priorDescs[0] );
+
+ /* The finishing transitions of the right machine get the higher
+ * priority. Use the same unique key. */
+ priorDescs[1].key = priorDescs[0].key;
+ priorDescs[1].priority = 1;
+ rhs->finishFsmPrior( pd->curPriorOrd++, &priorDescs[1] );
+
+ /* If the right machine's start state is final we need to guard
+ * against the left machine persisting by moving through the empty
+ * string. */
+ if ( rhs->startState->isFinState() ) {
+ rhs->startState->outPriorTable.setPrior(
+ pd->curPriorOrd++, &priorDescs[1] );
+ }
+
+ /* Perform concatenation. */
+ rtnVal->concatOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case LeftType: {
+ /* Evaluate the Term. */
+ rtnVal = term->walk( pd );
+
+ /* Evaluate the FactorWithRep. */
+ FsmAp *rhs = factorWithAug->walk( pd );
+
+ /* Set up the priority descriptors. The left machine gets the
+ * higher priority. */
+ priorDescs[0].key = pd->nextPriorKey++;
+ priorDescs[0].priority = 1;
+ rtnVal->allTransPrior( pd->curPriorOrd++, &priorDescs[0] );
+
+ /* The right machine gets the lower priority. We cannot use
+ * allTransPrior here in case the start state of the right machine
+ * is final. It would allow the right machine thread to run along
+ * with the left if just passing through the start state. Using
+ * startFsmPrior prevents this. */
+ priorDescs[1].key = priorDescs[0].key;
+ priorDescs[1].priority = 0;
+ rhs->startFsmPrior( pd->curPriorOrd++, &priorDescs[1] );
+
+ /* Perform concatenation. */
+ rtnVal->concatOp( rhs );
+ afterOpMinimize( rtnVal, lastInSeq );
+ break;
+ }
+ case FactorWithAugType: {
+ rtnVal = factorWithAug->walk( pd );
+ break;
+ }
+ }
+ return rtnVal;
+}
+
+void Term::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case ConcatType:
+ case RightStartType:
+ case RightFinishType:
+ case LeftType:
+ term->makeNameTree( pd );
+ factorWithAug->makeNameTree( pd );
+ break;
+ case FactorWithAugType:
+ factorWithAug->makeNameTree( pd );
+ break;
+ }
+}
+
+void Term::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case ConcatType:
+ case RightStartType:
+ case RightFinishType:
+ case LeftType:
+ term->resolveNameRefs( pd );
+ factorWithAug->resolveNameRefs( pd );
+ break;
+ case FactorWithAugType:
+ factorWithAug->resolveNameRefs( pd );
+ break;
+ }
+}
+
+/* Clean up after a factor with augmentation node. */
+FactorWithAug::~FactorWithAug()
+{
+ delete factorWithRep;
+
+ /* Walk the vector of parser actions, deleting function names. */
+
+ /* Clean up priority descriptors. */
+ if ( priorDescs != 0 )
+ delete[] priorDescs;
+}
+
+void FactorWithAug::assignActions( ParseData *pd, FsmAp *graph, int *actionOrd )
+{
+ /* Assign actions. */
+ for ( int i = 0; i < actions.length(); i++ ) {
+ switch ( actions[i].type ) {
+ /* Transition actions. */
+ case at_start:
+ graph->startFsmAction( actionOrd[i], actions[i].action );
+ afterOpMinimize( graph );
+ break;
+ case at_all:
+ graph->allTransAction( actionOrd[i], actions[i].action );
+ break;
+ case at_finish:
+ graph->finishFsmAction( actionOrd[i], actions[i].action );
+ break;
+ case at_leave:
+ graph->leaveFsmAction( actionOrd[i], actions[i].action );
+ break;
+
+ /* Global error actions. */
+ case at_start_gbl_error:
+ graph->startErrorAction( actionOrd[i], actions[i].action, 0 );
+ afterOpMinimize( graph );
+ break;
+ case at_all_gbl_error:
+ graph->allErrorAction( actionOrd[i], actions[i].action, 0 );
+ break;
+ case at_final_gbl_error:
+ graph->finalErrorAction( actionOrd[i], actions[i].action, 0 );
+ break;
+ case at_not_start_gbl_error:
+ graph->notStartErrorAction( actionOrd[i], actions[i].action, 0 );
+ break;
+ case at_not_final_gbl_error:
+ graph->notFinalErrorAction( actionOrd[i], actions[i].action, 0 );
+ break;
+ case at_middle_gbl_error:
+ graph->middleErrorAction( actionOrd[i], actions[i].action, 0 );
+ break;
+
+ /* Local error actions. */
+ case at_start_local_error:
+ graph->startErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ afterOpMinimize( graph );
+ break;
+ case at_all_local_error:
+ graph->allErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ break;
+ case at_final_local_error:
+ graph->finalErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ break;
+ case at_not_start_local_error:
+ graph->notStartErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ break;
+ case at_not_final_local_error:
+ graph->notFinalErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ break;
+ case at_middle_local_error:
+ graph->middleErrorAction( actionOrd[i], actions[i].action,
+ actions[i].localErrKey );
+ break;
+
+ /* EOF actions. */
+ case at_start_eof:
+ graph->startEOFAction( actionOrd[i], actions[i].action );
+ afterOpMinimize( graph );
+ break;
+ case at_all_eof:
+ graph->allEOFAction( actionOrd[i], actions[i].action );
+ break;
+ case at_final_eof:
+ graph->finalEOFAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_start_eof:
+ graph->notStartEOFAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_final_eof:
+ graph->notFinalEOFAction( actionOrd[i], actions[i].action );
+ break;
+ case at_middle_eof:
+ graph->middleEOFAction( actionOrd[i], actions[i].action );
+ break;
+
+ /* To State Actions. */
+ case at_start_to_state:
+ graph->startToStateAction( actionOrd[i], actions[i].action );
+ afterOpMinimize( graph );
+ break;
+ case at_all_to_state:
+ graph->allToStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_final_to_state:
+ graph->finalToStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_start_to_state:
+ graph->notStartToStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_final_to_state:
+ graph->notFinalToStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_middle_to_state:
+ graph->middleToStateAction( actionOrd[i], actions[i].action );
+ break;
+
+ /* From State Actions. */
+ case at_start_from_state:
+ graph->startFromStateAction( actionOrd[i], actions[i].action );
+ afterOpMinimize( graph );
+ break;
+ case at_all_from_state:
+ graph->allFromStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_final_from_state:
+ graph->finalFromStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_start_from_state:
+ graph->notStartFromStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_not_final_from_state:
+ graph->notFinalFromStateAction( actionOrd[i], actions[i].action );
+ break;
+ case at_middle_from_state:
+ graph->middleFromStateAction( actionOrd[i], actions[i].action );
+ break;
+
+ /* Remaining cases, prevented by the parser. */
+ default:
+ assert( false );
+ break;
+ }
+ }
+}
+
+void FactorWithAug::assignPriorities( FsmAp *graph, int *priorOrd )
+{
+ /* Assign priorities. */
+ for ( int i = 0; i < priorityAugs.length(); i++ ) {
+ switch ( priorityAugs[i].type ) {
+ case at_start:
+ graph->startFsmPrior( priorOrd[i], &priorDescs[i]);
+ /* Start fsm priorities are a special case that may require
+ * minimization afterwards. */
+ afterOpMinimize( graph );
+ break;
+ case at_all:
+ graph->allTransPrior( priorOrd[i], &priorDescs[i] );
+ break;
+ case at_finish:
+ graph->finishFsmPrior( priorOrd[i], &priorDescs[i] );
+ break;
+ case at_leave:
+ graph->leaveFsmPrior( priorOrd[i], &priorDescs[i] );
+ break;
+
+ default:
+ /* Parser Prevents this case. */
+ break;
+ }
+ }
+}
+
+void FactorWithAug::assignConditions( FsmAp *graph )
+{
+ for ( int i = 0; i < conditions.length(); i++ ) {
+ switch ( conditions[i].type ) {
+ /* Transition actions. */
+ case at_start:
+ graph->startFsmCondition( conditions[i].action, conditions[i].sense );
+ afterOpMinimize( graph );
+ break;
+ case at_all:
+ graph->allTransCondition( conditions[i].action, conditions[i].sense );
+ break;
+ case at_leave:
+ graph->leaveFsmCondition( conditions[i].action, conditions[i].sense );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+/* Evaluate a factor with augmentation node. */
+FsmAp *FactorWithAug::walk( ParseData *pd )
+{
+ /* Enter into the scopes created for the labels. */
+ NameFrame nameFrame = pd->enterNameScope( false, labels.length() );
+
+ /* Make the array of function orderings. */
+ int *actionOrd = 0;
+ if ( actions.length() > 0 )
+ actionOrd = new int[actions.length()];
+
+ /* First walk the list of actions, assigning order to all starting
+ * actions. */
+ for ( int i = 0; i < actions.length(); i++ ) {
+ if ( actions[i].type == at_start ||
+ actions[i].type == at_start_gbl_error ||
+ actions[i].type == at_start_local_error ||
+ actions[i].type == at_start_to_state ||
+ actions[i].type == at_start_from_state ||
+ actions[i].type == at_start_eof )
+ actionOrd[i] = pd->curActionOrd++;
+ }
+
+ /* Evaluate the factor with repetition. */
+ FsmAp *rtnVal = factorWithRep->walk( pd );
+
+ /* Compute the remaining action orderings. */
+ for ( int i = 0; i < actions.length(); i++ ) {
+ if ( actions[i].type != at_start &&
+ actions[i].type != at_start_gbl_error &&
+ actions[i].type != at_start_local_error &&
+ actions[i].type != at_start_to_state &&
+ actions[i].type != at_start_from_state &&
+ actions[i].type != at_start_eof )
+ actionOrd[i] = pd->curActionOrd++;
+ }
+
+ /* Embed conditions. */
+ assignConditions( rtnVal );
+
+ /* Embed actions. */
+ assignActions( pd, rtnVal , actionOrd );
+
+ /* Make the array of priority orderings. Orderings are local to this walk
+ * of the factor with augmentation. */
+ int *priorOrd = 0;
+ if ( priorityAugs.length() > 0 )
+ priorOrd = new int[priorityAugs.length()];
+
+ /* Walk all priorities, assigning the priority ordering. */
+ for ( int i = 0; i < priorityAugs.length(); i++ )
+ priorOrd[i] = pd->curPriorOrd++;
+
+ /* If the priority descriptors have not been made, make them now. Make
+ * priority descriptors for each priority asignment that will be passed to
+ * the fsm. Used to keep track of the key, value and used bit. */
+ if ( priorDescs == 0 && priorityAugs.length() > 0 ) {
+ priorDescs = new PriorDesc[priorityAugs.length()];
+ for ( int i = 0; i < priorityAugs.length(); i++ ) {
+ /* Init the prior descriptor for the priority setting. */
+ priorDescs[i].key = priorityAugs[i].priorKey;
+ priorDescs[i].priority = priorityAugs[i].priorValue;
+ }
+ }
+
+ /* Assign priorities into the machine. */
+ assignPriorities( rtnVal, priorOrd );
+
+ /* Assign epsilon transitions. */
+ for ( int e = 0; e < epsilonLinks.length(); e++ ) {
+ /* Get the name, which may not exist. If it doesn't then silently
+ * ignore it because an error has already been reported. */
+ NameInst *epTarg = pd->epsilonResolvedLinks[pd->nextEpsilonResolvedLink++];
+ if ( epTarg != 0 ) {
+ /* Make the epsilon transitions. */
+ rtnVal->epsilonTrans( epTarg->id );
+
+ /* Note that we have made a link to the name. */
+ pd->localNameScope->referencedNames.append( epTarg );
+ }
+ }
+
+ /* Set entry points for labels. */
+ if ( labels.length() > 0 ) {
+ /* Pop the names. */
+ pd->resetNameScope( nameFrame );
+
+ /* Make labels that are referenced into entry points. */
+ for ( int i = 0; i < labels.length(); i++ ) {
+ pd->enterNameScope( false, 1 );
+
+ /* Will always be found. */
+ NameInst *name = pd->curNameInst;
+
+ /* If the name is referenced then set the entry point. */
+ if ( name->numRefs > 0 )
+ rtnVal->setEntry( name->id, rtnVal->startState );
+ }
+
+ pd->popNameScope( nameFrame );
+ }
+
+ if ( priorOrd != 0 )
+ delete[] priorOrd;
+ if ( actionOrd != 0 )
+ delete[] actionOrd;
+ return rtnVal;
+}
+
+void FactorWithAug::makeNameTree( ParseData *pd )
+{
+ /* Add the labels to the tree of instantiated names. Each label
+ * makes a new scope. */
+ NameInst *prevNameInst = pd->curNameInst;
+ for ( int i = 0; i < labels.length(); i++ )
+ pd->curNameInst = pd->addNameInst( labels[i].loc, labels[i].data, true );
+
+ /* Recurse, then pop the names. */
+ factorWithRep->makeNameTree( pd );
+ pd->curNameInst = prevNameInst;
+}
+
+
+void FactorWithAug::resolveNameRefs( ParseData *pd )
+{
+ /* Enter into the name scope created by any labels. */
+ NameFrame nameFrame = pd->enterNameScope( false, labels.length() );
+
+ /* Note action references. */
+ for ( int i = 0; i < actions.length(); i++ )
+ actions[i].action->actionRefs.append( pd->localNameScope );
+
+ /* Recurse first. IMPORTANT: we must do the exact same traversal as when
+ * the tree is constructed. */
+ factorWithRep->resolveNameRefs( pd );
+
+ /* Resolve epsilon transitions. */
+ for ( int ep = 0; ep < epsilonLinks.length(); ep++ ) {
+ /* Get the link. */
+ EpsilonLink &link = epsilonLinks[ep];
+ NameInst *resolvedName = 0;
+
+ if ( link.target.length() == 1 && strcmp( link.target.data[0], "final" ) == 0 ) {
+ /* Epsilon drawn to an implicit final state. An implicit final is
+ * only available in join operations. */
+ resolvedName = pd->localNameScope->final;
+ }
+ else {
+ /* Do an search for the name. */
+ NameSet resolved;
+ pd->resolveFrom( resolved, pd->localNameScope, link.target, 0 );
+ if ( resolved.length() > 0 ) {
+ /* Take the first one. */
+ resolvedName = resolved[0];
+ if ( resolved.length() > 1 ) {
+ /* Complain about the multiple references. */
+ error(link.loc) << "state reference " << link.target <<
+ " resolves to multiple entry points" << endl;
+ errorStateLabels( resolved );
+ }
+ }
+ }
+
+ /* This is tricky, we stuff resolved epsilon transitions into one long
+ * vector in the parse data structure. Since the name resolution and
+ * graph generation both do identical walks of the parse tree we
+ * should always find the link resolutions in the right place. */
+ pd->epsilonResolvedLinks.append( resolvedName );
+
+ if ( resolvedName != 0 ) {
+ /* Found the name, bump of the reference count on it. */
+ resolvedName->numRefs += 1;
+ }
+ else {
+ /* Complain, no recovery action, the epsilon op will ignore any
+ * epsilon transitions whose names did not resolve. */
+ error(link.loc) << "could not resolve label " << link.target << endl;
+ }
+ }
+
+ if ( labels.length() > 0 )
+ pd->popNameScope( nameFrame );
+}
+
+
+/* Clean up after a factor with repetition node. */
+FactorWithRep::~FactorWithRep()
+{
+ switch ( type ) {
+ case StarType: case StarStarType: case OptionalType: case PlusType:
+ case ExactType: case MaxType: case MinType: case RangeType:
+ delete factorWithRep;
+ break;
+ case FactorWithNegType:
+ delete factorWithNeg;
+ break;
+ }
+}
+
+/* Evaluate a factor with repetition node. */
+FsmAp *FactorWithRep::walk( ParseData *pd )
+{
+ FsmAp *retFsm = 0;
+
+ switch ( type ) {
+ case StarType: {
+ /* Evaluate the FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying kleene star to a machine that "
+ "accepts zero length word" << endl;
+ retFsm->unsetFinState( retFsm->startState );
+ }
+
+ /* Shift over the start action orders then do the kleene star. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+ retFsm->starOp( );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case StarStarType: {
+ /* Evaluate the FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying kleene star to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* Set up the prior descs. All gets priority one, whereas leaving gets
+ * priority zero. Make a unique key so that these priorities don't
+ * interfere with any priorities set by the user. */
+ priorDescs[0].key = pd->nextPriorKey++;
+ priorDescs[0].priority = 1;
+ retFsm->allTransPrior( pd->curPriorOrd++, &priorDescs[0] );
+
+ /* Leaveing gets priority 0. Use same unique key. */
+ priorDescs[1].key = priorDescs[0].key;
+ priorDescs[1].priority = 0;
+ retFsm->leaveFsmPrior( pd->curPriorOrd++, &priorDescs[1] );
+
+ /* Shift over the start action orders then do the kleene star. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+ retFsm->starOp( );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case OptionalType: {
+ /* Make the null fsm. */
+ FsmAp *nu = new FsmAp();
+ nu->lambdaFsm( );
+
+ /* Evaluate the FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+
+ /* Perform the question operator. */
+ retFsm->unionOp( nu );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case PlusType: {
+ /* Evaluate the FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying plus operator to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* Need a duplicated for the star end. */
+ FsmAp *dup = new FsmAp( *retFsm );
+
+ /* The start func orders need to be shifted before doing the star. */
+ pd->curActionOrd += dup->shiftStartActionOrder( pd->curActionOrd );
+
+ /* Star the duplicate. */
+ dup->starOp( );
+ afterOpMinimize( dup );
+
+ retFsm->concatOp( dup );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case ExactType: {
+ /* Get an int from the repetition amount. */
+ if ( lowerRep == 0 ) {
+ /* No copies. Don't need to evaluate the factorWithRep.
+ * This Defeats the purpose so give a warning. */
+ warning(loc) << "exactly zero repetitions results "
+ "in the null machine" << endl;
+
+ retFsm = new FsmAp();
+ retFsm->lambdaFsm();
+ }
+ else {
+ /* Evaluate the first FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying repetition to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* The start func orders need to be shifted before doing the
+ * repetition. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+
+ /* Do the repetition on the machine. Already guarded against n == 0 */
+ retFsm->repeatOp( lowerRep );
+ afterOpMinimize( retFsm );
+ }
+ break;
+ }
+ case MaxType: {
+ /* Get an int from the repetition amount. */
+ if ( upperRep == 0 ) {
+ /* No copies. Don't need to evaluate the factorWithRep.
+ * This Defeats the purpose so give a warning. */
+ warning(loc) << "max zero repetitions results "
+ "in the null machine" << endl;
+
+ retFsm = new FsmAp();
+ retFsm->lambdaFsm();
+ }
+ else {
+ /* Evaluate the first FactorWithRep. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying max repetition to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* The start func orders need to be shifted before doing the
+ * repetition. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+
+ /* Do the repetition on the machine. Already guarded against n == 0 */
+ retFsm->optionalRepeatOp( upperRep );
+ afterOpMinimize( retFsm );
+ }
+ break;
+ }
+ case MinType: {
+ /* Evaluate the repeated machine. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying min repetition to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* The start func orders need to be shifted before doing the repetition
+ * and the kleene star. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+
+ if ( lowerRep == 0 ) {
+ /* Acts just like a star op on the machine to return. */
+ retFsm->starOp( );
+ afterOpMinimize( retFsm );
+ }
+ else {
+ /* Take a duplicate for the plus. */
+ FsmAp *dup = new FsmAp( *retFsm );
+
+ /* Do repetition on the first half. */
+ retFsm->repeatOp( lowerRep );
+ afterOpMinimize( retFsm );
+
+ /* Star the duplicate. */
+ dup->starOp( );
+ afterOpMinimize( dup );
+
+ /* Tak on the kleene star. */
+ retFsm->concatOp( dup );
+ afterOpMinimize( retFsm );
+ }
+ break;
+ }
+ case RangeType: {
+ /* Check for bogus range. */
+ if ( upperRep - lowerRep < 0 ) {
+ error(loc) << "invalid range repetition" << endl;
+
+ /* Return null machine as recovery. */
+ retFsm = new FsmAp();
+ retFsm->lambdaFsm();
+ }
+ else if ( lowerRep == 0 && upperRep == 0 ) {
+ /* No copies. Don't need to evaluate the factorWithRep. This
+ * defeats the purpose so give a warning. */
+ warning(loc) << "zero to zero repetitions results "
+ "in the null machine" << endl;
+
+ retFsm = new FsmAp();
+ retFsm->lambdaFsm();
+ }
+ else {
+ /* Now need to evaluate the repeated machine. */
+ retFsm = factorWithRep->walk( pd );
+ if ( retFsm->startState->isFinState() ) {
+ warning(loc) << "applying range repetition to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ /* The start func orders need to be shifted before doing both kinds
+ * of repetition. */
+ pd->curActionOrd += retFsm->shiftStartActionOrder( pd->curActionOrd );
+
+ if ( lowerRep == 0 ) {
+ /* Just doing max repetition. Already guarded against n == 0. */
+ retFsm->optionalRepeatOp( upperRep );
+ afterOpMinimize( retFsm );
+ }
+ else if ( lowerRep == upperRep ) {
+ /* Just doing exact repetition. Already guarded against n == 0. */
+ retFsm->repeatOp( lowerRep );
+ afterOpMinimize( retFsm );
+ }
+ else {
+ /* This is the case that 0 < lowerRep < upperRep. Take a
+ * duplicate for the optional repeat. */
+ FsmAp *dup = new FsmAp( *retFsm );
+
+ /* Do repetition on the first half. */
+ retFsm->repeatOp( lowerRep );
+ afterOpMinimize( retFsm );
+
+ /* Do optional repetition on the second half. */
+ dup->optionalRepeatOp( upperRep - lowerRep );
+ afterOpMinimize( dup );
+
+ /* Tak on the duplicate machine. */
+ retFsm->concatOp( dup );
+ afterOpMinimize( retFsm );
+ }
+ }
+ break;
+ }
+ case FactorWithNegType: {
+ /* Evaluate the Factor. Pass it up. */
+ retFsm = factorWithNeg->walk( pd );
+ break;
+ }}
+ return retFsm;
+}
+
+void FactorWithRep::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case StarType:
+ case StarStarType:
+ case OptionalType:
+ case PlusType:
+ case ExactType:
+ case MaxType:
+ case MinType:
+ case RangeType:
+ factorWithRep->makeNameTree( pd );
+ break;
+ case FactorWithNegType:
+ factorWithNeg->makeNameTree( pd );
+ break;
+ }
+}
+
+void FactorWithRep::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case StarType:
+ case StarStarType:
+ case OptionalType:
+ case PlusType:
+ case ExactType:
+ case MaxType:
+ case MinType:
+ case RangeType:
+ factorWithRep->resolveNameRefs( pd );
+ break;
+ case FactorWithNegType:
+ factorWithNeg->resolveNameRefs( pd );
+ break;
+ }
+}
+
+/* Clean up after a factor with negation node. */
+FactorWithNeg::~FactorWithNeg()
+{
+ switch ( type ) {
+ case NegateType:
+ case CharNegateType:
+ delete factorWithNeg;
+ break;
+ case FactorType:
+ delete factor;
+ break;
+ }
+}
+
+/* Evaluate a factor with negation node. */
+FsmAp *FactorWithNeg::walk( ParseData *pd )
+{
+ FsmAp *retFsm = 0;
+
+ switch ( type ) {
+ case NegateType: {
+ /* Evaluate the factorWithNeg. */
+ FsmAp *toNegate = factorWithNeg->walk( pd );
+
+ /* Negation is subtract from dot-star. */
+ retFsm = dotStarFsm( pd );
+ retFsm->subtractOp( toNegate );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case CharNegateType: {
+ /* Evaluate the factorWithNeg. */
+ FsmAp *toNegate = factorWithNeg->walk( pd );
+
+ /* CharNegation is subtract from dot. */
+ retFsm = dotFsm( pd );
+ retFsm->subtractOp( toNegate );
+ afterOpMinimize( retFsm );
+ break;
+ }
+ case FactorType: {
+ /* Evaluate the Factor. Pass it up. */
+ retFsm = factor->walk( pd );
+ break;
+ }}
+ return retFsm;
+}
+
+void FactorWithNeg::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case NegateType:
+ case CharNegateType:
+ factorWithNeg->makeNameTree( pd );
+ break;
+ case FactorType:
+ factor->makeNameTree( pd );
+ break;
+ }
+}
+
+void FactorWithNeg::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case NegateType:
+ case CharNegateType:
+ factorWithNeg->resolveNameRefs( pd );
+ break;
+ case FactorType:
+ factor->resolveNameRefs( pd );
+ break;
+ }
+}
+
+/* Clean up after a factor node. */
+Factor::~Factor()
+{
+ switch ( type ) {
+ case LiteralType:
+ delete literal;
+ break;
+ case RangeType:
+ delete range;
+ break;
+ case OrExprType:
+ delete reItem;
+ break;
+ case RegExprType:
+ delete regExpr;
+ break;
+ case ReferenceType:
+ break;
+ case ParenType:
+ delete join;
+ break;
+ case LongestMatchType:
+ delete longestMatch;
+ break;
+ }
+}
+
+/* Evaluate a factor node. */
+FsmAp *Factor::walk( ParseData *pd )
+{
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case LiteralType:
+ rtnVal = literal->walk( pd );
+ break;
+ case RangeType:
+ rtnVal = range->walk( pd );
+ break;
+ case OrExprType:
+ rtnVal = reItem->walk( pd, 0 );
+ break;
+ case RegExprType:
+ rtnVal = regExpr->walk( pd, 0 );
+ break;
+ case ReferenceType:
+ rtnVal = varDef->walk( pd );
+ break;
+ case ParenType:
+ rtnVal = join->walk( pd );
+ break;
+ case LongestMatchType:
+ rtnVal = longestMatch->walk( pd );
+ break;
+ }
+
+ return rtnVal;
+}
+
+void Factor::makeNameTree( ParseData *pd )
+{
+ switch ( type ) {
+ case LiteralType:
+ case RangeType:
+ case OrExprType:
+ case RegExprType:
+ break;
+ case ReferenceType:
+ varDef->makeNameTree( loc, pd );
+ break;
+ case ParenType:
+ join->makeNameTree( pd );
+ break;
+ case LongestMatchType:
+ longestMatch->makeNameTree( pd );
+ break;
+ }
+}
+
+void Factor::resolveNameRefs( ParseData *pd )
+{
+ switch ( type ) {
+ case LiteralType:
+ case RangeType:
+ case OrExprType:
+ case RegExprType:
+ break;
+ case ReferenceType:
+ varDef->resolveNameRefs( pd );
+ break;
+ case ParenType:
+ join->resolveNameRefs( pd );
+ break;
+ case LongestMatchType:
+ longestMatch->resolveNameRefs( pd );
+ break;
+ }
+}
+
+/* Clean up a range object. Must delete the two literals. */
+Range::~Range()
+{
+ delete lowerLit;
+ delete upperLit;
+}
+
+/* Evaluate a range. Gets the lower an upper key and makes an fsm range. */
+FsmAp *Range::walk( ParseData *pd )
+{
+ /* Construct and verify the suitability of the lower end of the range. */
+ FsmAp *lowerFsm = lowerLit->walk( pd );
+ if ( !lowerFsm->checkSingleCharMachine() ) {
+ error(lowerLit->token.loc) <<
+ "bad range lower end, must be a single character" << endl;
+ }
+
+ /* Construct and verify the upper end. */
+ FsmAp *upperFsm = upperLit->walk( pd );
+ if ( !upperFsm->checkSingleCharMachine() ) {
+ error(upperLit->token.loc) <<
+ "bad range upper end, must be a single character" << endl;
+ }
+
+ /* Grab the keys from the machines, then delete them. */
+ Key lowKey = lowerFsm->startState->outList.head->lowKey;
+ Key highKey = upperFsm->startState->outList.head->lowKey;
+ delete lowerFsm;
+ delete upperFsm;
+
+ /* Validate the range. */
+ if ( lowKey > highKey ) {
+ /* Recover by setting upper to lower; */
+ error(lowerLit->token.loc) << "lower end of range is greater then upper end" << endl;
+ highKey = lowKey;
+ }
+
+ /* Return the range now that it is validated. */
+ FsmAp *retFsm = new FsmAp();
+ retFsm->rangeFsm( lowKey, highKey );
+ return retFsm;
+}
+
+/* Evaluate a literal object. */
+FsmAp *Literal::walk( ParseData *pd )
+{
+ /* FsmAp to return, is the alphabet signed. */
+ FsmAp *rtnVal = 0;
+
+ switch ( type ) {
+ case Number: {
+ /* Make the fsm key in int format. */
+ Key fsmKey = makeFsmKeyNum( token.data, token.loc, pd );
+ /* Make the new machine. */
+ rtnVal = new FsmAp();
+ rtnVal->concatFsm( fsmKey );
+ break;
+ }
+ case LitString: {
+ /* Make the array of keys in int format. */
+ long length;
+ bool caseInsensitive;
+ char *data = prepareLitString( token.loc, token.data, token.length,
+ length, caseInsensitive );
+ Key *arr = new Key[length];
+ makeFsmKeyArray( arr, data, length, pd );
+
+ /* Make the new machine. */
+ rtnVal = new FsmAp();
+ if ( caseInsensitive )
+ rtnVal->concatFsmCI( arr, length );
+ else
+ rtnVal->concatFsm( arr, length );
+ delete[] data;
+ delete[] arr;
+ break;
+ }}
+ return rtnVal;
+}
+
+/* Clean up after a regular expression object. */
+RegExpr::~RegExpr()
+{
+ switch ( type ) {
+ case RecurseItem:
+ delete regExpr;
+ delete item;
+ break;
+ case Empty:
+ break;
+ }
+}
+
+/* Evaluate a regular expression object. */
+FsmAp *RegExpr::walk( ParseData *pd, RegExpr *rootRegex )
+{
+ /* This is the root regex, pass down a pointer to this. */
+ if ( rootRegex == 0 )
+ rootRegex = this;
+
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case RecurseItem: {
+ /* Walk both items. */
+ rtnVal = regExpr->walk( pd, rootRegex );
+ FsmAp *fsm2 = item->walk( pd, rootRegex );
+ rtnVal->concatOp( fsm2 );
+ break;
+ }
+ case Empty: {
+ rtnVal = new FsmAp();
+ rtnVal->lambdaFsm();
+ break;
+ }
+ }
+ return rtnVal;
+}
+
+/* Clean up after an item in a regular expression. */
+ReItem::~ReItem()
+{
+ switch ( type ) {
+ case Data:
+ case Dot:
+ break;
+ case OrBlock:
+ case NegOrBlock:
+ delete orBlock;
+ break;
+ }
+}
+
+/* Evaluate a regular expression object. */
+FsmAp *ReItem::walk( ParseData *pd, RegExpr *rootRegex )
+{
+ /* The fsm to return, is the alphabet signed? */
+ FsmAp *rtnVal = 0;
+
+ switch ( type ) {
+ case Data: {
+ /* Move the data into an integer array and make a concat fsm. */
+ Key *arr = new Key[token.length];
+ makeFsmKeyArray( arr, token.data, token.length, pd );
+
+ /* Make the concat fsm. */
+ rtnVal = new FsmAp();
+ if ( rootRegex != 0 && rootRegex->caseInsensitive )
+ rtnVal->concatFsmCI( arr, token.length );
+ else
+ rtnVal->concatFsm( arr, token.length );
+ delete[] arr;
+ break;
+ }
+ case Dot: {
+ /* Make the dot fsm. */
+ rtnVal = dotFsm( pd );
+ break;
+ }
+ case OrBlock: {
+ /* Get the or block and minmize it. */
+ rtnVal = orBlock->walk( pd, rootRegex );
+ if ( rtnVal == 0 ) {
+ rtnVal = new FsmAp();
+ rtnVal->lambdaFsm();
+ }
+ rtnVal->minimizePartition2();
+ break;
+ }
+ case NegOrBlock: {
+ /* Get the or block and minimize it. */
+ FsmAp *fsm = orBlock->walk( pd, rootRegex );
+ fsm->minimizePartition2();
+
+ /* Make a dot fsm and subtract from it. */
+ rtnVal = dotFsm( pd );
+ rtnVal->subtractOp( fsm );
+ rtnVal->minimizePartition2();
+ break;
+ }
+ }
+
+ /* If the item is followed by a star, then apply the star op. */
+ if ( star ) {
+ if ( rtnVal->startState->isFinState() ) {
+ warning(loc) << "applying kleene star to a machine that "
+ "accepts zero length word" << endl;
+ }
+
+ rtnVal->starOp();
+ rtnVal->minimizePartition2();
+ }
+ return rtnVal;
+}
+
+/* Clean up after an or block of a regular expression. */
+ReOrBlock::~ReOrBlock()
+{
+ switch ( type ) {
+ case RecurseItem:
+ delete orBlock;
+ delete item;
+ break;
+ case Empty:
+ break;
+ }
+}
+
+
+/* Evaluate an or block of a regular expression. */
+FsmAp *ReOrBlock::walk( ParseData *pd, RegExpr *rootRegex )
+{
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case RecurseItem: {
+ /* Evaluate the two fsm. */
+ FsmAp *fsm1 = orBlock->walk( pd, rootRegex );
+ FsmAp *fsm2 = item->walk( pd, rootRegex );
+ if ( fsm1 == 0 )
+ rtnVal = fsm2;
+ else {
+ fsm1->unionOp( fsm2 );
+ rtnVal = fsm1;
+ }
+ break;
+ }
+ case Empty: {
+ rtnVal = 0;
+ break;
+ }
+ }
+ return rtnVal;;
+}
+
+/* Evaluate an or block item of a regular expression. */
+FsmAp *ReOrItem::walk( ParseData *pd, RegExpr *rootRegex )
+{
+ /* The return value, is the alphabet signed? */
+ FsmAp *rtnVal = 0;
+ switch ( type ) {
+ case Data: {
+ /* Make the or machine. */
+ rtnVal = new FsmAp();
+
+ /* Put the or data into an array of ints. Note that we find unique
+ * keys. Duplicates are silently ignored. The alternative would be to
+ * issue warning or an error but since we can't with [a0-9a] or 'a' |
+ * 'a' don't bother here. */
+ KeySet keySet;
+ makeFsmUniqueKeyArray( keySet, token.data, token.length,
+ rootRegex != 0 ? rootRegex->caseInsensitive : false, pd );
+
+ /* Run the or operator. */
+ rtnVal->orFsm( keySet.data, keySet.length() );
+ break;
+ }
+ case Range: {
+ /* Make the upper and lower keys. */
+ Key lowKey = makeFsmKeyChar( lower, pd );
+ Key highKey = makeFsmKeyChar( upper, pd );
+
+ /* Validate the range. */
+ if ( lowKey > highKey ) {
+ /* Recover by setting upper to lower; */
+ error(loc) << "lower end of range is greater then upper end" << endl;
+ highKey = lowKey;
+ }
+
+ /* Make the range machine. */
+ rtnVal = new FsmAp();
+ rtnVal->rangeFsm( lowKey, highKey );
+
+ if ( rootRegex != 0 && rootRegex->caseInsensitive ) {
+ if ( lowKey <= 'Z' && 'A' <= highKey ) {
+ Key otherLow = lowKey < 'A' ? Key('A') : lowKey;
+ Key otherHigh = 'Z' < highKey ? Key('Z') : highKey;
+
+ otherLow = 'a' + ( otherLow - 'A' );
+ otherHigh = 'a' + ( otherHigh - 'A' );
+
+ FsmAp *otherRange = new FsmAp();
+ otherRange->rangeFsm( otherLow, otherHigh );
+ rtnVal->unionOp( otherRange );
+ rtnVal->minimizePartition2();
+ }
+ else if ( lowKey <= 'z' && 'a' <= highKey ) {
+ Key otherLow = lowKey < 'a' ? Key('a') : lowKey;
+ Key otherHigh = 'z' < highKey ? Key('z') : highKey;
+
+ otherLow = 'A' + ( otherLow - 'a' );
+ otherHigh = 'A' + ( otherHigh - 'a' );
+
+ FsmAp *otherRange = new FsmAp();
+ otherRange->rangeFsm( otherLow, otherHigh );
+ rtnVal->unionOp( otherRange );
+ rtnVal->minimizePartition2();
+ }
+ }
+
+ break;
+ }}
+ return rtnVal;
+}
diff --git a/ragel/parsetree.h b/ragel/parsetree.h
new file mode 100644
index 0000000..dd38678
--- /dev/null
+++ b/ragel/parsetree.h
@@ -0,0 +1,772 @@
+/*
+ * Copyright 2001-2006 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
+ */
+
+#ifndef _PARSETREE_H
+#define _PARSETREE_H
+
+#include "ragel.h"
+#include "avlmap.h"
+#include "bstmap.h"
+#include "vector.h"
+#include "dlist.h"
+
+struct NameInst;
+
+/* Types of builtin machines. */
+enum BuiltinMachine
+{
+ BT_Any,
+ BT_Ascii,
+ BT_Extend,
+ BT_Alpha,
+ BT_Digit,
+ BT_Alnum,
+ BT_Lower,
+ BT_Upper,
+ BT_Cntrl,
+ BT_Graph,
+ BT_Print,
+ BT_Punct,
+ BT_Space,
+ BT_Xdigit,
+ BT_Lambda,
+ BT_Empty
+};
+
+
+struct ParseData;
+
+/* Leaf type. */
+struct Literal;
+
+/* Tree nodes. */
+
+struct Term;
+struct FactorWithAug;
+struct FactorWithRep;
+struct FactorWithNeg;
+struct Factor;
+struct Expression;
+struct Join;
+struct MachineDef;
+struct LongestMatch;
+struct LongestMatchPart;
+struct LmPartList;
+struct Range;
+struct LengthDef;
+
+/* Type of augmentation. Describes locations in the machine. */
+enum AugType
+{
+ /* Transition actions/priorities. */
+ at_start,
+ at_all,
+ at_finish,
+ at_leave,
+
+ /* Global error actions. */
+ at_start_gbl_error,
+ at_all_gbl_error,
+ at_final_gbl_error,
+ at_not_start_gbl_error,
+ at_not_final_gbl_error,
+ at_middle_gbl_error,
+
+ /* Local error actions. */
+ at_start_local_error,
+ at_all_local_error,
+ at_final_local_error,
+ at_not_start_local_error,
+ at_not_final_local_error,
+ at_middle_local_error,
+
+ /* To State Action embedding. */
+ at_start_to_state,
+ at_all_to_state,
+ at_final_to_state,
+ at_not_start_to_state,
+ at_not_final_to_state,
+ at_middle_to_state,
+
+ /* From State Action embedding. */
+ at_start_from_state,
+ at_all_from_state,
+ at_final_from_state,
+ at_not_start_from_state,
+ at_not_final_from_state,
+ at_middle_from_state,
+
+ /* EOF Action embedding. */
+ at_start_eof,
+ at_all_eof,
+ at_final_eof,
+ at_not_start_eof,
+ at_not_final_eof,
+ at_middle_eof
+};
+
+/* IMPORTANT: These must follow the same order as the state augs in AugType
+ * since we will be using this to compose AugType. */
+enum StateAugType
+{
+ sat_start = 0,
+ sat_all,
+ sat_final,
+ sat_not_start,
+ sat_not_final,
+ sat_middle
+};
+
+struct Action;
+struct PriorDesc;
+struct RegExpr;
+struct ReItem;
+struct ReOrBlock;
+struct ReOrItem;
+struct ExplicitMachine;
+struct InlineItem;
+struct InlineList;
+
+/* Reference to a named state. */
+typedef Vector<char*> NameRef;
+typedef Vector<NameRef*> NameRefList;
+typedef Vector<NameInst*> NameTargList;
+
+/* Structure for storing location of epsilon transitons. */
+struct EpsilonLink
+{
+ EpsilonLink( const InputLoc &loc, NameRef &target )
+ : loc(loc), target(target) { }
+
+ InputLoc loc;
+ NameRef target;
+};
+
+struct Label
+{
+ Label( const InputLoc &loc, char *data )
+ : loc(loc), data(data) { }
+
+ InputLoc loc;
+ char *data;
+};
+
+/* Structrue represents an action assigned to some FactorWithAug node. The
+ * factor with aug will keep an array of these. */
+struct ParserAction
+{
+ ParserAction( const InputLoc &loc, AugType type, int localErrKey, Action *action )
+ : loc(loc), type(type), localErrKey(localErrKey), action(action) { }
+
+ InputLoc loc;
+ AugType type;
+ int localErrKey;
+ Action *action;
+};
+
+struct ConditionTest
+{
+ ConditionTest( const InputLoc &loc, AugType type, Action *action, bool sense ) :
+ loc(loc), type(type), action(action), sense(sense) { }
+
+ InputLoc loc;
+ AugType type;
+ Action *action;
+ bool sense;
+};
+
+struct Token
+{
+ char *data;
+ int length;
+ InputLoc loc;
+
+ void append( const Token &other );
+ void set( const char *str, int len );
+};
+
+char *prepareLitString( const InputLoc &loc, const char *src, long length,
+ long &resLen, bool &caseInsensitive );
+
+/* Store the value and type of a priority augmentation. */
+struct PriorityAug
+{
+ PriorityAug( AugType type, int priorKey, int priorValue ) :
+ type(type), priorKey(priorKey), priorValue(priorValue) { }
+
+ AugType type;
+ int priorKey;
+ int priorValue;
+};
+
+/*
+ * A Variable Definition
+ */
+struct VarDef
+{
+ VarDef( const char *name, MachineDef *machineDef )
+ : name(name), machineDef(machineDef), isExport(false) { }
+
+ /* Parse tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( const InputLoc &loc, ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ const char *name;
+ MachineDef *machineDef;
+ bool isExport;
+};
+
+
+/*
+ * LongestMatch
+ *
+ * Wherever possible the item match will execute on the character. If not
+ * possible the item match will execute on a lookahead character and either
+ * hold the current char (if one away) or backup.
+ *
+ * How to handle the problem of backing up over a buffer break?
+ *
+ * Don't want to use pending out transitions for embedding item match because
+ * the role of item match action is different: it may sometimes match on the
+ * final transition, or may match on a lookahead character.
+ *
+ * Don't want to invent a new operator just for this. So just trail action
+ * after machine, this means we can only use literal actions.
+ *
+ * The item action may
+ *
+ * What states of the machine will be final. The item actions that wrap around
+ * on the last character will go straight to the start state.
+ *
+ * Some transitions will be lookahead transitions, they will hold the current
+ * character. Crossing them with regular transitions must be restricted
+ * because it does not make sense. The transition cannot simultaneously hold
+ * and consume the current character.
+ */
+struct LongestMatchPart
+{
+ LongestMatchPart( Join *join, Action *action,
+ InputLoc &semiLoc, int longestMatchId )
+ :
+ join(join), action(action), semiLoc(semiLoc),
+ longestMatchId(longestMatchId), inLmSelect(false) { }
+
+ InputLoc getLoc();
+
+ Join *join;
+ Action *action;
+ InputLoc semiLoc;
+
+ Action *setActId;
+ Action *actOnLast;
+ Action *actOnNext;
+ Action *actLagBehind;
+ int longestMatchId;
+ bool inLmSelect;
+ LongestMatch *longestMatch;
+
+ LongestMatchPart *prev, *next;
+};
+
+/* Declare a new type so that ptreetypes.h need not include dlist.h. */
+struct LmPartList : DList<LongestMatchPart> {};
+
+struct LongestMatch
+{
+ /* Construct with a list of joins */
+ LongestMatch( const InputLoc &loc, LmPartList *longestMatchList ) :
+ loc(loc), longestMatchList(longestMatchList), name(0),
+ lmSwitchHandlesError(false) { }
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+ void transferScannerLeavingActions( FsmAp *graph );
+ void runLongestMatch( ParseData *pd, FsmAp *graph );
+ Action *newAction( ParseData *pd, const InputLoc &loc, const char *name,
+ InlineList *inlineList );
+ void makeActions( ParseData *pd );
+ void findName( ParseData *pd );
+ void restart( FsmAp *graph, TransAp *trans );
+
+ InputLoc loc;
+ LmPartList *longestMatchList;
+ const char *name;
+
+ Action *lmActSelect;
+ bool lmSwitchHandlesError;
+
+ LongestMatch *next, *prev;
+};
+
+
+/* List of Expressions. */
+typedef DList<Expression> ExprList;
+
+struct MachineDef
+{
+ enum Type {
+ JoinType,
+ LongestMatchType,
+ LengthDefType
+ };
+
+ MachineDef( Join *join )
+ : join(join), longestMatch(0), lengthDef(0), type(JoinType) {}
+ MachineDef( LongestMatch *longestMatch )
+ : join(0), longestMatch(longestMatch), lengthDef(0), type(LongestMatchType) {}
+ MachineDef( LengthDef *lengthDef )
+ : join(0), longestMatch(0), lengthDef(lengthDef), type(LengthDefType) {}
+
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ Join *join;
+ LongestMatch *longestMatch;
+ LengthDef *lengthDef;
+ Type type;
+};
+
+/*
+ * Join
+ */
+struct Join
+{
+ /* Construct with the first expression. */
+ Join( Expression *expr );
+ Join( const InputLoc &loc, Expression *expr );
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ FsmAp *walkJoin( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ /* Data. */
+ InputLoc loc;
+ ExprList exprList;
+};
+
+/*
+ * Expression
+ */
+struct Expression
+{
+ enum Type {
+ OrType,
+ IntersectType,
+ SubtractType,
+ StrongSubtractType,
+ TermType,
+ BuiltinType
+ };
+
+ /* Construct with an expression on the left and a term on the right. */
+ Expression( Expression *expression, Term *term, Type type ) :
+ expression(expression), term(term),
+ builtin(builtin), type(type), prev(this), next(this) { }
+
+ /* Construct with only a term. */
+ Expression( Term *term ) :
+ expression(0), term(term), builtin(builtin),
+ type(TermType) , prev(this), next(this) { }
+
+ /* Construct with a builtin type. */
+ Expression( BuiltinMachine builtin ) :
+ expression(0), term(0), builtin(builtin),
+ type(BuiltinType), prev(this), next(this) { }
+
+ ~Expression();
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd, bool lastInSeq = true );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ /* Node data. */
+ Expression *expression;
+ Term *term;
+ BuiltinMachine builtin;
+ Type type;
+
+ Expression *prev, *next;
+};
+
+/*
+ * Term
+ */
+struct Term
+{
+ enum Type {
+ ConcatType,
+ RightStartType,
+ RightFinishType,
+ LeftType,
+ FactorWithAugType
+ };
+
+ Term( Term *term, FactorWithAug *factorWithAug ) :
+ term(term), factorWithAug(factorWithAug), type(ConcatType) { }
+
+ Term( Term *term, FactorWithAug *factorWithAug, Type type ) :
+ term(term), factorWithAug(factorWithAug), type(type) { }
+
+ Term( FactorWithAug *factorWithAug ) :
+ term(0), factorWithAug(factorWithAug), type(FactorWithAugType) { }
+
+ ~Term();
+
+ FsmAp *walk( ParseData *pd, bool lastInSeq = true );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ Term *term;
+ FactorWithAug *factorWithAug;
+ Type type;
+
+ /* Priority descriptor for RightFinish type. */
+ PriorDesc priorDescs[2];
+};
+
+
+/* Third level of precedence. Augmenting nodes with actions and priorities. */
+struct FactorWithAug
+{
+ FactorWithAug( FactorWithRep *factorWithRep ) :
+ priorDescs(0), factorWithRep(factorWithRep) { }
+ ~FactorWithAug();
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ void assignActions( ParseData *pd, FsmAp *graph, int *actionOrd );
+ void assignPriorities( FsmAp *graph, int *priorOrd );
+
+ void assignConditions( FsmAp *graph );
+
+ /* Actions and priorities assigned to the factor node. */
+ Vector<ParserAction> actions;
+ Vector<PriorityAug> priorityAugs;
+ PriorDesc *priorDescs;
+ Vector<Label> labels;
+ Vector<EpsilonLink> epsilonLinks;
+ Vector<ConditionTest> conditions;
+
+ FactorWithRep *factorWithRep;
+};
+
+/* Fourth level of precedence. Trailing unary operators. Provide kleen star,
+ * optional and plus. */
+struct FactorWithRep
+{
+ enum Type {
+ StarType,
+ StarStarType,
+ OptionalType,
+ PlusType,
+ ExactType,
+ MaxType,
+ MinType,
+ RangeType,
+ FactorWithNegType
+ };
+
+ FactorWithRep( const InputLoc &loc, FactorWithRep *factorWithRep,
+ int lowerRep, int upperRep, Type type ) :
+ loc(loc), factorWithRep(factorWithRep),
+ factorWithNeg(0), lowerRep(lowerRep),
+ upperRep(upperRep), type(type) { }
+
+ FactorWithRep( FactorWithNeg *factorWithNeg )
+ : factorWithNeg(factorWithNeg), type(FactorWithNegType) { }
+
+ ~FactorWithRep();
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ InputLoc loc;
+ FactorWithRep *factorWithRep;
+ FactorWithNeg *factorWithNeg;
+ int lowerRep, upperRep;
+ Type type;
+
+ /* Priority descriptor for StarStar type. */
+ PriorDesc priorDescs[2];
+};
+
+/* Fifth level of precedence. Provides Negation. */
+struct FactorWithNeg
+{
+ enum Type {
+ NegateType,
+ CharNegateType,
+ FactorType
+ };
+
+ FactorWithNeg( const InputLoc &loc, FactorWithNeg *factorWithNeg, Type type) :
+ loc(loc), factorWithNeg(factorWithNeg), factor(0), type(type) { }
+
+ FactorWithNeg( Factor *factor ) :
+ factorWithNeg(0), factor(factor), type(FactorType) { }
+
+ ~FactorWithNeg();
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ InputLoc loc;
+ FactorWithNeg *factorWithNeg;
+ Factor *factor;
+ Type type;
+};
+
+/*
+ * Factor
+ */
+struct Factor
+{
+ /* Language elements a factor node can be. */
+ enum Type {
+ LiteralType,
+ RangeType,
+ OrExprType,
+ RegExprType,
+ ReferenceType,
+ ParenType,
+ LongestMatchType,
+ };
+
+ /* Construct with a literal fsm. */
+ Factor( Literal *literal ) :
+ literal(literal), type(LiteralType) { }
+
+ /* Construct with a range. */
+ Factor( Range *range ) :
+ range(range), type(RangeType) { }
+
+ /* Construct with the or part of a regular expression. */
+ Factor( ReItem *reItem ) :
+ reItem(reItem), type(OrExprType) { }
+
+ /* Construct with a regular expression. */
+ Factor( RegExpr *regExpr ) :
+ regExpr(regExpr), type(RegExprType) { }
+
+ /* Construct with a reference to a var def. */
+ Factor( const InputLoc &loc, VarDef *varDef ) :
+ loc(loc), varDef(varDef), type(ReferenceType) {}
+
+ /* Construct with a parenthesized join. */
+ Factor( Join *join ) :
+ join(join), type(ParenType) {}
+
+ /* Construct with a longest match operator. */
+ Factor( LongestMatch *longestMatch ) :
+ longestMatch(longestMatch), type(LongestMatchType) {}
+
+ /* Cleanup. */
+ ~Factor();
+
+ /* Tree traversal. */
+ FsmAp *walk( ParseData *pd );
+ void makeNameTree( ParseData *pd );
+ void resolveNameRefs( ParseData *pd );
+
+ InputLoc loc;
+ Literal *literal;
+ Range *range;
+ ReItem *reItem;
+ RegExpr *regExpr;
+ VarDef *varDef;
+ Join *join;
+ LongestMatch *longestMatch;
+ int lower, upper;
+ Type type;
+};
+
+/* A range machine. Only ever composed of two literals. */
+struct Range
+{
+ Range( Literal *lowerLit, Literal *upperLit )
+ : lowerLit(lowerLit), upperLit(upperLit) { }
+
+ ~Range();
+ FsmAp *walk( ParseData *pd );
+
+ Literal *lowerLit;
+ Literal *upperLit;
+};
+
+/* Some literal machine. Can be a number or literal string. */
+struct Literal
+{
+ enum LiteralType { Number, LitString };
+
+ Literal( const Token &token, LiteralType type )
+ : token(token), type(type) { }
+
+ FsmAp *walk( ParseData *pd );
+
+ Token token;
+ LiteralType type;
+};
+
+/* Regular expression. */
+struct RegExpr
+{
+ enum RegExpType { RecurseItem, Empty };
+
+ /* Constructors. */
+ RegExpr() :
+ type(Empty), caseInsensitive(false) { }
+ RegExpr(RegExpr *regExpr, ReItem *item) :
+ regExpr(regExpr), item(item),
+ type(RecurseItem), caseInsensitive(false) { }
+
+ ~RegExpr();
+ FsmAp *walk( ParseData *pd, RegExpr *rootRegex );
+
+ RegExpr *regExpr;
+ ReItem *item;
+ RegExpType type;
+ bool caseInsensitive;
+};
+
+/* An item in a regular expression. */
+struct ReItem
+{
+ enum ReItemType { Data, Dot, OrBlock, NegOrBlock };
+
+ ReItem( const InputLoc &loc, const Token &token )
+ : loc(loc), token(token), star(false), type(Data) { }
+ ReItem( const InputLoc &loc, ReItemType type )
+ : loc(loc), star(false), type(type) { }
+ ReItem( const InputLoc &loc, ReOrBlock *orBlock, ReItemType type )
+ : loc(loc), orBlock(orBlock), star(false), type(type) { }
+
+ ~ReItem();
+ FsmAp *walk( ParseData *pd, RegExpr *rootRegex );
+
+ InputLoc loc;
+ Token token;
+ ReOrBlock *orBlock;
+ bool star;
+ ReItemType type;
+};
+
+/* An or block item. */
+struct ReOrBlock
+{
+ enum ReOrBlockType { RecurseItem, Empty };
+
+ /* Constructors. */
+ ReOrBlock()
+ : type(Empty) { }
+ ReOrBlock(ReOrBlock *orBlock, ReOrItem *item)
+ : orBlock(orBlock), item(item), type(RecurseItem) { }
+
+ ~ReOrBlock();
+ FsmAp *walk( ParseData *pd, RegExpr *rootRegex );
+
+ ReOrBlock *orBlock;
+ ReOrItem *item;
+ ReOrBlockType type;
+};
+
+/* An item in an or block. */
+struct ReOrItem
+{
+ enum ReOrItemType { Data, Range };
+
+ ReOrItem( const InputLoc &loc, const Token &token )
+ : loc(loc), token(token), type(Data) {}
+ ReOrItem( const InputLoc &loc, char lower, char upper )
+ : loc(loc), lower(lower), upper(upper), type(Range) { }
+
+ FsmAp *walk( ParseData *pd, RegExpr *rootRegex );
+
+ InputLoc loc;
+ Token token;
+ char lower;
+ char upper;
+ ReOrItemType type;
+};
+
+
+/*
+ * Inline code tree
+ */
+struct InlineList;
+struct InlineItem
+{
+ enum Type
+ {
+ Text, Goto, Call, Next, GotoExpr, CallExpr, NextExpr, Ret, PChar,
+ Char, Hold, Curs, Targs, Entry, Exec, LmSwitch, LmSetActId,
+ LmSetTokEnd, LmOnLast, LmOnNext, LmOnLagBehind, LmInitAct,
+ LmInitTokStart, LmSetTokStart, Break
+ };
+
+ InlineItem( const InputLoc &loc, char *data, Type type ) :
+ loc(loc), data(data), nameRef(0), children(0), type(type) { }
+
+ InlineItem( const InputLoc &loc, NameRef *nameRef, Type type ) :
+ loc(loc), data(0), nameRef(nameRef), children(0), type(type) { }
+
+ InlineItem( const InputLoc &loc, LongestMatch *longestMatch,
+ LongestMatchPart *longestMatchPart, Type type ) : loc(loc), data(0),
+ nameRef(0), children(0), longestMatch(longestMatch),
+ longestMatchPart(longestMatchPart), type(type) { }
+
+ InlineItem( const InputLoc &loc, NameInst *nameTarg, Type type ) :
+ loc(loc), data(0), nameRef(0), nameTarg(nameTarg), children(0),
+ type(type) { }
+
+ InlineItem( const InputLoc &loc, Type type ) :
+ loc(loc), data(0), nameRef(0), children(0), type(type) { }
+
+ InputLoc loc;
+ char *data;
+ NameRef *nameRef;
+ NameInst *nameTarg;
+ InlineList *children;
+ LongestMatch *longestMatch;
+ LongestMatchPart *longestMatchPart;
+ Type type;
+
+ InlineItem *prev, *next;
+};
+
+/* Normally this would be atypedef, but that would entail including DList from
+ * ptreetypes, which should be just typedef forwards. */
+struct InlineList : public DList<InlineItem> { };
+
+#endif
diff --git a/ragel/pcheck.h b/ragel/pcheck.h
new file mode 100644
index 0000000..0e388f8
--- /dev/null
+++ b/ragel/pcheck.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001, 2002 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
+ */
+
+#ifndef _PCHECK_H
+#define _PCHECK_H
+
+class ParamCheck
+{
+public:
+ ParamCheck( const char *paramSpec, int argc, const char **argv);
+
+ bool check();
+
+ const char *paramArg; /* The argument to the parameter. */
+ char parameter; /* The parameter matched. */
+ enum { match, invalid, noparam } state;
+
+ const char *argOffset; /* If we are reading params inside an
+ * arg this points to the offset. */
+
+ const char *curArg; /* Pointer to the current arg. */
+ int iCurArg; /* Index to the current arg. */
+
+private:
+ const char *paramSpec; /* Parameter spec supplied by the coder. */
+ int argc; /* Arguement data from the command line. */
+ const char **argv;
+};
+
+#endif
diff --git a/ragel/ragel.h b/ragel/ragel.h
new file mode 100644
index 0000000..2f4d6ff
--- /dev/null
+++ b/ragel/ragel.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2001-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
+ */
+
+#ifndef _RAGEL_H
+#define _RAGEL_H
+
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include "vector.h"
+#include "config.h"
+#include "common.h"
+
+#define PROGNAME "ragel"
+
+/* Target output style. */
+enum CodeStyle
+{
+ GenTables,
+ GenFTables,
+ GenFlat,
+ GenFFlat,
+ GenGoto,
+ GenFGoto,
+ GenIpGoto,
+ GenSplit
+};
+
+/* To what degree are machine minimized. */
+enum MinimizeLevel {
+ MinimizeApprox,
+ MinimizeStable,
+ MinimizePartition1,
+ MinimizePartition2
+};
+
+enum MinimizeOpt {
+ MinimizeNone,
+ MinimizeEnd,
+ MinimizeMostOps,
+ MinimizeEveryOp
+};
+
+/* Target implementation */
+enum RubyImplEnum
+{
+ MRI,
+ Rubinius
+};
+
+/* Options. */
+extern MinimizeLevel minimizeLevel;
+extern MinimizeOpt minimizeOpt;
+extern const char *machineSpec, *machineName;
+extern bool printStatistics;
+extern bool wantDupsRemoved;
+extern bool generateDot;
+extern bool generateXML;
+extern RubyImplEnum rubyImpl;
+
+/* Error reporting format. */
+enum ErrorFormat {
+ ErrorFormatGNU,
+ ErrorFormatMSVC,
+};
+
+extern ErrorFormat errorFormat;
+extern int gblErrorCount;
+extern char mainMachine[];
+
+InputLoc makeInputLoc( const char *fileName, int line = 0, int col = 0 );
+std::ostream &operator<<( std::ostream &out, const InputLoc &loc );
+
+/* Error reporting. */
+std::ostream &error();
+std::ostream &error( const InputLoc &loc );
+std::ostream &warning( const InputLoc &loc );
+
+struct XmlParser;
+
+void xmlEscapeHost( std::ostream &out, char *data, long len );
+
+extern CodeStyle codeStyle;
+
+/* IO filenames and stream. */
+extern bool displayPrintables;
+extern int gblErrorCount;
+
+/* Options. */
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
+std::ostream &error();
+
+/* Target language and output style. */
+extern CodeStyle codeStyle;
+
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
+#endif
diff --git a/ragel/rbxgoto.cpp b/ragel/rbxgoto.cpp
new file mode 100644
index 0000000..c54cb00
--- /dev/null
+++ b/ragel/rbxgoto.cpp
@@ -0,0 +1,831 @@
+/*
+ * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * 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 <stdio.h>
+#include <string>
+
+#include "rbxgoto.h"
+#include "ragel.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+using std::ostream;
+using std::string;
+
+inline string label(string a, int i)
+{
+ return a + itoa(i);
+}
+
+ostream &RbxGotoCodeGen::rbxLabel(ostream &out, string label)
+{
+ out << "Rubinius.asm { @labels[:_" << FSM_NAME() << "_" << label << "].set! }\n";
+ return out;
+}
+
+ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label)
+{
+ out << "Rubinius.asm { goto @labels[:_" << FSM_NAME() << "_" << label << "] }\n";
+ return out;
+}
+
+/* Emit the goto to take for a given transition. */
+std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level);
+ return rbxGoto(out, label("tr",trans->id));
+}
+
+std::ostream &RbxGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, true );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void RbxGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ /* Label the state. */
+ out << "when " << state->id << " then\n";
+}
+
+
+void RbxGotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << "\tif " << GET_WIDE_KEY(state) << " == " <<
+ KEY(data[0].lowKey) << " \n\t\t";
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, 0) << "\n";
+
+ out << "end\n";
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << "\tcase " << GET_WIDE_KEY(state) << "\n";
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << "\t\twhen " << KEY(data[j].lowKey) << " then\n";
+ TRANS_GOTO(data[j].value, 0) << "\n";
+ }
+
+ /* Close off the transition switch. */
+ out << "\tend\n";
+ }
+}
+
+void RbxGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ RedTransEl *data = state->outRange.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " \n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " \n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ out << TABS(level) << "end\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " then\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "elsif" << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ out << TABS(level) << "end\n";
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " \n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " >= " <<
+ KEY(data[mid].lowKey) << " then\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ out << TABS(level) << "end\n";
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " \n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ out << TABS(level) << "end\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " \n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ out << TABS(level) << "end\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " \n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ out << TABS(level) << "end\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+}
+
+void RbxGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << "when " << state->id << " then\n";
+ rbxGoto(out << " ", "_out") << "\n";
+}
+
+void RbxGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
+{
+ GenCondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << ");\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << "\n _widec += " << condValOffset << ";\n end";
+ }
+}
+
+void RbxGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ GenStateCond **data = state->stateCondVect.data;
+
+ /* Determine if we need to look higher or lower. */
+ bool anyLower = mid > low;
+ bool anyHigher = mid < high;
+
+ /* Determine if the keys at mid are the limits of the alphabet. */
+ bool limitLow = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " \n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "elsif " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " \n";
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "else\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "end\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " \n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "else\n";
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ else {
+ out << TABS(level) << "elsif " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " then\n";
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ out << TABS(level) << "end\n";
+
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " \n";
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "else\n";
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ else {
+ out << TABS(level) << "elsif " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << " then\n";
+ COND_TRANSLATE(data[mid], level+1);
+ }
+ out << TABS(level) << "end\n";
+ }
+ else {
+ /* Cannot go higher or lower than mid. It's mid or bust. What
+ * tests to do depends on limits of alphabet. */
+ if ( !limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " then\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "end\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " then\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "end\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " then\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "end\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &RbxGotoCodeGen::STATE_GOTOS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ rbxLabel(out << " ", label("tr", trans->id)) << "\n";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << vCS() << "'n";
+ out << vCS() << " = " << trans->targ->id << "\n";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ rbxGoto(out, label("f", trans->action->actListId)) << "\n";
+ }
+ else {
+ /* No code to execute, just loop around. */
+ rbxGoto(out, "_again") << "\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ rbxLabel(out, label("f", redAct->actListId)) << "\n" <<
+ "_acts = " << itoa( redAct->location+1 ) << "\n";
+ rbxGoto(out, "execFuncs") << "\n";
+ }
+ }
+
+ rbxLabel(out, "execFuncs") <<
+ "\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while ( _nacts > 0 ) \n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case ( "<< A() << "[_acts-1] ) \n";
+ ACTION_SWITCH();
+ out <<
+ " end\n"
+ " end \n";
+ rbxGoto(out, "_again");
+ return out;
+}
+
+int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &RbxGotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &RbxGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\twhen " << st->id << " then\n";
+
+ /* Write the goto func. */
+ rbxGoto(out, label("f", st->eofAction->actListId)) << "\n";
+ }
+ }
+
+ return out;
+}
+
+void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "begin\n" << vCS() << " = " << gotoDest << " ";
+ rbxGoto(ret, "_again") <<
+ "\nend\n";
+}
+
+void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << "begin\n" << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ")";
+ rbxGoto(ret, "_again") <<
+ "\nend\n";
+}
+
+void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void RbxGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void RbxGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin\n"
+ << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
+ callDest << "; ";
+ rbxGoto(ret, "_again") <<
+ "\nend\n";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void RbxGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, prePushExpr, 0, false );
+ }
+
+ ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); ";
+ rbxGoto(ret, "_again") <<
+ "\nend\n";
+
+ if ( prePushExpr != 0 )
+ ret << "}";
+}
+
+void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "begin\n" << vCS() << " = " << STACK() << "[--" << TOP() << "]; " ;
+
+ if ( postPopExpr != 0 ) {
+ ret << "{";
+ INLINE_LIST( ret, postPopExpr, 0, false );
+ ret << "}";
+ }
+
+ rbxGoto(ret, "_again") <<
+ "\nend\n";
+}
+
+void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+
+ out <<
+ " begin\n"
+ " " << P() << " += 1\n"
+ " " << rbxGoto(ret, "_out") << "\n"
+ " end\n";
+}
+
+void RbxGotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void RbxGotoCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out << " begin\n";
+
+ out << " Rubinius.asm { @labels = Hash.new { |h,k| h[k] = new_label } }\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = 0;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out << " _acts, _nacts = nil\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ out << " _widec = nil\n";
+
+ out << "\n";
+
+ if ( !noEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n";
+ rbxGoto(out << " ", "_out") << "\n" <<
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n";
+ rbxGoto(out << " ", "_out") << "\n" <<
+ " end\n";
+ }
+
+ rbxLabel(out, "_resume") << "\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ out <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " case ( " << vCS() << " )\n";
+ STATE_GOTOS();
+ out <<
+ " end # case\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << "\n";
+
+
+ rbxLabel(out, "_again") << "\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
+ " _nacts = " << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ out <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << vCS() << " == " << redFsm->errState->id << " )\n";
+ rbxGoto(out << " ", "_out") << "\n" <<
+ " end" << "\n";
+ }
+
+ if ( !noEnd ) {
+ out << " " << P() << " += 1\n"
+ " if ( " << P() << " != " << PE() << " )\n";
+ rbxGoto(out << " ", "_resume") << "\n" <<
+ " end" << "\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ rbxGoto(out << " ", "_resume") << "\n";
+ }
+
+ if ( outLabelUsed )
+ rbxLabel(out, "_out") << "\n";
+
+ out << " end\n";
+}
+
+void RbxGotoCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " _acts = " <<
+ ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
+ " " << " _nacts = " << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ out <<
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/rbxgoto.h b/ragel/rbxgoto.h
new file mode 100644
index 0000000..291b656
--- /dev/null
+++ b/ragel/rbxgoto.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * 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
+ */
+
+#ifndef _RBX_GOTOCODEGEN_H
+#define _RBX_GOTOCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include "rubycodegen.h"
+
+using std::string;
+
+class RbxGotoCodeGen : public RubyCodeGen
+{
+public:
+ RbxGotoCodeGen( ostream &out ) : RubyCodeGen(out) {}
+ virtual ~RbxGotoCodeGen() {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &STATE_GOTOS();
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ int TO_STATE_ACTION( RedStateAp *state );
+ int FROM_STATE_ACTION( RedStateAp *state );
+ int EOF_ACTION( RedStateAp *state );
+
+ void COND_TRANSLATE( GenStateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+ void emitSingleSwitch( RedStateAp *state );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state );
+ virtual void STATE_GOTO_ERROR();
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+private:
+ ostream &rbxGoto(ostream &out, string label);
+ ostream &rbxLabel(ostream &out, string label);
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif
diff --git a/ragel/redfsm.cpp b/ragel/redfsm.cpp
new file mode 100644
index 0000000..9a58752
--- /dev/null
+++ b/ragel/redfsm.cpp
@@ -0,0 +1,583 @@
+/*
+ * Copyright 2001-2006 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 "redfsm.h"
+#include "avlmap.h"
+#include "mergesort.h"
+#include <iostream>
+#include <sstream>
+
+using std::ostringstream;
+
+string GenAction::nameOrLoc()
+{
+ if ( name != 0 )
+ return string(name);
+ else {
+ ostringstream ret;
+ ret << loc.line << ":" << loc.col;
+ return ret.str();
+ }
+}
+
+RedFsmAp::RedFsmAp()
+:
+ forcedErrorState(false),
+ nextActionId(0),
+ nextTransId(0),
+ startState(0),
+ errState(0),
+ errTrans(0),
+ firstFinState(0),
+ numFinStates(0),
+ bAnyToStateActions(false),
+ bAnyFromStateActions(false),
+ bAnyRegActions(false),
+ bAnyEofActions(false),
+ bAnyEofTrans(false),
+ bAnyActionGotos(false),
+ bAnyActionCalls(false),
+ bAnyActionRets(false),
+ bAnyRegActionRets(false),
+ bAnyRegActionByValControl(false),
+ bAnyRegNextStmt(false),
+ bAnyRegCurStateRef(false),
+ bAnyRegBreak(false),
+ bAnyConditions(false)
+{
+}
+
+/* Does the machine have any actions. */
+bool RedFsmAp::anyActions()
+{
+ return actionMap.length() > 0;
+}
+
+void RedFsmAp::depthFirstOrdering( RedStateAp *state )
+{
+ /* Nothing to do if the state is already on the list. */
+ if ( state->onStateList )
+ return;
+
+ /* Doing depth first, put state on the list. */
+ state->onStateList = true;
+ stateList.append( state );
+
+ /* At this point transitions should only be in ranges. */
+ assert( state->outSingle.length() == 0 );
+ assert( state->defTrans == 0 );
+
+ /* Recurse on everything ranges. */
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
+ if ( rtel->value->targ != 0 )
+ depthFirstOrdering( rtel->value->targ );
+ }
+}
+
+/* Ordering states by transition connections. */
+void RedFsmAp::depthFirstOrdering()
+{
+ /* Init on state list flags. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ )
+ st->onStateList = false;
+
+ /* Clear out the state list, we will rebuild it. */
+ int stateListLen = stateList.length();
+ stateList.abandon();
+
+ /* Add back to the state list from the start state and all other entry
+ * points. */
+ if ( startState != 0 )
+ depthFirstOrdering( startState );
+ for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ )
+ depthFirstOrdering( *en );
+ if ( forcedErrorState )
+ depthFirstOrdering( errState );
+
+ /* Make sure we put everything back on. */
+ assert( stateListLen == stateList.length() );
+}
+
+/* Assign state ids by appearance in the state list. */
+void RedFsmAp::sequentialStateIds()
+{
+ /* Table based machines depend on the state numbers starting at zero. */
+ nextStateId = 0;
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ )
+ st->id = nextStateId++;
+}
+
+/* Stable sort the states by final state status. */
+void RedFsmAp::sortStatesByFinal()
+{
+ /* Move forward through the list and throw final states onto the end. */
+ RedStateAp *state = 0;
+ RedStateAp *next = stateList.head;
+ RedStateAp *last = stateList.tail;
+ while ( state != last ) {
+ /* Move forward and load up the next. */
+ state = next;
+ next = state->next;
+
+ /* Throw to the end? */
+ if ( state->isFinal ) {
+ stateList.detach( state );
+ stateList.append( state );
+ }
+ }
+}
+
+/* Assign state ids by final state state status. */
+void RedFsmAp::sortStateIdsByFinal()
+{
+ /* Table based machines depend on this starting at zero. */
+ nextStateId = 0;
+
+ /* First pass to assign non final ids. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ if ( ! st->isFinal )
+ st->id = nextStateId++;
+ }
+
+ /* Second pass to assign final ids. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ if ( st->isFinal )
+ st->id = nextStateId++;
+ }
+}
+
+struct CmpStateById
+{
+ static int compare( RedStateAp *st1, RedStateAp *st2 )
+ {
+ if ( st1->id < st2->id )
+ return -1;
+ else if ( st1->id > st2->id )
+ return 1;
+ else
+ return 0;
+ }
+};
+
+void RedFsmAp::sortByStateId()
+{
+ /* Make the array. */
+ int pos = 0;
+ RedStateAp **ptrList = new RedStateAp*[stateList.length()];
+ for ( RedStateList::Iter st = stateList; st.lte(); st++, pos++ )
+ ptrList[pos] = st;
+
+ MergeSort<RedStateAp*, CmpStateById> mergeSort;
+ mergeSort.sort( ptrList, stateList.length() );
+
+ stateList.abandon();
+ for ( int st = 0; st < pos; st++ )
+ stateList.append( ptrList[st] );
+
+ delete[] ptrList;
+}
+
+/* Find the final state with the lowest id. */
+void RedFsmAp::findFirstFinState()
+{
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
+ firstFinState = st;
+ }
+}
+
+void RedFsmAp::assignActionLocs()
+{
+ int nextLocation = 0;
+ for ( GenActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
+ /* Store the loc, skip over the array and a null terminator. */
+ act->location = nextLocation;
+ nextLocation += act->key.length() + 1;
+ }
+}
+
+/* Check if we can extend the current range by displacing any ranges
+ * ahead to the singles. */
+bool RedFsmAp::canExtend( const RedTransList &list, int pos )
+{
+ /* Get the transition that we want to extend. */
+ RedTransAp *extendTrans = list[pos].value;
+
+ /* Look ahead in the transition list. */
+ for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
+ /* If they are not continuous then cannot extend. */
+ Key nextKey = list[next].lowKey;
+ nextKey.decrement();
+ if ( list[pos].highKey != nextKey )
+ break;
+
+ /* Check for the extenstion property. */
+ if ( extendTrans == list[next].value )
+ return true;
+
+ /* If the span of the next element is more than one, then don't keep
+ * checking, it won't be moved to single. */
+ unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
+ if ( nextSpan > 1 )
+ break;
+ }
+ return false;
+}
+
+/* Move ranges to the singles list. */
+void RedFsmAp::moveTransToSingle( RedStateAp *state )
+{
+ RedTransList &range = state->outRange;
+ RedTransList &single = state->outSingle;
+ for ( int rpos = 0; rpos < range.length(); ) {
+ /* Check if this is a range we can extend. */
+ if ( canExtend( range, rpos ) ) {
+ /* Transfer singles over. */
+ while ( range[rpos].value != range[rpos+1].value ) {
+ /* Transfer the range to single. */
+ single.append( range[rpos+1] );
+ range.remove( rpos+1 );
+ }
+
+ /* Extend. */
+ range[rpos].highKey = range[rpos+1].highKey;
+ range.remove( rpos+1 );
+ }
+ /* Maybe move it to the singles. */
+ else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
+ single.append( range[rpos] );
+ range.remove( rpos );
+ }
+ else {
+ /* Keeping it in the ranges. */
+ rpos += 1;
+ }
+ }
+}
+
+/* Look through ranges and choose suitable single character transitions. */
+void RedFsmAp::chooseSingle()
+{
+ /* Loop the states. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Rewrite the transition list taking out the suitable single
+ * transtions. */
+ moveTransToSingle( st );
+ }
+}
+
+void RedFsmAp::makeFlat()
+{
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ if ( st->stateCondList.length() == 0 ) {
+ st->condLowKey = 0;
+ st->condHighKey = 0;
+ }
+ else {
+ st->condLowKey = st->stateCondList.head->lowKey;
+ st->condHighKey = st->stateCondList.tail->highKey;
+
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ st->condList = new GenCondSpace*[ span ];
+ memset( st->condList, 0, sizeof(GenCondSpace*)*span );
+
+ for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
+ unsigned long long base, trSpan;
+ base = keyOps->span( st->condLowKey, sci->lowKey )-1;
+ trSpan = keyOps->span( sci->lowKey, sci->highKey );
+ for ( unsigned long long pos = 0; pos < trSpan; pos++ )
+ st->condList[base+pos] = sci->condSpace;
+ }
+ }
+
+ if ( st->outRange.length() == 0 ) {
+ st->lowKey = st->highKey = 0;
+ st->transList = 0;
+ }
+ else {
+ st->lowKey = st->outRange[0].lowKey;
+ st->highKey = st->outRange[st->outRange.length()-1].highKey;
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ st->transList = new RedTransAp*[ span ];
+ memset( st->transList, 0, sizeof(RedTransAp*)*span );
+
+ for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
+ unsigned long long base, trSpan;
+ base = keyOps->span( st->lowKey, trans->lowKey )-1;
+ trSpan = keyOps->span( trans->lowKey, trans->highKey );
+ for ( unsigned long long pos = 0; pos < trSpan; pos++ )
+ st->transList[base+pos] = trans->value;
+ }
+
+ /* Fill in the gaps with the default transition. */
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->transList[pos] == 0 )
+ st->transList[pos] = st->defTrans;
+ }
+ }
+ }
+}
+
+
+/* A default transition has been picked, move it from the outRange to the
+ * default pointer. */
+void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
+{
+ /* Rewrite the outRange, omitting any ranges that use
+ * the picked default. */
+ RedTransList outRange;
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
+ /* If it does not take the default, copy it over. */
+ if ( rtel->value != defTrans )
+ outRange.append( *rtel );
+ }
+
+ /* Save off the range we just created into the state's range. */
+ state->outRange.transfer( outRange );
+
+ /* Store the default. */
+ state->defTrans = defTrans;
+}
+
+bool RedFsmAp::alphabetCovered( RedTransList &outRange )
+{
+ /* Cannot cover without any out ranges. */
+ if ( outRange.length() == 0 )
+ return false;
+
+ /* If the first range doesn't start at the the lower bound then the
+ * alphabet is not covered. */
+ RedTransList::Iter rtel = outRange;
+ if ( keyOps->minKey < rtel->lowKey )
+ return false;
+
+ /* Check that every range is next to the previous one. */
+ rtel.increment();
+ for ( ; rtel.lte(); rtel++ ) {
+ Key highKey = rtel[-1].highKey;
+ highKey.increment();
+ if ( highKey != rtel->lowKey )
+ return false;
+ }
+
+ /* The last must extend to the upper bound. */
+ RedTransEl *last = &outRange[outRange.length()-1];
+ if ( last->highKey < keyOps->maxKey )
+ return false;
+
+ return true;
+}
+
+RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
+{
+ /* Make a set of transitions from the outRange. */
+ RedTransSet stateTransSet;
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
+ stateTransSet.insert( rtel->value );
+
+ /* For each transition in the find how many alphabet characters the
+ * transition spans. */
+ unsigned long long *span = new unsigned long long[stateTransSet.length()];
+ memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
+ /* Lookup the transition in the set. */
+ RedTransAp **inSet = stateTransSet.find( rtel->value );
+ int pos = inSet - stateTransSet.data;
+ span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
+ }
+
+ /* Find the max span, choose it for making the default. */
+ RedTransAp *maxTrans = 0;
+ unsigned long long maxSpan = 0;
+ for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
+ if ( span[rtel.pos()] > maxSpan ) {
+ maxSpan = span[rtel.pos()];
+ maxTrans = *rtel;
+ }
+ }
+
+ delete[] span;
+ return maxTrans;
+}
+
+/* Pick default transitions from ranges for the states. */
+void RedFsmAp::chooseDefaultSpan()
+{
+ /* Loop the states. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Only pick a default transition if the alphabet is covered. This
+ * avoids any transitions in the out range that go to error and avoids
+ * the need for an ERR state. */
+ if ( alphabetCovered( st->outRange ) ) {
+ /* Pick a default transition by largest span. */
+ RedTransAp *defTrans = chooseDefaultSpan( st );
+
+ /* Rewrite the transition list taking out the transition we picked
+ * as the default and store the default. */
+ moveToDefault( defTrans, st );
+ }
+ }
+}
+
+RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
+{
+ /* Make a set of transitions from the outRange. */
+ RedTransSet stateTransSet;
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
+ if ( rtel->value->targ == state->next )
+ return rtel->value;
+ }
+ return 0;
+}
+
+void RedFsmAp::chooseDefaultGoto()
+{
+ /* Loop the states. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Pick a default transition. */
+ RedTransAp *defTrans = chooseDefaultGoto( st );
+ if ( defTrans == 0 )
+ defTrans = chooseDefaultSpan( st );
+
+ /* Rewrite the transition list taking out the transition we picked
+ * as the default and store the default. */
+ moveToDefault( defTrans, st );
+ }
+}
+
+RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
+{
+ /* Make a set of transitions from the outRange. */
+ RedTransSet stateTransSet;
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
+ stateTransSet.insert( rtel->value );
+
+ /* For each transition in the find how many ranges use the transition. */
+ int *numRanges = new int[stateTransSet.length()];
+ memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
+ for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
+ /* Lookup the transition in the set. */
+ RedTransAp **inSet = stateTransSet.find( rtel->value );
+ numRanges[inSet - stateTransSet.data] += 1;
+ }
+
+ /* Find the max number of ranges. */
+ RedTransAp *maxTrans = 0;
+ int maxNumRanges = 0;
+ for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
+ if ( numRanges[rtel.pos()] > maxNumRanges ) {
+ maxNumRanges = numRanges[rtel.pos()];
+ maxTrans = *rtel;
+ }
+ }
+
+ delete[] numRanges;
+ return maxTrans;
+}
+
+void RedFsmAp::chooseDefaultNumRanges()
+{
+ /* Loop the states. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ /* Pick a default transition. */
+ RedTransAp *defTrans = chooseDefaultNumRanges( st );
+
+ /* Rewrite the transition list taking out the transition we picked
+ * as the default and store the default. */
+ moveToDefault( defTrans, st );
+ }
+}
+
+RedTransAp *RedFsmAp::getErrorTrans( )
+{
+ /* If the error trans has not been made aready, make it. */
+ if ( errTrans == 0 ) {
+ /* This insert should always succeed since no transition created by
+ * the user can point to the error state. */
+ errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
+ RedTransAp *inRes = transSet.insert( errTrans );
+ assert( inRes != 0 );
+ }
+ return errTrans;
+}
+
+RedStateAp *RedFsmAp::getErrorState()
+{
+ /* Something went wrong. An error state is needed but one was not supplied
+ * by the frontend. */
+ assert( errState != 0 );
+ return errState;
+}
+
+
+RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
+{
+ /* Create a reduced trans and look for it in the transiton set. */
+ RedTransAp redTrans( targ, action, 0 );
+ RedTransAp *inDict = transSet.find( &redTrans );
+ if ( inDict == 0 ) {
+ inDict = new RedTransAp( targ, action, nextTransId++ );
+ transSet.insert( inDict );
+ }
+ return inDict;
+}
+
+void RedFsmAp::partitionFsm( int nparts )
+{
+ /* At this point the states are ordered by a depth-first traversal. We
+ * will allocate to partitions based on this ordering. */
+ this->nParts = nparts;
+ int partSize = stateList.length() / nparts;
+ int remainder = stateList.length() % nparts;
+ int numInPart = partSize;
+ int partition = 0;
+ if ( remainder-- > 0 )
+ numInPart += 1;
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ st->partition = partition;
+
+ numInPart -= 1;
+ if ( numInPart == 0 ) {
+ partition += 1;
+ numInPart = partSize;
+ if ( remainder-- > 0 )
+ numInPart += 1;
+ }
+ }
+}
+
+void RedFsmAp::setInTrans()
+{
+ /* First pass counts the number of transitions. */
+ for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
+ trans->targ->numInTrans += 1;
+
+ /* Pass over states to allocate the needed memory. Reset the counts so we
+ * can use them as the current size. */
+ for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
+ st->inTrans = new RedTransAp*[st->numInTrans];
+ st->numInTrans = 0;
+ }
+
+ /* Second pass over transitions copies pointers into the in trans list. */
+ for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
+ trans->targ->inTrans[trans->targ->numInTrans++] = trans;
+}
diff --git a/ragel/redfsm.h b/ragel/redfsm.h
new file mode 100644
index 0000000..2e7ad7c
--- /dev/null
+++ b/ragel/redfsm.h
@@ -0,0 +1,530 @@
+/*
+ * Copyright 2001-2006 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
+ */
+
+#ifndef _REDFSM_H
+#define _REDFSM_H
+
+#include <assert.h>
+#include <string.h>
+#include <string>
+#include "config.h"
+#include "common.h"
+#include "vector.h"
+#include "dlist.h"
+#include "compare.h"
+#include "bstmap.h"
+#include "bstset.h"
+#include "avlmap.h"
+#include "avltree.h"
+#include "avlbasic.h"
+#include "mergesort.h"
+#include "sbstmap.h"
+#include "sbstset.h"
+#include "sbsttable.h"
+
+
+#define TRANS_ERR_TRANS 0
+#define STATE_ERR_STATE 0
+#define FUNC_NO_FUNC 0
+
+using std::string;
+
+struct RedStateAp;
+struct GenInlineList;
+struct GenAction;
+
+/*
+ * Inline code tree
+ */
+struct GenInlineItem
+{
+ enum Type
+ {
+ Text, Goto, Call, Next, GotoExpr, CallExpr, NextExpr, Ret,
+ PChar, Char, Hold, Exec, Curs, Targs, Entry,
+ LmSwitch, LmSetActId, LmSetTokEnd, LmGetTokEnd, LmInitTokStart,
+ LmInitAct, LmSetTokStart, SubAction, Break
+ };
+
+ GenInlineItem( const InputLoc &loc, Type type ) :
+ loc(loc), data(0), targId(0), targState(0),
+ lmId(0), children(0), offset(0),
+ type(type) { }
+
+ InputLoc loc;
+ char *data;
+ int targId;
+ RedStateAp *targState;
+ int lmId;
+ GenInlineList *children;
+ int offset;
+ Type type;
+
+ GenInlineItem *prev, *next;
+};
+
+/* Normally this would be atypedef, but that would entail including DList from
+ * ptreetypes, which should be just typedef forwards. */
+struct GenInlineList : public DList<GenInlineItem> { };
+
+/* Element in list of actions. Contains the string for the code to exectute. */
+struct GenAction
+:
+ public DListEl<GenAction>
+{
+ GenAction( )
+ :
+ name(0),
+ inlineList(0),
+ actionId(0),
+ numTransRefs(0),
+ numToStateRefs(0),
+ numFromStateRefs(0),
+ numEofRefs(0)
+ {
+ }
+
+ /* Data collected during parse. */
+ InputLoc loc;
+ const char *name;
+ GenInlineList *inlineList;
+ int actionId;
+
+ string nameOrLoc();
+
+ /* Number of references in the final machine. */
+ int numRefs()
+ { return numTransRefs + numToStateRefs + numFromStateRefs + numEofRefs; }
+ int numTransRefs;
+ int numToStateRefs;
+ int numFromStateRefs;
+ int numEofRefs;
+};
+
+
+/* Forwards. */
+struct RedStateAp;
+struct StateAp;
+
+/* Transistion GenAction Element. */
+typedef SBstMapEl< int, GenAction* > GenActionTableEl;
+
+/* Transition GenAction Table. */
+struct GenActionTable
+ : public SBstMap< int, GenAction*, CmpOrd<int> >
+{
+ void setAction( int ordering, GenAction *action );
+ void setActions( int *orderings, GenAction **actions, int nActs );
+ void setActions( const GenActionTable &other );
+};
+
+/* Compare of a whole action table element (key & value). */
+struct CmpGenActionTableEl
+{
+ static int compare( const GenActionTableEl &action1,
+ const GenActionTableEl &action2 )
+ {
+ if ( action1.key < action2.key )
+ return -1;
+ else if ( action1.key > action2.key )
+ return 1;
+ else if ( action1.value < action2.value )
+ return -1;
+ else if ( action1.value > action2.value )
+ return 1;
+ return 0;
+ }
+};
+
+/* Compare for GenActionTable. */
+typedef CmpSTable< GenActionTableEl, CmpGenActionTableEl > CmpGenActionTable;
+
+/* Set of states. */
+typedef BstSet<RedStateAp*> RedStateSet;
+typedef BstSet<int> IntSet;
+
+/* Reduced action. */
+struct RedAction
+:
+ public AvlTreeEl<RedAction>
+{
+ RedAction( )
+ :
+ key(),
+ eofRefs(0),
+ numTransRefs(0),
+ numToStateRefs(0),
+ numFromStateRefs(0),
+ numEofRefs(0),
+ bAnyNextStmt(false),
+ bAnyCurStateRef(false),
+ bAnyBreakStmt(false)
+ { }
+
+ const GenActionTable &getKey()
+ { return key; }
+
+ GenActionTable key;
+ int actListId;
+ int location;
+ IntSet *eofRefs;
+
+ /* Number of references in the final machine. */
+ int numRefs()
+ { return numTransRefs + numToStateRefs + numFromStateRefs + numEofRefs; }
+ int numTransRefs;
+ int numToStateRefs;
+ int numFromStateRefs;
+ int numEofRefs;
+
+ bool anyNextStmt() { return bAnyNextStmt; }
+ bool anyCurStateRef() { return bAnyCurStateRef; }
+ bool anyBreakStmt() { return bAnyBreakStmt; }
+
+ bool bAnyNextStmt;
+ bool bAnyCurStateRef;
+ bool bAnyBreakStmt;
+};
+typedef AvlTree<RedAction, GenActionTable, CmpGenActionTable> GenActionTableMap;
+
+/* Reduced transition. */
+struct RedTransAp
+:
+ public AvlTreeEl<RedTransAp>
+{
+ RedTransAp( RedStateAp *targ, RedAction *action, int id )
+ : targ(targ), action(action), id(id), pos(-1), labelNeeded(true) { }
+
+ RedStateAp *targ;
+ RedAction *action;
+ int id;
+ int pos;
+ bool partitionBoundary;
+ bool labelNeeded;
+};
+
+/* Compare of transitions for the final reduction of transitions. Comparison
+ * is on target and the pointer to the shared action table. It is assumed that
+ * when this is used the action tables have been reduced. */
+struct CmpRedTransAp
+{
+ static int compare( const RedTransAp &t1, const RedTransAp &t2 )
+ {
+ if ( t1.targ < t2.targ )
+ return -1;
+ else if ( t1.targ > t2.targ )
+ return 1;
+ else if ( t1.action < t2.action )
+ return -1;
+ else if ( t1.action > t2.action )
+ return 1;
+ else
+ return 0;
+ }
+};
+
+typedef AvlBasic<RedTransAp, CmpRedTransAp> TransApSet;
+
+/* Element in out range. */
+struct RedTransEl
+{
+ /* Constructors. */
+ RedTransEl( Key lowKey, Key highKey, RedTransAp *value )
+ : lowKey(lowKey), highKey(highKey), value(value) { }
+
+ Key lowKey, highKey;
+ RedTransAp *value;
+};
+
+typedef Vector<RedTransEl> RedTransList;
+typedef Vector<RedStateAp*> RedStateVect;
+
+typedef BstMapEl<RedStateAp*, unsigned long long> RedSpanMapEl;
+typedef BstMap<RedStateAp*, unsigned long long> RedSpanMap;
+
+/* Compare used by span map sort. Reverse sorts by the span. */
+struct CmpRedSpanMapEl
+{
+ static int compare( const RedSpanMapEl &smel1, const RedSpanMapEl &smel2 )
+ {
+ if ( smel1.value > smel2.value )
+ return -1;
+ else if ( smel1.value < smel2.value )
+ return 1;
+ else
+ return 0;
+ }
+};
+
+/* Sorting state-span map entries by span. */
+typedef MergeSort<RedSpanMapEl, CmpRedSpanMapEl> RedSpanMapSort;
+
+/* Set of entry ids that go into this state. */
+typedef Vector<int> EntryIdVect;
+typedef Vector<char*> EntryNameVect;
+
+typedef Vector< GenAction* > GenCondSet;
+
+struct Condition
+{
+ Condition( )
+ : key(0), baseKey(0) {}
+
+ Key key;
+ Key baseKey;
+ GenCondSet condSet;
+
+ Condition *next, *prev;
+};
+typedef DList<Condition> ConditionList;
+
+struct GenCondSpace
+{
+ Key baseKey;
+ GenCondSet condSet;
+ int condSpaceId;
+
+ GenCondSpace *next, *prev;
+};
+typedef DList<GenCondSpace> CondSpaceList;
+
+struct GenStateCond
+{
+ Key lowKey;
+ Key highKey;
+
+ GenCondSpace *condSpace;
+
+ GenStateCond *prev, *next;
+};
+typedef DList<GenStateCond> GenStateCondList;
+typedef Vector<GenStateCond*> StateCondVect;
+
+/* Reduced state. */
+struct RedStateAp
+{
+ RedStateAp()
+ :
+ defTrans(0),
+ condList(0),
+ transList(0),
+ isFinal(false),
+ labelNeeded(false),
+ outNeeded(false),
+ onStateList(false),
+ toStateAction(0),
+ fromStateAction(0),
+ eofAction(0),
+ eofTrans(0),
+ id(0),
+ bAnyRegCurStateRef(false),
+ partitionBoundary(false),
+ inTrans(0),
+ numInTrans(0)
+ { }
+
+ /* Transitions out. */
+ RedTransList outSingle;
+ RedTransList outRange;
+ RedTransAp *defTrans;
+
+ /* For flat conditions. */
+ Key condLowKey, condHighKey;
+ GenCondSpace **condList;
+
+ /* For flat keys. */
+ Key lowKey, highKey;
+ RedTransAp **transList;
+
+ /* The list of states that transitions from this state go to. */
+ RedStateVect targStates;
+
+ bool isFinal;
+ bool labelNeeded;
+ bool outNeeded;
+ bool onStateList;
+ RedAction *toStateAction;
+ RedAction *fromStateAction;
+ RedAction *eofAction;
+ RedTransAp *eofTrans;
+ int id;
+ GenStateCondList stateCondList;
+ StateCondVect stateCondVect;
+
+ /* Pointers for the list of states. */
+ RedStateAp *prev, *next;
+
+ bool anyRegCurStateRef() { return bAnyRegCurStateRef; }
+ bool bAnyRegCurStateRef;
+
+ int partition;
+ bool partitionBoundary;
+
+ RedTransAp **inTrans;
+ int numInTrans;
+};
+
+/* List of states. */
+typedef DList<RedStateAp> RedStateList;
+
+/* Set of reduced transitons. Comparison is by pointer. */
+typedef BstSet< RedTransAp*, CmpOrd<RedTransAp*> > RedTransSet;
+
+/* Next version of the fsm machine. */
+struct RedFsmAp
+{
+ RedFsmAp();
+
+ bool forcedErrorState;
+
+ int nextActionId;
+ int nextTransId;
+
+ /* Next State Id doubles as the total number of state ids. */
+ int nextStateId;
+
+ TransApSet transSet;
+ GenActionTableMap actionMap;
+ RedStateList stateList;
+ RedStateSet entryPoints;
+ RedStateAp *startState;
+ RedStateAp *errState;
+ RedTransAp *errTrans;
+ RedTransAp *errActionTrans;
+ RedStateAp *firstFinState;
+ int numFinStates;
+ int nParts;
+
+ bool bAnyToStateActions;
+ bool bAnyFromStateActions;
+ bool bAnyRegActions;
+ bool bAnyEofActions;
+ bool bAnyEofTrans;
+ bool bAnyActionGotos;
+ bool bAnyActionCalls;
+ bool bAnyActionRets;
+ bool bAnyRegActionRets;
+ bool bAnyRegActionByValControl;
+ bool bAnyRegNextStmt;
+ bool bAnyRegCurStateRef;
+ bool bAnyRegBreak;
+ bool bAnyConditions;
+
+ int maxState;
+ int maxSingleLen;
+ int maxRangeLen;
+ int maxKeyOffset;
+ int maxIndexOffset;
+ int maxIndex;
+ int maxActListId;
+ int maxActionLoc;
+ int maxActArrItem;
+ unsigned long long maxSpan;
+ unsigned long long maxCondSpan;
+ int maxFlatIndexOffset;
+ Key maxKey;
+ int maxCondOffset;
+ int maxCondLen;
+ int maxCondSpaceId;
+ int maxCondIndexOffset;
+ int maxCond;
+
+ bool anyActions();
+ bool anyToStateActions() { return bAnyToStateActions; }
+ bool anyFromStateActions() { return bAnyFromStateActions; }
+ bool anyRegActions() { return bAnyRegActions; }
+ bool anyEofActions() { return bAnyEofActions; }
+ bool anyEofTrans() { return bAnyEofTrans; }
+ bool anyActionGotos() { return bAnyActionGotos; }
+ bool anyActionCalls() { return bAnyActionCalls; }
+ bool anyActionRets() { return bAnyActionRets; }
+ bool anyRegActionRets() { return bAnyRegActionRets; }
+ bool anyRegActionByValControl() { return bAnyRegActionByValControl; }
+ bool anyRegNextStmt() { return bAnyRegNextStmt; }
+ bool anyRegCurStateRef() { return bAnyRegCurStateRef; }
+ bool anyRegBreak() { return bAnyRegBreak; }
+ bool anyConditions() { return bAnyConditions; }
+
+
+ /* Is is it possible to extend a range by bumping ranges that span only
+ * one character to the singles array. */
+ bool canExtend( const RedTransList &list, int pos );
+
+ /* Pick single transitions from the ranges. */
+ void moveTransToSingle( RedStateAp *state );
+ void chooseSingle();
+
+ void makeFlat();
+
+ /* Move a selected transition from ranges to default. */
+ void moveToDefault( RedTransAp *defTrans, RedStateAp *state );
+
+ /* Pick a default transition by largest span. */
+ RedTransAp *chooseDefaultSpan( RedStateAp *state );
+ void chooseDefaultSpan();
+
+ /* Pick a default transition by most number of ranges. */
+ RedTransAp *chooseDefaultNumRanges( RedStateAp *state );
+ void chooseDefaultNumRanges();
+
+ /* Pick a default transition tailored towards goto driven machine. */
+ RedTransAp *chooseDefaultGoto( RedStateAp *state );
+ void chooseDefaultGoto();
+
+ /* Ordering states by transition connections. */
+ void optimizeStateOrdering( RedStateAp *state );
+ void optimizeStateOrdering();
+
+ /* Ordering states by transition connections. */
+ void depthFirstOrdering( RedStateAp *state );
+ void depthFirstOrdering();
+
+ /* Set state ids. */
+ void sequentialStateIds();
+ void sortStateIdsByFinal();
+
+ /* Arrange states in by final id. This is a stable sort. */
+ void sortStatesByFinal();
+
+ /* Sorting states by id. */
+ void sortByStateId();
+
+ /* Locating the first final state. This is the final state with the lowest
+ * id. */
+ void findFirstFinState();
+
+ void assignActionLocs();
+
+ RedTransAp *getErrorTrans();
+ RedStateAp *getErrorState();
+
+ /* Is every char in the alphabet covered? */
+ bool alphabetCovered( RedTransList &outRange );
+
+ RedTransAp *allocateTrans( RedStateAp *targState, RedAction *actionTable );
+
+ void partitionFsm( int nParts );
+
+ void setInTrans();
+};
+
+
+#endif
diff --git a/ragel/rlparse.cpp b/ragel/rlparse.cpp
new file mode 100644
index 0000000..35b3fff
--- /dev/null
+++ b/ragel/rlparse.cpp
@@ -0,0 +1,6934 @@
+/* Automatically generated by Kelbt from "rlparse.kl".
+ *
+ * Parts of this file are copied from Kelbt source covered by the GNU
+ * GPL. As a special exception, you may use the parts of this file copied
+ * from Kelbt source without restriction. The remainder is derived from
+ * "rlparse.kl" and inherits the copyright status of that file.
+ */
+
+#line 1 "rlparse.kl"
+/*
+ * Copyright 2001-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 "rlparse.h"
+#include "ragel.h"
+#include <iostream>
+#include <errno.h>
+#include <stdlib.h>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+#line 102 "rlparse.kh"
+#line 105 "rlparse.kh"
+#line 140 "rlparse.kh"
+#line 1444 "rlparse.kl"
+
+
+#line 48 "rlparse.cpp"
+struct Parser_Lel_action_ref
+{
+#line 755 "rlparse.kl"
+
+ Action *action;
+
+
+#line 54 "rlparse.cpp"
+};
+
+struct Parser_Lel_aug_type
+{
+#line 546 "rlparse.kl"
+
+ InputLoc loc;
+ AugType augType;
+
+
+#line 65 "rlparse.cpp"
+};
+
+struct Parser_Lel_expression
+{
+#line 338 "rlparse.kl"
+
+ Expression *expression;
+
+
+#line 75 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor
+{
+#line 975 "rlparse.kl"
+
+ Factor *factor;
+
+
+#line 85 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_rep_num
+{
+#line 929 "rlparse.kl"
+
+ int rep;
+
+
+#line 95 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_with_aug
+{
+#line 452 "rlparse.kl"
+
+ FactorWithAug *factorWithAug;
+
+
+#line 105 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_with_ep
+{
+#line 436 "rlparse.kl"
+
+ FactorWithAug *factorWithAug;
+
+
+#line 115 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_with_label
+{
+#line 420 "rlparse.kl"
+
+ FactorWithAug *factorWithAug;
+
+
+#line 125 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_with_neg
+{
+#line 939 "rlparse.kl"
+
+ FactorWithNeg *factorWithNeg;
+
+
+#line 135 "rlparse.cpp"
+};
+
+struct Parser_Lel_factor_with_rep
+{
+#line 868 "rlparse.kl"
+
+ FactorWithRep *factorWithRep;
+
+
+#line 145 "rlparse.cpp"
+};
+
+struct Parser_Lel_inline_item
+{
+#line 1234 "rlparse.kl"
+
+ InlineItem *inlineItem;
+
+
+#line 155 "rlparse.cpp"
+};
+
+struct Parser_Lel_inline_list
+{
+#line 1213 "rlparse.kl"
+
+ InlineList *inlineList;
+
+
+#line 165 "rlparse.cpp"
+};
+
+struct Parser_Lel_join
+{
+#line 321 "rlparse.kl"
+
+ Join *join;
+
+
+#line 175 "rlparse.cpp"
+};
+
+struct Parser_Lel_join_or_lm
+{
+#line 229 "rlparse.kl"
+
+ MachineDef *machineDef;
+
+
+#line 185 "rlparse.cpp"
+};
+
+struct Parser_Lel_lm_part_list
+{
+#line 253 "rlparse.kl"
+
+ LmPartList *lmPartList;
+
+
+#line 195 "rlparse.cpp"
+};
+
+struct Parser_Lel_local_err_name
+{
+#line 856 "rlparse.kl"
+
+ int error_name;
+
+
+#line 205 "rlparse.cpp"
+};
+
+struct Parser_Lel_longest_match_part
+{
+#line 277 "rlparse.kl"
+
+ LongestMatchPart *lmPart;
+
+
+#line 215 "rlparse.cpp"
+};
+
+struct Parser_Lel_opt_export
+{
+#line 95 "rlparse.kl"
+
+ bool isSet;
+
+
+#line 225 "rlparse.cpp"
+};
+
+struct Parser_Lel_opt_lm_part_action
+{
+#line 294 "rlparse.kl"
+
+ Action *action;
+
+
+#line 235 "rlparse.cpp"
+};
+
+struct Parser_Lel_priority_aug
+{
+#line 803 "rlparse.kl"
+
+ int priorityNum;
+
+
+#line 245 "rlparse.cpp"
+};
+
+struct Parser_Lel_priority_name
+{
+#line 788 "rlparse.kl"
+
+ int priorityName;
+
+
+#line 255 "rlparse.cpp"
+};
+
+struct Parser_Lel_range_lit
+{
+#line 1042 "rlparse.kl"
+
+ Literal *literal;
+
+
+#line 265 "rlparse.cpp"
+};
+
+struct Parser_Lel_regular_expr
+{
+#line 1079 "rlparse.kl"
+
+ RegExpr *regExpr;
+
+
+#line 275 "rlparse.cpp"
+};
+
+struct Parser_Lel_regular_expr_char
+{
+#line 1131 "rlparse.kl"
+
+ ReItem *reItem;
+
+
+#line 285 "rlparse.cpp"
+};
+
+struct Parser_Lel_regular_expr_item
+{
+#line 1114 "rlparse.kl"
+
+ ReItem *reItem;
+
+
+#line 295 "rlparse.cpp"
+};
+
+struct Parser_Lel_regular_expr_or_char
+{
+#line 1188 "rlparse.kl"
+
+ ReOrItem *reOrItem;
+
+
+#line 305 "rlparse.cpp"
+};
+
+struct Parser_Lel_regular_expr_or_data
+{
+#line 1155 "rlparse.kl"
+
+ ReOrBlock *reOrBlock;
+
+
+#line 315 "rlparse.cpp"
+};
+
+struct Parser_Lel_term
+{
+#line 389 "rlparse.kl"
+
+ Term *term;
+
+
+#line 325 "rlparse.cpp"
+};
+
+struct Parser_Lel_term_short
+{
+#line 368 "rlparse.kl"
+
+ Term *term;
+
+
+#line 335 "rlparse.cpp"
+};
+
+struct Parser_Lel_token_type
+{
+#line 146 "rlparse.kl"
+
+ Token token;
+
+
+#line 345 "rlparse.cpp"
+};
+
+union Parser_UserData
+{
+ struct Parser_Lel_action_ref action_ref;
+ struct Parser_Lel_aug_type aug_type;
+ struct Parser_Lel_expression expression;
+ struct Parser_Lel_factor factor;
+ struct Parser_Lel_factor_rep_num factor_rep_num;
+ struct Parser_Lel_factor_with_aug factor_with_aug;
+ struct Parser_Lel_factor_with_ep factor_with_ep;
+ struct Parser_Lel_factor_with_label factor_with_label;
+ struct Parser_Lel_factor_with_neg factor_with_neg;
+ struct Parser_Lel_factor_with_rep factor_with_rep;
+ struct Parser_Lel_inline_item inline_item;
+ struct Parser_Lel_inline_list inline_list;
+ struct Parser_Lel_join join;
+ struct Parser_Lel_join_or_lm join_or_lm;
+ struct Parser_Lel_lm_part_list lm_part_list;
+ struct Parser_Lel_local_err_name local_err_name;
+ struct Parser_Lel_longest_match_part longest_match_part;
+ struct Parser_Lel_opt_export opt_export;
+ struct Parser_Lel_opt_lm_part_action opt_lm_part_action;
+ struct Parser_Lel_priority_aug priority_aug;
+ struct Parser_Lel_priority_name priority_name;
+ struct Parser_Lel_range_lit range_lit;
+ struct Parser_Lel_regular_expr regular_expr;
+ struct Parser_Lel_regular_expr_char regular_expr_char;
+ struct Parser_Lel_regular_expr_item regular_expr_item;
+ struct Parser_Lel_regular_expr_or_char regular_expr_or_char;
+ struct Parser_Lel_regular_expr_or_data regular_expr_or_data;
+ struct Parser_Lel_term term;
+ struct Parser_Lel_term_short term_short;
+ struct Parser_Lel_token_type token_type;
+ struct Token token;
+};
+
+struct Parser_LangEl
+{
+ char *file;
+ int line;
+ int type;
+ int reduction;
+ int state;
+ int causeReduce;
+ union Parser_UserData user;
+ unsigned int retry;
+ struct Parser_LangEl *next, *child, *prev;
+};
+
+struct Parser_Block
+{
+ struct Parser_LangEl data[8128];
+ struct Parser_Block *next;
+};
+
+#line 404 "rlparse.cpp"
+unsigned int Parser_startState = 0;
+
+short Parser_indicies[] = {
+ 152, -1, -1, 152, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 152, 152, 152, 152, -1,
+ -1, -1, -1, -1, -1, -1, -1, 152,
+ 152, 152, 152, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 152,
+ 152, 152, 1, 0, 404, 154, -1, -1,
+ 154, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 154, 154, 154, 154, -1, -1, -1, -1,
+ -1, -1, -1, -1, 154, 154, 154, 154,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 154, 154, 150, -1,
+ -1, 2, 161, -1, -1, 151, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, 5, 6,
+ 7, -1, -1, -1, -1, -1, -1, -1,
+ -1, 158, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 9, 8, -1, -1, -1, -1, 153,
+ 392, 393, 394, 395, 396, 397, 398, 399,
+ 400, 401, 402, 403, -1, 10, 3, 165,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 26, 14, 15, 17,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 326, 328,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 16, 364, 364, 364, -1, 364,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 364, -1, -1, -1, 364,
+ 364, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, 364,
+ 364, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, 364, -1, -1, -1, 364, 364,
+ 364, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 19, 364, 364, 364,
+ -1, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 364, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 364, -1, -1,
+ -1, 364, 364, -1, -1, -1, -1, -1,
+ -1, -1, -1, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 364, 364, 364, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 364, 364, -1, -1, -1,
+ 364, 364, 364, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 24, 174,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 174, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 23, 25, -1, -1, -1, -1, 159,
+ 20, 21, 22, 27, 168, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 28, 17, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 326, 328, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 29, 327, 376,
+ 377, 378, -1, 375, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 170, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 374,
+ -1, -1, -1, 372, 373, -1, -1, -1,
+ -1, -1, -1, -1, -1, 379, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 368, 369, 370, 371, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 380, 381, -1,
+ -1, -1, 382, 383, 30, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 365, -1,
+ 367, -1, 363, 366, 342, 342, 342, -1,
+ 342, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 342,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 342, -1, -1, 342, -1, -1, -1,
+ 342, 342, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 342,
+ 342, 342, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 342,
+ 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 31, 342,
+ 342, 342, -1, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 342, -1, -1, 342,
+ -1, -1, -1, 342, 342, -1, -1, -1,
+ -1, -1, -1, -1, -1, 342, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, 342, 342, 342, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, 342, 342, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 32, 155, 33, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 173, 376,
+ 377, 378, -1, 375, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 171, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 374,
+ -1, -1, -1, 372, 373, -1, -1, -1,
+ -1, -1, -1, -1, -1, 379, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 368, 369, 370, 371, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 380, 381, -1,
+ -1, -1, 382, 383, 30, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 365, -1,
+ 367, -1, 363, 366, 154, -1, -1, 154,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 154, 154, 154, 154, -1, -1,
+ -1, -1, -1, -1, -1, -1, 154, 154,
+ 154, 154, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 154, 154,
+ -1, -1, -1, 34, 35, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 36, 342, 342, 342,
+ -1, 342, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, -1, -1, 342, -1, -1,
+ -1, 342, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, 342, 342, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 37,
+ 167, 169, 38, 348, 349, 350, -1, 346,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 347, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 156, -1, -1, 374, -1, -1, -1, 372,
+ 373, -1, -1, -1, -1, -1, -1, -1,
+ -1, 351, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 368, 369,
+ 370, 371, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 45, 40,
+ 39, 380, 381, 41, 43, 44, 382, 383,
+ 30, 42, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 341, 345, 343, 344, 352, 348, 349, 350,
+ -1, 346, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 347, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 157, -1, -1, 374, -1, -1,
+ -1, 372, 373, -1, -1, -1, -1, -1,
+ -1, -1, -1, 351, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 368, 369, 370, 371, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, 40, 39, 380, 381, 41, 43, 44,
+ 382, 383, 30, 42, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 341, 345, 343, 344, 352, 364,
+ 364, 364, -1, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 364, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 364,
+ -1, -1, -1, 364, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, 364, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 364, 364, 364, 364, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 364, 364, -1,
+ -1, -1, 364, 364, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 46, 162, -1, -1, 161, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, 7, -1, -1, -1, -1, -1,
+ -1, -1, -1, 158, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 9, 8, -1, -1, -1,
+ -1, 153, 392, 393, 394, 395, 396, 397,
+ 398, 399, 400, 401, 402, 403, -1, 10,
+ 3, 55, -1, -1, -1, -1, -1, -1,
+ 63, -1, -1, -1, -1, 17, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 56, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 50, 57, -1, -1, 326, 328, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 61, 59, 60, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 47, -1,
+ 58, -1, -1, -1, -1, -1, -1, -1,
+ 48, 191, 49, 198, 52, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 54, -1, -1, -1, 308, 312, -1,
+ -1, 62, 55, -1, -1, -1, -1, -1,
+ -1, 63, -1, -1, -1, -1, 17, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 50, 57, -1, -1, 326, 328, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 66, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, 59, 60, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65,
+ 64, 58, -1, -1, -1, -1, -1, -1,
+ -1, 48, 191, 49, 198, 52, -1, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 54, -1, -1, -1, 308, 312,
+ -1, -1, 62, 348, 349, 350, -1, 346,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 347, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 166, -1, -1, 374, -1, -1, -1, 372,
+ 373, -1, -1, -1, -1, -1, -1, -1,
+ -1, 351, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 368, 369,
+ 370, 371, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 45, 40,
+ 39, 380, 381, 41, 43, 44, 382, 383,
+ 30, 42, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 341, 345, 343, 344, 352, 389, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 388, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 67,
+ -1, -1, -1, -1, 68, 353, 364, 364,
+ 364, -1, 364, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, -1,
+ -1, -1, 364, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, 364, 364, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, 364, -1, -1,
+ -1, 364, 364, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 69,
+ 71, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 389, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 388, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 70, -1, -1, -1, -1, 68, 75, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 389, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 388, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 74, -1,
+ -1, -1, -1, 68, 73, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 389, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 388, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 72, -1, -1, -1,
+ -1, 68, 361, 362, 376, 377, 378, -1,
+ 375, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 172,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 374, -1, -1, -1,
+ 372, 373, -1, -1, -1, -1, -1, -1,
+ -1, -1, 379, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 368,
+ 369, 370, 371, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 380, 381, -1, -1, -1, 382,
+ 383, 30, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 365, -1, 367, -1, 363,
+ 366, 81, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 163, 83, -1, -1, 186, -1, -1, 186,
+ 84, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 186, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 186, 82,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 186, -1,
+ -1, -1, -1, 85, 55, -1, -1, -1,
+ -1, 192, -1, 63, 192, -1, -1, 192,
+ 18, 86, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 192, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 192, 192,
+ -1, -1, -1, 50, 57, -1, -1, 326,
+ 328, -1, 87, 88, 89, -1, 192, -1,
+ -1, -1, -1, 192, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, 59,
+ 60, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 58, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 193, 52,
+ -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 54, -1, -1, -1,
+ 308, 312, -1, -1, 62, 315, -1, -1,
+ 315, 315, 315, -1, 315, 315, 315, 315,
+ 315, 315, 315, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 77, 315,
+ 315, -1, 315, 315, 315, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 315, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 315,
+ 315, -1, -1, -1, 315, 315, -1, -1,
+ 315, 315, -1, 315, 315, 315, 315, 315,
+ 315, -1, -1, -1, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 315, 315, 315, 200, -1,
+ -1, -1, -1, 200, -1, 200, 200, -1,
+ -1, 200, 200, 200, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 200, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 200, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 200, 200, -1, -1, -1, 200, 200, -1,
+ -1, 200, 200, -1, 200, 200, 200, 90,
+ 200, -1, -1, -1, -1, 200, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 200, 200, 200, 202, -1, -1, 100, 99,
+ 202, -1, 202, 202, -1, -1, 202, 202,
+ 202, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 202, 102, -1,
+ 101, -1, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 202, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 202, 202, -1,
+ -1, -1, 202, 202, -1, -1, 202, 202,
+ -1, 202, 202, 202, 202, 202, -1, -1,
+ -1, -1, 202, 219, 221, 223, 103, 264,
+ 268, 270, 272, 266, 274, 276, 280, 282,
+ 284, 278, 286, 252, 256, 258, 260, 254,
+ 262, 228, 232, 234, 236, 230, 238, 240,
+ 244, 246, 248, 242, 250, 202, 202, 202,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 226, 225, 227, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 91, -1, -1, 92, 93, 94, 95,
+ 96, 97, 214, -1, -1, 214, 214, 214,
+ -1, 214, 214, 300, 303, 214, 214, 214,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 214, 214, -1, 214,
+ 302, 214, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 214,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 104, 214, -1, -1,
+ -1, 214, 214, -1, -1, 214, 214, -1,
+ 214, 214, 214, 214, 214, 301, -1, -1,
+ -1, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 214, 214, 214, 55, -1, -1, -1, -1,
+ -1, -1, 63, -1, -1, -1, -1, 17,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 316, 57, -1, -1, 326, 328,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 61, 59, 60,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 58, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 310,
+ 312, -1, -1, 62, 55, -1, -1, -1,
+ -1, -1, -1, 63, -1, -1, -1, -1,
+ 17, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 316, 57, -1, -1, 326,
+ 328, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, 59,
+ 60, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 58, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 311, 312, -1, -1, 62, 313, -1, -1,
+ 313, 313, 313, -1, 313, 313, 313, 313,
+ 313, 313, 313, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 313,
+ 313, -1, 313, 313, 313, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 313, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 313,
+ 313, -1, -1, -1, 313, 313, -1, -1,
+ 313, 313, 322, 313, 313, 313, 313, 313,
+ 313, -1, -1, -1, 313, 313, 313, 313,
+ 313, 313, 313, 313, 313, 313, 313, 313,
+ 313, 313, 313, 313, 313, 313, 313, 313,
+ 313, 313, 313, 313, 313, 313, 313, 313,
+ 313, 313, 313, 313, 313, 313, 313, 313,
+ 313, 313, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 313, 313, 313, 314, -1,
+ -1, 314, 314, 314, -1, 314, 314, 314,
+ 314, 314, 314, 314, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 314, 314, -1, 314, 314, 314, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 314, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 314, 314, -1, -1, -1, 314, 314, -1,
+ -1, 314, 314, 324, 314, 314, 314, 314,
+ 314, 314, -1, -1, -1, 314, 314, 314,
+ 314, 314, 314, 314, 314, 314, 314, 314,
+ 314, 314, 314, 314, 314, 314, 314, 314,
+ 314, 314, 314, 314, 314, 314, 314, 314,
+ 314, 314, 314, 314, 314, 314, 314, 314,
+ 314, 314, 314, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 314, 314, 314, 338,
+ -1, -1, -1, 338, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 79, 338, -1, -1, -1, 338, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 80, 330, 330, 330, -1, 330,
+ -1, -1, 330, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 78, 105, 55, -1, -1, -1, -1, -1,
+ -1, 63, -1, -1, -1, -1, 17, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 50, 57, -1, -1, 326, 328, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, 59, 60, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 76,
+ -1, 58, -1, -1, -1, -1, -1, -1,
+ -1, 48, 191, 49, 198, 52, -1, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 54, -1, -1, -1, 308, 312,
+ -1, -1, 62, 164, 81, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 175, 55, -1, -1, -1,
+ -1, -1, -1, 63, -1, -1, -1, -1,
+ 17, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 51, 57, -1, -1, 326,
+ 328, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, 59,
+ 60, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 4, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 158, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 180, -1, 179, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 160, 108,
+ -1, 107, -1, 58, -1, -1, 106, 178,
+ -1, -1, -1, 48, 191, 49, 198, 52,
+ -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 54, -1, -1, -1,
+ 308, 312, -1, -1, 62, 384, 391, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 109, 376, 377, 378,
+ -1, 375, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 354, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 374, -1, -1,
+ -1, 372, 373, -1, -1, -1, -1, -1,
+ -1, -1, -1, 379, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 368, 369, 370, 371, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 380, 381, -1, -1, -1,
+ 382, 383, 30, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 365, -1, 367, -1,
+ 363, 366, 355, 364, 364, 364, -1, 364,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 364, -1, -1, -1, 364,
+ 364, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, 364,
+ 364, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, 364, -1, -1, -1, 364, 364,
+ 364, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 110, 359, 364, 364,
+ 364, -1, 364, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 364, -1,
+ -1, -1, 364, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, 364, 364, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, 364, -1, -1,
+ -1, 364, 364, 364, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 111,
+ 357, 364, 364, 364, -1, 364, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, -1, -1, 364, 364, -1,
+ -1, -1, -1, -1, -1, -1, -1, 364,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 364, 364, 364, 364,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 364,
+ 364, -1, -1, -1, 364, 364, 364, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 112, 321, -1, -1, 81, 55,
+ -1, -1, -1, -1, -1, -1, 63, -1,
+ -1, -1, -1, 17, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 56, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 50, 57,
+ -1, -1, 326, 328, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 61, 59, 60, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 199, 52, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 54,
+ -1, -1, -1, 308, 312, -1, -1, 62,
+ 319, 114, 115, -1, 335, -1, -1, 336,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 329,
+ 113, 317, -1, -1, -1, 116, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 337,
+ 318, -1, -1, -1, 116, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 337, 55,
+ -1, -1, -1, -1, -1, -1, 63, -1,
+ -1, -1, -1, 17, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 56, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 50, 57,
+ -1, -1, 326, 328, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 61, 59, 60, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, -1,
+ -1, -1, -1, -1, -1, -1, 117, 191,
+ 49, 198, 52, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 54,
+ -1, -1, -1, 308, 312, -1, -1, 62,
+ 55, -1, -1, -1, -1, -1, -1, 63,
+ -1, -1, -1, -1, 17, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 56, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 50,
+ 57, -1, -1, 326, 328, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 61, 59, 60, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 58,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 187, 49, 198, 52, -1, 53, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 54, -1, -1, -1, 308, 312, -1, -1,
+ 62, 55, -1, -1, -1, -1, -1, -1,
+ 63, -1, -1, -1, -1, 17, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 56, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 50, 57, -1, -1, 326, 328, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 61, 59, 60, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 58, -1, -1, -1, -1, -1, -1, -1,
+ -1, 188, 49, 198, 52, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 54, -1, -1, -1, 308, 312, -1,
+ -1, 62, 55, -1, -1, -1, -1, -1,
+ -1, 63, -1, -1, -1, -1, 17, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 50, 57, -1, -1, 326, 328, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, 59, 60, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 58, -1, -1, -1, -1, -1, -1,
+ -1, -1, 189, 49, 198, 52, -1, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 54, -1, -1, -1, 308, 312,
+ -1, -1, 62, 55, -1, -1, -1, -1,
+ -1, -1, 63, -1, -1, -1, -1, 17,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 50, 57, -1, -1, 326, 328,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 61, 59, 60,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 58, -1, -1, -1, -1, -1,
+ -1, -1, -1, 190, 49, 198, 52, -1,
+ 53, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 54, -1, -1, -1, 308,
+ 312, -1, -1, 62, 55, -1, -1, -1,
+ -1, -1, -1, 63, -1, -1, -1, -1,
+ 17, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 50, 57, -1, -1, 326,
+ 328, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, 59,
+ 60, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 58, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 194, 52,
+ -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 54, -1, -1, -1,
+ 308, 312, -1, -1, 62, 55, -1, -1,
+ -1, -1, -1, -1, 63, -1, -1, -1,
+ -1, 17, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 56, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 50, 57, -1, -1,
+ 326, 328, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 61,
+ 59, 60, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 58, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 195,
+ 52, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 54, -1, -1,
+ -1, 308, 312, -1, -1, 62, 55, -1,
+ -1, -1, -1, -1, -1, 63, -1, -1,
+ -1, -1, 17, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 56, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 50, 57, -1,
+ -1, 326, 328, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 61, 59, 60, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 58, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 196, 52, -1, 53, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 54, -1,
+ -1, -1, 308, 312, -1, -1, 62, 55,
+ -1, -1, -1, -1, -1, -1, 63, -1,
+ -1, -1, -1, 17, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 56, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 50, 57,
+ -1, -1, 326, 328, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 61, 59, 60, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 197, 52, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 54,
+ -1, -1, -1, 308, 312, -1, -1, 62,
+ 386, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 201, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 118, 119, -1,
+ -1, 121, -1, 122, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 120, -1, -1, -1, -1, 292, -1,
+ -1, -1, 296, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 203, 290, -1, -1,
+ -1, -1, -1, -1, -1, -1, 204, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 288, 295, 123, -1, -1, -1, -1, -1,
+ -1, 124, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 120, -1, -1, -1,
+ -1, 292, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 206,
+ 290, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 288, 124, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 120,
+ -1, -1, -1, -1, 292, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 208, 290, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 288, 124,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 120, -1, -1, -1, -1, 292,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 209, 290, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 288, 124, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 120, -1, -1,
+ -1, -1, 292, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 210, 290, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 288, 124, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 120, -1, -1, -1, -1, 292, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 211, 290, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 288,
+ 125, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 120, -1, -1, -1, -1,
+ 292, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 212, 290,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 288, 215, -1, -1, 215, -1,
+ 215, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 215, -1,
+ -1, -1, -1, 215, -1, -1, -1, 215,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 261, 273, 285,
+ 237, 249, 216, -1, -1, 216, -1, 216,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 216, -1, -1,
+ -1, -1, 216, -1, -1, -1, 216, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 224, -1, 259, 271, 283, 235,
+ 247, 217, -1, -1, 217, -1, 217, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 217, -1, -1, -1,
+ -1, 217, -1, -1, -1, 217, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 222, -1, 257, 269, 281, 233, 245,
+ 218, -1, -1, 218, -1, 218, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 218, -1, -1, -1, -1,
+ 218, -1, -1, -1, 218, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 220, -1, 253, 265, 277, 229, 241, 255,
+ 267, 279, 231, 243, 263, 275, 287, 239,
+ 251, 127, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 309, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 126, 17, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 323, -1,
+ -1, 326, 328, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 325, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 320, 55,
+ -1, -1, -1, -1, -1, -1, 63, -1,
+ 131, -1, -1, 17, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 56, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 51, 57,
+ -1, -1, 326, 328, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 61, 59, 60, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 158, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 180, -1, 179, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 160, 108, -1, 107, -1, 58, -1,
+ -1, -1, 177, -1, -1, -1, 48, 191,
+ 49, 198, 52, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 54,
+ -1, -1, -1, 308, 312, -1, -1, 62,
+ 81, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 184,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 120,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 130,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 129, -1, 183, 165, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 128, 387, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 387, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 132,
+ 376, 377, 378, -1, 375, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 356, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 374, -1, -1, -1, 372, 373, -1, -1,
+ -1, -1, -1, -1, -1, -1, 379, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 368, 369, 370, 371, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 380, 381,
+ -1, -1, -1, 382, 383, 30, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 365,
+ -1, 367, -1, 363, 366, 376, 377, 378,
+ -1, 375, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 360, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 374, -1, -1,
+ -1, 372, 373, -1, -1, -1, -1, -1,
+ -1, -1, -1, 379, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 368, 369, 370, 371, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 380, 381, -1, -1, -1,
+ 382, 383, 30, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 365, -1, 367, -1,
+ 363, 366, 376, 377, 378, -1, 375, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 358, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 374, -1, -1, -1, 372, 373,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 379, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 368, 369, 370,
+ 371, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 380, 381, -1, -1, -1, 382, 383, 30,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 365, -1, 367, -1, 363, 366, 332,
+ 332, 332, -1, 332, 331, -1, 332, 338,
+ -1, -1, -1, 338, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 133, 338, -1, -1, -1, 338, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 134, 339, -1, -1, 135, 339,
+ 83, -1, -1, 185, -1, -1, 185, 84,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 185, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 185, 82, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 185, -1, -1,
+ -1, -1, 85, 391, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 136, 139, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 137, -1, -1, -1, -1,
+ -1, -1, -1, -1, 138, 342, 342, 342,
+ -1, 342, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 342, -1, -1, 342, -1, -1,
+ -1, 342, 342, -1, -1, -1, -1, -1,
+ -1, -1, -1, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, 342, 342, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 140,
+ 297, 298, 124, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 120, -1, -1,
+ -1, -1, 292, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 207, 290, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 288, 292, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 138,
+ 142, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 141, -1, 138, 144, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 304, 309, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 143, 35, 181,
+ 124, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 120, -1, -1, -1, -1,
+ 292, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 182, 290,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 288, 176, 390, 333, -1, -1,
+ -1, 116, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 337, 334, -1, -1, -1,
+ 116, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 337, 340, 385, -1, -1, -1,
+ -1, 385, -1, 385, 385, -1, -1, 385,
+ 385, 385, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 385, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 385, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 385, 385,
+ -1, -1, -1, 385, 385, -1, -1, 385,
+ 385, -1, 385, 385, 385, 385, 385, -1,
+ -1, 132, -1, 385, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 385, 385,
+ 385, 145, 289, 291, -1, -1, 294, 348,
+ 349, 350, -1, 346, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 347, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 293, -1, -1, 374,
+ -1, -1, -1, 372, 373, -1, -1, -1,
+ -1, -1, -1, -1, -1, 351, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 368, 369, 370, 371, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 45, 40, 39, 380, 381, 41,
+ 43, 44, 382, 383, 30, 42, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 341, 345, 343, 344,
+ 352, 146, 291, -1, -1, 299, 305, 306,
+ -1, -1, -1, -1, -1, -1, 309, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 147, 121,
+ -1, 122, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 296, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 148, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 295,
+ 124, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 120, -1, -1, -1, -1,
+ 292, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 149, 290,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 288, 307, 205, 213,
+};
+
+unsigned short Parser_keys[] = {
+ 128, 227, 225, 225, 128, 228, 128, 244,
+ 128, 245, 128, 128, 128, 128, 45, 248,
+ 40, 249, 40, 249, 128, 250, 123, 128,
+ 123, 123, 123, 123, 128, 128, 123, 123,
+ 59, 128, 45, 248, 132, 132, 40, 292,
+ 40, 242, 40, 242, 59, 59, 128, 187,
+ 40, 292, 125, 228, 61, 141, 40, 242,
+ 59, 59, 59, 59, 40, 40, 40, 289,
+ 40, 289, 40, 249, 125, 244, 33, 281,
+ 33, 281, 40, 289, 128, 295, 59, 59,
+ 40, 249, 42, 295, 42, 295, 42, 295,
+ 59, 59, 59, 59, 40, 292, 44, 59,
+ 38, 144, 33, 281, 33, 201, 33, 181,
+ 33, 271, 33, 201, 33, 281, 33, 281,
+ 33, 201, 33, 201, 182, 279, 182, 279,
+ 179, 280, 134, 134, 33, 281, 59, 59,
+ 44, 59, 33, 281, 41, 41, 128, 294,
+ 40, 292, 59, 59, 40, 249, 59, 59,
+ 40, 249, 59, 59, 40, 249, 41, 44,
+ 33, 281, 179, 283, 182, 284, 182, 284,
+ 33, 281, 33, 281, 33, 281, 33, 281,
+ 33, 281, 33, 281, 33, 281, 33, 281,
+ 33, 281, 128, 293, 40, 275, 33, 274,
+ 40, 274, 40, 274, 40, 274, 40, 274,
+ 40, 274, 40, 206, 40, 206, 40, 206,
+ 40, 206, 202, 206, 202, 206, 44, 276,
+ 45, 281, 33, 281, 44, 255, 128, 245,
+ 41, 142, 40, 292, 40, 292, 40, 292,
+ 179, 186, 182, 279, 182, 279, 182, 186,
+ 38, 144, 128, 294, 128, 274, 40, 242,
+ 132, 132, 132, 132, 40, 274, 128, 274,
+ 128, 274, 44, 125, 132, 276, 61, 61,
+ 59, 59, 40, 274, 124, 124, 128, 128,
+ 182, 284, 182, 284, 186, 186, 33, 181,
+ 44, 44, 41, 41, 41, 44, 40, 289,
+ 44, 44, 41, 44, 125, 125, 125, 276,
+ 43, 275, 40, 274, 125, 125, 41, 41,
+ 41, 41, 0, 0
+};
+
+unsigned int Parser_offsets[] = {
+ 0, 100, 101, 202, 319, 437, 438, 439,
+ 643, 853, 1063, 1186, 1192, 1193, 1194, 1195,
+ 1196, 1266, 1470, 1471, 1724, 1927, 2130, 2131,
+ 2191, 2444, 2548, 2629, 2832, 2833, 2834, 2835,
+ 3085, 3335, 3545, 3665, 3914, 4163, 4413, 4581,
+ 4582, 4792, 5046, 5300, 5554, 5555, 5556, 5809,
+ 5825, 5932, 6181, 6350, 6499, 6738, 6907, 7156,
+ 7405, 7574, 7743, 7841, 7939, 8041, 8042, 8291,
+ 8292, 8308, 8557, 8558, 8725, 8978, 8979, 9189,
+ 9190, 9400, 9401, 9611, 9615, 9864, 9969, 10072,
+ 10175, 10424, 10673, 10922, 11171, 11420, 11669, 11918,
+ 12167, 12416, 12582, 12818, 13060, 13295, 13530, 13765,
+ 14000, 14235, 14402, 14569, 14736, 14903, 14908, 14913,
+ 15146, 15383, 15632, 15844, 15962, 16064, 16317, 16570,
+ 16823, 16831, 16929, 17027, 17032, 17139, 17306, 17453,
+ 17656, 17657, 17658, 17893, 18040, 18187, 18269, 18414,
+ 18415, 18416, 18651, 18652, 18653, 18756, 18859, 18860,
+ 19009, 19010, 19011, 19015, 19265, 19266, 19270, 19271,
+ 19423, 19656, 19891, 19892, 19893, 19894
+};
+
+unsigned short Parser_targs[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 120, 121, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149, 149, 149, 149,
+ 149, 149, 149, 149, 149
+};
+
+unsigned int Parser_actInds[] = {
+ 0, 2, 4, 6, 8, 10, 12, 14,
+ 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 39, 41, 43, 45, 47,
+ 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99, 101, 103, 106, 108, 110, 112,
+ 114, 116, 118, 120, 122, 124, 126, 128,
+ 130, 132, 134, 136, 138, 140, 142, 144,
+ 146, 148, 150, 152, 154, 156, 158, 160,
+ 162, 164, 166, 168, 170, 172, 174, 176,
+ 178, 180, 182, 184, 186, 188, 190, 192,
+ 194, 196, 198, 200, 202, 204, 206, 208,
+ 210, 213, 215, 217, 219, 221, 223, 225,
+ 227, 229, 231, 233, 235, 237, 239, 241,
+ 243, 245, 247, 249, 251, 253, 255, 257,
+ 259, 261, 263, 265, 267, 269, 271, 273,
+ 275, 277, 279, 281, 283, 285, 287, 289,
+ 291, 293, 295, 297, 299, 301, 303, 305,
+ 307, 309, 311, 313, 315, 317, 319, 321,
+ 323, 325, 327, 329, 331, 333, 335, 337,
+ 339, 341, 343, 345, 347, 349, 351, 353,
+ 355, 357, 359, 361, 363, 365, 367, 369,
+ 371, 373, 375, 377, 379, 381, 383, 385,
+ 387, 389, 391, 393, 395, 397, 399, 401,
+ 403, 405, 407, 409, 411, 413, 415, 417,
+ 419, 421, 423, 425, 427, 429, 431, 433,
+ 435, 437, 439, 441, 443, 445, 447, 449,
+ 451, 453, 455, 457, 459, 461, 463, 465,
+ 467, 469, 471, 473, 475, 477, 479, 481,
+ 483, 485, 487, 489, 491, 493, 495, 497,
+ 499, 501, 503, 505, 507, 509, 511, 513,
+ 515, 517, 519, 521, 523, 525, 527, 529,
+ 531, 533, 535, 537, 539, 541, 543, 545,
+ 547, 549, 551, 553, 555, 557, 559, 561,
+ 563, 565, 567, 569, 571, 573, 575, 577,
+ 579, 581, 583, 585, 587, 589, 591, 593,
+ 595, 597, 599, 601, 603, 605, 607, 609,
+ 611, 613, 615, 617, 619, 621, 623, 625,
+ 627, 629, 631, 633, 635, 637, 639, 641,
+ 643, 645, 647, 649, 651, 653, 655, 657,
+ 659, 661, 663, 665, 667, 669, 671, 673,
+ 675, 677, 679, 681, 683, 685, 687, 689,
+ 691, 693, 695, 697, 699, 701, 703, 705,
+ 707, 709, 711, 713, 715, 717, 719, 721,
+ 723, 725, 727, 729, 731, 733, 735, 737,
+ 739, 741, 743, 745, 747, 749, 751, 753,
+ 755, 757, 759, 761, 763, 765, 767, 769,
+ 771, 773, 775, 777, 779, 781, 783, 785,
+ 787, 789, 791, 793, 795, 797, 799, 801,
+ 803, 805, 807, 809, 811
+};
+
+unsigned int Parser_actions[] = {
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 214, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 90,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 302, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 2,
+ 0, 7, 0, 10, 0, 15, 0, 18,
+ 0, 71, 0, 75, 0, 79, 0, 83,
+ 0, 86, 0, 87, 0, 90, 0, 95,
+ 0, 99, 0, 103, 0, 107, 0, 111,
+ 0, 115, 0, 119, 0, 123, 0, 127,
+ 0, 131, 0, 135, 0, 139, 0, 142,
+ 0, 146, 0, 151, 0, 155, 0, 159,
+ 0, 163, 0, 167, 0, 171, 0, 175,
+ 0, 179, 0, 182, 0, 186, 0, 190,
+ 0, 195, 0, 199, 0, 203, 0, 207,
+ 0, 211, 0, 214, 0, 219, 0, 223,
+ 0, 227, 0, 231, 0, 235, 0, 239,
+ 0, 243, 0, 246, 0, 251, 0, 254,
+ 0, 259, 0, 263, 0, 267, 0, 271,
+ 0, 275, 0, 279, 0, 283, 0, 287,
+ 0, 291, 0, 295, 0, 299, 0, 302,
+ 0, 306, 0, 310, 0, 314, 0, 318,
+ 0, 323, 0, 327, 0, 331, 0, 335,
+ 0, 339, 0, 343, 0, 347, 0, 351,
+ 0, 355, 0, 359, 0, 363, 0, 367,
+ 0, 371, 0, 375, 0, 379, 0, 383,
+ 0, 387, 0, 391, 0, 395, 0, 399,
+ 0, 403, 0, 407, 0, 411, 0, 415,
+ 0, 419, 0, 423, 0, 427, 0, 431,
+ 0, 435, 0, 439, 0, 443, 0, 447,
+ 0, 451, 0, 455, 0, 459, 0, 463,
+ 0, 467, 0, 471, 0, 475, 0, 479,
+ 0, 483, 0, 487, 0, 491, 0, 495,
+ 0, 499, 0, 503, 0, 507, 0, 511,
+ 0, 515, 0, 519, 0, 523, 0, 527,
+ 0, 531, 0, 535, 0, 539, 0, 543,
+ 0, 547, 0, 551, 0, 555, 0, 559,
+ 0, 563, 0, 567, 0, 571, 0, 575,
+ 0, 579, 0, 583, 0, 587, 0, 591,
+ 0, 595, 0, 599, 0, 603, 0, 607,
+ 0, 610, 0, 611, 0, 615, 0, 618,
+ 0, 623, 0, 627, 0, 631, 0, 635,
+ 0, 638, 0, 643, 0, 647, 0, 651,
+ 0, 655, 0, 659, 0, 663, 0, 667,
+ 0, 671, 0, 675, 0, 679, 0, 683,
+ 0, 687, 0, 691, 0, 694, 0, 698,
+ 0, 702, 0, 703, 0, 707, 0, 711,
+ 0, 715, 0, 719, 0, 723, 0, 726,
+ 0, 727, 0, 730, 0, 731, 0, 735,
+ 0, 739, 0, 743, 0, 747, 0, 750,
+ 0, 755, 0, 758, 0, 763, 0, 767,
+ 0, 771, 0, 775, 0, 779, 0, 782,
+ 0, 786, 0, 791, 0, 795, 0, 798,
+ 0, 803, 0, 807, 0, 811, 0, 815,
+ 0, 819, 0, 823, 0, 827, 0, 831,
+ 0, 835, 0, 839, 0, 843, 0, 847,
+ 0, 851, 0, 855, 0, 859, 0, 863,
+ 0, 867, 0, 871, 0, 875, 0, 879,
+ 0, 883, 0, 886, 0, 891, 0, 895,
+ 0, 899, 0, 903, 0, 907, 0, 911,
+ 0, 915, 0, 919, 0, 923, 0, 927,
+ 0, 931, 0, 935, 0, 939, 0, 943,
+ 0, 947, 0, 951, 0, 955, 0, 959,
+ 0, 963, 0, 967, 0, 970, 0, 974,
+ 0, 978, 0, 983, 0, 986, 0, 991,
+ 0, 995, 0, 23, 0, 27, 0, 31,
+ 0, 35, 0, 39, 0, 43, 0, 47,
+ 0, 51, 0, 55, 0, 59, 0, 63,
+ 0, 67, 0, 1, 0
+};
+
+int Parser_commitLen[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2
+};
+
+char Parser_prodLengths[] = {
+ 1, 3, 0, 2, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 4, 4, 1, 1, 0, 4,
+ 5, 5, 1, 5, 4, 3, 4, 3,
+ 3, 5, 2, 0, 1, 4, 2, 1,
+ 1, 1, 3, 2, 1, 0, 3, 1,
+ 3, 3, 3, 3, 1, 1, 2, 3,
+ 3, 3, 3, 1, 3, 1, 3, 1,
+ 3, 3, 7, 3, 4, 3, 3, 3,
+ 3, 3, 7, 1, 1, 1, 1, 1,
+ 1, 2, 1, 2, 1, 2, 1, 1,
+ 1, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 1, 2, 1, 3, 1,
+ 1, 3, 1, 1, 1, 2, 2, 1,
+ 2, 2, 2, 2, 4, 5, 5, 6,
+ 1, 1, 2, 2, 1, 1, 1, 1,
+ 3, 3, 3, 3, 3, 1, 1, 1,
+ 2, 1, 2, 0, 2, 1, 3, 3,
+ 1, 1, 2, 0, 1, 3, 2, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 3, 3, 4, 3, 4,
+ 3, 4, 2, 2, 2, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 2, 0, 2, 1, 0, 3,
+ 1, 1
+};
+
+unsigned short Parser_prodLhsIds[] = {
+ 227, 226, 226, 228, 228, 229, 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229,
+ 229, 241, 239, 240, 243, 244, 244, 238,
+ 230, 231, 245, 232, 233, 233, 234, 235,
+ 236, 237, 250, 250, 247, 247, 251, 251,
+ 252, 252, 252, 253, 253, 253, 246, 246,
+ 256, 256, 256, 256, 256, 257, 258, 258,
+ 258, 258, 258, 258, 259, 259, 260, 260,
+ 262, 262, 262, 262, 262, 262, 262, 262,
+ 262, 262, 262, 262, 263, 263, 263, 263,
+ 266, 266, 266, 266, 266, 266, 266, 266,
+ 266, 267, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 268, 268, 268,
+ 268, 268, 268, 268, 268, 268, 268, 268,
+ 268, 269, 269, 269, 269, 269, 269, 269,
+ 269, 269, 269, 269, 269, 270, 270, 270,
+ 270, 270, 270, 270, 270, 270, 270, 270,
+ 270, 271, 271, 271, 271, 271, 271, 271,
+ 271, 271, 271, 271, 271, 254, 254, 254,
+ 274, 255, 265, 264, 275, 275, 275, 272,
+ 273, 273, 273, 273, 273, 273, 273, 273,
+ 273, 276, 277, 277, 277, 278, 278, 278,
+ 278, 278, 278, 278, 278, 281, 281, 248,
+ 248, 248, 280, 280, 282, 282, 283, 283,
+ 283, 283, 279, 279, 284, 284, 242, 242,
+ 285, 285, 285, 288, 288, 288, 288, 288,
+ 288, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 249, 249, 291, 291,
+ 291, 287, 287, 287, 287, 287, 287, 287,
+ 292, 292, 292, 292, 292, 289, 289, 289,
+ 289, 289, 261, 293, 290, 295, 295, 294,
+ 294, 296
+};
+
+const char *Parser_prodNames[] = {
+ "start-1",
+ "section_list-1",
+ "section_list-2",
+ "statement_list-1",
+ "statement_list-2",
+ "statement-1",
+ "statement-2",
+ "statement-3",
+ "statement-4",
+ "statement-5",
+ "statement-6",
+ "statement-7",
+ "statement-8",
+ "statement-9",
+ "statement-10",
+ "statement-11",
+ "statement-12",
+ "length_spec-1",
+ "pre_push_spec-1",
+ "post_pop_spec-1",
+ "export_open-1",
+ "opt_export-1",
+ "opt_export-2",
+ "export_block-1",
+ "assignment-1",
+ "instantiation-1",
+ "machine_name-1",
+ "action_spec-1",
+ "alphtype_spec-1",
+ "alphtype_spec-2",
+ "range_spec-1",
+ "getkey_spec-1",
+ "access_spec-1",
+ "variable_spec-1",
+ "opt_whitespace-1",
+ "opt_whitespace-2",
+ "join_or_lm-1",
+ "join_or_lm-2",
+ "lm_part_list-1",
+ "lm_part_list-2",
+ "longest_match_part-1",
+ "longest_match_part-2",
+ "longest_match_part-3",
+ "opt_lm_part_action-1",
+ "opt_lm_part_action-2",
+ "opt_lm_part_action-3",
+ "join-1",
+ "join-2",
+ "expression-1",
+ "expression-2",
+ "expression-3",
+ "expression-4",
+ "expression-5",
+ "term_short-1",
+ "term-1",
+ "term-2",
+ "term-3",
+ "term-4",
+ "term-5",
+ "term-6",
+ "factor_with_label-1",
+ "factor_with_label-2",
+ "factor_with_ep-1",
+ "factor_with_ep-2",
+ "factor_with_aug-1",
+ "factor_with_aug-2",
+ "factor_with_aug-3",
+ "factor_with_aug-4",
+ "factor_with_aug-5",
+ "factor_with_aug-6",
+ "factor_with_aug-7",
+ "factor_with_aug-8",
+ "factor_with_aug-9",
+ "factor_with_aug-10",
+ "factor_with_aug-11",
+ "factor_with_aug-12",
+ "aug_type_base-1",
+ "aug_type_base-2",
+ "aug_type_base-3",
+ "aug_type_base-4",
+ "aug_type_cond-1",
+ "aug_type_cond-2",
+ "aug_type_cond-3",
+ "aug_type_cond-4",
+ "aug_type_cond-5",
+ "aug_type_cond-6",
+ "aug_type_cond-7",
+ "aug_type_cond-8",
+ "aug_type_cond-9",
+ "aug_type_to_state-1",
+ "aug_type_to_state-2",
+ "aug_type_to_state-3",
+ "aug_type_to_state-4",
+ "aug_type_to_state-5",
+ "aug_type_to_state-6",
+ "aug_type_to_state-7",
+ "aug_type_to_state-8",
+ "aug_type_to_state-9",
+ "aug_type_to_state-10",
+ "aug_type_to_state-11",
+ "aug_type_to_state-12",
+ "aug_type_from_state-1",
+ "aug_type_from_state-2",
+ "aug_type_from_state-3",
+ "aug_type_from_state-4",
+ "aug_type_from_state-5",
+ "aug_type_from_state-6",
+ "aug_type_from_state-7",
+ "aug_type_from_state-8",
+ "aug_type_from_state-9",
+ "aug_type_from_state-10",
+ "aug_type_from_state-11",
+ "aug_type_from_state-12",
+ "aug_type_eof-1",
+ "aug_type_eof-2",
+ "aug_type_eof-3",
+ "aug_type_eof-4",
+ "aug_type_eof-5",
+ "aug_type_eof-6",
+ "aug_type_eof-7",
+ "aug_type_eof-8",
+ "aug_type_eof-9",
+ "aug_type_eof-10",
+ "aug_type_eof-11",
+ "aug_type_eof-12",
+ "aug_type_gbl_error-1",
+ "aug_type_gbl_error-2",
+ "aug_type_gbl_error-3",
+ "aug_type_gbl_error-4",
+ "aug_type_gbl_error-5",
+ "aug_type_gbl_error-6",
+ "aug_type_gbl_error-7",
+ "aug_type_gbl_error-8",
+ "aug_type_gbl_error-9",
+ "aug_type_gbl_error-10",
+ "aug_type_gbl_error-11",
+ "aug_type_gbl_error-12",
+ "aug_type_local_error-1",
+ "aug_type_local_error-2",
+ "aug_type_local_error-3",
+ "aug_type_local_error-4",
+ "aug_type_local_error-5",
+ "aug_type_local_error-6",
+ "aug_type_local_error-7",
+ "aug_type_local_error-8",
+ "aug_type_local_error-9",
+ "aug_type_local_error-10",
+ "aug_type_local_error-11",
+ "aug_type_local_error-12",
+ "action_embed-1",
+ "action_embed-2",
+ "action_embed-3",
+ "action_embed_word-1",
+ "action_embed_block-1",
+ "priority_name-1",
+ "priority_aug-1",
+ "priority_aug_num-1",
+ "priority_aug_num-2",
+ "priority_aug_num-3",
+ "local_err_name-1",
+ "factor_with_rep-1",
+ "factor_with_rep-2",
+ "factor_with_rep-3",
+ "factor_with_rep-4",
+ "factor_with_rep-5",
+ "factor_with_rep-6",
+ "factor_with_rep-7",
+ "factor_with_rep-8",
+ "factor_with_rep-9",
+ "factor_rep_num-1",
+ "factor_with_neg-1",
+ "factor_with_neg-2",
+ "factor_with_neg-3",
+ "factor-1",
+ "factor-2",
+ "factor-3",
+ "factor-4",
+ "factor-5",
+ "factor-6",
+ "factor-7",
+ "factor-8",
+ "range_lit-1",
+ "range_lit-2",
+ "alphabet_num-1",
+ "alphabet_num-2",
+ "alphabet_num-3",
+ "regular_expr-1",
+ "regular_expr-2",
+ "regular_expr_item-1",
+ "regular_expr_item-2",
+ "regular_expr_char-1",
+ "regular_expr_char-2",
+ "regular_expr_char-3",
+ "regular_expr_char-4",
+ "regular_expr_or_data-1",
+ "regular_expr_or_data-2",
+ "regular_expr_or_char-1",
+ "regular_expr_or_char-2",
+ "inline_block-1",
+ "inline_block-2",
+ "inline_block_item-1",
+ "inline_block_item-2",
+ "inline_block_item-3",
+ "inline_block_symbol-1",
+ "inline_block_symbol-2",
+ "inline_block_symbol-3",
+ "inline_block_symbol-4",
+ "inline_block_symbol-5",
+ "inline_block_symbol-6",
+ "inline_block_interpret-1",
+ "inline_block_interpret-2",
+ "inline_block_interpret-3",
+ "inline_block_interpret-4",
+ "inline_block_interpret-5",
+ "inline_block_interpret-6",
+ "inline_block_interpret-7",
+ "inline_block_interpret-8",
+ "inline_block_interpret-9",
+ "inline_block_interpret-10",
+ "inline_block_interpret-11",
+ "inline_expr-1",
+ "inline_expr-2",
+ "inline_expr_item-1",
+ "inline_expr_item-2",
+ "inline_expr_item-3",
+ "inline_expr_any-1",
+ "inline_expr_any-2",
+ "inline_expr_any-3",
+ "inline_expr_any-4",
+ "inline_expr_any-5",
+ "inline_expr_any-6",
+ "inline_expr_any-7",
+ "inline_expr_symbol-1",
+ "inline_expr_symbol-2",
+ "inline_expr_symbol-3",
+ "inline_expr_symbol-4",
+ "inline_expr_symbol-5",
+ "inline_expr_interpret-1",
+ "inline_expr_interpret-2",
+ "inline_expr_interpret-3",
+ "inline_expr_interpret-4",
+ "inline_expr_interpret-5",
+ "local_state_ref-1",
+ "no_name_sep-1",
+ "state_ref-1",
+ "opt_name_sep-1",
+ "opt_name_sep-2",
+ "state_ref_names-1",
+ "state_ref_names-2",
+ "_start-1"
+};
+
+const char *Parser_lelNames[] = {
+ "D-0",
+ "D-1",
+ "D-2",
+ "D-3",
+ "D-4",
+ "D-5",
+ "D-6",
+ "D-7",
+ "D-8",
+ "D-9",
+ "D-10",
+ "D-11",
+ "D-12",
+ "D-13",
+ "D-14",
+ "D-15",
+ "D-16",
+ "D-17",
+ "D-18",
+ "D-19",
+ "D-20",
+ "D-21",
+ "D-22",
+ "D-23",
+ "D-24",
+ "D-25",
+ "D-26",
+ "D-27",
+ "D-28",
+ "D-29",
+ "D-30",
+ "D-31",
+ "D-32",
+ "!",
+ "\"",
+ "#",
+ "$",
+ "%",
+ "&",
+ "'",
+ "(",
+ ")",
+ "*",
+ "+",
+ ",",
+ "-",
+ ".",
+ "/",
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ ":",
+ ";",
+ "<",
+ "=",
+ ">",
+ "?",
+ "@",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "[",
+ "\\",
+ "]",
+ "^",
+ "_",
+ "`",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "{",
+ "|",
+ "}",
+ "~",
+ "D-127",
+ "TK_Word",
+ "TK_Literal",
+ "TK_Number",
+ "TK_EndSection",
+ "TK_UInt",
+ "TK_Hex",
+ "TK_DotDot",
+ "TK_ColonGt",
+ "TK_ColonGtGt",
+ "TK_LtColon",
+ "TK_Arrow",
+ "TK_DoubleArrow",
+ "TK_StarStar",
+ "TK_ColonEquals",
+ "TK_NameSep",
+ "TK_BarStar",
+ "TK_DashDash",
+ "TK_StartCond",
+ "TK_AllCond",
+ "TK_LeavingCond",
+ "TK_Middle",
+ "TK_StartGblError",
+ "TK_AllGblError",
+ "TK_FinalGblError",
+ "TK_NotFinalGblError",
+ "TK_NotStartGblError",
+ "TK_MiddleGblError",
+ "TK_StartLocalError",
+ "TK_AllLocalError",
+ "TK_FinalLocalError",
+ "TK_NotFinalLocalError",
+ "TK_NotStartLocalError",
+ "TK_MiddleLocalError",
+ "TK_StartEOF",
+ "TK_AllEOF",
+ "TK_FinalEOF",
+ "TK_NotFinalEOF",
+ "TK_NotStartEOF",
+ "TK_MiddleEOF",
+ "TK_StartToState",
+ "TK_AllToState",
+ "TK_FinalToState",
+ "TK_NotFinalToState",
+ "TK_NotStartToState",
+ "TK_MiddleToState",
+ "TK_StartFromState",
+ "TK_AllFromState",
+ "TK_FinalFromState",
+ "TK_NotFinalFromState",
+ "TK_NotStartFromState",
+ "TK_MiddleFromState",
+ "RE_Slash",
+ "RE_SqOpen",
+ "RE_SqOpenNeg",
+ "RE_SqClose",
+ "RE_Dot",
+ "RE_Star",
+ "RE_Dash",
+ "RE_Char",
+ "IL_WhiteSpace",
+ "IL_Comment",
+ "IL_Literal",
+ "IL_Symbol",
+ "KW_Machine",
+ "KW_Include",
+ "KW_Import",
+ "KW_Write",
+ "KW_Action",
+ "KW_AlphType",
+ "KW_Range",
+ "KW_GetKey",
+ "KW_InWhen",
+ "KW_When",
+ "KW_OutWhen",
+ "KW_Eof",
+ "KW_Err",
+ "KW_Lerr",
+ "KW_To",
+ "KW_From",
+ "KW_Export",
+ "KW_PrePush",
+ "KW_PostPop",
+ "KW_Length",
+ "KW_Break",
+ "KW_Exec",
+ "KW_Hold",
+ "KW_PChar",
+ "KW_Char",
+ "KW_Goto",
+ "KW_Call",
+ "KW_Ret",
+ "KW_CurState",
+ "KW_TargState",
+ "KW_Entry",
+ "KW_Next",
+ "KW_Variable",
+ "KW_Access",
+ "Parser_tk_eof",
+ "section_list",
+ "start",
+ "statement_list",
+ "statement",
+ "assignment",
+ "instantiation",
+ "action_spec",
+ "alphtype_spec",
+ "range_spec",
+ "getkey_spec",
+ "access_spec",
+ "variable_spec",
+ "export_block",
+ "pre_push_spec",
+ "post_pop_spec",
+ "length_spec",
+ "inline_block",
+ "export_open",
+ "opt_export",
+ "machine_name",
+ "join",
+ "join_or_lm",
+ "alphabet_num",
+ "inline_expr",
+ "opt_whitespace",
+ "lm_part_list",
+ "longest_match_part",
+ "opt_lm_part_action",
+ "action_embed",
+ "action_embed_block",
+ "expression",
+ "term_short",
+ "term",
+ "factor_with_label",
+ "factor_with_ep",
+ "local_state_ref",
+ "factor_with_aug",
+ "aug_type_base",
+ "priority_aug",
+ "priority_name",
+ "aug_type_cond",
+ "aug_type_to_state",
+ "aug_type_from_state",
+ "aug_type_eof",
+ "aug_type_gbl_error",
+ "aug_type_local_error",
+ "local_err_name",
+ "factor_with_rep",
+ "action_embed_word",
+ "priority_aug_num",
+ "factor_rep_num",
+ "factor_with_neg",
+ "factor",
+ "regular_expr_or_data",
+ "regular_expr",
+ "range_lit",
+ "regular_expr_item",
+ "regular_expr_char",
+ "regular_expr_or_char",
+ "inline_block_item",
+ "inline_block_interpret",
+ "inline_expr_any",
+ "inline_block_symbol",
+ "inline_expr_interpret",
+ "state_ref",
+ "inline_expr_item",
+ "inline_expr_symbol",
+ "no_name_sep",
+ "state_ref_names",
+ "opt_name_sep",
+ "_start"
+};
+
+#line 1449 "rlparse.kl"
+
+
+void Parser::init()
+{
+ #line 3855 "rlparse.cpp"
+ curs = Parser_startState;
+ pool = 0;
+ block = (struct Parser_Block*) malloc( sizeof(struct Parser_Block) );
+ block->next = 0;
+ freshEl = block->data;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "allocating 8128 LangEls" << endl;
+ #endif
+ stackTop = freshEl;
+ stackTop->type = 0;
+ stackTop->state = -1;
+ stackTop->next = 0;
+ stackTop->child = 0;
+ stackTop->causeReduce = 0;
+ freshPos = 1;
+ lastFinal = stackTop;
+ numRetry = 0;
+ numNodes = 0;
+ errCount = 0;
+#line 1454 "rlparse.kl"
+}
+
+int Parser::parseLangEl( int type, const Token *token )
+{
+ #line 3880 "rlparse.cpp"
+#define reject() induceReject = 1
+
+ int pos, targState;
+ unsigned int *action;
+ int rhsLen;
+ struct Parser_LangEl *rhs[32];
+ struct Parser_LangEl *lel = 0;
+ struct Parser_LangEl *input = 0;
+ struct Parser_LangEl *queue = 0;
+ char induceReject;
+
+ if ( curs < 0 )
+ return 0;
+
+ if ( pool == 0 ) {
+ if ( freshPos == 8128 ) {
+ struct Parser_Block* newBlock = (struct Parser_Block*) malloc( sizeof(struct Parser_Block) );
+ newBlock->next = block;
+ block = newBlock;
+ freshEl = newBlock->data;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "allocating 8128 LangEls" << endl;
+ #endif
+ freshPos = 0;
+ }
+ queue = freshEl + freshPos++;
+ }
+ else {
+ queue = pool;
+ pool = pool->next;
+ }
+ numNodes += 1;
+
+ queue->type = type;
+ queue->user.token = *token;
+ queue->next = 0;
+ queue->retry = 0;
+ queue->child = 0;
+ queue->causeReduce = 0;
+
+again:
+ if ( input == 0 ) {
+ if ( queue == 0 )
+ goto _out;
+
+ input = queue;
+ queue = queue->next;
+ input->next = 0;
+ }
+
+ lel = input;
+ if ( lel->type < Parser_keys[curs<<1] || lel->type > Parser_keys[(curs<<1)+1] )
+ goto parseError;
+
+ pos = Parser_indicies[Parser_offsets[curs] + (lel->type - Parser_keys[curs<<1])];
+ if ( pos < 0 )
+ goto parseError;
+
+ induceReject = 0;
+ targState = Parser_targs[pos];
+ action = Parser_actions + Parser_actInds[pos];
+ if ( lel->retry & 0x0000ffff )
+ action += (lel->retry & 0x0000ffff);
+
+ if ( *action & 0x1 ) {
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "shifted: " << Parser_lelNames[lel->type];
+ #endif
+ input = input->next;
+ lel->state = curs;
+ lel->next = stackTop;
+ stackTop = lel;
+
+ if ( action[1] == 0 )
+ lel->retry &= 0xffff0000;
+ else {
+ lel->retry += 1;
+ numRetry += 1;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << " retry: " << stackTop;
+ #endif
+ }
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << endl;
+ #endif
+ }
+
+ if ( Parser_commitLen[pos] != 0 ) {
+ struct Parser_LangEl *commitHead = stackTop, *lel;
+ int sp = 0, doExec = 0;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "commit encountered, executing final actions" << endl;
+ #endif
+ if ( Parser_commitLen[pos] < 0 )
+ commitHead = commitHead->next;
+
+ lel = commitHead;
+
+commit_head:
+ if ( lel == lastFinal ) {
+ doExec = 1;
+ goto commit_base;
+ }
+
+ if ( lel->next != 0 ) {
+ sp += 1;
+ lel->next->prev = lel;
+ lel = lel->next;
+ lel->retry = 0;
+ goto commit_head;
+ }
+
+commit_reverse:
+
+ if ( lel->child != 0 ) {
+ sp += 1;
+ lel->child->prev = lel;
+ lel = lel->child;
+ lel->retry = 1;
+ goto commit_head;
+ }
+
+commit_upwards:
+
+ if ( doExec ) {
+ if ( lel->type < 226 ) {
+ }
+ else {
+ struct Parser_LangEl *redLel = lel;
+ if ( redLel->child != 0 ) {
+ int r = Parser_prodLengths[redLel->reduction] - 1;
+ struct Parser_LangEl *rhsEl = redLel->child;
+ while ( rhsEl != 0 ) {
+ rhs[r--] = rhsEl;
+ rhsEl = rhsEl->next;
+ }
+ }
+switch ( lel->reduction ) {
+case 17: {
+Token *__ref0 = (Token*)&rhs[1]->user.token;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Token *__ref2 = (Token*)&rhs[1]->user.token;
+#line 61 "rlparse.kl"
+
+ LengthDef *lengthDef = new LengthDef( (__ref0)->data );
+ pd->lengthDefList.append( lengthDef );
+
+ /* Generic creation of machine for instantiation and assignment. */
+ MachineDef *machineDef = new MachineDef( lengthDef );
+ tryMachineDef( (__ref1)->loc, (__ref2)->data, machineDef, false );
+
+
+#line 4031 "rlparse.cpp"
+} break;
+case 18: {
+Token *__ref0 = (Token*)&rhs[1]->user.token;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[2]->user.inline_list;
+#line 72 "rlparse.kl"
+
+ if ( pd->prePushExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error((__ref0)->loc) << "pre_push code already defined" << endl;
+ }
+
+ pd->prePushExpr = (__ref1)->inlineList;
+
+
+#line 4046 "rlparse.cpp"
+} break;
+case 19: {
+Token *__ref0 = (Token*)&rhs[1]->user.token;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[2]->user.inline_list;
+#line 84 "rlparse.kl"
+
+ if ( pd->postPopExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error((__ref0)->loc) << "post_pop code already defined" << endl;
+ }
+
+ pd->postPopExpr = (__ref1)->inlineList;
+
+
+#line 4061 "rlparse.cpp"
+} break;
+case 20: {
+#line 95 "rlparse.kl"
+
+ exportContext.append( true );
+
+
+#line 4069 "rlparse.cpp"
+} break;
+case 21: {
+Parser_Lel_opt_export *__ref0 = (Parser_Lel_opt_export*)&redLel->user.opt_export;
+#line 104 "rlparse.kl"
+ (__ref0)->isSet = true;
+
+#line 4076 "rlparse.cpp"
+} break;
+case 22: {
+Parser_Lel_opt_export *__ref0 = (Parser_Lel_opt_export*)&redLel->user.opt_export;
+#line 105 "rlparse.kl"
+ (__ref0)->isSet = false;
+
+#line 4083 "rlparse.cpp"
+} break;
+case 23: {
+#line 108 "rlparse.kl"
+
+ exportContext.remove( exportContext.length()-1 );
+
+
+#line 4091 "rlparse.cpp"
+} break;
+case 24: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_join *__ref2 = (Parser_Lel_join*)&rhs[3]->user.join;
+Parser_Lel_token_type *__ref3 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_token_type *__ref4 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_opt_export *__ref5 = (Parser_Lel_opt_export*)&rhs[0]->user.opt_export;
+Parser_Lel_join *__ref6 = (Parser_Lel_join*)&rhs[3]->user.join;
+Token *__ref7 = (Token*)&rhs[2]->user.token;
+#line 113 "rlparse.kl"
+
+ /* Main machine must be an instance. */
+ bool isInstance = false;
+ if ( strcmp((__ref0)->token.data, mainMachine) == 0 ) {
+ warning((__ref1)->token.loc) <<
+ "main machine will be implicitly instantiated" << endl;
+ isInstance = true;
+ }
+
+ /* Generic creation of machine for instantiation and assignment. */
+ MachineDef *machineDef = new MachineDef( (__ref2)->join );
+ tryMachineDef( (__ref3)->token.loc, (__ref4)->token.data, machineDef, isInstance );
+
+ if ( (__ref5)->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ (__ref6)->join->loc = (__ref7)->loc;
+
+
+#line 4122 "rlparse.cpp"
+} break;
+case 25: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_join_or_lm *__ref2 = (Parser_Lel_join_or_lm*)&rhs[3]->user.join_or_lm;
+Parser_Lel_opt_export *__ref3 = (Parser_Lel_opt_export*)&rhs[0]->user.opt_export;
+Parser_Lel_join_or_lm *__ref4 = (Parser_Lel_join_or_lm*)&rhs[3]->user.join_or_lm;
+Parser_Lel_join_or_lm *__ref5 = (Parser_Lel_join_or_lm*)&rhs[3]->user.join_or_lm;
+Token *__ref6 = (Token*)&rhs[2]->user.token;
+#line 133 "rlparse.kl"
+
+ /* Generic creation of machine for instantiation and assignment. */
+ tryMachineDef( (__ref0)->token.loc, (__ref1)->token.data, (__ref2)->machineDef, true );
+
+ if ( (__ref3)->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ /* Pass a location to join_or_lm */
+ if ( (__ref4)->machineDef->join != 0 )
+ (__ref5)->machineDef->join->loc = (__ref6)->loc;
+
+
+#line 4145 "rlparse.cpp"
+} break;
+case 26: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref3 = (Token*)&rhs[0]->user.token;
+#line 153 "rlparse.kl"
+
+ /* Make/get the priority key. The name may have already been referenced
+ * and therefore exist. */
+ PriorDictEl *priorDictEl;
+ if ( pd->priorDict.insert( (__ref0)->data, pd->nextPriorKey, &priorDictEl ) )
+ pd->nextPriorKey += 1;
+ pd->curDefPriorKey = priorDictEl->value;
+
+ /* Make/get the local error key. */
+ LocalErrDictEl *localErrDictEl;
+ if ( pd->localErrDict.insert( (__ref1)->data, pd->nextLocalErrKey, &localErrDictEl ) )
+ pd->nextLocalErrKey += 1;
+ pd->curDefLocalErrKey = localErrDictEl->value;
+
+ (__ref2)->token = *(__ref3);
+
+
+#line 4170 "rlparse.cpp"
+} break;
+case 27: {
+Token *__ref0 = (Token*)&rhs[1]->user.token;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Token *__ref2 = (Token*)&rhs[1]->user.token;
+Token *__ref3 = (Token*)&rhs[2]->user.token;
+Token *__ref4 = (Token*)&rhs[1]->user.token;
+Parser_Lel_inline_list *__ref5 = (Parser_Lel_inline_list*)&rhs[3]->user.inline_list;
+#line 171 "rlparse.kl"
+
+ if ( pd->actionDict.find( (__ref0)->data ) ) {
+ /* Recover by just ignoring the duplicate. */
+ error((__ref1)->loc) << "action \"" << (__ref2)->data << "\" already defined" << endl;
+ }
+ else {
+ //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
+ /* Add the action to the list of actions. */
+ Action *newAction = new Action( (__ref3)->loc, (__ref4)->data,
+ (__ref5)->inlineList, pd->nextCondId++ );
+
+ /* Insert to list and dict. */
+ pd->actionList.append( newAction );
+ pd->actionDict.insert( newAction );
+ }
+
+
+#line 4197 "rlparse.cpp"
+} break;
+case 28: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Token *__ref2 = (Token*)&rhs[2]->user.token;
+Token *__ref3 = (Token*)&rhs[1]->user.token;
+Token *__ref4 = (Token*)&rhs[1]->user.token;
+Token *__ref5 = (Token*)&rhs[2]->user.token;
+#line 191 "rlparse.kl"
+
+ if ( ! pd->setAlphType( (__ref0)->loc, (__ref1)->data, (__ref2)->data ) ) {
+ // Recover by ignoring the alphtype statement.
+ error((__ref3)->loc) << "\"" << (__ref4)->data <<
+ " " << (__ref5)->data << "\" is not a valid alphabet type" << endl;
+ }
+
+
+#line 4215 "rlparse.cpp"
+} break;
+case 29: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Token *__ref2 = (Token*)&rhs[1]->user.token;
+Token *__ref3 = (Token*)&rhs[1]->user.token;
+#line 200 "rlparse.kl"
+
+ if ( ! pd->setAlphType( (__ref0)->loc, (__ref1)->data ) ) {
+ // Recover by ignoring the alphtype statement.
+ error((__ref2)->loc) << "\"" << (__ref3)->data <<
+ "\" is not a valid alphabet type" << endl;
+ }
+
+
+#line 4231 "rlparse.cpp"
+} break;
+case 30: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[2]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[1]->user.token_type;
+Parser_Lel_token_type *__ref3 = (Parser_Lel_token_type*)&rhs[2]->user.token_type;
+#line 210 "rlparse.kl"
+
+ // Save the upper and lower ends of the range and emit the line number.
+ pd->lowerNum = (__ref0)->token.data;
+ pd->upperNum = (__ref1)->token.data;
+ pd->rangeLowLoc = (__ref2)->token.loc;
+ pd->rangeHighLoc = (__ref3)->token.loc;
+
+
+#line 4247 "rlparse.cpp"
+} break;
+case 31: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&rhs[1]->user.inline_list;
+#line 219 "rlparse.kl"
+
+ pd->getKeyExpr = (__ref0)->inlineList;
+
+
+#line 4256 "rlparse.cpp"
+} break;
+case 32: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&rhs[1]->user.inline_list;
+#line 224 "rlparse.kl"
+
+ pd->accessExpr = (__ref0)->inlineList;
+
+
+#line 4265 "rlparse.cpp"
+} break;
+case 33: {
+Token *__ref0 = (Token*)&rhs[2]->user.token;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[3]->user.inline_list;
+Token *__ref2 = (Token*)&rhs[2]->user.token;
+#line 229 "rlparse.kl"
+
+ /* FIXME: Need to implement the rest of this. */
+ bool wasSet = pd->setVariable( (__ref0)->data, (__ref1)->inlineList );
+ if ( !wasSet )
+ error((__ref2)->loc) << "bad variable name" << endl;
+
+
+#line 4279 "rlparse.cpp"
+} break;
+case 36: {
+Parser_Lel_join_or_lm *__ref0 = (Parser_Lel_join_or_lm*)&redLel->user.join_or_lm;
+Parser_Lel_join *__ref1 = (Parser_Lel_join*)&rhs[0]->user.join;
+#line 249 "rlparse.kl"
+
+ (__ref0)->machineDef = new MachineDef( (__ref1)->join );
+
+
+#line 4289 "rlparse.cpp"
+} break;
+case 37: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Parser_Lel_lm_part_list *__ref1 = (Parser_Lel_lm_part_list*)&rhs[1]->user.lm_part_list;
+Parser_Lel_lm_part_list *__ref2 = (Parser_Lel_lm_part_list*)&rhs[1]->user.lm_part_list;
+Parser_Lel_join_or_lm *__ref3 = (Parser_Lel_join_or_lm*)&redLel->user.join_or_lm;
+#line 253 "rlparse.kl"
+
+ /* Create a new factor going to a longest match structure. Record
+ * in the parse data that we have a longest match. */
+ LongestMatch *lm = new LongestMatch( (__ref0)->loc, (__ref1)->lmPartList );
+ pd->lmList.append( lm );
+ for ( LmPartList::Iter lmp = *((__ref2)->lmPartList); lmp.lte(); lmp++ )
+ lmp->longestMatch = lm;
+ (__ref3)->machineDef = new MachineDef( lm );
+
+
+#line 4307 "rlparse.cpp"
+} break;
+case 38: {
+Parser_Lel_longest_match_part *__ref0 = (Parser_Lel_longest_match_part*)&rhs[1]->user.longest_match_part;
+Parser_Lel_lm_part_list *__ref1 = (Parser_Lel_lm_part_list*)&rhs[0]->user.lm_part_list;
+Parser_Lel_longest_match_part *__ref2 = (Parser_Lel_longest_match_part*)&rhs[1]->user.longest_match_part;
+Parser_Lel_lm_part_list *__ref3 = (Parser_Lel_lm_part_list*)&redLel->user.lm_part_list;
+Parser_Lel_lm_part_list *__ref4 = (Parser_Lel_lm_part_list*)&rhs[0]->user.lm_part_list;
+#line 270 "rlparse.kl"
+
+ if ( (__ref0)->lmPart != 0 )
+ (__ref1)->lmPartList->append( (__ref2)->lmPart );
+ (__ref3)->lmPartList = (__ref4)->lmPartList;
+
+
+#line 4322 "rlparse.cpp"
+} break;
+case 39: {
+Parser_Lel_lm_part_list *__ref0 = (Parser_Lel_lm_part_list*)&redLel->user.lm_part_list;
+Parser_Lel_longest_match_part *__ref1 = (Parser_Lel_longest_match_part*)&rhs[0]->user.longest_match_part;
+Parser_Lel_lm_part_list *__ref2 = (Parser_Lel_lm_part_list*)&redLel->user.lm_part_list;
+Parser_Lel_longest_match_part *__ref3 = (Parser_Lel_longest_match_part*)&rhs[0]->user.longest_match_part;
+#line 277 "rlparse.kl"
+
+ /* Create a new list with the part. */
+ (__ref0)->lmPartList = new LmPartList;
+ if ( (__ref1)->lmPart != 0 )
+ (__ref2)->lmPartList->append( (__ref3)->lmPart );
+
+
+#line 4337 "rlparse.cpp"
+} break;
+case 40: {
+Parser_Lel_longest_match_part *__ref0 = (Parser_Lel_longest_match_part*)&redLel->user.longest_match_part;
+#line 290 "rlparse.kl"
+ (__ref0)->lmPart = 0;
+
+#line 4344 "rlparse.cpp"
+} break;
+case 41: {
+Parser_Lel_longest_match_part *__ref0 = (Parser_Lel_longest_match_part*)&redLel->user.longest_match_part;
+#line 292 "rlparse.kl"
+ (__ref0)->lmPart = 0;
+
+#line 4351 "rlparse.cpp"
+} break;
+case 42: {
+Parser_Lel_longest_match_part *__ref0 = (Parser_Lel_longest_match_part*)&redLel->user.longest_match_part;
+Parser_Lel_opt_lm_part_action *__ref1 = (Parser_Lel_opt_lm_part_action*)&rhs[1]->user.opt_lm_part_action;
+Parser_Lel_longest_match_part *__ref2 = (Parser_Lel_longest_match_part*)&redLel->user.longest_match_part;
+Parser_Lel_join *__ref3 = (Parser_Lel_join*)&rhs[0]->user.join;
+Token *__ref4 = (Token*)&rhs[2]->user.token;
+Parser_Lel_join *__ref5 = (Parser_Lel_join*)&rhs[0]->user.join;
+Token *__ref6 = (Token*)&rhs[2]->user.token;
+#line 294 "rlparse.kl"
+
+ (__ref0)->lmPart = 0;
+ Action *action = (__ref1)->action;
+ if ( action != 0 )
+ action->isLmAction = true;
+ (__ref2)->lmPart = new LongestMatchPart( (__ref3)->join, action,
+ (__ref4)->loc, pd->nextLongestMatchId++ );
+
+ /* Provide a location to join. Unfortunately We don't
+ * have the start of the join as in other occurances. Use the end. */
+ (__ref5)->join->loc = (__ref6)->loc;
+
+
+#line 4375 "rlparse.cpp"
+} break;
+case 43: {
+Parser_Lel_opt_lm_part_action *__ref0 = (Parser_Lel_opt_lm_part_action*)&redLel->user.opt_lm_part_action;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&rhs[1]->user.action_ref;
+#line 313 "rlparse.kl"
+
+ (__ref0)->action = (__ref1)->action;
+
+
+#line 4385 "rlparse.cpp"
+} break;
+case 44: {
+Parser_Lel_opt_lm_part_action *__ref0 = (Parser_Lel_opt_lm_part_action*)&redLel->user.opt_lm_part_action;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&rhs[0]->user.action_ref;
+#line 317 "rlparse.kl"
+
+ (__ref0)->action = (__ref1)->action;
+
+
+#line 4395 "rlparse.cpp"
+} break;
+case 45: {
+Parser_Lel_opt_lm_part_action *__ref0 = (Parser_Lel_opt_lm_part_action*)&redLel->user.opt_lm_part_action;
+#line 321 "rlparse.kl"
+
+ (__ref0)->action = 0;
+
+
+#line 4404 "rlparse.cpp"
+} break;
+case 46: {
+Parser_Lel_join *__ref0 = (Parser_Lel_join*)&rhs[0]->user.join;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[2]->user.expression;
+Parser_Lel_join *__ref2 = (Parser_Lel_join*)&redLel->user.join;
+Parser_Lel_join *__ref3 = (Parser_Lel_join*)&rhs[0]->user.join;
+#line 332 "rlparse.kl"
+
+ /* Append the expression to the list and return it. */
+ (__ref0)->join->exprList.append( (__ref1)->expression );
+ (__ref2)->join = (__ref3)->join;
+
+
+#line 4418 "rlparse.cpp"
+} break;
+case 47: {
+Parser_Lel_join *__ref0 = (Parser_Lel_join*)&redLel->user.join;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[0]->user.expression;
+#line 338 "rlparse.kl"
+
+ (__ref0)->join = new Join( (__ref1)->expression );
+
+
+#line 4428 "rlparse.cpp"
+} break;
+case 48: {
+Parser_Lel_expression *__ref0 = (Parser_Lel_expression*)&redLel->user.expression;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[0]->user.expression;
+Parser_Lel_term_short *__ref2 = (Parser_Lel_term_short*)&rhs[2]->user.term_short;
+#line 348 "rlparse.kl"
+
+ (__ref0)->expression = new Expression( (__ref1)->expression,
+ (__ref2)->term, Expression::OrType );
+
+
+#line 4440 "rlparse.cpp"
+} break;
+case 49: {
+Parser_Lel_expression *__ref0 = (Parser_Lel_expression*)&redLel->user.expression;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[0]->user.expression;
+Parser_Lel_term_short *__ref2 = (Parser_Lel_term_short*)&rhs[2]->user.term_short;
+#line 353 "rlparse.kl"
+
+ (__ref0)->expression = new Expression( (__ref1)->expression,
+ (__ref2)->term, Expression::IntersectType );
+
+
+#line 4452 "rlparse.cpp"
+} break;
+case 50: {
+Parser_Lel_expression *__ref0 = (Parser_Lel_expression*)&redLel->user.expression;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[0]->user.expression;
+Parser_Lel_term_short *__ref2 = (Parser_Lel_term_short*)&rhs[2]->user.term_short;
+#line 358 "rlparse.kl"
+
+ (__ref0)->expression = new Expression( (__ref1)->expression,
+ (__ref2)->term, Expression::SubtractType );
+
+
+#line 4464 "rlparse.cpp"
+} break;
+case 51: {
+Parser_Lel_expression *__ref0 = (Parser_Lel_expression*)&redLel->user.expression;
+Parser_Lel_expression *__ref1 = (Parser_Lel_expression*)&rhs[0]->user.expression;
+Parser_Lel_term_short *__ref2 = (Parser_Lel_term_short*)&rhs[2]->user.term_short;
+#line 363 "rlparse.kl"
+
+ (__ref0)->expression = new Expression( (__ref1)->expression,
+ (__ref2)->term, Expression::StrongSubtractType );
+
+
+#line 4476 "rlparse.cpp"
+} break;
+case 52: {
+Parser_Lel_expression *__ref0 = (Parser_Lel_expression*)&redLel->user.expression;
+Parser_Lel_term_short *__ref1 = (Parser_Lel_term_short*)&rhs[0]->user.term_short;
+#line 368 "rlparse.kl"
+
+ (__ref0)->expression = new Expression( (__ref1)->term );
+
+
+#line 4486 "rlparse.cpp"
+} break;
+case 53: {
+Parser_Lel_term_short *__ref0 = (Parser_Lel_term_short*)&redLel->user.term_short;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+#line 389 "rlparse.kl"
+
+ (__ref0)->term = (__ref1)->term;
+
+
+#line 4496 "rlparse.cpp"
+} break;
+case 54: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+Parser_Lel_factor_with_label *__ref2 = (Parser_Lel_factor_with_label*)&rhs[1]->user.factor_with_label;
+#line 399 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->term, (__ref2)->factorWithAug );
+
+
+#line 4507 "rlparse.cpp"
+} break;
+case 55: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+Parser_Lel_factor_with_label *__ref2 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+#line 403 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->term, (__ref2)->factorWithAug );
+
+
+#line 4518 "rlparse.cpp"
+} break;
+case 56: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+Parser_Lel_factor_with_label *__ref2 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+#line 407 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->term, (__ref2)->factorWithAug, Term::RightStartType );
+
+
+#line 4529 "rlparse.cpp"
+} break;
+case 57: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+Parser_Lel_factor_with_label *__ref2 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+#line 411 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->term, (__ref2)->factorWithAug, Term::RightFinishType );
+
+
+#line 4540 "rlparse.cpp"
+} break;
+case 58: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_term *__ref1 = (Parser_Lel_term*)&rhs[0]->user.term;
+Parser_Lel_factor_with_label *__ref2 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+#line 415 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->term,
+ (__ref2)->factorWithAug, Term::LeftType );
+
+
+#line 4552 "rlparse.cpp"
+} break;
+case 59: {
+Parser_Lel_term *__ref0 = (Parser_Lel_term*)&redLel->user.term;
+Parser_Lel_factor_with_label *__ref1 = (Parser_Lel_factor_with_label*)&rhs[0]->user.factor_with_label;
+#line 420 "rlparse.kl"
+
+ (__ref0)->term = new Term( (__ref1)->factorWithAug );
+
+
+#line 4562 "rlparse.cpp"
+} break;
+case 60: {
+Parser_Lel_factor_with_label *__ref0 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor_with_label *__ref3 = (Parser_Lel_factor_with_label*)&redLel->user.factor_with_label;
+Parser_Lel_factor_with_label *__ref4 = (Parser_Lel_factor_with_label*)&rhs[2]->user.factor_with_label;
+#line 430 "rlparse.kl"
+
+ /* Add the label to the list and pass the factor up. */
+ (__ref0)->factorWithAug->labels.prepend( Label((__ref1)->loc, (__ref2)->data) );
+ (__ref3)->factorWithAug = (__ref4)->factorWithAug;
+
+
+#line 4577 "rlparse.cpp"
+} break;
+case 61: {
+Parser_Lel_factor_with_label *__ref0 = (Parser_Lel_factor_with_label*)&redLel->user.factor_with_label;
+Parser_Lel_factor_with_ep *__ref1 = (Parser_Lel_factor_with_ep*)&rhs[0]->user.factor_with_ep;
+#line 436 "rlparse.kl"
+
+ (__ref0)->factorWithAug = (__ref1)->factorWithAug;
+
+
+#line 4587 "rlparse.cpp"
+} break;
+case 62: {
+Parser_Lel_factor_with_ep *__ref0 = (Parser_Lel_factor_with_ep*)&rhs[0]->user.factor_with_ep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_ep *__ref2 = (Parser_Lel_factor_with_ep*)&redLel->user.factor_with_ep;
+Parser_Lel_factor_with_ep *__ref3 = (Parser_Lel_factor_with_ep*)&rhs[0]->user.factor_with_ep;
+#line 446 "rlparse.kl"
+
+ /* Add the target to the list and return the factor object. */
+ (__ref0)->factorWithAug->epsilonLinks.append( EpsilonLink( (__ref1)->loc, nameRef ) );
+ (__ref2)->factorWithAug = (__ref3)->factorWithAug;
+
+
+#line 4601 "rlparse.cpp"
+} break;
+case 63: {
+Parser_Lel_factor_with_ep *__ref0 = (Parser_Lel_factor_with_ep*)&redLel->user.factor_with_ep;
+Parser_Lel_factor_with_aug *__ref1 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 452 "rlparse.kl"
+
+ (__ref0)->factorWithAug = (__ref1)->factorWithAug;
+
+
+#line 4611 "rlparse.cpp"
+} break;
+case 64: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 462 "rlparse.kl"
+
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ (__ref0)->factorWithAug->actions.append(
+ ParserAction( (__ref1)->loc, (__ref2)->augType, 0, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4629 "rlparse.cpp"
+} break;
+case 65: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_priority_aug *__ref2 = (Parser_Lel_priority_aug*)&rhs[2]->user.priority_aug;
+Parser_Lel_factor_with_aug *__ref3 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 470 "rlparse.kl"
+
+ /* Append the named priority to the factorWithAug and pass it up. */
+ (__ref0)->factorWithAug->priorityAugs.append(
+ PriorityAug( (__ref1)->augType, pd->curDefPriorKey, (__ref2)->priorityNum ) );
+ (__ref3)->factorWithAug = (__ref4)->factorWithAug;
+
+
+#line 4645 "rlparse.cpp"
+} break;
+case 66: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_priority_name *__ref2 = (Parser_Lel_priority_name*)&rhs[3]->user.priority_name;
+Parser_Lel_priority_aug *__ref3 = (Parser_Lel_priority_aug*)&rhs[5]->user.priority_aug;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 477 "rlparse.kl"
+
+ /* Append the priority using a default name. */
+ (__ref0)->factorWithAug->priorityAugs.append(
+ PriorityAug( (__ref1)->augType, (__ref2)->priorityName, (__ref3)->priorityNum ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4662 "rlparse.cpp"
+} break;
+case 67: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 484 "rlparse.kl"
+
+ (__ref0)->factorWithAug->conditions.append( ConditionTest( (__ref1)->loc,
+ (__ref2)->augType, (__ref3)->action, true ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4678 "rlparse.cpp"
+} break;
+case 68: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[3]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 490 "rlparse.kl"
+
+ (__ref0)->factorWithAug->conditions.append( ConditionTest( (__ref1)->loc,
+ (__ref2)->augType, (__ref3)->action, false ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4694 "rlparse.cpp"
+} break;
+case 69: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 496 "rlparse.kl"
+
+ /* Append the action, pass it up. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, 0, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4711 "rlparse.cpp"
+} break;
+case 70: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 503 "rlparse.kl"
+
+ /* Append the action, pass it up. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, 0, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4728 "rlparse.cpp"
+} break;
+case 71: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 510 "rlparse.kl"
+
+ /* Append the action, pass it up. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, 0, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4745 "rlparse.cpp"
+} break;
+case 72: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 517 "rlparse.kl"
+
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, pd->curDefLocalErrKey, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4763 "rlparse.cpp"
+} break;
+case 73: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_action_ref *__ref3 = (Parser_Lel_action_ref*)&rhs[2]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref4 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 525 "rlparse.kl"
+
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, pd->curDefLocalErrKey, (__ref3)->action ) );
+ (__ref4)->factorWithAug = (__ref5)->factorWithAug;
+
+
+#line 4781 "rlparse.cpp"
+} break;
+case 74: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+Parser_Lel_aug_type *__ref1 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&rhs[1]->user.aug_type;
+Parser_Lel_local_err_name *__ref3 = (Parser_Lel_local_err_name*)&rhs[3]->user.local_err_name;
+Parser_Lel_action_ref *__ref4 = (Parser_Lel_action_ref*)&rhs[5]->user.action_ref;
+Parser_Lel_factor_with_aug *__ref5 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_aug *__ref6 = (Parser_Lel_factor_with_aug*)&rhs[0]->user.factor_with_aug;
+#line 533 "rlparse.kl"
+
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ (__ref0)->factorWithAug->actions.append( ParserAction( (__ref1)->loc,
+ (__ref2)->augType, (__ref3)->error_name, (__ref4)->action ) );
+ (__ref5)->factorWithAug = (__ref6)->factorWithAug;
+
+
+#line 4800 "rlparse.cpp"
+} break;
+case 75: {
+Parser_Lel_factor_with_aug *__ref0 = (Parser_Lel_factor_with_aug*)&redLel->user.factor_with_aug;
+Parser_Lel_factor_with_rep *__ref1 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+#line 541 "rlparse.kl"
+
+ (__ref0)->factorWithAug = new FactorWithAug( (__ref1)->factorWithRep );
+
+
+#line 4810 "rlparse.cpp"
+} break;
+case 76: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 554 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_finish;
+
+#line 4819 "rlparse.cpp"
+} break;
+case 77: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 555 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_leave;
+
+#line 4828 "rlparse.cpp"
+} break;
+case 78: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 556 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all;
+
+#line 4837 "rlparse.cpp"
+} break;
+case 79: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 557 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start;
+
+#line 4846 "rlparse.cpp"
+} break;
+case 80: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 562 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start;
+
+#line 4855 "rlparse.cpp"
+} break;
+case 81: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 563 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start;
+
+#line 4864 "rlparse.cpp"
+} break;
+case 82: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 564 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all;
+
+#line 4873 "rlparse.cpp"
+} break;
+case 83: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 565 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all;
+
+#line 4882 "rlparse.cpp"
+} break;
+case 84: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 566 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_leave;
+
+#line 4891 "rlparse.cpp"
+} break;
+case 85: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 567 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_leave;
+
+#line 4900 "rlparse.cpp"
+} break;
+case 86: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 568 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all;
+
+#line 4909 "rlparse.cpp"
+} break;
+case 87: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 569 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start;
+
+#line 4918 "rlparse.cpp"
+} break;
+case 88: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 570 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_leave;
+
+#line 4927 "rlparse.cpp"
+} break;
+case 89: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 579 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_to_state;
+
+#line 4936 "rlparse.cpp"
+} break;
+case 90: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 581 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_to_state;
+
+#line 4945 "rlparse.cpp"
+} break;
+case 91: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 584 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_to_state;
+
+#line 4954 "rlparse.cpp"
+} break;
+case 92: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 586 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_to_state;
+
+#line 4963 "rlparse.cpp"
+} break;
+case 93: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 589 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_to_state;
+
+#line 4972 "rlparse.cpp"
+} break;
+case 94: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 591 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_to_state;
+
+#line 4981 "rlparse.cpp"
+} break;
+case 95: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 594 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_to_state;
+
+#line 4990 "rlparse.cpp"
+} break;
+case 96: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 596 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_to_state;
+
+#line 4999 "rlparse.cpp"
+} break;
+case 97: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 599 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_to_state;
+
+#line 5008 "rlparse.cpp"
+} break;
+case 98: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 601 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_to_state;
+
+#line 5017 "rlparse.cpp"
+} break;
+case 99: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 604 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_to_state;
+
+#line 5026 "rlparse.cpp"
+} break;
+case 100: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 606 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_to_state;
+
+#line 5035 "rlparse.cpp"
+} break;
+case 101: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 615 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_from_state;
+
+#line 5044 "rlparse.cpp"
+} break;
+case 102: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 617 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_from_state;
+
+#line 5053 "rlparse.cpp"
+} break;
+case 103: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 620 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_from_state;
+
+#line 5062 "rlparse.cpp"
+} break;
+case 104: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 622 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_from_state;
+
+#line 5071 "rlparse.cpp"
+} break;
+case 105: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 625 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_from_state;
+
+#line 5080 "rlparse.cpp"
+} break;
+case 106: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 627 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_from_state;
+
+#line 5089 "rlparse.cpp"
+} break;
+case 107: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 630 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_from_state;
+
+#line 5098 "rlparse.cpp"
+} break;
+case 108: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 632 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_from_state;
+
+#line 5107 "rlparse.cpp"
+} break;
+case 109: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 635 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_from_state;
+
+#line 5116 "rlparse.cpp"
+} break;
+case 110: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 637 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_from_state;
+
+#line 5125 "rlparse.cpp"
+} break;
+case 111: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 640 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_from_state;
+
+#line 5134 "rlparse.cpp"
+} break;
+case 112: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 642 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_from_state;
+
+#line 5143 "rlparse.cpp"
+} break;
+case 113: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 651 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_eof;
+
+#line 5152 "rlparse.cpp"
+} break;
+case 114: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 653 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_eof;
+
+#line 5161 "rlparse.cpp"
+} break;
+case 115: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 656 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_eof;
+
+#line 5170 "rlparse.cpp"
+} break;
+case 116: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 658 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_eof;
+
+#line 5179 "rlparse.cpp"
+} break;
+case 117: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 661 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_eof;
+
+#line 5188 "rlparse.cpp"
+} break;
+case 118: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 663 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_eof;
+
+#line 5197 "rlparse.cpp"
+} break;
+case 119: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 666 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_eof;
+
+#line 5206 "rlparse.cpp"
+} break;
+case 120: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 668 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_eof;
+
+#line 5215 "rlparse.cpp"
+} break;
+case 121: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 671 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_eof;
+
+#line 5224 "rlparse.cpp"
+} break;
+case 122: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 673 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_eof;
+
+#line 5233 "rlparse.cpp"
+} break;
+case 123: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 676 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_eof;
+
+#line 5242 "rlparse.cpp"
+} break;
+case 124: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 678 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_eof;
+
+#line 5251 "rlparse.cpp"
+} break;
+case 125: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 687 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_gbl_error;
+
+#line 5260 "rlparse.cpp"
+} break;
+case 126: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 689 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_gbl_error;
+
+#line 5269 "rlparse.cpp"
+} break;
+case 127: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 692 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_gbl_error;
+
+#line 5278 "rlparse.cpp"
+} break;
+case 128: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 694 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_gbl_error;
+
+#line 5287 "rlparse.cpp"
+} break;
+case 129: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 697 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_gbl_error;
+
+#line 5296 "rlparse.cpp"
+} break;
+case 130: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 699 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_gbl_error;
+
+#line 5305 "rlparse.cpp"
+} break;
+case 131: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 702 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_gbl_error;
+
+#line 5314 "rlparse.cpp"
+} break;
+case 132: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 704 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_gbl_error;
+
+#line 5323 "rlparse.cpp"
+} break;
+case 133: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 707 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_gbl_error;
+
+#line 5332 "rlparse.cpp"
+} break;
+case 134: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 709 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_gbl_error;
+
+#line 5341 "rlparse.cpp"
+} break;
+case 135: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 712 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_gbl_error;
+
+#line 5350 "rlparse.cpp"
+} break;
+case 136: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 714 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_gbl_error;
+
+#line 5359 "rlparse.cpp"
+} break;
+case 137: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 724 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_local_error;
+
+#line 5368 "rlparse.cpp"
+} break;
+case 138: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 726 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_start_local_error;
+
+#line 5377 "rlparse.cpp"
+} break;
+case 139: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 729 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_local_error;
+
+#line 5386 "rlparse.cpp"
+} break;
+case 140: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 731 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_start_local_error;
+
+#line 5395 "rlparse.cpp"
+} break;
+case 141: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 734 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_local_error;
+
+#line 5404 "rlparse.cpp"
+} break;
+case 142: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 736 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_all_local_error;
+
+#line 5413 "rlparse.cpp"
+} break;
+case 143: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 739 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_local_error;
+
+#line 5422 "rlparse.cpp"
+} break;
+case 144: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 741 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_final_local_error;
+
+#line 5431 "rlparse.cpp"
+} break;
+case 145: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 744 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_local_error;
+
+#line 5440 "rlparse.cpp"
+} break;
+case 146: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 746 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_not_final_local_error;
+
+#line 5449 "rlparse.cpp"
+} break;
+case 147: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 749 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_local_error;
+
+#line 5458 "rlparse.cpp"
+} break;
+case 148: {
+Parser_Lel_aug_type *__ref0 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_aug_type *__ref2 = (Parser_Lel_aug_type*)&redLel->user.aug_type;
+#line 751 "rlparse.kl"
+ (__ref0)->loc = (__ref1)->loc; (__ref2)->augType = at_middle_local_error;
+
+#line 5467 "rlparse.cpp"
+} break;
+case 149: {
+Parser_Lel_action_ref *__ref0 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&rhs[0]->user.action_ref;
+#line 764 "rlparse.kl"
+ (__ref0)->action = (__ref1)->action;
+
+#line 5475 "rlparse.cpp"
+} break;
+case 150: {
+Parser_Lel_action_ref *__ref0 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&rhs[1]->user.action_ref;
+#line 765 "rlparse.kl"
+ (__ref0)->action = (__ref1)->action;
+
+#line 5483 "rlparse.cpp"
+} break;
+case 151: {
+Parser_Lel_action_ref *__ref0 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&rhs[0]->user.action_ref;
+#line 766 "rlparse.kl"
+ (__ref0)->action = (__ref1)->action;
+
+#line 5491 "rlparse.cpp"
+} break;
+case 152: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Parser_Lel_action_ref *__ref1 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Token *__ref3 = (Token*)&rhs[0]->user.token;
+Parser_Lel_action_ref *__ref4 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+#line 771 "rlparse.kl"
+
+ /* Set the name in the actionDict. */
+ Action *action = pd->actionDict.find( (__ref0)->data );
+ if ( action != 0 ) {
+ /* Pass up the action element */
+ (__ref1)->action = action;
+ }
+ else {
+ /* Will recover by returning null as the action. */
+ error((__ref2)->loc) << "action lookup of \"" << (__ref3)->data << "\" failed" << endl;
+ (__ref4)->action = 0;
+ }
+
+
+#line 5514 "rlparse.cpp"
+} break;
+case 153: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[1]->user.inline_list;
+Parser_Lel_action_ref *__ref2 = (Parser_Lel_action_ref*)&redLel->user.action_ref;
+#line 788 "rlparse.kl"
+
+ /* Create the action, add it to the list and pass up. */
+ Action *newAction = new Action( (__ref0)->loc, 0, (__ref1)->inlineList, pd->nextCondId++ );
+ pd->actionList.append( newAction );
+ (__ref2)->action = newAction;
+
+
+#line 5528 "rlparse.cpp"
+} break;
+case 154: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Parser_Lel_priority_name *__ref1 = (Parser_Lel_priority_name*)&redLel->user.priority_name;
+#line 803 "rlparse.kl"
+
+ // Lookup/create the priority key.
+ PriorDictEl *priorDictEl;
+ if ( pd->priorDict.insert( (__ref0)->data, pd->nextPriorKey, &priorDictEl ) )
+ pd->nextPriorKey += 1;
+
+ // Use the inserted/found priority key.
+ (__ref1)->priorityName = priorDictEl->value;
+
+
+#line 5544 "rlparse.cpp"
+} break;
+case 155: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_priority_aug *__ref3 = (Parser_Lel_priority_aug*)&redLel->user.priority_aug;
+Parser_Lel_token_type *__ref4 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref5 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_priority_aug *__ref6 = (Parser_Lel_priority_aug*)&redLel->user.priority_aug;
+Parser_Lel_priority_aug *__ref7 = (Parser_Lel_priority_aug*)&redLel->user.priority_aug;
+#line 820 "rlparse.kl"
+
+ // Convert the priority number to a long. Check for overflow.
+ errno = 0;
+ //cerr << "PRIOR AUG: " << $1->token.data << endl;
+ long aug = strtol( (__ref0)->token.data, 0, 10 );
+ if ( errno == ERANGE && aug == LONG_MAX ) {
+ /* Priority number too large. Recover by setting the priority to 0. */
+ error((__ref1)->token.loc) << "priority number " << (__ref2)->token.data <<
+ " overflows" << endl;
+ (__ref3)->priorityNum = 0;
+ }
+ else if ( errno == ERANGE && aug == LONG_MIN ) {
+ /* Priority number too large in the neg. Recover by using 0. */
+ error((__ref4)->token.loc) << "priority number " << (__ref5)->token.data <<
+ " underflows" << endl;
+ (__ref6)->priorityNum = 0;
+ }
+ else {
+ /* No overflow or underflow. */
+ (__ref7)->priorityNum = aug;
+ }
+
+
+#line 5579 "rlparse.cpp"
+} break;
+case 156: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 846 "rlparse.kl"
+
+ (__ref0)->token = *(__ref1);
+
+
+#line 5589 "rlparse.cpp"
+} break;
+case 157: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_token_type *__ref3 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref4 = (Token*)&rhs[1]->user.token;
+#line 850 "rlparse.kl"
+
+ (__ref0)->token.set( "+", 1 );
+ (__ref1)->token.loc = (__ref2)->loc;
+ (__ref3)->token.append( *(__ref4) );
+
+
+#line 5604 "rlparse.cpp"
+} break;
+case 158: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_token_type *__ref3 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref4 = (Token*)&rhs[1]->user.token;
+#line 856 "rlparse.kl"
+
+ (__ref0)->token.set( "-", 1 );
+ (__ref1)->token.loc = (__ref2)->loc;
+ (__ref3)->token.append( *(__ref4) );
+
+
+#line 5619 "rlparse.cpp"
+} break;
+case 159: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Parser_Lel_local_err_name *__ref1 = (Parser_Lel_local_err_name*)&redLel->user.local_err_name;
+#line 868 "rlparse.kl"
+
+ /* Lookup/create the priority key. */
+ LocalErrDictEl *localErrDictEl;
+ if ( pd->localErrDict.insert( (__ref0)->data, pd->nextLocalErrKey, &localErrDictEl ) )
+ pd->nextLocalErrKey += 1;
+
+ /* Use the inserted/found priority key. */
+ (__ref1)->error_name = localErrDictEl->value;
+
+
+#line 5635 "rlparse.cpp"
+} break;
+case 160: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+#line 889 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ 0, 0, FactorWithRep::StarType );
+
+
+#line 5647 "rlparse.cpp"
+} break;
+case 161: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+#line 894 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ 0, 0, FactorWithRep::StarStarType );
+
+
+#line 5659 "rlparse.cpp"
+} break;
+case 162: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+#line 899 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ 0, 0, FactorWithRep::OptionalType );
+
+
+#line 5671 "rlparse.cpp"
+} break;
+case 163: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+#line 904 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ 0, 0, FactorWithRep::PlusType );
+
+
+#line 5683 "rlparse.cpp"
+} break;
+case 164: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+Parser_Lel_factor_rep_num *__ref3 = (Parser_Lel_factor_rep_num*)&rhs[2]->user.factor_rep_num;
+#line 909 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ (__ref3)->rep, 0, FactorWithRep::ExactType );
+
+
+#line 5696 "rlparse.cpp"
+} break;
+case 165: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+Parser_Lel_factor_rep_num *__ref3 = (Parser_Lel_factor_rep_num*)&rhs[3]->user.factor_rep_num;
+#line 914 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ 0, (__ref3)->rep, FactorWithRep::MaxType );
+
+
+#line 5709 "rlparse.cpp"
+} break;
+case 166: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+Parser_Lel_factor_rep_num *__ref3 = (Parser_Lel_factor_rep_num*)&rhs[2]->user.factor_rep_num;
+#line 919 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ (__ref3)->rep, 0, FactorWithRep::MinType );
+
+
+#line 5722 "rlparse.cpp"
+} break;
+case 167: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Parser_Lel_factor_with_rep *__ref2 = (Parser_Lel_factor_with_rep*)&rhs[0]->user.factor_with_rep;
+Parser_Lel_factor_rep_num *__ref3 = (Parser_Lel_factor_rep_num*)&rhs[2]->user.factor_rep_num;
+Parser_Lel_factor_rep_num *__ref4 = (Parser_Lel_factor_rep_num*)&rhs[4]->user.factor_rep_num;
+#line 924 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->loc, (__ref2)->factorWithRep,
+ (__ref3)->rep, (__ref4)->rep, FactorWithRep::RangeType );
+
+
+#line 5736 "rlparse.cpp"
+} break;
+case 168: {
+Parser_Lel_factor_with_rep *__ref0 = (Parser_Lel_factor_with_rep*)&redLel->user.factor_with_rep;
+Parser_Lel_factor_with_neg *__ref1 = (Parser_Lel_factor_with_neg*)&rhs[0]->user.factor_with_neg;
+#line 929 "rlparse.kl"
+
+ (__ref0)->factorWithRep = new FactorWithRep( (__ref1)->factorWithNeg );
+
+
+#line 5746 "rlparse.cpp"
+} break;
+case 169: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor_rep_num *__ref3 = (Parser_Lel_factor_rep_num*)&redLel->user.factor_rep_num;
+Parser_Lel_factor_rep_num *__ref4 = (Parser_Lel_factor_rep_num*)&redLel->user.factor_rep_num;
+#line 939 "rlparse.kl"
+
+ // Convert the priority number to a long. Check for overflow.
+ errno = 0;
+ long rep = strtol( (__ref0)->data, 0, 10 );
+ if ( errno == ERANGE && rep == LONG_MAX ) {
+ // Repetition too large. Recover by returing repetition 1. */
+ error((__ref1)->loc) << "repetition number " << (__ref2)->data << " overflows" << endl;
+ (__ref3)->rep = 1;
+ }
+ else {
+ // Cannot be negative, so no overflow.
+ (__ref4)->rep = rep;
+ }
+
+
+#line 5770 "rlparse.cpp"
+} break;
+case 170: {
+Parser_Lel_factor_with_neg *__ref0 = (Parser_Lel_factor_with_neg*)&redLel->user.factor_with_neg;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor_with_neg *__ref2 = (Parser_Lel_factor_with_neg*)&rhs[1]->user.factor_with_neg;
+#line 965 "rlparse.kl"
+
+ (__ref0)->factorWithNeg = new FactorWithNeg( (__ref1)->loc,
+ (__ref2)->factorWithNeg, FactorWithNeg::NegateType );
+
+
+#line 5782 "rlparse.cpp"
+} break;
+case 171: {
+Parser_Lel_factor_with_neg *__ref0 = (Parser_Lel_factor_with_neg*)&redLel->user.factor_with_neg;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor_with_neg *__ref2 = (Parser_Lel_factor_with_neg*)&rhs[1]->user.factor_with_neg;
+#line 970 "rlparse.kl"
+
+ (__ref0)->factorWithNeg = new FactorWithNeg( (__ref1)->loc,
+ (__ref2)->factorWithNeg, FactorWithNeg::CharNegateType );
+
+
+#line 5794 "rlparse.cpp"
+} break;
+case 172: {
+Parser_Lel_factor_with_neg *__ref0 = (Parser_Lel_factor_with_neg*)&redLel->user.factor_with_neg;
+Parser_Lel_factor *__ref1 = (Parser_Lel_factor*)&rhs[0]->user.factor;
+#line 975 "rlparse.kl"
+
+ (__ref0)->factorWithNeg = new FactorWithNeg( (__ref1)->factor );
+
+
+#line 5804 "rlparse.cpp"
+} break;
+case 173: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 985 "rlparse.kl"
+
+ /* Create a new factor node going to a concat literal. */
+ (__ref0)->factor = new Factor( new Literal( *(__ref1), Literal::LitString ) );
+
+
+#line 5815 "rlparse.cpp"
+} break;
+case 174: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 990 "rlparse.kl"
+
+ /* Create a new factor node going to a literal number. */
+ (__ref0)->factor = new Factor( new Literal( (__ref1)->token, Literal::Number ) );
+
+
+#line 5826 "rlparse.cpp"
+} break;
+case 175: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor *__ref3 = (Parser_Lel_factor*)&redLel->user.factor;
+Token *__ref4 = (Token*)&rhs[0]->user.token;
+Parser_Lel_factor *__ref5 = (Parser_Lel_factor*)&redLel->user.factor;
+Parser_Lel_factor *__ref6 = (Parser_Lel_factor*)&redLel->user.factor;
+Token *__ref7 = (Token*)&rhs[0]->user.token;
+#line 995 "rlparse.kl"
+
+ /* Find the named graph. */
+ GraphDictEl *gdNode = pd->graphDict.find( (__ref0)->data );
+ if ( gdNode == 0 ) {
+ /* Recover by returning null as the factor node. */
+ error((__ref1)->loc) << "graph lookup of \"" << (__ref2)->data << "\" failed" << endl;
+ (__ref3)->factor = 0;
+ }
+ else if ( gdNode->isInstance ) {
+ /* Recover by retuning null as the factor node. */
+ error((__ref4)->loc) << "references to graph instantiations not allowed "
+ "in expressions" << endl;
+ (__ref5)->factor = 0;
+ }
+ else {
+ /* Create a factor node that is a lookup of an expression. */
+ (__ref6)->factor = new Factor( (__ref7)->loc, gdNode->value );
+ }
+
+
+#line 5858 "rlparse.cpp"
+} break;
+case 176: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_regular_expr_or_data *__ref2 = (Parser_Lel_regular_expr_or_data*)&rhs[1]->user.regular_expr_or_data;
+#line 1015 "rlparse.kl"
+
+ /* Create a new factor node going to an OR expression. */
+ (__ref0)->factor = new Factor( new ReItem( (__ref1)->loc, (__ref2)->reOrBlock, ReItem::OrBlock ) );
+
+
+#line 5870 "rlparse.cpp"
+} break;
+case 177: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_regular_expr_or_data *__ref2 = (Parser_Lel_regular_expr_or_data*)&rhs[1]->user.regular_expr_or_data;
+#line 1020 "rlparse.kl"
+
+ /* Create a new factor node going to a negated OR expression. */
+ (__ref0)->factor = new Factor( new ReItem( (__ref1)->loc, (__ref2)->reOrBlock, ReItem::NegOrBlock ) );
+
+
+#line 5882 "rlparse.cpp"
+} break;
+case 178: {
+Token *__ref0 = (Token*)&rhs[2]->user.token;
+Token *__ref1 = (Token*)&rhs[2]->user.token;
+Parser_Lel_regular_expr *__ref2 = (Parser_Lel_regular_expr*)&rhs[1]->user.regular_expr;
+Parser_Lel_factor *__ref3 = (Parser_Lel_factor*)&redLel->user.factor;
+Parser_Lel_regular_expr *__ref4 = (Parser_Lel_regular_expr*)&rhs[1]->user.regular_expr;
+#line 1025 "rlparse.kl"
+
+ if ( (__ref0)->length > 1 ) {
+ for ( char *p = (__ref1)->data; *p != 0; p++ ) {
+ if ( *p == 'i' )
+ (__ref2)->regExpr->caseInsensitive = true;
+ }
+ }
+
+ /* Create a new factor node going to a regular exp. */
+ (__ref3)->factor = new Factor( (__ref4)->regExpr );
+
+
+#line 5903 "rlparse.cpp"
+} break;
+case 179: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Parser_Lel_range_lit *__ref1 = (Parser_Lel_range_lit*)&rhs[0]->user.range_lit;
+Parser_Lel_range_lit *__ref2 = (Parser_Lel_range_lit*)&rhs[2]->user.range_lit;
+#line 1037 "rlparse.kl"
+
+ /* Create a new factor node going to a range. */
+ (__ref0)->factor = new Factor( new Range( (__ref1)->literal, (__ref2)->literal ) );
+
+
+#line 5915 "rlparse.cpp"
+} break;
+case 180: {
+Parser_Lel_factor *__ref0 = (Parser_Lel_factor*)&redLel->user.factor;
+Parser_Lel_join *__ref1 = (Parser_Lel_join*)&rhs[1]->user.join;
+Parser_Lel_join *__ref2 = (Parser_Lel_join*)&rhs[1]->user.join;
+Token *__ref3 = (Token*)&rhs[0]->user.token;
+#line 1042 "rlparse.kl"
+
+ /* Create a new factor going to a parenthesized join. */
+ (__ref0)->factor = new Factor( (__ref1)->join );
+ (__ref2)->join->loc = (__ref3)->loc;
+
+
+#line 5929 "rlparse.cpp"
+} break;
+case 181: {
+Parser_Lel_range_lit *__ref0 = (Parser_Lel_range_lit*)&redLel->user.range_lit;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1055 "rlparse.kl"
+
+ /* Range literas must have only one char. We restrict this in the parse tree. */
+ (__ref0)->literal = new Literal( *(__ref1), Literal::LitString );
+
+
+#line 5940 "rlparse.cpp"
+} break;
+case 182: {
+Parser_Lel_range_lit *__ref0 = (Parser_Lel_range_lit*)&redLel->user.range_lit;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 1060 "rlparse.kl"
+
+ /* Create a new literal number. */
+ (__ref0)->literal = new Literal( (__ref1)->token, Literal::Number );
+
+
+#line 5951 "rlparse.cpp"
+} break;
+case 183: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1069 "rlparse.kl"
+
+ (__ref0)->token = *(__ref1);
+
+
+#line 5961 "rlparse.cpp"
+} break;
+case 184: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Parser_Lel_token_type *__ref3 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref4 = (Token*)&rhs[1]->user.token;
+#line 1073 "rlparse.kl"
+
+ (__ref0)->token.set( "-", 1 );
+ (__ref1)->token.loc = (__ref2)->loc;
+ (__ref3)->token.append( *(__ref4) );
+
+
+#line 5976 "rlparse.cpp"
+} break;
+case 185: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1079 "rlparse.kl"
+
+ (__ref0)->token = *(__ref1);
+
+
+#line 5986 "rlparse.cpp"
+} break;
+case 186: {
+Parser_Lel_regular_expr_item *__ref0 = (Parser_Lel_regular_expr_item*)&rhs[1]->user.regular_expr_item;
+Parser_Lel_regular_expr_item *__ref1 = (Parser_Lel_regular_expr_item*)&rhs[1]->user.regular_expr_item;
+Parser_Lel_regular_expr *__ref2 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr *__ref3 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr *__ref4 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr *__ref5 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr_item *__ref6 = (Parser_Lel_regular_expr_item*)&rhs[1]->user.regular_expr_item;
+Parser_Lel_regular_expr_item *__ref7 = (Parser_Lel_regular_expr_item*)&rhs[1]->user.regular_expr_item;
+Parser_Lel_regular_expr *__ref8 = (Parser_Lel_regular_expr*)&redLel->user.regular_expr;
+Parser_Lel_regular_expr *__ref9 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr *__ref10 = (Parser_Lel_regular_expr*)&redLel->user.regular_expr;
+Parser_Lel_regular_expr *__ref11 = (Parser_Lel_regular_expr*)&rhs[0]->user.regular_expr;
+Parser_Lel_regular_expr_item *__ref12 = (Parser_Lel_regular_expr_item*)&rhs[1]->user.regular_expr_item;
+#line 1094 "rlparse.kl"
+
+ /* An optimization to lessen the tree size. If a non-starred char is
+ * directly under the left side on the right and the right side is
+ * another non-starred char then paste them together and return the
+ * left side. Otherwise just put the two under a new reg exp node. */
+ if ( (__ref0)->reItem->type == ReItem::Data && !(__ref1)->reItem->star &&
+ (__ref2)->regExpr->type == RegExpr::RecurseItem &&
+ (__ref3)->regExpr->item->type == ReItem::Data && !(__ref4)->regExpr->item->star )
+ {
+ /* Append the right side to the right side of the left and toss the
+ * right side. */
+ (__ref5)->regExpr->item->token.append( (__ref6)->reItem->token );
+ delete (__ref7)->reItem;
+ (__ref8)->regExpr = (__ref9)->regExpr;
+ }
+ else {
+ (__ref10)->regExpr = new RegExpr( (__ref11)->regExpr, (__ref12)->reItem );
+ }
+
+
+#line 6023 "rlparse.cpp"
+} break;
+case 187: {
+Parser_Lel_regular_expr *__ref0 = (Parser_Lel_regular_expr*)&redLel->user.regular_expr;
+#line 1114 "rlparse.kl"
+
+ /* Can't optimize the tree. */
+ (__ref0)->regExpr = new RegExpr();
+
+
+#line 6033 "rlparse.cpp"
+} break;
+case 188: {
+Parser_Lel_regular_expr_char *__ref0 = (Parser_Lel_regular_expr_char*)&rhs[0]->user.regular_expr_char;
+Parser_Lel_regular_expr_item *__ref1 = (Parser_Lel_regular_expr_item*)&redLel->user.regular_expr_item;
+Parser_Lel_regular_expr_char *__ref2 = (Parser_Lel_regular_expr_char*)&rhs[0]->user.regular_expr_char;
+#line 1126 "rlparse.kl"
+
+ (__ref0)->reItem->star = true;
+ (__ref1)->reItem = (__ref2)->reItem;
+
+
+#line 6045 "rlparse.cpp"
+} break;
+case 189: {
+Parser_Lel_regular_expr_item *__ref0 = (Parser_Lel_regular_expr_item*)&redLel->user.regular_expr_item;
+Parser_Lel_regular_expr_char *__ref1 = (Parser_Lel_regular_expr_char*)&rhs[0]->user.regular_expr_char;
+#line 1131 "rlparse.kl"
+
+ (__ref0)->reItem = (__ref1)->reItem;
+
+
+#line 6055 "rlparse.cpp"
+} break;
+case 190: {
+Parser_Lel_regular_expr_char *__ref0 = (Parser_Lel_regular_expr_char*)&redLel->user.regular_expr_char;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_regular_expr_or_data *__ref2 = (Parser_Lel_regular_expr_or_data*)&rhs[1]->user.regular_expr_or_data;
+#line 1143 "rlparse.kl"
+
+ (__ref0)->reItem = new ReItem( (__ref1)->loc, (__ref2)->reOrBlock, ReItem::OrBlock );
+
+
+#line 6066 "rlparse.cpp"
+} break;
+case 191: {
+Parser_Lel_regular_expr_char *__ref0 = (Parser_Lel_regular_expr_char*)&redLel->user.regular_expr_char;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_regular_expr_or_data *__ref2 = (Parser_Lel_regular_expr_or_data*)&rhs[1]->user.regular_expr_or_data;
+#line 1147 "rlparse.kl"
+
+ (__ref0)->reItem = new ReItem( (__ref1)->loc, (__ref2)->reOrBlock, ReItem::NegOrBlock );
+
+
+#line 6077 "rlparse.cpp"
+} break;
+case 192: {
+Parser_Lel_regular_expr_char *__ref0 = (Parser_Lel_regular_expr_char*)&redLel->user.regular_expr_char;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1151 "rlparse.kl"
+
+ (__ref0)->reItem = new ReItem( (__ref1)->loc, ReItem::Dot );
+
+
+#line 6087 "rlparse.cpp"
+} break;
+case 193: {
+Parser_Lel_regular_expr_char *__ref0 = (Parser_Lel_regular_expr_char*)&redLel->user.regular_expr_char;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+#line 1155 "rlparse.kl"
+
+ (__ref0)->reItem = new ReItem( (__ref1)->loc, *(__ref2) );
+
+
+#line 6098 "rlparse.cpp"
+} break;
+case 194: {
+Parser_Lel_regular_expr_or_char *__ref0 = (Parser_Lel_regular_expr_or_char*)&rhs[1]->user.regular_expr_or_char;
+Parser_Lel_regular_expr_or_data *__ref1 = (Parser_Lel_regular_expr_or_data*)&rhs[0]->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_data *__ref2 = (Parser_Lel_regular_expr_or_data*)&rhs[0]->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_data *__ref3 = (Parser_Lel_regular_expr_or_data*)&rhs[0]->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_char *__ref4 = (Parser_Lel_regular_expr_or_char*)&rhs[1]->user.regular_expr_or_char;
+Parser_Lel_regular_expr_or_char *__ref5 = (Parser_Lel_regular_expr_or_char*)&rhs[1]->user.regular_expr_or_char;
+Parser_Lel_regular_expr_or_data *__ref6 = (Parser_Lel_regular_expr_or_data*)&redLel->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_data *__ref7 = (Parser_Lel_regular_expr_or_data*)&rhs[0]->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_data *__ref8 = (Parser_Lel_regular_expr_or_data*)&redLel->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_data *__ref9 = (Parser_Lel_regular_expr_or_data*)&rhs[0]->user.regular_expr_or_data;
+Parser_Lel_regular_expr_or_char *__ref10 = (Parser_Lel_regular_expr_or_char*)&rhs[1]->user.regular_expr_or_char;
+#line 1167 "rlparse.kl"
+
+ /* An optimization to lessen the tree size. If an or char is directly
+ * under the left side on the right and the right side is another or
+ * char then paste them together and return the left side. Otherwise
+ * just put the two under a new or data node. */
+ if ( (__ref0)->reOrItem->type == ReOrItem::Data &&
+ (__ref1)->reOrBlock->type == ReOrBlock::RecurseItem &&
+ (__ref2)->reOrBlock->item->type == ReOrItem::Data )
+ {
+ /* Append the right side to right side of the left and toss the
+ * right side. */
+ (__ref3)->reOrBlock->item->token.append( (__ref4)->reOrItem->token );
+ delete (__ref5)->reOrItem;
+ (__ref6)->reOrBlock = (__ref7)->reOrBlock;
+ }
+ else {
+ /* Can't optimize, put the left and right under a new node. */
+ (__ref8)->reOrBlock = new ReOrBlock( (__ref9)->reOrBlock, (__ref10)->reOrItem );
+ }
+
+
+#line 6134 "rlparse.cpp"
+} break;
+case 195: {
+Parser_Lel_regular_expr_or_data *__ref0 = (Parser_Lel_regular_expr_or_data*)&redLel->user.regular_expr_or_data;
+#line 1188 "rlparse.kl"
+
+ (__ref0)->reOrBlock = new ReOrBlock();
+
+
+#line 6143 "rlparse.cpp"
+} break;
+case 196: {
+Parser_Lel_regular_expr_or_char *__ref0 = (Parser_Lel_regular_expr_or_char*)&redLel->user.regular_expr_or_char;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+#line 1200 "rlparse.kl"
+
+ (__ref0)->reOrItem = new ReOrItem( (__ref1)->loc, *(__ref2) );
+
+
+#line 6154 "rlparse.cpp"
+} break;
+case 197: {
+Parser_Lel_regular_expr_or_char *__ref0 = (Parser_Lel_regular_expr_or_char*)&redLel->user.regular_expr_or_char;
+Token *__ref1 = (Token*)&rhs[1]->user.token;
+Token *__ref2 = (Token*)&rhs[0]->user.token;
+Token *__ref3 = (Token*)&rhs[2]->user.token;
+#line 1204 "rlparse.kl"
+
+ (__ref0)->reOrItem = new ReOrItem( (__ref1)->loc, (__ref2)->data[0], (__ref3)->data[0] );
+
+
+#line 6166 "rlparse.cpp"
+} break;
+case 198: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[0]->user.inline_list;
+Parser_Lel_inline_list *__ref2 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+Parser_Lel_inline_item *__ref3 = (Parser_Lel_inline_item*)&rhs[1]->user.inline_item;
+#line 1221 "rlparse.kl"
+
+ /* Append the item to the list, return the list. */
+ (__ref0)->inlineList = (__ref1)->inlineList;
+ (__ref2)->inlineList->append( (__ref3)->inlineItem );
+
+
+#line 6180 "rlparse.cpp"
+} break;
+case 199: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+#line 1228 "rlparse.kl"
+
+ /* Start with empty list. */
+ (__ref0)->inlineList = new InlineList;
+
+
+#line 6190 "rlparse.cpp"
+} break;
+case 200: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 1243 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->token.loc, (__ref2)->token.data, InlineItem::Text );
+
+
+#line 6201 "rlparse.cpp"
+} break;
+case 201: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 1249 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->token.loc, (__ref2)->token.data, InlineItem::Text );
+
+
+#line 6212 "rlparse.cpp"
+} break;
+case 202: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_item *__ref1 = (Parser_Lel_inline_item*)&rhs[0]->user.inline_item;
+#line 1255 "rlparse.kl"
+
+ /* Pass the inline item up. */
+ (__ref0)->inlineItem = (__ref1)->inlineItem;
+
+
+#line 6223 "rlparse.cpp"
+} break;
+case 203: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1262 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6231 "rlparse.cpp"
+} break;
+case 204: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1263 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6239 "rlparse.cpp"
+} break;
+case 205: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1264 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6247 "rlparse.cpp"
+} break;
+case 206: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1265 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6255 "rlparse.cpp"
+} break;
+case 207: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1266 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6263 "rlparse.cpp"
+} break;
+case 208: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1267 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6271 "rlparse.cpp"
+} break;
+case 209: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_item *__ref1 = (Parser_Lel_inline_item*)&rhs[0]->user.inline_item;
+#line 1271 "rlparse.kl"
+
+ /* Pass up interpreted items of inline expressions. */
+ (__ref0)->inlineItem = (__ref1)->inlineItem;
+
+
+#line 6282 "rlparse.cpp"
+} break;
+case 210: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1276 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Hold );
+
+
+#line 6292 "rlparse.cpp"
+} break;
+case 211: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_inline_item *__ref2 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_list *__ref3 = (Parser_Lel_inline_list*)&rhs[1]->user.inline_list;
+#line 1280 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Exec );
+ (__ref2)->inlineItem->children = (__ref3)->inlineList;
+
+
+#line 6305 "rlparse.cpp"
+} break;
+case 212: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1285 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc,
+ new NameRef(nameRef), InlineItem::Goto );
+
+
+#line 6316 "rlparse.cpp"
+} break;
+case 213: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_inline_item *__ref2 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_list *__ref3 = (Parser_Lel_inline_list*)&rhs[2]->user.inline_list;
+#line 1290 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::GotoExpr );
+ (__ref2)->inlineItem->children = (__ref3)->inlineList;
+
+
+#line 6329 "rlparse.cpp"
+} break;
+case 214: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1295 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, new NameRef(nameRef), InlineItem::Next );
+
+
+#line 6339 "rlparse.cpp"
+} break;
+case 215: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_inline_item *__ref2 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_list *__ref3 = (Parser_Lel_inline_list*)&rhs[2]->user.inline_list;
+#line 1299 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::NextExpr );
+ (__ref2)->inlineItem->children = (__ref3)->inlineList;
+
+
+#line 6352 "rlparse.cpp"
+} break;
+case 216: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1304 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, new NameRef(nameRef), InlineItem::Call );
+
+
+#line 6362 "rlparse.cpp"
+} break;
+case 217: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+Parser_Lel_inline_item *__ref2 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_list *__ref3 = (Parser_Lel_inline_list*)&rhs[2]->user.inline_list;
+#line 1308 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::CallExpr );
+ (__ref2)->inlineItem->children = (__ref3)->inlineList;
+
+
+#line 6375 "rlparse.cpp"
+} break;
+case 218: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1313 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Ret );
+
+
+#line 6385 "rlparse.cpp"
+} break;
+case 219: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1317 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Break );
+
+
+#line 6395 "rlparse.cpp"
+} break;
+case 220: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+Parser_Lel_inline_list *__ref1 = (Parser_Lel_inline_list*)&rhs[0]->user.inline_list;
+Parser_Lel_inline_list *__ref2 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+Parser_Lel_inline_item *__ref3 = (Parser_Lel_inline_item*)&rhs[1]->user.inline_item;
+#line 1325 "rlparse.kl"
+
+ (__ref0)->inlineList = (__ref1)->inlineList;
+ (__ref2)->inlineList->append( (__ref3)->inlineItem );
+
+
+#line 6408 "rlparse.cpp"
+} break;
+case 221: {
+Parser_Lel_inline_list *__ref0 = (Parser_Lel_inline_list*)&redLel->user.inline_list;
+#line 1330 "rlparse.kl"
+
+ /* Init the list used for this expr. */
+ (__ref0)->inlineList = new InlineList;
+
+
+#line 6418 "rlparse.cpp"
+} break;
+case 222: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 1339 "rlparse.kl"
+
+ /* Return a text segment. */
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->token.loc, (__ref2)->token.data, InlineItem::Text );
+
+
+#line 6430 "rlparse.cpp"
+} break;
+case 223: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_token_type *__ref1 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+Parser_Lel_token_type *__ref2 = (Parser_Lel_token_type*)&rhs[0]->user.token_type;
+#line 1345 "rlparse.kl"
+
+ /* Return a text segment, must heap alloc the text. */
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->token.loc, (__ref2)->token.data, InlineItem::Text );
+
+
+#line 6442 "rlparse.cpp"
+} break;
+case 224: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Parser_Lel_inline_item *__ref1 = (Parser_Lel_inline_item*)&rhs[0]->user.inline_item;
+#line 1351 "rlparse.kl"
+
+ /* Pass the inline item up. */
+ (__ref0)->inlineItem = (__ref1)->inlineItem;
+
+
+#line 6453 "rlparse.cpp"
+} break;
+case 237: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1381 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::PChar );
+
+
+#line 6463 "rlparse.cpp"
+} break;
+case 238: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1386 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Char );
+
+
+#line 6473 "rlparse.cpp"
+} break;
+case 239: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1391 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Curs );
+
+
+#line 6483 "rlparse.cpp"
+} break;
+case 240: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1396 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc, InlineItem::Targs );
+
+
+#line 6493 "rlparse.cpp"
+} break;
+case 241: {
+Parser_Lel_inline_item *__ref0 = (Parser_Lel_inline_item*)&redLel->user.inline_item;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1401 "rlparse.kl"
+
+ (__ref0)->inlineItem = new InlineItem( (__ref1)->loc,
+ new NameRef(nameRef), InlineItem::Entry );
+
+
+#line 6504 "rlparse.cpp"
+} break;
+case 243: {
+#line 1412 "rlparse.kl"
+
+ nameRef.empty();
+
+
+#line 6512 "rlparse.cpp"
+} break;
+case 245: {
+#line 1422 "rlparse.kl"
+
+ /* Insert an initial null pointer val to indicate the existence of the
+ * initial name seperator. */
+ nameRef.setAs( 0 );
+
+
+#line 6522 "rlparse.cpp"
+} break;
+case 246: {
+#line 1428 "rlparse.kl"
+
+ nameRef.empty();
+
+
+#line 6530 "rlparse.cpp"
+} break;
+case 247: {
+Token *__ref0 = (Token*)&rhs[2]->user.token;
+#line 1435 "rlparse.kl"
+
+ nameRef.append( (__ref0)->data );
+
+
+#line 6539 "rlparse.cpp"
+} break;
+case 248: {
+Token *__ref0 = (Token*)&rhs[0]->user.token;
+#line 1440 "rlparse.kl"
+
+ nameRef.append( (__ref0)->data );
+
+
+#line 6548 "rlparse.cpp"
+} break;
+}
+ }
+
+ if ( lel->child != 0 ) {
+ struct Parser_LangEl *first = lel->child;
+ struct Parser_LangEl *child = lel->child;
+ lel->child = 0;
+ while ( 1 ) {
+ if ( child->type < 226 ) {
+ }
+ else {
+ }
+ numNodes -= 1;
+ if ( child->next == 0 )
+ break;
+ child = child->next;
+ }
+ child->next = pool;
+ pool = first;
+ }
+ }
+
+commit_base:
+ if ( sp > 0 ) {
+ sp -= 1;
+ if ( lel->retry == 0 ) {
+ lel = lel->prev;
+ goto commit_reverse;
+ }
+ else {
+ lel->retry = 0;
+ lel = lel->prev;
+ goto commit_upwards;
+ }
+ }
+ lel->retry = 0;
+
+ lastFinal = lel;
+ numRetry = 0;
+ }
+
+ if ( *action & 0x2 ) {
+ int reduction = *action >> 2;
+ struct Parser_LangEl *redLel;
+
+ if ( input != 0 )
+ input->causeReduce += 1;
+
+ if ( pool == 0 ) {
+ if ( freshPos == 8128 ) {
+ struct Parser_Block* newBlock = (struct Parser_Block*) malloc( sizeof(struct Parser_Block) );
+ newBlock->next = block;
+ block = newBlock;
+ freshEl = newBlock->data;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "allocating 8128 LangEls" << endl;
+ #endif
+ freshPos = 0;
+ }
+ redLel = freshEl + freshPos++;
+ }
+ else {
+ redLel = pool;
+ pool = pool->next;
+ }
+ numNodes += 1;
+
+ redLel->type = Parser_prodLhsIds[reduction];
+ redLel->reduction = reduction;
+ redLel->child = 0;
+ redLel->next = 0;
+ redLel->retry = (lel->retry << 16);
+ redLel->causeReduce = 0;
+ lel->retry &= 0xffff0000;
+
+ rhsLen = Parser_prodLengths[reduction];
+ if ( rhsLen > 0 ) {
+ int r;
+ for ( r = rhsLen-1; r > 0; r-- ) {
+ rhs[r] = stackTop;
+ stackTop = stackTop->next;
+ }
+ rhs[0] = stackTop;
+ stackTop = stackTop->next;
+ rhs[0]->next = 0;
+ }
+switch ( reduction ) {
+case 225: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1358 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6643 "rlparse.cpp"
+} break;
+case 226: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1359 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6651 "rlparse.cpp"
+} break;
+case 227: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1360 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6659 "rlparse.cpp"
+} break;
+case 228: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1361 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6667 "rlparse.cpp"
+} break;
+case 229: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1362 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6675 "rlparse.cpp"
+} break;
+case 230: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1363 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6683 "rlparse.cpp"
+} break;
+case 231: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1364 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6691 "rlparse.cpp"
+} break;
+case 232: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1371 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6699 "rlparse.cpp"
+} break;
+case 233: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1372 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6707 "rlparse.cpp"
+} break;
+case 234: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1373 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6715 "rlparse.cpp"
+} break;
+case 235: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1374 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6723 "rlparse.cpp"
+} break;
+case 236: {
+Parser_Lel_token_type *__ref0 = (Parser_Lel_token_type*)&redLel->user.token_type;
+Token *__ref1 = (Token*)&rhs[0]->user.token;
+#line 1375 "rlparse.kl"
+ (__ref0)->token = *(__ref1);
+
+#line 6731 "rlparse.cpp"
+} break;
+}
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "reduced: "
+ << Parser_prodNames[reduction]
+ << " rhsLen: " << rhsLen;
+ #endif
+ if ( action[1] == 0 )
+ redLel->retry = 0;
+ else {
+ redLel->retry += 0x10000;
+ numRetry += 1;
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << " retry: " << redLel;
+ #endif
+ }
+
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << endl;
+ #endif
+
+ if ( rhsLen == 0 ) {
+ redLel->file = lel->file;
+ redLel->line = lel->line;
+ targState = curs;
+ }
+ else {
+ redLel->child = rhs[rhsLen-1];
+ redLel->file = rhs[0]->file;
+ redLel->line = rhs[0]->line;
+ targState = rhs[0]->state;
+ }
+
+ if ( induceReject ) {
+ #ifdef KELBT_LOG_ACTIONS
+ cerr << "error induced during reduction of " <<
+ Parser_lelNames[redLel->type] << endl;
+ #endif
+ redLel->state = curs;
+ redLel->next = stackTop;
+ stackTop = redLel;
+ curs = targState;
+ goto parseError;
+ }
+ else {
+ redLel->next = input;
+ input = redLel;
+ }
+ }
+
+
+ curs = targState;
+ goto again;
+
+parseError:
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "hit error" << endl;
+ #endif
+ if ( numRetry > 0 ) {
+ struct Parser_LangEl *redLel;
+
+ if ( input != 0 ) {
+ redLel = input;
+ goto have_undo_element;
+ }
+
+ while ( 1 ) {
+ redLel = stackTop;
+ if ( stackTop->type < 226 ) {
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "backing up over terminal: " <<
+ Parser_lelNames[stackTop->type] << endl;
+ #endif
+ stackTop = stackTop->next;
+ redLel->next = input;
+ input = redLel;
+ }
+ else {
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "backing up over non-terminal: " <<
+ Parser_lelNames[stackTop->type] << endl;
+ #endif
+ stackTop = stackTop->next;
+ struct Parser_LangEl *first = redLel->child;
+ if ( first == 0 )
+ rhsLen = 0;
+ else {
+ rhsLen = 1;
+ while ( first->next != 0 ) {
+ first = first->next;
+ rhsLen += 1;
+ }
+ first->next = stackTop;
+ stackTop = redLel->child;
+
+ struct Parser_LangEl *rhsEl = stackTop;
+ int p = rhsLen;
+ while ( p > 0 ) {
+ rhs[--p] = rhsEl;
+ rhsEl = rhsEl->next;
+ }
+ }
+ redLel->next = pool;
+ pool = redLel;
+ numNodes -= 1;
+
+ if ( input != 0 )
+ input->causeReduce -= 1;
+ }
+
+have_undo_element:
+ if ( redLel->retry == 0 ) {
+ if ( input != 0 && input->causeReduce == 0 ) {
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "pushing back: " << Parser_lelNames[input->type] << endl;
+ #endif
+ input->next = queue;
+ queue = input;
+ input = 0;
+ }
+ }
+ else {
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "found retry targ: " << redLel << endl;
+ #endif
+ numRetry -= 1;
+ #ifdef KELBT_LOG_BACKTRACK
+ cerr << "found retry: " << redLel << endl;
+ #endif
+ if ( redLel->retry & 0x0000ffff )
+ curs = input->state;
+ else {
+ input->retry = redLel->retry >> 16;
+ if ( stackTop->state < 0 )
+ curs = Parser_startState;
+ else {
+ curs = Parser_targs[(int)Parser_indicies[Parser_offsets[stackTop->state] + (stackTop->type - Parser_keys[stackTop->state<<1])]];
+ }
+ }
+ goto again;
+ }
+ }
+ }
+ curs = -1;
+ errCount += 1;
+_out: {}
+#line 1459 "rlparse.kl"
+ return errCount == 0 ? 0 : -1;
+}
+
+void Parser::tryMachineDef( InputLoc &loc, char *name,
+ MachineDef *machineDef, bool isInstance )
+{
+ GraphDictEl *newEl = pd->graphDict.insert( name );
+ if ( newEl != 0 ) {
+ /* New element in the dict, all good. */
+ newEl->value = new VarDef( name, machineDef );
+ newEl->isInstance = isInstance;
+ newEl->loc = loc;
+ newEl->value->isExport = exportContext[exportContext.length()-1];
+
+ /* It it is an instance, put on the instance list. */
+ if ( isInstance )
+ pd->instanceList.append( newEl );
+ }
+ else {
+ // Recover by ignoring the duplicate.
+ error(loc) << "fsm \"" << name << "\" previously defined" << endl;
+ }
+}
+
+ostream &Parser::parse_error( int tokId, Token &token )
+{
+ /* Maintain the error count. */
+ gblErrorCount += 1;
+
+ cerr << token.loc << ": ";
+ cerr << "at token ";
+ if ( tokId < 128 )
+ cerr << "\"" << Parser_lelNames[tokId] << "\"";
+ else
+ cerr << Parser_lelNames[tokId];
+ if ( token.data != 0 )
+ cerr << " with data \"" << token.data << "\"";
+ cerr << ": ";
+
+ return cerr;
+}
+
+int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
+{
+ Token token;
+ token.data = tokstart;
+ token.length = toklen;
+ token.loc = loc;
+ int res = parseLangEl( tokId, &token );
+ if ( res < 0 ) {
+ parse_error(tokId, token) << "parse error" << endl;
+ exit(1);
+ }
+ return res;
+}
diff --git a/ragel/rlparse.h b/ragel/rlparse.h
new file mode 100644
index 0000000..e3f7c3c
--- /dev/null
+++ b/ragel/rlparse.h
@@ -0,0 +1,210 @@
+/* Automatically generated by Kelbt from "rlparse.kh".
+ *
+ * Parts of this file are copied from Kelbt source covered by the GNU
+ * GPL. As a special exception, you may use the parts of this file copied
+ * from Kelbt source without restriction. The remainder is derived from
+ * "rlparse.kh" and inherits the copyright status of that file.
+ */
+
+#line 1 "rlparse.kh"
+/*
+ * Copyright 2001-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
+ */
+
+#ifndef _RLPARSE_H
+#define _RLPARSE_H
+
+#include <iostream>
+#include "avltree.h"
+#include "parsedata.h"
+
+
+/* Import scanner tokens. */
+#define IMP_Word 128
+#define IMP_Literal 129
+#define IMP_UInt 130
+#define IMP_Define 131
+
+/* This is used for tracking the include files/machine pairs. */
+struct IncludeHistoryItem
+{
+ IncludeHistoryItem( const char *fileName, const char *sectionName )
+ : fileName(fileName), sectionName(sectionName) {}
+
+ const char *fileName;
+ const char *sectionName;
+};
+
+typedef Vector<IncludeHistoryItem> IncludeHistory;
+
+struct Parser
+{
+#line 102 "rlparse.kh"
+
+
+ #line 63 "rlparse.h"
+ struct Parser_Block *block;
+ struct Parser_LangEl *freshEl;
+ int freshPos;
+ struct Parser_LangEl *pool;
+ int numRetry;
+ int numNodes;
+ struct Parser_LangEl *stackTop;
+ struct Parser_LangEl *lastFinal;
+ int errCount;
+ int curs;
+#line 105 "rlparse.kh"
+
+ void init();
+ int parseLangEl( int type, const Token *token );
+
+ Parser( const char *fileName, char *sectionName, InputLoc &sectionLoc )
+ : sectionName(sectionName)
+ {
+ pd = new ParseData( fileName, sectionName, sectionLoc );
+ exportContext.append( false );
+ includeHistory.append( IncludeHistoryItem(
+ fileName, sectionName ) );
+ }
+
+ int token( InputLoc &loc, int tokId, char *tokstart, int toklen );
+ void tryMachineDef( InputLoc &loc, char *name,
+ MachineDef *machineDef, bool isInstance );
+
+ /* Report an error encountered by the parser. */
+ ostream &parse_error( int tokId, Token &token );
+
+ ParseData *pd;
+
+ /* The name of the root section, this does not change during an include. */
+ char *sectionName;
+
+ NameRef nameRef;
+ NameRefList nameRefList;
+
+ Vector<bool> exportContext;
+ IncludeHistory includeHistory;
+
+ Parser *prev, *next;
+};
+
+#line 109 "rlparse.h"
+#define TK_Word 128
+#define TK_Literal 129
+#define TK_Number 130
+#define TK_EndSection 131
+#define TK_UInt 132
+#define TK_Hex 133
+#define TK_DotDot 134
+#define TK_ColonGt 135
+#define TK_ColonGtGt 136
+#define TK_LtColon 137
+#define TK_Arrow 138
+#define TK_DoubleArrow 139
+#define TK_StarStar 140
+#define TK_ColonEquals 141
+#define TK_NameSep 142
+#define TK_BarStar 143
+#define TK_DashDash 144
+#define TK_StartCond 145
+#define TK_AllCond 146
+#define TK_LeavingCond 147
+#define TK_Middle 148
+#define TK_StartGblError 149
+#define TK_AllGblError 150
+#define TK_FinalGblError 151
+#define TK_NotFinalGblError 152
+#define TK_NotStartGblError 153
+#define TK_MiddleGblError 154
+#define TK_StartLocalError 155
+#define TK_AllLocalError 156
+#define TK_FinalLocalError 157
+#define TK_NotFinalLocalError 158
+#define TK_NotStartLocalError 159
+#define TK_MiddleLocalError 160
+#define TK_StartEOF 161
+#define TK_AllEOF 162
+#define TK_FinalEOF 163
+#define TK_NotFinalEOF 164
+#define TK_NotStartEOF 165
+#define TK_MiddleEOF 166
+#define TK_StartToState 167
+#define TK_AllToState 168
+#define TK_FinalToState 169
+#define TK_NotFinalToState 170
+#define TK_NotStartToState 171
+#define TK_MiddleToState 172
+#define TK_StartFromState 173
+#define TK_AllFromState 174
+#define TK_FinalFromState 175
+#define TK_NotFinalFromState 176
+#define TK_NotStartFromState 177
+#define TK_MiddleFromState 178
+#define RE_Slash 179
+#define RE_SqOpen 180
+#define RE_SqOpenNeg 181
+#define RE_SqClose 182
+#define RE_Dot 183
+#define RE_Star 184
+#define RE_Dash 185
+#define RE_Char 186
+#define IL_WhiteSpace 187
+#define IL_Comment 188
+#define IL_Literal 189
+#define IL_Symbol 190
+#define KW_Machine 191
+#define KW_Include 192
+#define KW_Import 193
+#define KW_Write 194
+#define KW_Action 195
+#define KW_AlphType 196
+#define KW_Range 197
+#define KW_GetKey 198
+#define KW_InWhen 199
+#define KW_When 200
+#define KW_OutWhen 201
+#define KW_Eof 202
+#define KW_Err 203
+#define KW_Lerr 204
+#define KW_To 205
+#define KW_From 206
+#define KW_Export 207
+#define KW_PrePush 208
+#define KW_PostPop 209
+#define KW_Length 210
+#define KW_Break 211
+#define KW_Exec 212
+#define KW_Hold 213
+#define KW_PChar 214
+#define KW_Char 215
+#define KW_Goto 216
+#define KW_Call 217
+#define KW_Ret 218
+#define KW_CurState 219
+#define KW_TargState 220
+#define KW_Entry 221
+#define KW_Next 222
+#define KW_Variable 223
+#define KW_Access 224
+#define Parser_tk_eof 225
+
+#line 140 "rlparse.kh"
+
+#endif
diff --git a/ragel/rlparse.kh b/ragel/rlparse.kh
new file mode 100644
index 0000000..899bbbc
--- /dev/null
+++ b/ragel/rlparse.kh
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2001-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
+ */
+
+#ifndef _RLPARSE_H
+#define _RLPARSE_H
+
+#include <iostream>
+#include "avltree.h"
+#include "parsedata.h"
+
+
+/* Import scanner tokens. */
+#define IMP_Word 128
+#define IMP_Literal 129
+#define IMP_UInt 130
+#define IMP_Define 131
+
+/* This is used for tracking the include files/machine pairs. */
+struct IncludeHistoryItem
+{
+ IncludeHistoryItem( const char *fileName, const char *sectionName )
+ : fileName(fileName), sectionName(sectionName) {}
+
+ const char *fileName;
+ const char *sectionName;
+};
+
+typedef Vector<IncludeHistoryItem> IncludeHistory;
+
+struct Parser
+{
+%%{
+ parser Parser;
+
+ # General tokens.
+ token TK_Word, TK_Literal, TK_Number, TK_EndSection, TK_UInt, TK_Hex,
+ TK_Word, TK_Literal, TK_DotDot, TK_ColonGt, TK_ColonGtGt, TK_LtColon,
+ TK_Arrow, TK_DoubleArrow, TK_StarStar, TK_ColonEquals, TK_NameSep,
+ TK_BarStar, TK_DashDash;
+
+ # Conditions.
+ token TK_StartCond, TK_AllCond, TK_LeavingCond;
+
+ # State embedding actions.
+ token TK_Middle;
+
+ # Global error actions.
+ token TK_StartGblError, TK_AllGblError, TK_FinalGblError,
+ TK_NotFinalGblError, TK_NotStartGblError, TK_MiddleGblError;
+
+ # Local error actions.
+ token TK_StartLocalError, TK_AllLocalError, TK_FinalLocalError,
+ TK_NotFinalLocalError, TK_NotStartLocalError, TK_MiddleLocalError;
+
+ # EOF Action embedding.
+ token TK_StartEOF, TK_AllEOF, TK_FinalEOF, TK_NotFinalEOF, TK_NotStartEOF,
+ TK_MiddleEOF;
+
+ # To State Actions.
+ token TK_StartToState, TK_AllToState, TK_FinalToState, TK_NotFinalToState,
+ TK_NotStartToState, TK_MiddleToState;
+
+ # In State Actions.
+ token TK_StartFromState, TK_AllFromState, TK_FinalFromState,
+ TK_NotFinalFromState, TK_NotStartFromState, TK_MiddleFromState;
+
+ # Regular expression tokens. */
+ token RE_Slash, RE_SqOpen, RE_SqOpenNeg, RE_SqClose, RE_Dot, RE_Star,
+ RE_Dash, RE_Char;
+
+ # Tokens specific to inline code.
+ token IL_WhiteSpace, IL_Comment, IL_Literal, IL_Symbol;
+
+ # Keywords.
+ token KW_Machine, KW_Include, KW_Import, KW_Write, KW_Action, KW_AlphType,
+ KW_Range, KW_GetKey, KW_Include, KW_Write, KW_Machine, KW_InWhen,
+ KW_When, KW_OutWhen, KW_Eof, KW_Err, KW_Lerr, KW_To, KW_From,
+ KW_Export, KW_PrePush, KW_PostPop, KW_Length;
+
+ # Specials in code blocks.
+ token KW_Break, KW_Exec, KW_Hold, KW_PChar, KW_Char, KW_Goto, KW_Call,
+ KW_Ret, KW_CurState, KW_TargState, KW_Entry, KW_Next, KW_Exec,
+ KW_Variable, KW_Access;
+}%%
+
+ %% write instance_data;
+
+ void init();
+ int parseLangEl( int type, const Token *token );
+
+ Parser( const char *fileName, char *sectionName, InputLoc &sectionLoc )
+ : sectionName(sectionName)
+ {
+ pd = new ParseData( fileName, sectionName, sectionLoc );
+ exportContext.append( false );
+ includeHistory.append( IncludeHistoryItem(
+ fileName, sectionName ) );
+ }
+
+ int token( InputLoc &loc, int tokId, char *tokstart, int toklen );
+ void tryMachineDef( InputLoc &loc, char *name,
+ MachineDef *machineDef, bool isInstance );
+
+ /* Report an error encountered by the parser. */
+ ostream &parse_error( int tokId, Token &token );
+
+ ParseData *pd;
+
+ /* The name of the root section, this does not change during an include. */
+ char *sectionName;
+
+ NameRef nameRef;
+ NameRefList nameRefList;
+
+ Vector<bool> exportContext;
+ IncludeHistory includeHistory;
+
+ Parser *prev, *next;
+};
+
+%% write token_defs;
+
+#endif
diff --git a/ragel/rlparse.kl b/ragel/rlparse.kl
new file mode 100644
index 0000000..36b8777
--- /dev/null
+++ b/ragel/rlparse.kl
@@ -0,0 +1,1513 @@
+/*
+ * Copyright 2001-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 "rlparse.h"
+#include "ragel.h"
+#include <iostream>
+#include <errno.h>
+#include <stdlib.h>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+%%{
+
+parser Parser;
+
+include "rlparse.kh";
+
+start: section_list;
+
+section_list: section_list statement_list TK_EndSection;
+section_list: ;
+
+statement_list: statement_list statement;
+statement_list: ;
+
+statement: assignment commit;
+statement: instantiation commit;
+statement: action_spec commit;
+statement: alphtype_spec commit;
+statement: range_spec commit;
+statement: getkey_spec commit;
+statement: access_spec commit;
+statement: variable_spec commit;
+statement: export_block commit;
+statement: pre_push_spec commit;
+statement: post_pop_spec commit;
+statement: length_spec commit;
+
+length_spec:
+ KW_Length TK_Word ';'
+ final {
+ LengthDef *lengthDef = new LengthDef( $2->data );
+ pd->lengthDefList.append( lengthDef );
+
+ /* Generic creation of machine for instantiation and assignment. */
+ MachineDef *machineDef = new MachineDef( lengthDef );
+ tryMachineDef( $2->loc, $2->data, machineDef, false );
+ };
+
+pre_push_spec:
+ KW_PrePush '{' inline_block '}'
+ final {
+ if ( pd->prePushExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error($2->loc) << "pre_push code already defined" << endl;
+ }
+
+ pd->prePushExpr = $3->inlineList;
+ };
+
+
+post_pop_spec:
+ KW_PostPop '{' inline_block '}'
+ final {
+ if ( pd->postPopExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error($2->loc) << "post_pop code already defined" << endl;
+ }
+
+ pd->postPopExpr = $3->inlineList;
+ };
+
+
+export_open: KW_Export
+ final {
+ exportContext.append( true );
+ };
+
+nonterm opt_export
+{
+ bool isSet;
+};
+
+opt_export: export_open final { $$->isSet = true; };
+opt_export: final { $$->isSet = false; };
+
+export_block: export_open '{' statement_list '}'
+ final {
+ exportContext.remove( exportContext.length()-1 );
+ };
+
+assignment:
+ opt_export machine_name '=' join ';' final {
+ /* Main machine must be an instance. */
+ bool isInstance = false;
+ if ( strcmp($2->token.data, mainMachine) == 0 ) {
+ warning($2->token.loc) <<
+ "main machine will be implicitly instantiated" << endl;
+ isInstance = true;
+ }
+
+ /* Generic creation of machine for instantiation and assignment. */
+ MachineDef *machineDef = new MachineDef( $4->join );
+ tryMachineDef( $2->token.loc, $2->token.data, machineDef, isInstance );
+
+ if ( $1->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ $4->join->loc = $3->loc;
+ };
+
+instantiation:
+ opt_export machine_name TK_ColonEquals join_or_lm ';' final {
+ /* Generic creation of machine for instantiation and assignment. */
+ tryMachineDef( $2->token.loc, $2->token.data, $4->machineDef, true );
+
+ if ( $1->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ /* Pass a location to join_or_lm */
+ if ( $4->machineDef->join != 0 )
+ $4->machineDef->join->loc = $3->loc;
+ };
+
+type token_type
+{
+ Token token;
+};
+
+nonterm machine_name uses token_type;
+
+machine_name:
+ TK_Word final {
+ /* Make/get the priority key. The name may have already been referenced
+ * and therefore exist. */
+ PriorDictEl *priorDictEl;
+ if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
+ pd->nextPriorKey += 1;
+ pd->curDefPriorKey = priorDictEl->value;
+
+ /* Make/get the local error key. */
+ LocalErrDictEl *localErrDictEl;
+ if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
+ pd->nextLocalErrKey += 1;
+ pd->curDefLocalErrKey = localErrDictEl->value;
+
+ $$->token = *$1;
+ };
+
+action_spec:
+ KW_Action TK_Word '{' inline_block '}' final {
+ if ( pd->actionDict.find( $2->data ) ) {
+ /* Recover by just ignoring the duplicate. */
+ error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
+ }
+ else {
+ //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
+ /* Add the action to the list of actions. */
+ Action *newAction = new Action( $3->loc, $2->data,
+ $4->inlineList, pd->nextCondId++ );
+
+ /* Insert to list and dict. */
+ pd->actionList.append( newAction );
+ pd->actionDict.insert( newAction );
+ }
+ };
+
+# Specifies the data type of the input alphabet. One or two words followed by a
+# semi-colon.
+alphtype_spec:
+ KW_AlphType TK_Word TK_Word ';' final {
+ if ( ! pd->setAlphType( $1->loc, $2->data, $3->data ) ) {
+ // Recover by ignoring the alphtype statement.
+ error($2->loc) << "\"" << $2->data <<
+ " " << $3->data << "\" is not a valid alphabet type" << endl;
+ }
+ };
+
+alphtype_spec:
+ KW_AlphType TK_Word ';' final {
+ if ( ! pd->setAlphType( $1->loc, $2->data ) ) {
+ // Recover by ignoring the alphtype statement.
+ error($2->loc) << "\"" << $2->data <<
+ "\" is not a valid alphabet type" << endl;
+ }
+ };
+
+# Specifies a range to assume that the input characters will fall into.
+range_spec:
+ KW_Range alphabet_num alphabet_num ';' final {
+ // Save the upper and lower ends of the range and emit the line number.
+ pd->lowerNum = $2->token.data;
+ pd->upperNum = $3->token.data;
+ pd->rangeLowLoc = $2->token.loc;
+ pd->rangeHighLoc = $3->token.loc;
+ };
+
+getkey_spec:
+ KW_GetKey inline_expr ';' final {
+ pd->getKeyExpr = $2->inlineList;
+ };
+
+access_spec:
+ KW_Access inline_expr ';' final {
+ pd->accessExpr = $2->inlineList;
+ };
+
+variable_spec:
+ KW_Variable opt_whitespace TK_Word inline_expr ';' final {
+ /* FIXME: Need to implement the rest of this. */
+ bool wasSet = pd->setVariable( $3->data, $4->inlineList );
+ if ( !wasSet )
+ error($3->loc) << "bad variable name" << endl;
+ };
+
+opt_whitespace: opt_whitespace IL_WhiteSpace;
+opt_whitespace: ;
+
+#
+# Expressions
+#
+
+nonterm join_or_lm
+{
+ MachineDef *machineDef;
+};
+
+join_or_lm:
+ join final {
+ $$->machineDef = new MachineDef( $1->join );
+ };
+join_or_lm:
+ TK_BarStar lm_part_list '*' '|' final {
+ /* Create a new factor going to a longest match structure. Record
+ * in the parse data that we have a longest match. */
+ LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
+ pd->lmList.append( lm );
+ for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
+ lmp->longestMatch = lm;
+ $$->machineDef = new MachineDef( lm );
+ };
+
+nonterm lm_part_list
+{
+ LmPartList *lmPartList;
+};
+
+lm_part_list:
+ lm_part_list longest_match_part
+ final {
+ if ( $2->lmPart != 0 )
+ $1->lmPartList->append( $2->lmPart );
+ $$->lmPartList = $1->lmPartList;
+ };
+lm_part_list:
+ longest_match_part
+ final {
+ /* Create a new list with the part. */
+ $$->lmPartList = new LmPartList;
+ if ( $1->lmPart != 0 )
+ $$->lmPartList->append( $1->lmPart );
+ };
+
+nonterm longest_match_part
+{
+ LongestMatchPart *lmPart;
+};
+
+longest_match_part:
+ action_spec final { $$->lmPart = 0; };
+longest_match_part:
+ assignment final { $$->lmPart = 0; };
+longest_match_part:
+ join opt_lm_part_action ';' final {
+ $$->lmPart = 0;
+ Action *action = $2->action;
+ if ( action != 0 )
+ action->isLmAction = true;
+ $$->lmPart = new LongestMatchPart( $1->join, action,
+ $3->loc, pd->nextLongestMatchId++ );
+
+ /* Provide a location to join. Unfortunately We don't
+ * have the start of the join as in other occurances. Use the end. */
+ $1->join->loc = $3->loc;
+ };
+
+nonterm opt_lm_part_action
+{
+ Action *action;
+};
+
+opt_lm_part_action:
+ TK_DoubleArrow action_embed final {
+ $$->action = $2->action;
+ };
+opt_lm_part_action:
+ action_embed_block final {
+ $$->action = $1->action;
+ };
+opt_lm_part_action:
+ final {
+ $$->action = 0;
+ };
+
+
+nonterm join
+{
+ Join *join;
+};
+
+join:
+ join ',' expression final {
+ /* Append the expression to the list and return it. */
+ $1->join->exprList.append( $3->expression );
+ $$->join = $1->join;
+ };
+join:
+ expression final {
+ $$->join = new Join( $1->expression );
+ };
+
+nonterm expression
+{
+ Expression *expression;
+};
+
+expression:
+ expression '|' term_short final {
+ $$->expression = new Expression( $1->expression,
+ $3->term, Expression::OrType );
+ };
+expression:
+ expression '&' term_short final {
+ $$->expression = new Expression( $1->expression,
+ $3->term, Expression::IntersectType );
+ };
+expression:
+ expression '-' term_short final {
+ $$->expression = new Expression( $1->expression,
+ $3->term, Expression::SubtractType );
+ };
+expression:
+ expression TK_DashDash term_short final {
+ $$->expression = new Expression( $1->expression,
+ $3->term, Expression::StrongSubtractType );
+ };
+expression:
+ term_short final {
+ $$->expression = new Expression( $1->term );
+ };
+
+# This is where we resolve the ambiguity involving -. By default ragel tries to
+# do a longest match, which gives precedence to a concatenation because it is
+# innermost. What we need is to force term into a shortest match so that when -
+# is seen it doesn't try to extend term with a concatenation, but ends term and
+# goes for a subtraction.
+#
+# The shortest tag overrides the default longest match action ordering strategy
+# and instead forces a shortest match stragegy. The wrap the term production in
+# a new nonterminal 'term_short' to guarantee the shortest match behaviour.
+
+shortest term_short;
+nonterm term_short
+{
+ Term *term;
+};
+
+term_short:
+ term final {
+ $$->term = $1->term;
+ };
+
+nonterm term
+{
+ Term *term;
+};
+
+term:
+ term factor_with_label final {
+ $$->term = new Term( $1->term, $2->factorWithAug );
+ };
+term:
+ term '.' factor_with_label final {
+ $$->term = new Term( $1->term, $3->factorWithAug );
+ };
+term:
+ term TK_ColonGt factor_with_label final {
+ $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
+ };
+term:
+ term TK_ColonGtGt factor_with_label final {
+ $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
+ };
+term:
+ term TK_LtColon factor_with_label final {
+ $$->term = new Term( $1->term,
+ $3->factorWithAug, Term::LeftType );
+ };
+term:
+ factor_with_label final {
+ $$->term = new Term( $1->factorWithAug );
+ };
+
+nonterm factor_with_label
+{
+ FactorWithAug *factorWithAug;
+};
+
+factor_with_label:
+ TK_Word ':' factor_with_label final {
+ /* Add the label to the list and pass the factor up. */
+ $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
+ $$->factorWithAug = $3->factorWithAug;
+ };
+factor_with_label:
+ factor_with_ep final {
+ $$->factorWithAug = $1->factorWithAug;
+ };
+
+nonterm factor_with_ep
+{
+ FactorWithAug *factorWithAug;
+};
+
+factor_with_ep:
+ factor_with_ep TK_Arrow local_state_ref final {
+ /* Add the target to the list and return the factor object. */
+ $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_ep:
+ factor_with_aug final {
+ $$->factorWithAug = $1->factorWithAug;
+ };
+
+nonterm factor_with_aug
+{
+ FactorWithAug *factorWithAug;
+};
+
+factor_with_aug:
+ factor_with_aug aug_type_base action_embed final {
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ $1->factorWithAug->actions.append(
+ ParserAction( $2->loc, $2->augType, 0, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_base priority_aug final {
+ /* Append the named priority to the factorWithAug and pass it up. */
+ $1->factorWithAug->priorityAugs.append(
+ PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
+ /* Append the priority using a default name. */
+ $1->factorWithAug->priorityAugs.append(
+ PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_cond action_embed final {
+ $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
+ $2->augType, $3->action, true ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_cond '!' action_embed final {
+ $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
+ $2->augType, $4->action, false ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_to_state action_embed final {
+ /* Append the action, pass it up. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, 0, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_from_state action_embed final {
+ /* Append the action, pass it up. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, 0, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_eof action_embed final {
+ /* Append the action, pass it up. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, 0, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_gbl_error action_embed final {
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, pd->curDefLocalErrKey, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_local_error action_embed final {
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, pd->curDefLocalErrKey, $3->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
+ /* Append the action to the factorWithAug, record the refernce from
+ * factorWithAug to the action and pass up the factorWithAug. */
+ $1->factorWithAug->actions.append( ParserAction( $2->loc,
+ $2->augType, $4->error_name, $6->action ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_rep final {
+ $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
+ };
+
+type aug_type
+{
+ InputLoc loc;
+ AugType augType;
+};
+
+# Classes of transtions on which to embed actions or change priorities.
+nonterm aug_type_base uses aug_type;
+
+aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
+aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
+aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
+aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
+
+# Embedding conditions.
+nonterm aug_type_cond uses aug_type;
+
+aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
+aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
+aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
+aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
+aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
+aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
+aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
+aug_type_cond: KW_InWhen final { $$->loc = $1->loc; $$->augType = at_start; };
+aug_type_cond: KW_OutWhen final { $$->loc = $1->loc; $$->augType = at_leave; };
+
+#
+# To state actions.
+#
+
+nonterm aug_type_to_state uses aug_type;
+
+aug_type_to_state: TK_StartToState
+ final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
+aug_type_to_state: '>' KW_To
+ final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
+
+aug_type_to_state: TK_NotStartToState
+ final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
+aug_type_to_state: '<' KW_To
+ final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
+
+aug_type_to_state: TK_AllToState
+ final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
+aug_type_to_state: '$' KW_To
+ final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
+
+aug_type_to_state: TK_FinalToState
+ final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
+aug_type_to_state: '%' KW_To
+ final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
+
+aug_type_to_state: TK_NotFinalToState
+ final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
+aug_type_to_state: '@' KW_To
+ final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
+
+aug_type_to_state: TK_MiddleToState
+ final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
+aug_type_to_state: TK_Middle KW_To
+ final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
+
+#
+# From state actions.
+#
+
+nonterm aug_type_from_state uses aug_type;
+
+aug_type_from_state: TK_StartFromState
+ final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
+aug_type_from_state: '>' KW_From
+ final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
+
+aug_type_from_state: TK_NotStartFromState
+ final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
+aug_type_from_state: '<' KW_From
+ final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
+
+aug_type_from_state: TK_AllFromState
+ final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
+aug_type_from_state: '$' KW_From
+ final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
+
+aug_type_from_state: TK_FinalFromState
+ final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
+aug_type_from_state: '%' KW_From
+ final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
+
+aug_type_from_state: TK_NotFinalFromState
+ final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
+aug_type_from_state: '@' KW_From
+ final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
+
+aug_type_from_state: TK_MiddleFromState
+ final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
+aug_type_from_state: TK_Middle KW_From
+ final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
+
+#
+# Eof state actions.
+#
+
+nonterm aug_type_eof uses aug_type;
+
+aug_type_eof: TK_StartEOF
+ final { $$->loc = $1->loc; $$->augType = at_start_eof; };
+aug_type_eof: '>' KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_start_eof; };
+
+aug_type_eof: TK_NotStartEOF
+ final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
+aug_type_eof: '<' KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
+
+aug_type_eof: TK_AllEOF
+ final { $$->loc = $1->loc; $$->augType = at_all_eof; };
+aug_type_eof: '$' KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_all_eof; };
+
+aug_type_eof: TK_FinalEOF
+ final { $$->loc = $1->loc; $$->augType = at_final_eof; };
+aug_type_eof: '%' KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_final_eof; };
+
+aug_type_eof: TK_NotFinalEOF
+ final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
+aug_type_eof: '@' KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
+
+aug_type_eof: TK_MiddleEOF
+ final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
+aug_type_eof: TK_Middle KW_Eof
+ final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
+
+#
+# Global error actions.
+#
+
+nonterm aug_type_gbl_error uses aug_type;
+
+aug_type_gbl_error: TK_StartGblError
+ final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
+aug_type_gbl_error: '>' KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
+
+aug_type_gbl_error: TK_NotStartGblError
+ final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
+aug_type_gbl_error: '<' KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
+
+aug_type_gbl_error: TK_AllGblError
+ final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
+aug_type_gbl_error: '$' KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
+
+aug_type_gbl_error: TK_FinalGblError
+ final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
+aug_type_gbl_error: '%' KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
+
+aug_type_gbl_error: TK_NotFinalGblError
+ final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
+aug_type_gbl_error: '@' KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
+
+aug_type_gbl_error: TK_MiddleGblError
+ final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
+aug_type_gbl_error: TK_Middle KW_Err
+ final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
+
+
+#
+# Local error actions.
+#
+
+nonterm aug_type_local_error uses aug_type;
+
+aug_type_local_error: TK_StartLocalError
+ final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
+aug_type_local_error: '>' KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
+
+aug_type_local_error: TK_NotStartLocalError
+ final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
+aug_type_local_error: '<' KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
+
+aug_type_local_error: TK_AllLocalError
+ final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
+aug_type_local_error: '$' KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
+
+aug_type_local_error: TK_FinalLocalError
+ final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
+aug_type_local_error: '%' KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
+
+aug_type_local_error: TK_NotFinalLocalError
+ final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
+aug_type_local_error: '@' KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
+
+aug_type_local_error: TK_MiddleLocalError
+ final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
+aug_type_local_error: TK_Middle KW_Lerr
+ final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
+
+
+type action_ref
+{
+ Action *action;
+};
+
+# Different ways to embed actions. A TK_Word is reference to an action given by
+# the user as a statement in the fsm specification. An action can also be
+# specified immediately.
+nonterm action_embed uses action_ref;
+
+action_embed: action_embed_word final { $$->action = $1->action; };
+action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
+action_embed: action_embed_block final { $$->action = $1->action; };
+
+nonterm action_embed_word uses action_ref;
+
+action_embed_word:
+ TK_Word final {
+ /* Set the name in the actionDict. */
+ Action *action = pd->actionDict.find( $1->data );
+ if ( action != 0 ) {
+ /* Pass up the action element */
+ $$->action = action;
+ }
+ else {
+ /* Will recover by returning null as the action. */
+ error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
+ $$->action = 0;
+ }
+ };
+
+nonterm action_embed_block uses action_ref;
+
+action_embed_block:
+ '{' inline_block '}' final {
+ /* Create the action, add it to the list and pass up. */
+ Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
+ pd->actionList.append( newAction );
+ $$->action = newAction;
+ };
+
+nonterm priority_name
+{
+ int priorityName;
+};
+
+# A specified priority name. Looks up the name in the current priority
+# dictionary.
+priority_name:
+ TK_Word final {
+ // Lookup/create the priority key.
+ PriorDictEl *priorDictEl;
+ if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
+ pd->nextPriorKey += 1;
+
+ // Use the inserted/found priority key.
+ $$->priorityName = priorDictEl->value;
+ };
+
+nonterm priority_aug
+{
+ int priorityNum;
+};
+
+# Priority change specs.
+priority_aug:
+ priority_aug_num final {
+ // Convert the priority number to a long. Check for overflow.
+ errno = 0;
+ //cerr << "PRIOR AUG: " << $1->token.data << endl;
+ long aug = strtol( $1->token.data, 0, 10 );
+ if ( errno == ERANGE && aug == LONG_MAX ) {
+ /* Priority number too large. Recover by setting the priority to 0. */
+ error($1->token.loc) << "priority number " << $1->token.data <<
+ " overflows" << endl;
+ $$->priorityNum = 0;
+ }
+ else if ( errno == ERANGE && aug == LONG_MIN ) {
+ /* Priority number too large in the neg. Recover by using 0. */
+ error($1->token.loc) << "priority number " << $1->token.data <<
+ " underflows" << endl;
+ $$->priorityNum = 0;
+ }
+ else {
+ /* No overflow or underflow. */
+ $$->priorityNum = aug;
+ }
+ };
+
+nonterm priority_aug_num uses token_type;
+
+priority_aug_num:
+ TK_UInt final {
+ $$->token = *$1;
+ };
+priority_aug_num:
+ '+' TK_UInt final {
+ $$->token.set( "+", 1 );
+ $$->token.loc = $1->loc;
+ $$->token.append( *$2 );
+ };
+priority_aug_num:
+ '-' TK_UInt final {
+ $$->token.set( "-", 1 );
+ $$->token.loc = $1->loc;
+ $$->token.append( *$2 );
+ };
+
+nonterm local_err_name
+{
+ int error_name;
+};
+
+local_err_name:
+ TK_Word final {
+ /* Lookup/create the priority key. */
+ LocalErrDictEl *localErrDictEl;
+ if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
+ pd->nextLocalErrKey += 1;
+
+ /* Use the inserted/found priority key. */
+ $$->error_name = localErrDictEl->value;
+ };
+
+
+
+# The fourth level of precedence. These are the trailing unary operators that
+# allow for repetition.
+
+nonterm factor_with_rep
+{
+ FactorWithRep *factorWithRep;
+};
+
+factor_with_rep:
+ factor_with_rep '*' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ 0, 0, FactorWithRep::StarType );
+ };
+factor_with_rep:
+ factor_with_rep TK_StarStar final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ 0, 0, FactorWithRep::StarStarType );
+ };
+factor_with_rep:
+ factor_with_rep '?' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ 0, 0, FactorWithRep::OptionalType );
+ };
+factor_with_rep:
+ factor_with_rep '+' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ 0, 0, FactorWithRep::PlusType );
+ };
+factor_with_rep:
+ factor_with_rep '{' factor_rep_num '}' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ $3->rep, 0, FactorWithRep::ExactType );
+ };
+factor_with_rep:
+ factor_with_rep '{' ',' factor_rep_num '}' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ 0, $4->rep, FactorWithRep::MaxType );
+ };
+factor_with_rep:
+ factor_with_rep '{' factor_rep_num ',' '}' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ $3->rep, 0, FactorWithRep::MinType );
+ };
+factor_with_rep:
+ factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
+ $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
+ $3->rep, $5->rep, FactorWithRep::RangeType );
+ };
+factor_with_rep:
+ factor_with_neg final {
+ $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
+ };
+
+nonterm factor_rep_num
+{
+ int rep;
+};
+
+factor_rep_num:
+ TK_UInt final {
+ // Convert the priority number to a long. Check for overflow.
+ errno = 0;
+ long rep = strtol( $1->data, 0, 10 );
+ if ( errno == ERANGE && rep == LONG_MAX ) {
+ // Repetition too large. Recover by returing repetition 1. */
+ error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
+ $$->rep = 1;
+ }
+ else {
+ // Cannot be negative, so no overflow.
+ $$->rep = rep;
+ }
+ };
+
+
+#
+# The fifth level up in precedence. Negation.
+#
+
+nonterm factor_with_neg
+{
+ FactorWithNeg *factorWithNeg;
+};
+
+factor_with_neg:
+ '!' factor_with_neg final {
+ $$->factorWithNeg = new FactorWithNeg( $1->loc,
+ $2->factorWithNeg, FactorWithNeg::NegateType );
+ };
+factor_with_neg:
+ '^' factor_with_neg final {
+ $$->factorWithNeg = new FactorWithNeg( $1->loc,
+ $2->factorWithNeg, FactorWithNeg::CharNegateType );
+ };
+factor_with_neg:
+ factor final {
+ $$->factorWithNeg = new FactorWithNeg( $1->factor );
+ };
+
+nonterm factor
+{
+ Factor *factor;
+};
+
+factor:
+ TK_Literal final {
+ /* Create a new factor node going to a concat literal. */
+ $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
+ };
+factor:
+ alphabet_num final {
+ /* Create a new factor node going to a literal number. */
+ $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
+ };
+factor:
+ TK_Word final {
+ /* Find the named graph. */
+ GraphDictEl *gdNode = pd->graphDict.find( $1->data );
+ if ( gdNode == 0 ) {
+ /* Recover by returning null as the factor node. */
+ error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
+ $$->factor = 0;
+ }
+ else if ( gdNode->isInstance ) {
+ /* Recover by retuning null as the factor node. */
+ error($1->loc) << "references to graph instantiations not allowed "
+ "in expressions" << endl;
+ $$->factor = 0;
+ }
+ else {
+ /* Create a factor node that is a lookup of an expression. */
+ $$->factor = new Factor( $1->loc, gdNode->value );
+ }
+ };
+factor:
+ RE_SqOpen regular_expr_or_data RE_SqClose final {
+ /* Create a new factor node going to an OR expression. */
+ $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
+ };
+factor:
+ RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
+ /* Create a new factor node going to a negated OR expression. */
+ $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
+ };
+factor:
+ RE_Slash regular_expr RE_Slash final {
+ if ( $3->length > 1 ) {
+ for ( char *p = $3->data; *p != 0; p++ ) {
+ if ( *p == 'i' )
+ $2->regExpr->caseInsensitive = true;
+ }
+ }
+
+ /* Create a new factor node going to a regular exp. */
+ $$->factor = new Factor( $2->regExpr );
+ };
+factor:
+ range_lit TK_DotDot range_lit final {
+ /* Create a new factor node going to a range. */
+ $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
+ };
+factor:
+ '(' join ')' final {
+ /* Create a new factor going to a parenthesized join. */
+ $$->factor = new Factor( $2->join );
+ $2->join->loc = $1->loc;
+ };
+
+nonterm range_lit
+{
+ Literal *literal;
+};
+
+# Literals which can be the end points of ranges.
+range_lit:
+ TK_Literal final {
+ /* Range literas must have only one char. We restrict this in the parse tree. */
+ $$->literal = new Literal( *$1, Literal::LitString );
+ };
+range_lit:
+ alphabet_num final {
+ /* Create a new literal number. */
+ $$->literal = new Literal( $1->token, Literal::Number );
+ };
+
+nonterm alphabet_num uses token_type;
+
+# Any form of a number that can be used as a basic machine. */
+alphabet_num:
+ TK_UInt final {
+ $$->token = *$1;
+ };
+alphabet_num:
+ '-' TK_UInt final {
+ $$->token.set( "-", 1 );
+ $$->token.loc = $1->loc;
+ $$->token.append( *$2 );
+ };
+alphabet_num:
+ TK_Hex final {
+ $$->token = *$1;
+ };
+#
+# Regular Expressions.
+#
+
+nonterm regular_expr
+{
+ RegExpr *regExpr;
+};
+
+# Parser for regular expression fsms. Any number of expression items which
+# generally gives a machine one character long or one character long stared.
+regular_expr:
+ regular_expr regular_expr_item final {
+ /* An optimization to lessen the tree size. If a non-starred char is
+ * directly under the left side on the right and the right side is
+ * another non-starred char then paste them together and return the
+ * left side. Otherwise just put the two under a new reg exp node. */
+ if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
+ $1->regExpr->type == RegExpr::RecurseItem &&
+ $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
+ {
+ /* Append the right side to the right side of the left and toss the
+ * right side. */
+ $1->regExpr->item->token.append( $2->reItem->token );
+ delete $2->reItem;
+ $$->regExpr = $1->regExpr;
+ }
+ else {
+ $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
+ }
+ };
+regular_expr:
+ final {
+ /* Can't optimize the tree. */
+ $$->regExpr = new RegExpr();
+ };
+
+nonterm regular_expr_item
+{
+ ReItem *reItem;
+};
+
+# RegularExprItems can be a character spec with an optional staring of the char.
+regular_expr_item:
+ regular_expr_char RE_Star final {
+ $1->reItem->star = true;
+ $$->reItem = $1->reItem;
+ };
+regular_expr_item:
+ regular_expr_char final {
+ $$->reItem = $1->reItem;
+ };
+
+nonterm regular_expr_char
+{
+ ReItem *reItem;
+};
+
+# A character spec can be a set of characters inside of square parenthesis, a
+# dot specifying any character or some explicitly stated character.
+regular_expr_char:
+ RE_SqOpen regular_expr_or_data RE_SqClose final {
+ $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
+ };
+regular_expr_char:
+ RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
+ $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
+ };
+regular_expr_char:
+ RE_Dot final {
+ $$->reItem = new ReItem( $1->loc, ReItem::Dot );
+ };
+regular_expr_char:
+ RE_Char final {
+ $$->reItem = new ReItem( $1->loc, *$1 );
+ };
+
+# The data inside of a [] expression in a regular expression. Accepts any
+# number of characters or ranges. */
+nonterm regular_expr_or_data
+{
+ ReOrBlock *reOrBlock;
+};
+
+regular_expr_or_data:
+ regular_expr_or_data regular_expr_or_char final {
+ /* An optimization to lessen the tree size. If an or char is directly
+ * under the left side on the right and the right side is another or
+ * char then paste them together and return the left side. Otherwise
+ * just put the two under a new or data node. */
+ if ( $2->reOrItem->type == ReOrItem::Data &&
+ $1->reOrBlock->type == ReOrBlock::RecurseItem &&
+ $1->reOrBlock->item->type == ReOrItem::Data )
+ {
+ /* Append the right side to right side of the left and toss the
+ * right side. */
+ $1->reOrBlock->item->token.append( $2->reOrItem->token );
+ delete $2->reOrItem;
+ $$->reOrBlock = $1->reOrBlock;
+ }
+ else {
+ /* Can't optimize, put the left and right under a new node. */
+ $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
+ }
+ };
+regular_expr_or_data:
+ final {
+ $$->reOrBlock = new ReOrBlock();
+ };
+
+# A single character inside of an or expression. Can either be a character or a
+# set of characters.
+nonterm regular_expr_or_char
+{
+ ReOrItem *reOrItem;
+};
+
+regular_expr_or_char:
+ RE_Char final {
+ $$->reOrItem = new ReOrItem( $1->loc, *$1 );
+ };
+regular_expr_or_char:
+ RE_Char RE_Dash RE_Char final {
+ $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
+ };
+
+#
+# Inline Lists for inline host code.
+#
+
+type inline_list
+{
+ InlineList *inlineList;
+};
+
+nonterm inline_block uses inline_list;
+
+inline_block:
+ inline_block inline_block_item
+ final {
+ /* Append the item to the list, return the list. */
+ $$->inlineList = $1->inlineList;
+ $$->inlineList->append( $2->inlineItem );
+ };
+
+inline_block:
+ final {
+ /* Start with empty list. */
+ $$->inlineList = new InlineList;
+ };
+
+type inline_item
+{
+ InlineItem *inlineItem;
+};
+
+nonterm inline_block_item uses inline_item;
+nonterm inline_block_interpret uses inline_item;
+
+inline_block_item:
+ inline_expr_any
+ final {
+ $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
+ };
+
+inline_block_item:
+ inline_block_symbol
+ final {
+ $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
+ };
+
+inline_block_item:
+ inline_block_interpret
+ final {
+ /* Pass the inline item up. */
+ $$->inlineItem = $1->inlineItem;
+ };
+
+nonterm inline_block_symbol uses token_type;
+
+inline_block_symbol: ',' final { $$->token = *$1; };
+inline_block_symbol: ';' final { $$->token = *$1; };
+inline_block_symbol: '(' final { $$->token = *$1; };
+inline_block_symbol: ')' final { $$->token = *$1; };
+inline_block_symbol: '*' final { $$->token = *$1; };
+inline_block_symbol: TK_NameSep final { $$->token = *$1; };
+
+# Interpreted statements in a struct block. */
+inline_block_interpret:
+ inline_expr_interpret final {
+ /* Pass up interpreted items of inline expressions. */
+ $$->inlineItem = $1->inlineItem;
+ };
+inline_block_interpret:
+ KW_Hold ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
+ };
+inline_block_interpret:
+ KW_Exec inline_expr ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
+ $$->inlineItem->children = $2->inlineList;
+ };
+inline_block_interpret:
+ KW_Goto state_ref ';' final {
+ $$->inlineItem = new InlineItem( $1->loc,
+ new NameRef(nameRef), InlineItem::Goto );
+ };
+inline_block_interpret:
+ KW_Goto '*' inline_expr ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
+ $$->inlineItem->children = $3->inlineList;
+ };
+inline_block_interpret:
+ KW_Next state_ref ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
+ };
+inline_block_interpret:
+ KW_Next '*' inline_expr ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
+ $$->inlineItem->children = $3->inlineList;
+ };
+inline_block_interpret:
+ KW_Call state_ref ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
+ };
+inline_block_interpret:
+ KW_Call '*' inline_expr ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
+ $$->inlineItem->children = $3->inlineList;
+ };
+inline_block_interpret:
+ KW_Ret ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
+ };
+inline_block_interpret:
+ KW_Break ';' final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
+ };
+
+nonterm inline_expr uses inline_list;
+
+inline_expr:
+ inline_expr inline_expr_item
+ final {
+ $$->inlineList = $1->inlineList;
+ $$->inlineList->append( $2->inlineItem );
+ };
+inline_expr:
+ final {
+ /* Init the list used for this expr. */
+ $$->inlineList = new InlineList;
+ };
+
+nonterm inline_expr_item uses inline_item;
+
+inline_expr_item:
+ inline_expr_any
+ final {
+ /* Return a text segment. */
+ $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
+ };
+inline_expr_item:
+ inline_expr_symbol
+ final {
+ /* Return a text segment, must heap alloc the text. */
+ $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
+ };
+inline_expr_item:
+ inline_expr_interpret
+ final{
+ /* Pass the inline item up. */
+ $$->inlineItem = $1->inlineItem;
+ };
+
+nonterm inline_expr_any uses token_type;
+
+inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
+inline_expr_any: IL_Comment try { $$->token = *$1; };
+inline_expr_any: IL_Literal try { $$->token = *$1; };
+inline_expr_any: IL_Symbol try { $$->token = *$1; };
+inline_expr_any: TK_UInt try { $$->token = *$1; };
+inline_expr_any: TK_Hex try { $$->token = *$1; };
+inline_expr_any: TK_Word try { $$->token = *$1; };
+
+# Anything in a ExecValExpr that is not dynamically allocated. This includes
+# all special symbols caught in inline code except the semi.
+
+nonterm inline_expr_symbol uses token_type;
+
+inline_expr_symbol: ',' try { $$->token = *$1; };
+inline_expr_symbol: '(' try { $$->token = *$1; };
+inline_expr_symbol: ')' try { $$->token = *$1; };
+inline_expr_symbol: '*' try { $$->token = *$1; };
+inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
+
+nonterm inline_expr_interpret uses inline_item;
+
+inline_expr_interpret:
+ KW_PChar
+ final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
+ };
+inline_expr_interpret:
+ KW_Char
+ final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
+ };
+inline_expr_interpret:
+ KW_CurState
+ final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
+ };
+inline_expr_interpret:
+ KW_TargState
+ final {
+ $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
+ };
+inline_expr_interpret:
+ KW_Entry '(' state_ref ')'
+ final {
+ $$->inlineItem = new InlineItem( $1->loc,
+ new NameRef(nameRef), InlineItem::Entry );
+ };
+
+# A local state reference. Cannot have :: prefix.
+local_state_ref:
+ no_name_sep state_ref_names;
+
+# Clear the name ref structure.
+no_name_sep:
+ final {
+ nameRef.empty();
+ };
+
+# A qualified state reference.
+state_ref: opt_name_sep state_ref_names;
+
+# Optional leading name separator.
+opt_name_sep:
+ TK_NameSep
+ final {
+ /* Insert an initial null pointer val to indicate the existence of the
+ * initial name seperator. */
+ nameRef.setAs( 0 );
+ };
+opt_name_sep:
+ final {
+ nameRef.empty();
+ };
+
+# List of names separated by ::
+state_ref_names:
+ state_ref_names TK_NameSep TK_Word
+ final {
+ nameRef.append( $3->data );
+ };
+state_ref_names:
+ TK_Word
+ final {
+ nameRef.append( $1->data );
+ };
+
+}%%
+
+%%{
+ write types;
+ write data;
+}%%
+
+void Parser::init()
+{
+ %% write init;
+}
+
+int Parser::parseLangEl( int type, const Token *token )
+{
+ %% write exec;
+ return errCount == 0 ? 0 : -1;
+}
+
+void Parser::tryMachineDef( InputLoc &loc, char *name,
+ MachineDef *machineDef, bool isInstance )
+{
+ GraphDictEl *newEl = pd->graphDict.insert( name );
+ if ( newEl != 0 ) {
+ /* New element in the dict, all good. */
+ newEl->value = new VarDef( name, machineDef );
+ newEl->isInstance = isInstance;
+ newEl->loc = loc;
+ newEl->value->isExport = exportContext[exportContext.length()-1];
+
+ /* It it is an instance, put on the instance list. */
+ if ( isInstance )
+ pd->instanceList.append( newEl );
+ }
+ else {
+ // Recover by ignoring the duplicate.
+ error(loc) << "fsm \"" << name << "\" previously defined" << endl;
+ }
+}
+
+ostream &Parser::parse_error( int tokId, Token &token )
+{
+ /* Maintain the error count. */
+ gblErrorCount += 1;
+
+ cerr << token.loc << ": ";
+ cerr << "at token ";
+ if ( tokId < 128 )
+ cerr << "\"" << Parser_lelNames[tokId] << "\"";
+ else
+ cerr << Parser_lelNames[tokId];
+ if ( token.data != 0 )
+ cerr << " with data \"" << token.data << "\"";
+ cerr << ": ";
+
+ return cerr;
+}
+
+int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
+{
+ Token token;
+ token.data = tokstart;
+ token.length = toklen;
+ token.loc = loc;
+ int res = parseLangEl( tokId, &token );
+ if ( res < 0 ) {
+ parse_error(tokId, token) << "parse error" << endl;
+ exit(1);
+ }
+ return res;
+}
diff --git a/ragel/rlscan.cpp b/ragel/rlscan.cpp
new file mode 100644
index 0000000..0912002
--- /dev/null
+++ b/ragel/rlscan.cpp
@@ -0,0 +1,7229 @@
+
+#line 1 "rlscan.rl"
+/*
+ * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
+ * Copyright 2011 Josef Goettgens
+ */
+
+/* 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 "ragel.h"
+#include "rlscan.h"
+#include "inputdata.h"
+
+//#define LOG_TOKENS
+
+using std::ifstream;
+using std::istream;
+using std::ostream;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+enum InlineBlockType
+{
+ CurlyDelimited,
+ SemiTerminated
+};
+
+#ifdef _WIN32
+#define PATH_SEP '\\'
+#else
+#define PATH_SEP '/'
+#endif
+
+
+/*
+ * The Scanner for Importing
+ */
+
+
+#line 125 "rlscan.rl"
+
+
+
+#line 65 "rlscan.cpp"
+static const int inline_token_scan_start = 2;
+static const int inline_token_scan_first_final = 2;
+static const int inline_token_scan_error = -1;
+
+static const int inline_token_scan_en_main = 2;
+
+
+#line 128 "rlscan.rl"
+
+void Scanner::flushImport()
+{
+ int *p = token_data;
+ int *pe = token_data + cur_token;
+ int *eof = 0;
+
+
+#line 82 "rlscan.cpp"
+ {
+ tok_cs = inline_token_scan_start;
+ tok_ts = 0;
+ tok_te = 0;
+ tok_act = 0;
+ }
+
+#line 90 "rlscan.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( tok_cs )
+ {
+tr0:
+#line 123 "rlscan.rl"
+ {{p = (( tok_te))-1;}}
+ goto st2;
+tr1:
+#line 109 "rlscan.rl"
+ { tok_te = p+1;{
+ int base = tok_ts - token_data;
+ int nameOff = 0;
+ int litOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_Literal,
+ token_strings[base+litOff], token_lens[base+litOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ }}
+ goto st2;
+tr2:
+#line 81 "rlscan.rl"
+ { tok_te = p+1;{
+ int base = tok_ts - token_data;
+ int nameOff = 0;
+ int numOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_UInt,
+ token_strings[base+numOff], token_lens[base+numOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ }}
+ goto st2;
+tr3:
+#line 95 "rlscan.rl"
+ { tok_te = p+1;{
+ int base = tok_ts - token_data;
+ int nameOff = 1;
+ int litOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_Literal,
+ token_strings[base+litOff], token_lens[base+litOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ }}
+ goto st2;
+tr4:
+#line 67 "rlscan.rl"
+ { tok_te = p+1;{
+ int base = tok_ts - token_data;
+ int nameOff = 1;
+ int numOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_UInt,
+ token_strings[base+numOff], token_lens[base+numOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ }}
+ goto st2;
+tr5:
+#line 123 "rlscan.rl"
+ { tok_te = p+1;}
+ goto st2;
+tr8:
+#line 123 "rlscan.rl"
+ { tok_te = p;p--;}
+ goto st2;
+st2:
+#line 1 "NONE"
+ { tok_ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 1 "NONE"
+ { tok_ts = p;}
+#line 176 "rlscan.cpp"
+ switch( (*p) ) {
+ case 128: goto tr6;
+ case 131: goto tr7;
+ }
+ goto tr5;
+tr6:
+#line 1 "NONE"
+ { tok_te = p+1;}
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 190 "rlscan.cpp"
+ if ( (*p) == 61 )
+ goto st0;
+ goto tr8;
+st0:
+ if ( ++p == pe )
+ goto _test_eof0;
+case 0:
+ switch( (*p) ) {
+ case 129: goto tr1;
+ case 130: goto tr2;
+ }
+ goto tr0;
+tr7:
+#line 1 "NONE"
+ { tok_te = p+1;}
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 211 "rlscan.cpp"
+ if ( (*p) == 128 )
+ goto st1;
+ goto tr8;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ switch( (*p) ) {
+ case 129: goto tr3;
+ case 130: goto tr4;
+ }
+ goto tr0;
+ }
+ _test_eof2: tok_cs = 2; goto _test_eof;
+ _test_eof3: tok_cs = 3; goto _test_eof;
+ _test_eof0: tok_cs = 0; goto _test_eof;
+ _test_eof4: tok_cs = 4; goto _test_eof;
+ _test_eof1: tok_cs = 1; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( tok_cs ) {
+ case 3: goto tr8;
+ case 0: goto tr0;
+ case 4: goto tr8;
+ case 1: goto tr0;
+ }
+ }
+
+ }
+
+#line 139 "rlscan.rl"
+
+
+ if ( tok_ts == 0 )
+ cur_token = 0;
+ else {
+ cur_token = pe - tok_ts;
+ int ts_offset = tok_ts - token_data;
+ memmove( token_data, token_data+ts_offset, cur_token*sizeof(token_data[0]) );
+ memmove( token_strings, token_strings+ts_offset, cur_token*sizeof(token_strings[0]) );
+ memmove( token_lens, token_lens+ts_offset, cur_token*sizeof(token_lens[0]) );
+ }
+}
+
+void Scanner::directToParser( Parser *toParser, const char *tokFileName, int tokLine,
+ int tokColumn, int type, char *tokdata, int toklen )
+{
+ InputLoc loc;
+
+ #ifdef LOG_TOKENS
+ cerr << "scanner:" << tokLine << ":" << tokColumn <<
+ ": sending token to the parser " << Parser_lelNames[type];
+ cerr << " " << toklen;
+ if ( tokdata != 0 )
+ cerr << " " << tokdata;
+ cerr << endl;
+ #endif
+
+ loc.fileName = tokFileName;
+ loc.line = tokLine;
+ loc.col = tokColumn;
+
+ toParser->token( loc, type, tokdata, toklen );
+}
+
+void Scanner::importToken( int token, char *start, char *end )
+{
+ if ( cur_token == max_tokens )
+ flushImport();
+
+ token_data[cur_token] = token;
+ if ( start == 0 ) {
+ token_strings[cur_token] = 0;
+ token_lens[cur_token] = 0;
+ }
+ else {
+ int toklen = end-start;
+ token_lens[cur_token] = toklen;
+ token_strings[cur_token] = new char[toklen+1];
+ memcpy( token_strings[cur_token], start, toklen );
+ token_strings[cur_token][toklen] = 0;
+ }
+ cur_token++;
+}
+
+void Scanner::pass( int token, char *start, char *end )
+{
+ if ( importMachines )
+ importToken( token, start, end );
+ pass();
+}
+
+void Scanner::pass()
+{
+ updateCol();
+
+ /* If no errors and we are at the bottom of the include stack (the
+ * source file listed on the command line) then write out the data. */
+ if ( includeDepth == 0 && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->data.write( ts, te-ts );
+}
+
+/*
+ * The scanner for processing sections, includes, imports, etc.
+ */
+
+
+#line 321 "rlscan.cpp"
+static const int section_parse_start = 10;
+static const int section_parse_first_final = 10;
+static const int section_parse_error = 0;
+
+static const int section_parse_en_main = 10;
+
+
+#line 218 "rlscan.rl"
+
+
+
+void Scanner::init( )
+{
+
+#line 336 "rlscan.cpp"
+ {
+ cs = section_parse_start;
+ }
+
+#line 224 "rlscan.rl"
+}
+
+bool Scanner::active()
+{
+ if ( ignoreSection )
+ return false;
+
+ if ( parser == 0 && ! parserExistsError ) {
+ scan_error() << "this specification has no name, nor does any previous"
+ " specification" << endl;
+ parserExistsError = true;
+ }
+
+ if ( parser == 0 )
+ return false;
+
+ return true;
+}
+
+ostream &Scanner::scan_error()
+{
+ /* Maintain the error count. */
+ gblErrorCount += 1;
+ cerr << makeInputLoc( fileName, line, column ) << ": ";
+ return cerr;
+}
+
+/* An approximate check for duplicate includes. Due to aliasing of files it's
+ * possible for duplicates to creep in. */
+bool Scanner::duplicateInclude( char *inclFileName, char *inclSectionName )
+{
+ for ( IncludeHistory::Iter hi = parser->includeHistory; hi.lte(); hi++ ) {
+ if ( strcmp( hi->fileName, inclFileName ) == 0 &&
+ strcmp( hi->sectionName, inclSectionName ) == 0 )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Scanner::updateCol()
+{
+ char *from = lastnl;
+ if ( from == 0 )
+ from = ts;
+ //cerr << "adding " << te - from << " to column" << endl;
+ column += te - from;
+ lastnl = 0;
+}
+
+void Scanner::handleMachine()
+{
+ /* Assign a name to the machine. */
+ char *machine = word;
+
+ if ( !importMachines && inclSectionTarg == 0 ) {
+ ignoreSection = false;
+
+ ParserDictEl *pdEl = id.parserDict.find( machine );
+ if ( pdEl == 0 ) {
+ pdEl = new ParserDictEl( machine );
+ pdEl->value = new Parser( fileName, machine, sectionLoc );
+ pdEl->value->init();
+ id.parserDict.insert( pdEl );
+ id.parserList.append( pdEl->value );
+ }
+
+ parser = pdEl->value;
+ }
+ else if ( !importMachines && strcmp( inclSectionTarg, machine ) == 0 ) {
+ /* found include target */
+ ignoreSection = false;
+ parser = inclToParser;
+ }
+ else {
+ /* ignoring section */
+ ignoreSection = true;
+ parser = 0;
+ }
+}
+
+void Scanner::handleInclude()
+{
+ if ( active() ) {
+ char *inclSectionName = word;
+ char **includeChecks = 0;
+
+ /* Implement defaults for the input file and section name. */
+ if ( inclSectionName == 0 )
+ inclSectionName = parser->sectionName;
+
+ if ( lit != 0 )
+ includeChecks = makeIncludePathChecks( fileName, lit, lit_len );
+ else {
+ char *test = new char[strlen(fileName)+1];
+ strcpy( test, fileName );
+
+ includeChecks = new char*[2];
+
+ includeChecks[0] = test;
+ includeChecks[1] = 0;
+ }
+
+ long found = 0;
+ ifstream *inFile = tryOpenInclude( includeChecks, found );
+ if ( inFile == 0 ) {
+ scan_error() << "include: failed to locate file" << endl;
+ char **tried = includeChecks;
+ while ( *tried != 0 )
+ scan_error() << "include: attempted: \"" << *tried++ << '\"' << endl;
+ }
+ else {
+ /* Don't include anything that's already been included. */
+ if ( !duplicateInclude( includeChecks[found], inclSectionName ) ) {
+ parser->includeHistory.append( IncludeHistoryItem(
+ includeChecks[found], inclSectionName ) );
+
+ Scanner scanner( id, includeChecks[found], *inFile, parser,
+ inclSectionName, includeDepth+1, false );
+ scanner.do_scan( );
+ delete inFile;
+ }
+ }
+ }
+}
+
+void Scanner::handleImport()
+{
+ if ( active() ) {
+ char **importChecks = makeIncludePathChecks( fileName, lit, lit_len );
+
+ /* Open the input file for reading. */
+ long found = 0;
+ ifstream *inFile = tryOpenInclude( importChecks, found );
+ if ( inFile == 0 ) {
+ scan_error() << "import: could not open import file " <<
+ "for reading" << endl;
+ char **tried = importChecks;
+ while ( *tried != 0 )
+ scan_error() << "import: attempted: \"" << *tried++ << '\"' << endl;
+ }
+
+ Scanner scanner( id, importChecks[found], *inFile, parser,
+ 0, includeDepth+1, true );
+ scanner.do_scan( );
+ scanner.importToken( 0, 0, 0 );
+ scanner.flushImport();
+ delete inFile;
+ }
+}
+
+
+#line 461 "rlscan.rl"
+
+
+void Scanner::token( int type, char c )
+{
+ token( type, &c, &c + 1 );
+}
+
+void Scanner::token( int type )
+{
+ token( type, 0, 0 );
+}
+
+void Scanner::token( int type, char *start, char *end )
+{
+ char *tokdata = 0;
+ int toklen = 0;
+ if ( start != 0 ) {
+ toklen = end-start;
+ tokdata = new char[toklen+1];
+ memcpy( tokdata, start, toklen );
+ tokdata[toklen] = 0;
+ }
+
+ processToken( type, tokdata, toklen );
+}
+
+void Scanner::processToken( int type, char *tokdata, int toklen )
+{
+ int *p, *pe, *eof;
+
+ if ( type < 0 )
+ p = pe = eof = 0;
+ else {
+ p = &type;
+ pe = &type + 1;
+ eof = 0;
+ }
+
+
+#line 535 "rlscan.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+tr2:
+#line 391 "rlscan.rl"
+ { handleMachine(); }
+ goto st10;
+tr6:
+#line 392 "rlscan.rl"
+ { handleInclude(); }
+ goto st10;
+tr10:
+#line 393 "rlscan.rl"
+ { handleImport(); }
+ goto st10;
+tr13:
+#line 433 "rlscan.rl"
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->writeArgs.append( 0 );
+ }
+ goto st10;
+tr14:
+#line 444 "rlscan.rl"
+ {
+ /* Send the token off to the parser. */
+ if ( active() )
+ directToParser( parser, fileName, line, column, type, tokdata, toklen );
+ }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+#line 572 "rlscan.cpp"
+ switch( (*p) ) {
+ case 191: goto st1;
+ case 192: goto st3;
+ case 193: goto st6;
+ case 194: goto tr18;
+ }
+ goto tr14;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ if ( (*p) == 128 )
+ goto tr1;
+ goto tr0;
+tr0:
+#line 386 "rlscan.rl"
+ { scan_error() << "bad machine statement" << endl; }
+ goto st0;
+tr3:
+#line 387 "rlscan.rl"
+ { scan_error() << "bad include statement" << endl; }
+ goto st0;
+tr8:
+#line 388 "rlscan.rl"
+ { scan_error() << "bad import statement" << endl; }
+ goto st0;
+tr11:
+#line 389 "rlscan.rl"
+ { scan_error() << "bad write statement" << endl; }
+ goto st0;
+#line 603 "rlscan.cpp"
+st0:
+cs = 0;
+ goto _out;
+tr1:
+#line 383 "rlscan.rl"
+ { word = tokdata; word_len = toklen; }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 615 "rlscan.cpp"
+ if ( (*p) == 59 )
+ goto tr2;
+ goto tr0;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ switch( (*p) ) {
+ case 128: goto tr4;
+ case 129: goto tr5;
+ }
+ goto tr3;
+tr4:
+#line 382 "rlscan.rl"
+ { word = lit = 0; word_len = lit_len = 0; }
+#line 383 "rlscan.rl"
+ { word = tokdata; word_len = toklen; }
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 638 "rlscan.cpp"
+ switch( (*p) ) {
+ case 59: goto tr6;
+ case 129: goto tr7;
+ }
+ goto tr3;
+tr5:
+#line 382 "rlscan.rl"
+ { word = lit = 0; word_len = lit_len = 0; }
+#line 384 "rlscan.rl"
+ { lit = tokdata; lit_len = toklen; }
+ goto st5;
+tr7:
+#line 384 "rlscan.rl"
+ { lit = tokdata; lit_len = toklen; }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+#line 658 "rlscan.cpp"
+ if ( (*p) == 59 )
+ goto tr6;
+ goto tr3;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ if ( (*p) == 129 )
+ goto tr9;
+ goto tr8;
+tr9:
+#line 384 "rlscan.rl"
+ { lit = tokdata; lit_len = toklen; }
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+#line 677 "rlscan.cpp"
+ if ( (*p) == 59 )
+ goto tr10;
+ goto tr8;
+tr18:
+#line 413 "rlscan.rl"
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 ) {
+ InputItem *inputItem = new InputItem;
+ inputItem->type = InputItem::Write;
+ inputItem->loc.fileName = fileName;
+ inputItem->loc.line = line;
+ inputItem->loc.col = column;
+ inputItem->name = parser->sectionName;
+ inputItem->pd = parser->pd;
+ id.inputItems.append( inputItem );
+ }
+ }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 700 "rlscan.cpp"
+ if ( (*p) == 128 )
+ goto tr12;
+ goto tr11;
+tr12:
+#line 427 "rlscan.rl"
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->writeArgs.append( strdup(tokdata) );
+ }
+ goto st9;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+#line 715 "rlscan.cpp"
+ switch( (*p) ) {
+ case 59: goto tr13;
+ case 128: goto tr12;
+ }
+ goto tr11;
+ }
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 1:
+ case 2:
+#line 386 "rlscan.rl"
+ { scan_error() << "bad machine statement" << endl; }
+ break;
+ case 3:
+ case 4:
+ case 5:
+#line 387 "rlscan.rl"
+ { scan_error() << "bad include statement" << endl; }
+ break;
+ case 6:
+ case 7:
+#line 388 "rlscan.rl"
+ { scan_error() << "bad import statement" << endl; }
+ break;
+ case 8:
+ case 9:
+#line 389 "rlscan.rl"
+ { scan_error() << "bad write statement" << endl; }
+ break;
+#line 758 "rlscan.cpp"
+ }
+ }
+
+ _out: {}
+ }
+
+#line 502 "rlscan.rl"
+
+
+ updateCol();
+
+ /* Record the last token for use in controlling the scan of subsequent
+ * tokens. */
+ lastToken = type;
+}
+
+void Scanner::startSection( )
+{
+ parserExistsError = false;
+
+ sectionLoc.fileName = fileName;
+ sectionLoc.line = line;
+ sectionLoc.col = column;
+}
+
+void Scanner::endSection( )
+{
+ /* Execute the eof actions for the section parser. */
+ processToken( -1, 0, 0 );
+
+ /* Close off the section with the parser. */
+ if ( active() ) {
+ InputLoc loc;
+ loc.fileName = fileName;
+ loc.line = line;
+ loc.col = column;
+
+ parser->token( loc, TK_EndSection, 0, 0 );
+ }
+
+ if ( includeDepth == 0 ) {
+ if ( machineSpec == 0 && machineName == 0 ) {
+ /* The end section may include a newline on the end, so
+ * we use the last line, which will count the newline. */
+ InputItem *inputItem = new InputItem;
+ inputItem->type = InputItem::HostData;
+ inputItem->loc.line = line;
+ inputItem->loc.col = column;
+ id.inputItems.append( inputItem );
+ }
+ }
+}
+
+bool isAbsolutePath( const char *path )
+{
+#ifdef _WIN32
+ return isalpha( path[0] ) && path[1] == ':' && path[2] == '\\';
+#else
+ return path[0] == '/';
+#endif
+}
+
+char **Scanner::makeIncludePathChecks( const char *thisFileName,
+ const char *fileName, int fnlen )
+{
+ char **checks = 0;
+ long nextCheck = 0;
+ long length = 0;
+ bool caseInsensitive = false;
+ char *data = prepareLitString( InputLoc(), fileName, fnlen,
+ length, caseInsensitive );
+
+ /* Absolute path? */
+ if ( isAbsolutePath( data ) ) {
+ checks = new char*[2];
+ checks[nextCheck++] = data;
+ }
+ else {
+ checks = new char*[2 + id.includePaths.length()];
+
+ /* Search from the the location of the current file. */
+ const char *lastSlash = strrchr( thisFileName, PATH_SEP );
+ if ( lastSlash == 0 )
+ checks[nextCheck++] = data;
+ else {
+ long givenPathLen = (lastSlash - thisFileName) + 1;
+ long checklen = givenPathLen + length;
+ char *check = new char[checklen+1];
+ memcpy( check, thisFileName, givenPathLen );
+ memcpy( check+givenPathLen, data, length );
+ check[checklen] = 0;
+ checks[nextCheck++] = check;
+ }
+
+ /* Search from the include paths given on the command line. */
+ for ( ArgsVector::Iter incp = id.includePaths; incp.lte(); incp++ ) {
+ long pathLen = strlen( *incp );
+ long checkLen = pathLen + 1 + length;
+ char *check = new char[checkLen+1];
+ memcpy( check, *incp, pathLen );
+ check[pathLen] = PATH_SEP;
+ memcpy( check+pathLen+1, data, length );
+ check[checkLen] = 0;
+ checks[nextCheck++] = check;
+ }
+ }
+
+ checks[nextCheck] = 0;
+ return checks;
+}
+
+ifstream *Scanner::tryOpenInclude( char **pathChecks, long &found )
+{
+ char **check = pathChecks;
+ ifstream *inFile = new ifstream;
+
+ while ( *check != 0 ) {
+ inFile->open( *check );
+ if ( inFile->is_open() ) {
+ found = check - pathChecks;
+ return inFile;
+ }
+
+ /*
+ * 03/26/2011 jg:
+ * Don't rely on sloppy runtime behaviour: reset the state of the stream explicitly.
+ * If inFile->open() fails, which happens when include dirs are tested, the fail bit
+ * is set by the runtime library. Currently the VS runtime library opens new files,
+ * but when it comes to reading it refuses to work.
+ */
+ inFile->clear();
+
+ check += 1;
+ }
+
+ found = -1;
+ delete inFile;
+ return 0;
+}
+
+
+#line 1173 "rlscan.rl"
+
+
+
+#line 904 "rlscan.cpp"
+static const int rlscan_start = 38;
+static const int rlscan_first_final = 38;
+static const int rlscan_error = 0;
+
+static const int rlscan_en_inline_code_ruby = 52;
+static const int rlscan_en_inline_code = 95;
+static const int rlscan_en_or_literal = 137;
+static const int rlscan_en_ragel_re_literal = 139;
+static const int rlscan_en_write_statement = 143;
+static const int rlscan_en_parser_def = 146;
+static const int rlscan_en_main_ruby = 253;
+static const int rlscan_en_main = 38;
+
+
+#line 1176 "rlscan.rl"
+
+void Scanner::do_scan()
+{
+ int bufsize = 8;
+ char *buf = new char[bufsize];
+ int cs, act, have = 0;
+ int top;
+
+ /* The stack is two deep, one level for going into ragel defs from the main
+ * machines which process outside code, and another for going into or literals
+ * from either a ragel spec, or a regular expression. */
+ int stack[2];
+ int curly_count = 0;
+ bool execute = true;
+ bool singleLineSpec = false;
+ InlineBlockType inlineBlockType = CurlyDelimited;
+
+ /* Init the section parser and the character scanner. */
+ init();
+
+#line 940 "rlscan.cpp"
+ {
+ cs = rlscan_start;
+ top = 0;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 1196 "rlscan.rl"
+
+ /* Set up the start state. FIXME: After 5.20 is released the nocs write
+ * init option should be used, the main machine eliminated and this statement moved
+ * above the write init. */
+ if ( hostLang->lang == HostLang::Ruby )
+ cs = rlscan_en_main_ruby;
+ else
+ cs = rlscan_en_main;
+
+ 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 ( ts != 0 )
+ ts = newbuf + ( ts - buf );
+ te = newbuf + ( te - buf );
+
+ /* Copy the new buffer in. */
+ memcpy( newbuf, buf, have );
+ delete[] buf;
+ buf = newbuf;
+ }
+
+ input.read( p, space );
+ int len = input.gcount();
+ char *pe = p + len;
+
+ /* If we see eof then append the eof var. */
+ char *eof = 0;
+ if ( len == 0 ) {
+ eof = pe;
+ execute = false;
+ }
+
+
+#line 995 "rlscan.cpp"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ goto _resume;
+
+_again:
+ switch ( cs ) {
+ case 38: goto st38;
+ case 39: goto st39;
+ case 40: goto st40;
+ case 1: goto st1;
+ case 2: goto st2;
+ case 41: goto st41;
+ case 42: goto st42;
+ case 43: goto st43;
+ case 3: goto st3;
+ case 4: goto st4;
+ case 44: goto st44;
+ case 5: goto st5;
+ case 6: goto st6;
+ case 7: goto st7;
+ case 45: goto st45;
+ case 46: goto st46;
+ case 47: goto st47;
+ case 48: goto st48;
+ case 49: goto st49;
+ case 50: goto st50;
+ case 51: goto st51;
+ case 52: goto st52;
+ case 53: goto st53;
+ case 54: goto st54;
+ case 8: goto st8;
+ case 9: goto st9;
+ case 55: goto st55;
+ case 10: goto st10;
+ case 56: goto st56;
+ case 11: goto st11;
+ case 12: goto st12;
+ case 57: goto st57;
+ case 13: goto st13;
+ case 14: goto st14;
+ case 58: goto st58;
+ case 59: goto st59;
+ case 15: goto st15;
+ case 60: goto st60;
+ case 61: goto st61;
+ case 62: goto st62;
+ case 63: goto st63;
+ case 64: goto st64;
+ case 65: goto st65;
+ case 66: goto st66;
+ case 67: goto st67;
+ case 68: goto st68;
+ case 69: goto st69;
+ case 70: goto st70;
+ case 71: goto st71;
+ case 72: goto st72;
+ case 73: goto st73;
+ case 74: goto st74;
+ case 75: goto st75;
+ case 76: goto st76;
+ case 77: goto st77;
+ case 78: goto st78;
+ case 79: goto st79;
+ case 80: goto st80;
+ case 81: goto st81;
+ case 82: goto st82;
+ case 83: goto st83;
+ case 84: goto st84;
+ case 85: goto st85;
+ case 86: goto st86;
+ case 87: goto st87;
+ case 88: goto st88;
+ case 89: goto st89;
+ case 90: goto st90;
+ case 91: goto st91;
+ case 92: goto st92;
+ case 93: goto st93;
+ case 94: goto st94;
+ case 95: goto st95;
+ case 96: goto st96;
+ case 97: goto st97;
+ case 16: goto st16;
+ case 17: goto st17;
+ case 98: goto st98;
+ case 18: goto st18;
+ case 19: goto st19;
+ case 99: goto st99;
+ case 20: goto st20;
+ case 21: goto st21;
+ case 22: goto st22;
+ case 100: goto st100;
+ case 101: goto st101;
+ case 23: goto st23;
+ case 102: goto st102;
+ case 103: goto st103;
+ case 104: goto st104;
+ case 105: goto st105;
+ case 106: goto st106;
+ case 107: goto st107;
+ case 108: goto st108;
+ case 109: goto st109;
+ case 110: goto st110;
+ case 111: goto st111;
+ case 112: goto st112;
+ case 113: goto st113;
+ case 114: goto st114;
+ case 115: goto st115;
+ case 116: goto st116;
+ case 117: goto st117;
+ case 118: goto st118;
+ case 119: goto st119;
+ case 120: goto st120;
+ case 121: goto st121;
+ case 122: goto st122;
+ case 123: goto st123;
+ case 124: goto st124;
+ case 125: goto st125;
+ case 126: goto st126;
+ case 127: goto st127;
+ case 128: goto st128;
+ case 129: goto st129;
+ case 130: goto st130;
+ case 131: goto st131;
+ case 132: goto st132;
+ case 133: goto st133;
+ case 134: goto st134;
+ case 135: goto st135;
+ case 136: goto st136;
+ case 137: goto st137;
+ case 138: goto st138;
+ case 139: goto st139;
+ case 140: goto st140;
+ case 141: goto st141;
+ case 142: goto st142;
+ case 143: goto st143;
+ case 0: goto st0;
+ case 144: goto st144;
+ case 145: goto st145;
+ case 146: goto st146;
+ case 147: goto st147;
+ case 148: goto st148;
+ case 24: goto st24;
+ case 149: goto st149;
+ case 25: goto st25;
+ case 150: goto st150;
+ case 26: goto st26;
+ case 151: goto st151;
+ case 152: goto st152;
+ case 153: goto st153;
+ case 27: goto st27;
+ case 28: goto st28;
+ case 154: goto st154;
+ case 155: goto st155;
+ case 156: goto st156;
+ case 157: goto st157;
+ case 158: goto st158;
+ case 29: goto st29;
+ case 159: goto st159;
+ case 160: goto st160;
+ case 161: goto st161;
+ case 162: goto st162;
+ case 163: goto st163;
+ case 164: goto st164;
+ case 165: goto st165;
+ case 166: goto st166;
+ case 167: goto st167;
+ case 168: goto st168;
+ case 169: goto st169;
+ case 170: goto st170;
+ case 171: goto st171;
+ case 172: goto st172;
+ case 173: goto st173;
+ case 174: goto st174;
+ case 175: goto st175;
+ case 176: goto st176;
+ case 177: goto st177;
+ case 178: goto st178;
+ case 179: goto st179;
+ case 180: goto st180;
+ case 181: goto st181;
+ case 182: goto st182;
+ case 183: goto st183;
+ case 184: goto st184;
+ case 185: goto st185;
+ case 186: goto st186;
+ case 187: goto st187;
+ case 188: goto st188;
+ case 189: goto st189;
+ case 190: goto st190;
+ case 191: goto st191;
+ case 192: goto st192;
+ case 193: goto st193;
+ case 194: goto st194;
+ case 195: goto st195;
+ case 196: goto st196;
+ case 197: goto st197;
+ case 198: goto st198;
+ case 199: goto st199;
+ case 200: goto st200;
+ case 201: goto st201;
+ case 202: goto st202;
+ case 203: goto st203;
+ case 204: goto st204;
+ case 205: goto st205;
+ case 206: goto st206;
+ case 207: goto st207;
+ case 208: goto st208;
+ case 209: goto st209;
+ case 210: goto st210;
+ case 211: goto st211;
+ case 212: goto st212;
+ case 213: goto st213;
+ case 214: goto st214;
+ case 215: goto st215;
+ case 216: goto st216;
+ case 217: goto st217;
+ case 218: goto st218;
+ case 219: goto st219;
+ case 220: goto st220;
+ case 221: goto st221;
+ case 222: goto st222;
+ case 223: goto st223;
+ case 224: goto st224;
+ case 225: goto st225;
+ case 226: goto st226;
+ case 227: goto st227;
+ case 228: goto st228;
+ case 229: goto st229;
+ case 230: goto st230;
+ case 231: goto st231;
+ case 232: goto st232;
+ case 233: goto st233;
+ case 234: goto st234;
+ case 235: goto st235;
+ case 236: goto st236;
+ case 237: goto st237;
+ case 238: goto st238;
+ case 239: goto st239;
+ case 240: goto st240;
+ case 241: goto st241;
+ case 242: goto st242;
+ case 243: goto st243;
+ case 244: goto st244;
+ case 245: goto st245;
+ case 246: goto st246;
+ case 247: goto st247;
+ case 248: goto st248;
+ case 249: goto st249;
+ case 250: goto st250;
+ case 251: goto st251;
+ case 252: goto st252;
+ case 30: goto st30;
+ case 253: goto st253;
+ case 254: goto st254;
+ case 255: goto st255;
+ case 31: goto st31;
+ case 32: goto st32;
+ case 256: goto st256;
+ case 33: goto st33;
+ case 257: goto st257;
+ case 258: goto st258;
+ case 259: goto st259;
+ case 34: goto st34;
+ case 35: goto st35;
+ case 260: goto st260;
+ case 36: goto st36;
+ case 37: goto st37;
+ case 261: goto st261;
+ case 262: goto st262;
+ default: break;
+ }
+
+ if ( ++p == pe )
+ goto _test_eof;
+_resume:
+ switch ( cs )
+ {
+tr0:
+#line 1171 "rlscan.rl"
+ {{p = ((te))-1;}{ pass( *ts, 0, 0 ); }}
+ goto st38;
+tr3:
+#line 1155 "rlscan.rl"
+ {te = p+1;{ pass( IMP_Literal, ts, te ); }}
+ goto st38;
+tr11:
+#line 1154 "rlscan.rl"
+ {te = p+1;{ pass(); }}
+ goto st38;
+tr13:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 1154 "rlscan.rl"
+ {te = p+1;{ pass(); }}
+ goto st38;
+tr71:
+#line 1171 "rlscan.rl"
+ {te = p+1;{ pass( *ts, 0, 0 ); }}
+ goto st38;
+tr72:
+#line 1170 "rlscan.rl"
+ {te = p+1;}
+ goto st38;
+tr82:
+#line 1169 "rlscan.rl"
+ {te = p;p--;{ pass(); }}
+ goto st38;
+tr83:
+#line 1171 "rlscan.rl"
+ {te = p;p--;{ pass( *ts, 0, 0 ); }}
+ goto st38;
+tr85:
+#line 1163 "rlscan.rl"
+ {te = p;p--;{
+ updateCol();
+ singleLineSpec = true;
+ startSection();
+ {stack[top++] = 38; goto st146;}
+ }}
+ goto st38;
+tr86:
+#line 1157 "rlscan.rl"
+ {te = p+1;{
+ updateCol();
+ singleLineSpec = false;
+ startSection();
+ {stack[top++] = 38; goto st146;}
+ }}
+ goto st38;
+tr87:
+#line 1153 "rlscan.rl"
+ {te = p;p--;{ pass( IMP_UInt, ts, te ); }}
+ goto st38;
+tr88:
+#line 1 "NONE"
+ { switch( act ) {
+ case 176:
+ {{p = ((te))-1;} pass( IMP_Define, 0, 0 ); }
+ break;
+ case 177:
+ {{p = ((te))-1;} pass( IMP_Word, ts, te ); }
+ break;
+ }
+ }
+ goto st38;
+tr89:
+#line 1152 "rlscan.rl"
+ {te = p;p--;{ pass( IMP_Word, ts, te ); }}
+ goto st38;
+st38:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+#line 1 "NONE"
+ {ts = p;}
+#line 1358 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr72;
+ case 9: goto st39;
+ case 10: goto tr74;
+ case 32: goto st39;
+ case 34: goto tr75;
+ case 37: goto st41;
+ case 39: goto tr77;
+ case 47: goto tr78;
+ case 95: goto tr80;
+ case 100: goto st47;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st45;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr71;
+tr74:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st39;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+#line 1392 "rlscan.cpp"
+ switch( (*p) ) {
+ case 9: goto st39;
+ case 10: goto tr74;
+ case 32: goto st39;
+ }
+ goto tr82;
+tr75:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st40;
+st40:
+ if ( ++p == pe )
+ goto _test_eof40;
+case 40:
+#line 1407 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr2;
+ case 34: goto tr3;
+ case 92: goto st2;
+ }
+ goto st1;
+tr2:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+#line 1426 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr2;
+ case 34: goto tr3;
+ case 92: goto st2;
+ }
+ goto st1;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ if ( (*p) == 10 )
+ goto tr2;
+ goto st1;
+st41:
+ if ( ++p == pe )
+ goto _test_eof41;
+case 41:
+ if ( (*p) == 37 )
+ goto st42;
+ goto tr83;
+st42:
+ if ( ++p == pe )
+ goto _test_eof42;
+case 42:
+ if ( (*p) == 123 )
+ goto tr86;
+ goto tr85;
+tr77:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st43;
+st43:
+ if ( ++p == pe )
+ goto _test_eof43;
+case 43:
+#line 1462 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr6;
+ case 39: goto tr3;
+ case 92: goto st4;
+ }
+ goto st3;
+tr6:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 1481 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr6;
+ case 39: goto tr3;
+ case 92: goto st4;
+ }
+ goto st3;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ if ( (*p) == 10 )
+ goto tr6;
+ goto st3;
+tr78:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st44;
+st44:
+ if ( ++p == pe )
+ goto _test_eof44;
+case 44:
+#line 1503 "rlscan.cpp"
+ switch( (*p) ) {
+ case 42: goto st5;
+ case 47: goto st7;
+ }
+ goto tr83;
+tr9:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+#line 1521 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr9;
+ case 42: goto st6;
+ }
+ goto st5;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ switch( (*p) ) {
+ case 10: goto tr9;
+ case 42: goto st6;
+ case 47: goto tr11;
+ }
+ goto st5;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( (*p) == 10 )
+ goto tr13;
+ goto st7;
+st45:
+ if ( ++p == pe )
+ goto _test_eof45;
+case 45:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st45;
+ goto tr87;
+tr80:
+#line 1 "NONE"
+ {te = p+1;}
+#line 1152 "rlscan.rl"
+ {act = 177;}
+ goto st46;
+tr94:
+#line 1 "NONE"
+ {te = p+1;}
+#line 1151 "rlscan.rl"
+ {act = 176;}
+ goto st46;
+st46:
+ if ( ++p == pe )
+ goto _test_eof46;
+case 46:
+#line 1567 "rlscan.cpp"
+ if ( (*p) == 95 )
+ goto tr80;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr88;
+st47:
+ if ( ++p == pe )
+ goto _test_eof47;
+case 47:
+ switch( (*p) ) {
+ case 95: goto tr80;
+ case 101: goto st48;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr89;
+st48:
+ if ( ++p == pe )
+ goto _test_eof48;
+case 48:
+ switch( (*p) ) {
+ case 95: goto tr80;
+ case 102: goto st49;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr89;
+st49:
+ if ( ++p == pe )
+ goto _test_eof49;
+case 49:
+ switch( (*p) ) {
+ case 95: goto tr80;
+ case 105: goto st50;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr89;
+st50:
+ if ( ++p == pe )
+ goto _test_eof50;
+case 50:
+ switch( (*p) ) {
+ case 95: goto tr80;
+ case 110: goto st51;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr89;
+st51:
+ if ( ++p == pe )
+ goto _test_eof51;
+case 51:
+ switch( (*p) ) {
+ case 95: goto tr80;
+ case 101: goto tr94;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr80;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr80;
+ } else
+ goto tr80;
+ goto tr89;
+tr14:
+#line 770 "rlscan.rl"
+ {{p = ((te))-1;}{ token( IL_Symbol, ts, te ); }}
+ goto st52;
+tr17:
+#line 716 "rlscan.rl"
+ {te = p+1;{ token( IL_Literal, ts, te ); }}
+ goto st52;
+tr20:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 723 "rlscan.rl"
+ {te = p+1;{ token( IL_Comment, ts, te ); }}
+ goto st52;
+tr27:
+#line 712 "rlscan.rl"
+ {{p = ((te))-1;}{ token( TK_UInt, ts, te ); }}
+ goto st52;
+tr95:
+#line 770 "rlscan.rl"
+ {te = p+1;{ token( IL_Symbol, ts, te ); }}
+ goto st52;
+tr96:
+#line 765 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated code block" << endl;
+ }}
+ goto st52;
+tr102:
+#line 745 "rlscan.rl"
+ {te = p+1;{ token( *ts, ts, te ); }}
+ goto st52;
+tr103:
+#line 740 "rlscan.rl"
+ {te = p+1;{
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ }}
+ goto st52;
+tr108:
+#line 733 "rlscan.rl"
+ {te = p+1;{
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ if ( inlineBlockType == SemiTerminated )
+ {cs = stack[--top];goto _again;}
+ }}
+ goto st52;
+tr111:
+#line 747 "rlscan.rl"
+ {te = p+1;{
+ token( IL_Symbol, ts, te );
+ curly_count += 1;
+ }}
+ goto st52;
+tr112:
+#line 752 "rlscan.rl"
+ {te = p+1;{
+ if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
+ /* Inline code block ends. */
+ token( '}' );
+ {cs = stack[--top];goto _again;}
+ }
+ else {
+ /* Either a semi terminated inline block or only the closing
+ * brace of some inner scope, not the block's closing brace. */
+ token( IL_Symbol, ts, te );
+ }
+ }}
+ goto st52;
+tr113:
+#line 718 "rlscan.rl"
+ {te = p;p--;{
+ if ( whitespaceOn )
+ token( IL_WhiteSpace, ts, te );
+ }}
+ goto st52;
+tr114:
+#line 770 "rlscan.rl"
+ {te = p;p--;{ token( IL_Symbol, ts, te ); }}
+ goto st52;
+tr115:
+#line 712 "rlscan.rl"
+ {te = p;p--;{ token( TK_UInt, ts, te ); }}
+ goto st52;
+tr117:
+#line 713 "rlscan.rl"
+ {te = p;p--;{ token( TK_Hex, ts, te ); }}
+ goto st52;
+tr118:
+#line 725 "rlscan.rl"
+ {te = p+1;{ token( TK_NameSep, ts, te ); }}
+ goto st52;
+tr119:
+#line 1 "NONE"
+ { switch( act ) {
+ case 1:
+ {{p = ((te))-1;} token( KW_PChar ); }
+ break;
+ case 3:
+ {{p = ((te))-1;} token( KW_CurState ); }
+ break;
+ case 4:
+ {{p = ((te))-1;} token( KW_TargState ); }
+ break;
+ case 5:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Entry );
+ }
+ break;
+ case 6:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Hold );
+ }
+ break;
+ case 7:
+ {{p = ((te))-1;} token( KW_Exec, 0, 0 ); }
+ break;
+ case 8:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Goto );
+ }
+ break;
+ case 9:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Next );
+ }
+ break;
+ case 10:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Call );
+ }
+ break;
+ case 11:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Ret );
+ }
+ break;
+ case 12:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Break );
+ }
+ break;
+ case 13:
+ {{p = ((te))-1;} token( TK_Word, ts, te ); }
+ break;
+ }
+ }
+ goto st52;
+tr120:
+#line 710 "rlscan.rl"
+ {te = p;p--;{ token( TK_Word, ts, te ); }}
+ goto st52;
+tr134:
+#line 675 "rlscan.rl"
+ {te = p;p--;{ token( KW_Char ); }}
+ goto st52;
+st52:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof52;
+case 52:
+#line 1 "NONE"
+ {ts = p;}
+#line 1840 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr96;
+ case 9: goto st53;
+ case 10: goto tr98;
+ case 32: goto st53;
+ case 34: goto tr99;
+ case 35: goto tr100;
+ case 39: goto tr101;
+ case 40: goto tr102;
+ case 44: goto tr102;
+ case 47: goto tr104;
+ case 48: goto tr105;
+ case 58: goto st61;
+ case 59: goto tr108;
+ case 95: goto tr109;
+ case 102: goto st63;
+ case 123: goto tr111;
+ case 125: goto tr112;
+ }
+ if ( (*p) < 49 ) {
+ if ( 41 <= (*p) && (*p) <= 42 )
+ goto tr103;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else if ( (*p) >= 65 )
+ goto tr109;
+ } else
+ goto st59;
+ goto tr95;
+tr98:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st53;
+st53:
+ if ( ++p == pe )
+ goto _test_eof53;
+case 53:
+#line 1884 "rlscan.cpp"
+ switch( (*p) ) {
+ case 9: goto st53;
+ case 10: goto tr98;
+ case 32: goto st53;
+ }
+ goto tr113;
+tr99:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st54;
+st54:
+ if ( ++p == pe )
+ goto _test_eof54;
+case 54:
+#line 1899 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr16;
+ case 34: goto tr17;
+ case 92: goto st9;
+ }
+ goto st8;
+tr16:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+#line 1918 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr16;
+ case 34: goto tr17;
+ case 92: goto st9;
+ }
+ goto st8;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) == 10 )
+ goto tr16;
+ goto st8;
+tr100:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st55;
+st55:
+ if ( ++p == pe )
+ goto _test_eof55;
+case 55:
+#line 1940 "rlscan.cpp"
+ if ( (*p) == 10 )
+ goto tr20;
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ if ( (*p) == 10 )
+ goto tr20;
+ goto st10;
+tr101:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st56;
+st56:
+ if ( ++p == pe )
+ goto _test_eof56;
+case 56:
+#line 1959 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr22;
+ case 39: goto tr17;
+ case 92: goto st12;
+ }
+ goto st11;
+tr22:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st11;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+#line 1978 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr22;
+ case 39: goto tr17;
+ case 92: goto st12;
+ }
+ goto st11;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ if ( (*p) == 10 )
+ goto tr22;
+ goto st11;
+tr104:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st57;
+st57:
+ if ( ++p == pe )
+ goto _test_eof57;
+case 57:
+#line 2000 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr25;
+ case 47: goto tr17;
+ case 92: goto st14;
+ }
+ goto st13;
+tr25:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st13;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+#line 2019 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr25;
+ case 47: goto tr17;
+ case 92: goto st14;
+ }
+ goto st13;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ if ( (*p) == 10 )
+ goto tr25;
+ goto st13;
+tr105:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st58;
+st58:
+ if ( ++p == pe )
+ goto _test_eof58;
+case 58:
+#line 2041 "rlscan.cpp"
+ if ( (*p) == 120 )
+ goto st15;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st59;
+ goto tr115;
+st59:
+ if ( ++p == pe )
+ goto _test_eof59;
+case 59:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st59;
+ goto tr115;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st60;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st60;
+ } else
+ goto st60;
+ goto tr27;
+st60:
+ if ( ++p == pe )
+ goto _test_eof60;
+case 60:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st60;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st60;
+ } else
+ goto st60;
+ goto tr117;
+st61:
+ if ( ++p == pe )
+ goto _test_eof61;
+case 61:
+ if ( (*p) == 58 )
+ goto tr118;
+ goto tr114;
+tr109:
+#line 1 "NONE"
+ {te = p+1;}
+#line 710 "rlscan.rl"
+ {act = 13;}
+ goto st62;
+tr133:
+#line 1 "NONE"
+ {te = p+1;}
+#line 705 "rlscan.rl"
+ {act = 12;}
+ goto st62;
+tr138:
+#line 1 "NONE"
+ {te = p+1;}
+#line 697 "rlscan.rl"
+ {act = 10;}
+ goto st62;
+tr140:
+#line 1 "NONE"
+ {te = p+1;}
+#line 676 "rlscan.rl"
+ {act = 3;}
+ goto st62;
+tr145:
+#line 1 "NONE"
+ {te = p+1;}
+#line 678 "rlscan.rl"
+ {act = 5;}
+ goto st62;
+tr147:
+#line 1 "NONE"
+ {te = p+1;}
+#line 688 "rlscan.rl"
+ {act = 7;}
+ goto st62;
+tr150:
+#line 1 "NONE"
+ {te = p+1;}
+#line 689 "rlscan.rl"
+ {act = 8;}
+ goto st62;
+tr153:
+#line 1 "NONE"
+ {te = p+1;}
+#line 684 "rlscan.rl"
+ {act = 6;}
+ goto st62;
+tr156:
+#line 1 "NONE"
+ {te = p+1;}
+#line 693 "rlscan.rl"
+ {act = 9;}
+ goto st62;
+tr157:
+#line 1 "NONE"
+ {te = p+1;}
+#line 674 "rlscan.rl"
+ {act = 1;}
+ goto st62;
+tr159:
+#line 1 "NONE"
+ {te = p+1;}
+#line 701 "rlscan.rl"
+ {act = 11;}
+ goto st62;
+tr163:
+#line 1 "NONE"
+ {te = p+1;}
+#line 677 "rlscan.rl"
+ {act = 4;}
+ goto st62;
+st62:
+ if ( ++p == pe )
+ goto _test_eof62;
+case 62:
+#line 2163 "rlscan.cpp"
+ if ( (*p) == 95 )
+ goto tr109;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr119;
+st63:
+ if ( ++p == pe )
+ goto _test_eof63;
+case 63:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 98: goto st64;
+ case 99: goto st68;
+ case 101: goto st73;
+ case 103: goto st79;
+ case 104: goto st82;
+ case 110: goto st85;
+ case 112: goto st88;
+ case 114: goto st89;
+ case 116: goto st91;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st64:
+ if ( ++p == pe )
+ goto _test_eof64;
+case 64:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 114: goto st65;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st65:
+ if ( ++p == pe )
+ goto _test_eof65;
+case 65:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 101: goto st66;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st66:
+ if ( ++p == pe )
+ goto _test_eof66;
+case 66:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 97: goto st67;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st67:
+ if ( ++p == pe )
+ goto _test_eof67;
+case 67:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 107: goto tr133;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st68:
+ if ( ++p == pe )
+ goto _test_eof68;
+case 68:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 97: goto st69;
+ case 117: goto st71;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr134;
+st69:
+ if ( ++p == pe )
+ goto _test_eof69;
+case 69:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 108: goto st70;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st70:
+ if ( ++p == pe )
+ goto _test_eof70;
+case 70:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 108: goto tr138;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st71:
+ if ( ++p == pe )
+ goto _test_eof71;
+case 71:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 114: goto st72;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st72:
+ if ( ++p == pe )
+ goto _test_eof72;
+case 72:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 115: goto tr140;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st73:
+ if ( ++p == pe )
+ goto _test_eof73;
+case 73:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 110: goto st74;
+ case 120: goto st77;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st74:
+ if ( ++p == pe )
+ goto _test_eof74;
+case 74:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 116: goto st75;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st75:
+ if ( ++p == pe )
+ goto _test_eof75;
+case 75:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 114: goto st76;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st76:
+ if ( ++p == pe )
+ goto _test_eof76;
+case 76:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 121: goto tr145;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st77:
+ if ( ++p == pe )
+ goto _test_eof77;
+case 77:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 101: goto st78;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st78:
+ if ( ++p == pe )
+ goto _test_eof78;
+case 78:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 99: goto tr147;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st79:
+ if ( ++p == pe )
+ goto _test_eof79;
+case 79:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 111: goto st80;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st80:
+ if ( ++p == pe )
+ goto _test_eof80;
+case 80:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 116: goto st81;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st81:
+ if ( ++p == pe )
+ goto _test_eof81;
+case 81:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 111: goto tr150;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st82:
+ if ( ++p == pe )
+ goto _test_eof82;
+case 82:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 111: goto st83;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st83:
+ if ( ++p == pe )
+ goto _test_eof83;
+case 83:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 108: goto st84;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st84:
+ if ( ++p == pe )
+ goto _test_eof84;
+case 84:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 100: goto tr153;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st85:
+ if ( ++p == pe )
+ goto _test_eof85;
+case 85:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 101: goto st86;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st86:
+ if ( ++p == pe )
+ goto _test_eof86;
+case 86:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 120: goto st87;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st87:
+ if ( ++p == pe )
+ goto _test_eof87;
+case 87:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 116: goto tr156;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st88:
+ if ( ++p == pe )
+ goto _test_eof88;
+case 88:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 99: goto tr157;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st89:
+ if ( ++p == pe )
+ goto _test_eof89;
+case 89:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 101: goto st90;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st90:
+ if ( ++p == pe )
+ goto _test_eof90;
+case 90:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 116: goto tr159;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st91:
+ if ( ++p == pe )
+ goto _test_eof91;
+case 91:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 97: goto st92;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st92:
+ if ( ++p == pe )
+ goto _test_eof92;
+case 92:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 114: goto st93;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st93:
+ if ( ++p == pe )
+ goto _test_eof93;
+case 93:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 103: goto st94;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+st94:
+ if ( ++p == pe )
+ goto _test_eof94;
+case 94:
+ switch( (*p) ) {
+ case 95: goto tr109;
+ case 115: goto tr163;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr109;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr109;
+ } else
+ goto tr109;
+ goto tr120;
+tr29:
+#line 873 "rlscan.rl"
+ {{p = ((te))-1;}{ token( IL_Symbol, ts, te ); }}
+ goto st95;
+tr32:
+#line 819 "rlscan.rl"
+ {te = p+1;{ token( IL_Literal, ts, te ); }}
+ goto st95;
+tr40:
+#line 826 "rlscan.rl"
+ {te = p+1;{ token( IL_Comment, ts, te ); }}
+ goto st95;
+tr42:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 826 "rlscan.rl"
+ {te = p+1;{ token( IL_Comment, ts, te ); }}
+ goto st95;
+tr43:
+#line 815 "rlscan.rl"
+ {{p = ((te))-1;}{ token( TK_UInt, ts, te ); }}
+ goto st95;
+tr164:
+#line 873 "rlscan.rl"
+ {te = p+1;{ token( IL_Symbol, ts, te ); }}
+ goto st95;
+tr165:
+#line 868 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated code block" << endl;
+ }}
+ goto st95;
+tr170:
+#line 848 "rlscan.rl"
+ {te = p+1;{ token( *ts, ts, te ); }}
+ goto st95;
+tr171:
+#line 843 "rlscan.rl"
+ {te = p+1;{
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ }}
+ goto st95;
+tr176:
+#line 836 "rlscan.rl"
+ {te = p+1;{
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ if ( inlineBlockType == SemiTerminated )
+ {cs = stack[--top];goto _again;}
+ }}
+ goto st95;
+tr179:
+#line 850 "rlscan.rl"
+ {te = p+1;{
+ token( IL_Symbol, ts, te );
+ curly_count += 1;
+ }}
+ goto st95;
+tr180:
+#line 855 "rlscan.rl"
+ {te = p+1;{
+ if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
+ /* Inline code block ends. */
+ token( '}' );
+ {cs = stack[--top];goto _again;}
+ }
+ else {
+ /* Either a semi terminated inline block or only the closing
+ * brace of some inner scope, not the block's closing brace. */
+ token( IL_Symbol, ts, te );
+ }
+ }}
+ goto st95;
+tr181:
+#line 821 "rlscan.rl"
+ {te = p;p--;{
+ if ( whitespaceOn )
+ token( IL_WhiteSpace, ts, te );
+ }}
+ goto st95;
+tr182:
+#line 873 "rlscan.rl"
+ {te = p;p--;{ token( IL_Symbol, ts, te ); }}
+ goto st95;
+tr183:
+#line 815 "rlscan.rl"
+ {te = p;p--;{ token( TK_UInt, ts, te ); }}
+ goto st95;
+tr185:
+#line 816 "rlscan.rl"
+ {te = p;p--;{ token( TK_Hex, ts, te ); }}
+ goto st95;
+tr186:
+#line 828 "rlscan.rl"
+ {te = p+1;{ token( TK_NameSep, ts, te ); }}
+ goto st95;
+tr187:
+#line 1 "NONE"
+ { switch( act ) {
+ case 27:
+ {{p = ((te))-1;} token( KW_PChar ); }
+ break;
+ case 29:
+ {{p = ((te))-1;} token( KW_CurState ); }
+ break;
+ case 30:
+ {{p = ((te))-1;} token( KW_TargState ); }
+ break;
+ case 31:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Entry );
+ }
+ break;
+ case 32:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Hold );
+ }
+ break;
+ case 33:
+ {{p = ((te))-1;} token( KW_Exec, 0, 0 ); }
+ break;
+ case 34:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Goto );
+ }
+ break;
+ case 35:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Next );
+ }
+ break;
+ case 36:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Call );
+ }
+ break;
+ case 37:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Ret );
+ }
+ break;
+ case 38:
+ {{p = ((te))-1;}
+ whitespaceOn = false;
+ token( KW_Break );
+ }
+ break;
+ case 39:
+ {{p = ((te))-1;} token( TK_Word, ts, te ); }
+ break;
+ }
+ }
+ goto st95;
+tr188:
+#line 813 "rlscan.rl"
+ {te = p;p--;{ token( TK_Word, ts, te ); }}
+ goto st95;
+tr202:
+#line 778 "rlscan.rl"
+ {te = p;p--;{ token( KW_Char ); }}
+ goto st95;
+st95:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof95;
+case 95:
+#line 1 "NONE"
+ {ts = p;}
+#line 2909 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr165;
+ case 9: goto st96;
+ case 10: goto tr167;
+ case 32: goto st96;
+ case 34: goto tr168;
+ case 39: goto tr169;
+ case 40: goto tr170;
+ case 44: goto tr170;
+ case 47: goto tr172;
+ case 48: goto tr173;
+ case 58: goto st103;
+ case 59: goto tr176;
+ case 95: goto tr177;
+ case 102: goto st105;
+ case 123: goto tr179;
+ case 125: goto tr180;
+ }
+ if ( (*p) < 49 ) {
+ if ( 41 <= (*p) && (*p) <= 42 )
+ goto tr171;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else if ( (*p) >= 65 )
+ goto tr177;
+ } else
+ goto st101;
+ goto tr164;
+tr167:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st96;
+st96:
+ if ( ++p == pe )
+ goto _test_eof96;
+case 96:
+#line 2952 "rlscan.cpp"
+ switch( (*p) ) {
+ case 9: goto st96;
+ case 10: goto tr167;
+ case 32: goto st96;
+ }
+ goto tr181;
+tr168:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st97;
+st97:
+ if ( ++p == pe )
+ goto _test_eof97;
+case 97:
+#line 2967 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr31;
+ case 34: goto tr32;
+ case 92: goto st17;
+ }
+ goto st16;
+tr31:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st16;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+#line 2986 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr31;
+ case 34: goto tr32;
+ case 92: goto st17;
+ }
+ goto st16;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ if ( (*p) == 10 )
+ goto tr31;
+ goto st16;
+tr169:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st98;
+st98:
+ if ( ++p == pe )
+ goto _test_eof98;
+case 98:
+#line 3008 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr35;
+ case 39: goto tr32;
+ case 92: goto st19;
+ }
+ goto st18;
+tr35:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st18;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+#line 3027 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr35;
+ case 39: goto tr32;
+ case 92: goto st19;
+ }
+ goto st18;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ if ( (*p) == 10 )
+ goto tr35;
+ goto st18;
+tr172:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st99;
+st99:
+ if ( ++p == pe )
+ goto _test_eof99;
+case 99:
+#line 3049 "rlscan.cpp"
+ switch( (*p) ) {
+ case 42: goto st20;
+ case 47: goto st22;
+ }
+ goto tr182;
+tr38:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st20;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+#line 3067 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr38;
+ case 42: goto st21;
+ }
+ goto st20;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+ switch( (*p) ) {
+ case 10: goto tr38;
+ case 42: goto st21;
+ case 47: goto tr40;
+ }
+ goto st20;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+ if ( (*p) == 10 )
+ goto tr42;
+ goto st22;
+tr173:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st100;
+st100:
+ if ( ++p == pe )
+ goto _test_eof100;
+case 100:
+#line 3098 "rlscan.cpp"
+ if ( (*p) == 120 )
+ goto st23;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st101;
+ goto tr183;
+st101:
+ if ( ++p == pe )
+ goto _test_eof101;
+case 101:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st101;
+ goto tr183;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st102;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st102;
+ } else
+ goto st102;
+ goto tr43;
+st102:
+ if ( ++p == pe )
+ goto _test_eof102;
+case 102:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st102;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st102;
+ } else
+ goto st102;
+ goto tr185;
+st103:
+ if ( ++p == pe )
+ goto _test_eof103;
+case 103:
+ if ( (*p) == 58 )
+ goto tr186;
+ goto tr182;
+tr177:
+#line 1 "NONE"
+ {te = p+1;}
+#line 813 "rlscan.rl"
+ {act = 39;}
+ goto st104;
+tr201:
+#line 1 "NONE"
+ {te = p+1;}
+#line 808 "rlscan.rl"
+ {act = 38;}
+ goto st104;
+tr206:
+#line 1 "NONE"
+ {te = p+1;}
+#line 800 "rlscan.rl"
+ {act = 36;}
+ goto st104;
+tr208:
+#line 1 "NONE"
+ {te = p+1;}
+#line 779 "rlscan.rl"
+ {act = 29;}
+ goto st104;
+tr213:
+#line 1 "NONE"
+ {te = p+1;}
+#line 781 "rlscan.rl"
+ {act = 31;}
+ goto st104;
+tr215:
+#line 1 "NONE"
+ {te = p+1;}
+#line 791 "rlscan.rl"
+ {act = 33;}
+ goto st104;
+tr218:
+#line 1 "NONE"
+ {te = p+1;}
+#line 792 "rlscan.rl"
+ {act = 34;}
+ goto st104;
+tr221:
+#line 1 "NONE"
+ {te = p+1;}
+#line 787 "rlscan.rl"
+ {act = 32;}
+ goto st104;
+tr224:
+#line 1 "NONE"
+ {te = p+1;}
+#line 796 "rlscan.rl"
+ {act = 35;}
+ goto st104;
+tr225:
+#line 1 "NONE"
+ {te = p+1;}
+#line 777 "rlscan.rl"
+ {act = 27;}
+ goto st104;
+tr227:
+#line 1 "NONE"
+ {te = p+1;}
+#line 804 "rlscan.rl"
+ {act = 37;}
+ goto st104;
+tr231:
+#line 1 "NONE"
+ {te = p+1;}
+#line 780 "rlscan.rl"
+ {act = 30;}
+ goto st104;
+st104:
+ if ( ++p == pe )
+ goto _test_eof104;
+case 104:
+#line 3220 "rlscan.cpp"
+ if ( (*p) == 95 )
+ goto tr177;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr187;
+st105:
+ if ( ++p == pe )
+ goto _test_eof105;
+case 105:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 98: goto st106;
+ case 99: goto st110;
+ case 101: goto st115;
+ case 103: goto st121;
+ case 104: goto st124;
+ case 110: goto st127;
+ case 112: goto st130;
+ case 114: goto st131;
+ case 116: goto st133;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st106:
+ if ( ++p == pe )
+ goto _test_eof106;
+case 106:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 114: goto st107;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st107:
+ if ( ++p == pe )
+ goto _test_eof107;
+case 107:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 101: goto st108;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st108:
+ if ( ++p == pe )
+ goto _test_eof108;
+case 108:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 97: goto st109;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st109:
+ if ( ++p == pe )
+ goto _test_eof109;
+case 109:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 107: goto tr201;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st110:
+ if ( ++p == pe )
+ goto _test_eof110;
+case 110:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 97: goto st111;
+ case 117: goto st113;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr202;
+st111:
+ if ( ++p == pe )
+ goto _test_eof111;
+case 111:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 108: goto st112;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st112:
+ if ( ++p == pe )
+ goto _test_eof112;
+case 112:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 108: goto tr206;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st113:
+ if ( ++p == pe )
+ goto _test_eof113;
+case 113:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 114: goto st114;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st114:
+ if ( ++p == pe )
+ goto _test_eof114;
+case 114:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 115: goto tr208;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st115:
+ if ( ++p == pe )
+ goto _test_eof115;
+case 115:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 110: goto st116;
+ case 120: goto st119;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st116:
+ if ( ++p == pe )
+ goto _test_eof116;
+case 116:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 116: goto st117;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st117:
+ if ( ++p == pe )
+ goto _test_eof117;
+case 117:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 114: goto st118;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st118:
+ if ( ++p == pe )
+ goto _test_eof118;
+case 118:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 121: goto tr213;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st119:
+ if ( ++p == pe )
+ goto _test_eof119;
+case 119:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 101: goto st120;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st120:
+ if ( ++p == pe )
+ goto _test_eof120;
+case 120:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 99: goto tr215;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st121:
+ if ( ++p == pe )
+ goto _test_eof121;
+case 121:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 111: goto st122;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st122:
+ if ( ++p == pe )
+ goto _test_eof122;
+case 122:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 116: goto st123;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st123:
+ if ( ++p == pe )
+ goto _test_eof123;
+case 123:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 111: goto tr218;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st124:
+ if ( ++p == pe )
+ goto _test_eof124;
+case 124:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 111: goto st125;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st125:
+ if ( ++p == pe )
+ goto _test_eof125;
+case 125:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 108: goto st126;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st126:
+ if ( ++p == pe )
+ goto _test_eof126;
+case 126:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 100: goto tr221;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st127:
+ if ( ++p == pe )
+ goto _test_eof127;
+case 127:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 101: goto st128;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st128:
+ if ( ++p == pe )
+ goto _test_eof128;
+case 128:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 120: goto st129;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st129:
+ if ( ++p == pe )
+ goto _test_eof129;
+case 129:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 116: goto tr224;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st130:
+ if ( ++p == pe )
+ goto _test_eof130;
+case 130:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 99: goto tr225;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st131:
+ if ( ++p == pe )
+ goto _test_eof131;
+case 131:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 101: goto st132;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st132:
+ if ( ++p == pe )
+ goto _test_eof132;
+case 132:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 116: goto tr227;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st133:
+ if ( ++p == pe )
+ goto _test_eof133;
+case 133:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 97: goto st134;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st134:
+ if ( ++p == pe )
+ goto _test_eof134;
+case 134:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 114: goto st135;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st135:
+ if ( ++p == pe )
+ goto _test_eof135;
+case 135:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 103: goto st136;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+st136:
+ if ( ++p == pe )
+ goto _test_eof136;
+case 136:
+ switch( (*p) ) {
+ case 95: goto tr177;
+ case 115: goto tr231;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr177;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr177;
+ } else
+ goto tr177;
+ goto tr188;
+tr232:
+#line 900 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, ts, te ); }}
+ goto st137;
+tr233:
+#line 895 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated OR literal" << endl;
+ }}
+ goto st137;
+tr234:
+#line 890 "rlscan.rl"
+ {te = p+1;{ token( RE_Dash, 0, 0 ); }}
+ goto st137;
+tr236:
+#line 893 "rlscan.rl"
+ {te = p+1;{ token( RE_SqClose ); {cs = stack[--top];goto _again;} }}
+ goto st137;
+tr237:
+#line 900 "rlscan.rl"
+ {te = p;p--;{ token( RE_Char, ts, te ); }}
+ goto st137;
+tr238:
+#line 887 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, ts+1, te ); }}
+ goto st137;
+tr239:
+#line 886 "rlscan.rl"
+ {te = p+1;{ updateCol(); }}
+ goto st137;
+tr240:
+#line 878 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\0' ); }}
+ goto st137;
+tr241:
+#line 879 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\a' ); }}
+ goto st137;
+tr242:
+#line 880 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\b' ); }}
+ goto st137;
+tr243:
+#line 884 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\f' ); }}
+ goto st137;
+tr244:
+#line 882 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\n' ); }}
+ goto st137;
+tr245:
+#line 885 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\r' ); }}
+ goto st137;
+tr246:
+#line 881 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\t' ); }}
+ goto st137;
+tr247:
+#line 883 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\v' ); }}
+ goto st137;
+st137:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof137;
+case 137:
+#line 1 "NONE"
+ {ts = p;}
+#line 3856 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr233;
+ case 45: goto tr234;
+ case 92: goto st138;
+ case 93: goto tr236;
+ }
+ goto tr232;
+st138:
+ if ( ++p == pe )
+ goto _test_eof138;
+case 138:
+ switch( (*p) ) {
+ case 10: goto tr239;
+ case 48: goto tr240;
+ case 97: goto tr241;
+ case 98: goto tr242;
+ case 102: goto tr243;
+ case 110: goto tr244;
+ case 114: goto tr245;
+ case 116: goto tr246;
+ case 118: goto tr247;
+ }
+ goto tr238;
+tr248:
+#line 935 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, ts, te ); }}
+ goto st139;
+tr249:
+#line 930 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated regular expression" << endl;
+ }}
+ goto st139;
+tr250:
+#line 925 "rlscan.rl"
+ {te = p+1;{ token( RE_Star ); }}
+ goto st139;
+tr251:
+#line 924 "rlscan.rl"
+ {te = p+1;{ token( RE_Dot ); }}
+ goto st139;
+tr255:
+#line 918 "rlscan.rl"
+ {te = p;p--;{
+ token( RE_Slash, ts, te );
+ {goto st146;}
+ }}
+ goto st139;
+tr256:
+#line 918 "rlscan.rl"
+ {te = p+1;{
+ token( RE_Slash, ts, te );
+ {goto st146;}
+ }}
+ goto st139;
+tr257:
+#line 927 "rlscan.rl"
+ {te = p;p--;{ token( RE_SqOpen ); {stack[top++] = 139; goto st137;} }}
+ goto st139;
+tr258:
+#line 928 "rlscan.rl"
+ {te = p+1;{ token( RE_SqOpenNeg ); {stack[top++] = 139; goto st137;} }}
+ goto st139;
+tr259:
+#line 935 "rlscan.rl"
+ {te = p;p--;{ token( RE_Char, ts, te ); }}
+ goto st139;
+tr260:
+#line 915 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, ts+1, te ); }}
+ goto st139;
+tr261:
+#line 914 "rlscan.rl"
+ {te = p+1;{ updateCol(); }}
+ goto st139;
+tr262:
+#line 906 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\0' ); }}
+ goto st139;
+tr263:
+#line 907 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\a' ); }}
+ goto st139;
+tr264:
+#line 908 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\b' ); }}
+ goto st139;
+tr265:
+#line 912 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\f' ); }}
+ goto st139;
+tr266:
+#line 910 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\n' ); }}
+ goto st139;
+tr267:
+#line 913 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\r' ); }}
+ goto st139;
+tr268:
+#line 909 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\t' ); }}
+ goto st139;
+tr269:
+#line 911 "rlscan.rl"
+ {te = p+1;{ token( RE_Char, '\v' ); }}
+ goto st139;
+st139:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof139;
+case 139:
+#line 1 "NONE"
+ {ts = p;}
+#line 3972 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr249;
+ case 42: goto tr250;
+ case 46: goto tr251;
+ case 47: goto st140;
+ case 91: goto st141;
+ case 92: goto st142;
+ }
+ goto tr248;
+st140:
+ if ( ++p == pe )
+ goto _test_eof140;
+case 140:
+ if ( (*p) == 105 )
+ goto tr256;
+ goto tr255;
+st141:
+ if ( ++p == pe )
+ goto _test_eof141;
+case 141:
+ if ( (*p) == 94 )
+ goto tr258;
+ goto tr257;
+st142:
+ if ( ++p == pe )
+ goto _test_eof142;
+case 142:
+ switch( (*p) ) {
+ case 10: goto tr261;
+ case 48: goto tr262;
+ case 97: goto tr263;
+ case 98: goto tr264;
+ case 102: goto tr265;
+ case 110: goto tr266;
+ case 114: goto tr267;
+ case 116: goto tr268;
+ case 118: goto tr269;
+ }
+ goto tr260;
+tr270:
+#line 944 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated write statement" << endl;
+ }}
+ goto st143;
+tr273:
+#line 942 "rlscan.rl"
+ {te = p+1;{ token( ';' ); {goto st146;} }}
+ goto st143;
+tr275:
+#line 941 "rlscan.rl"
+ {te = p;p--;{ updateCol(); }}
+ goto st143;
+tr276:
+#line 940 "rlscan.rl"
+ {te = p;p--;{ token( TK_Word, ts, te ); }}
+ goto st143;
+st143:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof143;
+case 143:
+#line 1 "NONE"
+ {ts = p;}
+#line 4038 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr270;
+ case 32: goto st144;
+ case 59: goto tr273;
+ case 95: goto st145;
+ }
+ if ( (*p) < 65 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto st144;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st145;
+ } else
+ goto st145;
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+st144:
+ if ( ++p == pe )
+ goto _test_eof144;
+case 144:
+ if ( (*p) == 32 )
+ goto st144;
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto st144;
+ goto tr275;
+st145:
+ if ( ++p == pe )
+ goto _test_eof145;
+case 145:
+ if ( (*p) == 95 )
+ goto st145;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st145;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st145;
+ } else
+ goto st145;
+ goto tr276;
+tr45:
+#line 1121 "rlscan.rl"
+ {{p = ((te))-1;}{ token( *ts ); }}
+ goto st146;
+tr51:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 1018 "rlscan.rl"
+ {te = p+1;{ updateCol(); }}
+ goto st146;
+tr55:
+#line 1005 "rlscan.rl"
+ {{p = ((te))-1;}{ token( TK_UInt, ts, te ); }}
+ goto st146;
+tr57:
+#line 1086 "rlscan.rl"
+ {te = p+1;{
+ updateCol();
+ endSection();
+ {cs = stack[--top];goto _again;}
+ }}
+ goto st146;
+tr277:
+#line 1121 "rlscan.rl"
+ {te = p+1;{ token( *ts ); }}
+ goto st146;
+tr278:
+#line 1117 "rlscan.rl"
+ {te = p+1;{
+ scan_error() << "unterminated ragel section" << endl;
+ }}
+ goto st146;
+tr280:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 1095 "rlscan.rl"
+ {te = p+1;{
+ updateCol();
+ if ( singleLineSpec ) {
+ endSection();
+ {cs = stack[--top];goto _again;}
+ }
+ }}
+ goto st146;
+tr289:
+#line 1015 "rlscan.rl"
+ {te = p+1;{ token( RE_Slash ); {goto st139;} }}
+ goto st146;
+tr311:
+#line 1103 "rlscan.rl"
+ {te = p+1;{
+ if ( lastToken == KW_Export || lastToken == KW_Entry )
+ token( '{' );
+ else {
+ token( '{' );
+ curly_count = 1;
+ inlineBlockType = CurlyDelimited;
+ if ( hostLang->lang == HostLang::Ruby )
+ {stack[top++] = 146; goto st52;}
+ else
+ {stack[top++] = 146; goto st95;}
+ }
+ }}
+ goto st146;
+tr314:
+#line 1092 "rlscan.rl"
+ {te = p;p--;{ updateCol(); }}
+ goto st146;
+tr315:
+#line 1121 "rlscan.rl"
+ {te = p;p--;{ token( *ts ); }}
+ goto st146;
+tr316:
+#line 1010 "rlscan.rl"
+ {te = p;p--;{ token( TK_Literal, ts, te ); }}
+ goto st146;
+tr317:
+#line 1010 "rlscan.rl"
+ {te = p+1;{ token( TK_Literal, ts, te ); }}
+ goto st146;
+tr318:
+#line 1048 "rlscan.rl"
+ {te = p+1;{ token( TK_AllGblError ); }}
+ goto st146;
+tr319:
+#line 1032 "rlscan.rl"
+ {te = p+1;{ token( TK_AllFromState ); }}
+ goto st146;
+tr320:
+#line 1040 "rlscan.rl"
+ {te = p+1;{ token( TK_AllEOF ); }}
+ goto st146;
+tr321:
+#line 1067 "rlscan.rl"
+ {te = p+1;{ token( TK_AllCond ); }}
+ goto st146;
+tr322:
+#line 1056 "rlscan.rl"
+ {te = p+1;{ token( TK_AllLocalError ); }}
+ goto st146;
+tr323:
+#line 1024 "rlscan.rl"
+ {te = p+1;{ token( TK_AllToState ); }}
+ goto st146;
+tr324:
+#line 1049 "rlscan.rl"
+ {te = p+1;{ token( TK_FinalGblError ); }}
+ goto st146;
+tr325:
+#line 1033 "rlscan.rl"
+ {te = p+1;{ token( TK_FinalFromState ); }}
+ goto st146;
+tr326:
+#line 1041 "rlscan.rl"
+ {te = p+1;{ token( TK_FinalEOF ); }}
+ goto st146;
+tr327:
+#line 1068 "rlscan.rl"
+ {te = p+1;{ token( TK_LeavingCond ); }}
+ goto st146;
+tr328:
+#line 1057 "rlscan.rl"
+ {te = p+1;{ token( TK_FinalLocalError ); }}
+ goto st146;
+tr329:
+#line 1025 "rlscan.rl"
+ {te = p+1;{ token( TK_FinalToState ); }}
+ goto st146;
+tr330:
+#line 1071 "rlscan.rl"
+ {te = p+1;{ token( TK_StarStar ); }}
+ goto st146;
+tr331:
+#line 1072 "rlscan.rl"
+ {te = p+1;{ token( TK_DashDash ); }}
+ goto st146;
+tr332:
+#line 1073 "rlscan.rl"
+ {te = p+1;{ token( TK_Arrow ); }}
+ goto st146;
+tr333:
+#line 1070 "rlscan.rl"
+ {te = p+1;{ token( TK_DotDot ); }}
+ goto st146;
+tr334:
+#line 1005 "rlscan.rl"
+ {te = p;p--;{ token( TK_UInt, ts, te ); }}
+ goto st146;
+tr336:
+#line 1006 "rlscan.rl"
+ {te = p;p--;{ token( TK_Hex, ts, te ); }}
+ goto st146;
+tr337:
+#line 1084 "rlscan.rl"
+ {te = p+1;{ token( TK_NameSep, ts, te ); }}
+ goto st146;
+tr338:
+#line 1020 "rlscan.rl"
+ {te = p+1;{ token( TK_ColonEquals ); }}
+ goto st146;
+tr340:
+#line 1076 "rlscan.rl"
+ {te = p;p--;{ token( TK_ColonGt ); }}
+ goto st146;
+tr341:
+#line 1077 "rlscan.rl"
+ {te = p+1;{ token( TK_ColonGtGt ); }}
+ goto st146;
+tr342:
+#line 1050 "rlscan.rl"
+ {te = p+1;{ token( TK_NotStartGblError ); }}
+ goto st146;
+tr343:
+#line 1034 "rlscan.rl"
+ {te = p+1;{ token( TK_NotStartFromState ); }}
+ goto st146;
+tr344:
+#line 1042 "rlscan.rl"
+ {te = p+1;{ token( TK_NotStartEOF ); }}
+ goto st146;
+tr345:
+#line 1078 "rlscan.rl"
+ {te = p+1;{ token( TK_LtColon ); }}
+ goto st146;
+tr347:
+#line 1058 "rlscan.rl"
+ {te = p+1;{ token( TK_NotStartLocalError ); }}
+ goto st146;
+tr348:
+#line 1026 "rlscan.rl"
+ {te = p+1;{ token( TK_NotStartToState ); }}
+ goto st146;
+tr349:
+#line 1063 "rlscan.rl"
+ {te = p;p--;{ token( TK_Middle ); }}
+ goto st146;
+tr350:
+#line 1052 "rlscan.rl"
+ {te = p+1;{ token( TK_MiddleGblError ); }}
+ goto st146;
+tr351:
+#line 1036 "rlscan.rl"
+ {te = p+1;{ token( TK_MiddleFromState ); }}
+ goto st146;
+tr352:
+#line 1044 "rlscan.rl"
+ {te = p+1;{ token( TK_MiddleEOF ); }}
+ goto st146;
+tr353:
+#line 1060 "rlscan.rl"
+ {te = p+1;{ token( TK_MiddleLocalError ); }}
+ goto st146;
+tr354:
+#line 1028 "rlscan.rl"
+ {te = p+1;{ token( TK_MiddleToState ); }}
+ goto st146;
+tr355:
+#line 1074 "rlscan.rl"
+ {te = p+1;{ token( TK_DoubleArrow ); }}
+ goto st146;
+tr356:
+#line 1047 "rlscan.rl"
+ {te = p+1;{ token( TK_StartGblError ); }}
+ goto st146;
+tr357:
+#line 1031 "rlscan.rl"
+ {te = p+1;{ token( TK_StartFromState ); }}
+ goto st146;
+tr358:
+#line 1039 "rlscan.rl"
+ {te = p+1;{ token( TK_StartEOF ); }}
+ goto st146;
+tr359:
+#line 1066 "rlscan.rl"
+ {te = p+1;{ token( TK_StartCond ); }}
+ goto st146;
+tr360:
+#line 1055 "rlscan.rl"
+ {te = p+1;{ token( TK_StartLocalError ); }}
+ goto st146;
+tr361:
+#line 1023 "rlscan.rl"
+ {te = p+1;{ token( TK_StartToState ); }}
+ goto st146;
+tr362:
+#line 1051 "rlscan.rl"
+ {te = p+1;{ token( TK_NotFinalGblError ); }}
+ goto st146;
+tr363:
+#line 1035 "rlscan.rl"
+ {te = p+1;{ token( TK_NotFinalFromState ); }}
+ goto st146;
+tr364:
+#line 1043 "rlscan.rl"
+ {te = p+1;{ token( TK_NotFinalEOF ); }}
+ goto st146;
+tr365:
+#line 1059 "rlscan.rl"
+ {te = p+1;{ token( TK_NotFinalLocalError ); }}
+ goto st146;
+tr366:
+#line 1027 "rlscan.rl"
+ {te = p+1;{ token( TK_NotFinalToState ); }}
+ goto st146;
+tr367:
+#line 1 "NONE"
+ { switch( act ) {
+ case 88:
+ {{p = ((te))-1;} token( KW_Machine ); }
+ break;
+ case 89:
+ {{p = ((te))-1;} token( KW_Include ); }
+ break;
+ case 90:
+ {{p = ((te))-1;} token( KW_Import ); }
+ break;
+ case 91:
+ {{p = ((te))-1;}
+ token( KW_Write );
+ {goto st143;}
+ }
+ break;
+ case 92:
+ {{p = ((te))-1;} token( KW_Action ); }
+ break;
+ case 93:
+ {{p = ((te))-1;} token( KW_AlphType ); }
+ break;
+ case 94:
+ {{p = ((te))-1;} token( KW_PrePush ); }
+ break;
+ case 95:
+ {{p = ((te))-1;} token( KW_PostPop ); }
+ break;
+ case 96:
+ {{p = ((te))-1;}
+ token( KW_GetKey );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ {stack[top++] = 146; goto st52;}
+ else
+ {stack[top++] = 146; goto st95;}
+ }
+ break;
+ case 97:
+ {{p = ((te))-1;}
+ token( KW_Access );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ {stack[top++] = 146; goto st52;}
+ else
+ {stack[top++] = 146; goto st95;}
+ }
+ break;
+ case 98:
+ {{p = ((te))-1;}
+ token( KW_Variable );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ {stack[top++] = 146; goto st52;}
+ else
+ {stack[top++] = 146; goto st95;}
+ }
+ break;
+ case 99:
+ {{p = ((te))-1;} token( KW_When ); }
+ break;
+ case 100:
+ {{p = ((te))-1;} token( KW_InWhen ); }
+ break;
+ case 101:
+ {{p = ((te))-1;} token( KW_OutWhen ); }
+ break;
+ case 102:
+ {{p = ((te))-1;} token( KW_Eof ); }
+ break;
+ case 103:
+ {{p = ((te))-1;} token( KW_Err ); }
+ break;
+ case 104:
+ {{p = ((te))-1;} token( KW_Lerr ); }
+ break;
+ case 105:
+ {{p = ((te))-1;} token( KW_To ); }
+ break;
+ case 106:
+ {{p = ((te))-1;} token( KW_From ); }
+ break;
+ case 107:
+ {{p = ((te))-1;} token( KW_Export ); }
+ break;
+ case 108:
+ {{p = ((te))-1;} token( TK_Word, ts, te ); }
+ break;
+ }
+ }
+ goto st146;
+tr368:
+#line 1012 "rlscan.rl"
+ {te = p;p--;{ token( RE_SqOpen ); {stack[top++] = 146; goto st137;} }}
+ goto st146;
+tr369:
+#line 1013 "rlscan.rl"
+ {te = p+1;{ token( RE_SqOpenNeg ); {stack[top++] = 146; goto st137;} }}
+ goto st146;
+tr370:
+#line 1002 "rlscan.rl"
+ {te = p;p--;{ token( TK_Word, ts, te ); }}
+ goto st146;
+tr461:
+#line 1081 "rlscan.rl"
+ {te = p+1;{ token( TK_BarStar ); }}
+ goto st146;
+st146:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof146;
+case 146:
+#line 1 "NONE"
+ {ts = p;}
+#line 4470 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr278;
+ case 9: goto st147;
+ case 10: goto tr280;
+ case 13: goto st147;
+ case 32: goto st147;
+ case 34: goto tr281;
+ case 35: goto tr282;
+ case 36: goto st151;
+ case 37: goto st152;
+ case 39: goto tr285;
+ case 42: goto st154;
+ case 45: goto st155;
+ case 46: goto st156;
+ case 47: goto tr289;
+ case 48: goto tr290;
+ case 58: goto st160;
+ case 60: goto st162;
+ case 61: goto st164;
+ case 62: goto st165;
+ case 64: goto st166;
+ case 91: goto st168;
+ case 95: goto tr297;
+ case 97: goto st169;
+ case 101: goto st183;
+ case 102: goto st190;
+ case 103: goto st193;
+ case 105: goto st198;
+ case 108: goto st211;
+ case 109: goto st214;
+ case 111: goto st220;
+ case 112: goto st226;
+ case 116: goto st237;
+ case 118: goto st238;
+ case 119: goto st245;
+ case 123: goto tr311;
+ case 124: goto st251;
+ case 125: goto tr313;
+ }
+ if ( (*p) < 65 ) {
+ if ( 49 <= (*p) && (*p) <= 57 )
+ goto st158;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr277;
+st147:
+ if ( ++p == pe )
+ goto _test_eof147;
+case 147:
+ switch( (*p) ) {
+ case 9: goto st147;
+ case 13: goto st147;
+ case 32: goto st147;
+ }
+ goto tr314;
+tr281:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st148;
+st148:
+ if ( ++p == pe )
+ goto _test_eof148;
+case 148:
+#line 4537 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr47;
+ case 34: goto st149;
+ case 92: goto st25;
+ }
+ goto st24;
+tr47:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st24;
+st24:
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+#line 4556 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr47;
+ case 34: goto st149;
+ case 92: goto st25;
+ }
+ goto st24;
+st149:
+ if ( ++p == pe )
+ goto _test_eof149;
+case 149:
+ if ( (*p) == 105 )
+ goto tr317;
+ goto tr316;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+ if ( (*p) == 10 )
+ goto tr47;
+ goto st24;
+tr282:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st150;
+st150:
+ if ( ++p == pe )
+ goto _test_eof150;
+case 150:
+#line 4585 "rlscan.cpp"
+ if ( (*p) == 10 )
+ goto tr51;
+ goto st26;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+ if ( (*p) == 10 )
+ goto tr51;
+ goto st26;
+st151:
+ if ( ++p == pe )
+ goto _test_eof151;
+case 151:
+ switch( (*p) ) {
+ case 33: goto tr318;
+ case 42: goto tr319;
+ case 47: goto tr320;
+ case 63: goto tr321;
+ case 94: goto tr322;
+ case 126: goto tr323;
+ }
+ goto tr315;
+st152:
+ if ( ++p == pe )
+ goto _test_eof152;
+case 152:
+ switch( (*p) ) {
+ case 33: goto tr324;
+ case 42: goto tr325;
+ case 47: goto tr326;
+ case 63: goto tr327;
+ case 94: goto tr328;
+ case 126: goto tr329;
+ }
+ goto tr315;
+tr285:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st153;
+st153:
+ if ( ++p == pe )
+ goto _test_eof153;
+case 153:
+#line 4630 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr53;
+ case 39: goto st149;
+ case 92: goto st28;
+ }
+ goto st27;
+tr53:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st27;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+#line 4649 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr53;
+ case 39: goto st149;
+ case 92: goto st28;
+ }
+ goto st27;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+ if ( (*p) == 10 )
+ goto tr53;
+ goto st27;
+st154:
+ if ( ++p == pe )
+ goto _test_eof154;
+case 154:
+ if ( (*p) == 42 )
+ goto tr330;
+ goto tr315;
+st155:
+ if ( ++p == pe )
+ goto _test_eof155;
+case 155:
+ switch( (*p) ) {
+ case 45: goto tr331;
+ case 62: goto tr332;
+ }
+ goto tr315;
+st156:
+ if ( ++p == pe )
+ goto _test_eof156;
+case 156:
+ if ( (*p) == 46 )
+ goto tr333;
+ goto tr315;
+tr290:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st157;
+st157:
+ if ( ++p == pe )
+ goto _test_eof157;
+case 157:
+#line 4694 "rlscan.cpp"
+ if ( (*p) == 120 )
+ goto st29;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st158;
+ goto tr334;
+st158:
+ if ( ++p == pe )
+ goto _test_eof158;
+case 158:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st158;
+ goto tr334;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st159;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st159;
+ } else
+ goto st159;
+ goto tr55;
+st159:
+ if ( ++p == pe )
+ goto _test_eof159;
+case 159:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st159;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st159;
+ } else
+ goto st159;
+ goto tr336;
+st160:
+ if ( ++p == pe )
+ goto _test_eof160;
+case 160:
+ switch( (*p) ) {
+ case 58: goto tr337;
+ case 61: goto tr338;
+ case 62: goto st161;
+ }
+ goto tr315;
+st161:
+ if ( ++p == pe )
+ goto _test_eof161;
+case 161:
+ if ( (*p) == 62 )
+ goto tr341;
+ goto tr340;
+st162:
+ if ( ++p == pe )
+ goto _test_eof162;
+case 162:
+ switch( (*p) ) {
+ case 33: goto tr342;
+ case 42: goto tr343;
+ case 47: goto tr344;
+ case 58: goto tr345;
+ case 62: goto st163;
+ case 94: goto tr347;
+ case 126: goto tr348;
+ }
+ goto tr315;
+st163:
+ if ( ++p == pe )
+ goto _test_eof163;
+case 163:
+ switch( (*p) ) {
+ case 33: goto tr350;
+ case 42: goto tr351;
+ case 47: goto tr352;
+ case 94: goto tr353;
+ case 126: goto tr354;
+ }
+ goto tr349;
+st164:
+ if ( ++p == pe )
+ goto _test_eof164;
+case 164:
+ if ( (*p) == 62 )
+ goto tr355;
+ goto tr315;
+st165:
+ if ( ++p == pe )
+ goto _test_eof165;
+case 165:
+ switch( (*p) ) {
+ case 33: goto tr356;
+ case 42: goto tr357;
+ case 47: goto tr358;
+ case 63: goto tr359;
+ case 94: goto tr360;
+ case 126: goto tr361;
+ }
+ goto tr315;
+st166:
+ if ( ++p == pe )
+ goto _test_eof166;
+case 166:
+ switch( (*p) ) {
+ case 33: goto tr362;
+ case 42: goto tr363;
+ case 47: goto tr364;
+ case 94: goto tr365;
+ case 126: goto tr366;
+ }
+ goto tr315;
+tr297:
+#line 1 "NONE"
+ {te = p+1;}
+#line 1002 "rlscan.rl"
+ {act = 108;}
+ goto st167;
+tr377:
+#line 1 "NONE"
+ {te = p+1;}
+#line 975 "rlscan.rl"
+ {act = 97;}
+ goto st167;
+tr380:
+#line 1 "NONE"
+ {te = p+1;}
+#line 959 "rlscan.rl"
+ {act = 92;}
+ goto st167;
+tr386:
+#line 1 "NONE"
+ {te = p+1;}
+#line 960 "rlscan.rl"
+ {act = 93;}
+ goto st167;
+tr390:
+#line 1 "NONE"
+ {te = p+1;}
+#line 994 "rlscan.rl"
+ {act = 102;}
+ goto st167;
+tr391:
+#line 1 "NONE"
+ {te = p+1;}
+#line 995 "rlscan.rl"
+ {act = 103;}
+ goto st167;
+tr395:
+#line 1 "NONE"
+ {te = p+1;}
+#line 999 "rlscan.rl"
+ {act = 107;}
+ goto st167;
+tr398:
+#line 1 "NONE"
+ {te = p+1;}
+#line 998 "rlscan.rl"
+ {act = 106;}
+ goto st167;
+tr403:
+#line 1 "NONE"
+ {te = p+1;}
+#line 967 "rlscan.rl"
+ {act = 96;}
+ goto st167;
+tr409:
+#line 1 "NONE"
+ {te = p+1;}
+#line 954 "rlscan.rl"
+ {act = 90;}
+ goto st167;
+tr415:
+#line 1 "NONE"
+ {te = p+1;}
+#line 953 "rlscan.rl"
+ {act = 89;}
+ goto st167;
+tr418:
+#line 1 "NONE"
+ {te = p+1;}
+#line 992 "rlscan.rl"
+ {act = 100;}
+ goto st167;
+tr421:
+#line 1 "NONE"
+ {te = p+1;}
+#line 996 "rlscan.rl"
+ {act = 104;}
+ goto st167;
+tr427:
+#line 1 "NONE"
+ {te = p+1;}
+#line 952 "rlscan.rl"
+ {act = 88;}
+ goto st167;
+tr433:
+#line 1 "NONE"
+ {te = p+1;}
+#line 993 "rlscan.rl"
+ {act = 101;}
+ goto st167;
+tr440:
+#line 1 "NONE"
+ {te = p+1;}
+#line 962 "rlscan.rl"
+ {act = 95;}
+ goto st167;
+tr445:
+#line 1 "NONE"
+ {te = p+1;}
+#line 961 "rlscan.rl"
+ {act = 94;}
+ goto st167;
+tr446:
+#line 1 "NONE"
+ {te = p+1;}
+#line 997 "rlscan.rl"
+ {act = 105;}
+ goto st167;
+tr453:
+#line 1 "NONE"
+ {te = p+1;}
+#line 983 "rlscan.rl"
+ {act = 98;}
+ goto st167;
+tr457:
+#line 1 "NONE"
+ {te = p+1;}
+#line 991 "rlscan.rl"
+ {act = 99;}
+ goto st167;
+tr460:
+#line 1 "NONE"
+ {te = p+1;}
+#line 955 "rlscan.rl"
+ {act = 91;}
+ goto st167;
+st167:
+ if ( ++p == pe )
+ goto _test_eof167;
+case 167:
+#line 4938 "rlscan.cpp"
+ if ( (*p) == 95 )
+ goto tr297;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr367;
+st168:
+ if ( ++p == pe )
+ goto _test_eof168;
+case 168:
+ if ( (*p) == 94 )
+ goto tr369;
+ goto tr368;
+st169:
+ if ( ++p == pe )
+ goto _test_eof169;
+case 169:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 99: goto st170;
+ case 108: goto st177;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st170:
+ if ( ++p == pe )
+ goto _test_eof170;
+case 170:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 99: goto st171;
+ case 116: goto st174;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st171:
+ if ( ++p == pe )
+ goto _test_eof171;
+case 171:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st172;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st172:
+ if ( ++p == pe )
+ goto _test_eof172;
+case 172:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 115: goto st173;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st173:
+ if ( ++p == pe )
+ goto _test_eof173;
+case 173:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 115: goto tr377;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st174:
+ if ( ++p == pe )
+ goto _test_eof174;
+case 174:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 105: goto st175;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st175:
+ if ( ++p == pe )
+ goto _test_eof175;
+case 175:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st176;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st176:
+ if ( ++p == pe )
+ goto _test_eof176;
+case 176:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 110: goto tr380;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st177:
+ if ( ++p == pe )
+ goto _test_eof177;
+case 177:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st178;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st178:
+ if ( ++p == pe )
+ goto _test_eof178;
+case 178:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto st179;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st179:
+ if ( ++p == pe )
+ goto _test_eof179;
+case 179:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto st180;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st180:
+ if ( ++p == pe )
+ goto _test_eof180;
+case 180:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 121: goto st181;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st181:
+ if ( ++p == pe )
+ goto _test_eof181;
+case 181:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st182;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st182:
+ if ( ++p == pe )
+ goto _test_eof182;
+case 182:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto tr386;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st183:
+ if ( ++p == pe )
+ goto _test_eof183;
+case 183:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st184;
+ case 114: goto st185;
+ case 120: goto st186;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st184:
+ if ( ++p == pe )
+ goto _test_eof184;
+case 184:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 102: goto tr390;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st185:
+ if ( ++p == pe )
+ goto _test_eof185;
+case 185:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto tr391;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st186:
+ if ( ++p == pe )
+ goto _test_eof186;
+case 186:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st187;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st187:
+ if ( ++p == pe )
+ goto _test_eof187;
+case 187:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st188;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st188:
+ if ( ++p == pe )
+ goto _test_eof188;
+case 188:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto st189;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st189:
+ if ( ++p == pe )
+ goto _test_eof189;
+case 189:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto tr395;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st190:
+ if ( ++p == pe )
+ goto _test_eof190;
+case 190:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto st191;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st191:
+ if ( ++p == pe )
+ goto _test_eof191;
+case 191:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st192;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st192:
+ if ( ++p == pe )
+ goto _test_eof192;
+case 192:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 109: goto tr398;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st193:
+ if ( ++p == pe )
+ goto _test_eof193;
+case 193:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st194;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st194:
+ if ( ++p == pe )
+ goto _test_eof194;
+case 194:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto st195;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st195:
+ if ( ++p == pe )
+ goto _test_eof195;
+case 195:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 107: goto st196;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st196:
+ if ( ++p == pe )
+ goto _test_eof196;
+case 196:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st197;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st197:
+ if ( ++p == pe )
+ goto _test_eof197;
+case 197:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 121: goto tr403;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st198:
+ if ( ++p == pe )
+ goto _test_eof198;
+case 198:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 109: goto st199;
+ case 110: goto st203;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st199:
+ if ( ++p == pe )
+ goto _test_eof199;
+case 199:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st200;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st200:
+ if ( ++p == pe )
+ goto _test_eof200;
+case 200:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st201;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st201:
+ if ( ++p == pe )
+ goto _test_eof201;
+case 201:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto st202;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st202:
+ if ( ++p == pe )
+ goto _test_eof202;
+case 202:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto tr409;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st203:
+ if ( ++p == pe )
+ goto _test_eof203;
+case 203:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 99: goto st204;
+ case 119: goto st208;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st204:
+ if ( ++p == pe )
+ goto _test_eof204;
+case 204:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 108: goto st205;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st205:
+ if ( ++p == pe )
+ goto _test_eof205;
+case 205:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 117: goto st206;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st206:
+ if ( ++p == pe )
+ goto _test_eof206;
+case 206:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 100: goto st207;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st207:
+ if ( ++p == pe )
+ goto _test_eof207;
+case 207:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto tr415;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st208:
+ if ( ++p == pe )
+ goto _test_eof208;
+case 208:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto st209;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st209:
+ if ( ++p == pe )
+ goto _test_eof209;
+case 209:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st210;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st210:
+ if ( ++p == pe )
+ goto _test_eof210;
+case 210:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 110: goto tr418;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st211:
+ if ( ++p == pe )
+ goto _test_eof211;
+case 211:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st212;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st212:
+ if ( ++p == pe )
+ goto _test_eof212;
+case 212:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto st213;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st213:
+ if ( ++p == pe )
+ goto _test_eof213;
+case 213:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto tr421;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st214:
+ if ( ++p == pe )
+ goto _test_eof214;
+case 214:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 97: goto st215;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st215:
+ if ( ++p == pe )
+ goto _test_eof215;
+case 215:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 99: goto st216;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st216:
+ if ( ++p == pe )
+ goto _test_eof216;
+case 216:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto st217;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st217:
+ if ( ++p == pe )
+ goto _test_eof217;
+case 217:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 105: goto st218;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st218:
+ if ( ++p == pe )
+ goto _test_eof218;
+case 218:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 110: goto st219;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st219:
+ if ( ++p == pe )
+ goto _test_eof219;
+case 219:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto tr427;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st220:
+ if ( ++p == pe )
+ goto _test_eof220;
+case 220:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 117: goto st221;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st221:
+ if ( ++p == pe )
+ goto _test_eof221;
+case 221:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto st222;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st222:
+ if ( ++p == pe )
+ goto _test_eof222;
+case 222:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 119: goto st223;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st223:
+ if ( ++p == pe )
+ goto _test_eof223;
+case 223:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto st224;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st224:
+ if ( ++p == pe )
+ goto _test_eof224;
+case 224:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st225;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st225:
+ if ( ++p == pe )
+ goto _test_eof225;
+case 225:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 110: goto tr433;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st226:
+ if ( ++p == pe )
+ goto _test_eof226;
+case 226:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st227;
+ case 114: goto st232;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st227:
+ if ( ++p == pe )
+ goto _test_eof227;
+case 227:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 115: goto st228;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st228:
+ if ( ++p == pe )
+ goto _test_eof228;
+case 228:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto st229;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st229:
+ if ( ++p == pe )
+ goto _test_eof229;
+case 229:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st230;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st230:
+ if ( ++p == pe )
+ goto _test_eof230;
+case 230:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto st231;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st231:
+ if ( ++p == pe )
+ goto _test_eof231;
+case 231:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto tr440;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st232:
+ if ( ++p == pe )
+ goto _test_eof232;
+case 232:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st233;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st233:
+ if ( ++p == pe )
+ goto _test_eof233;
+case 233:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 112: goto st234;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st234:
+ if ( ++p == pe )
+ goto _test_eof234;
+case 234:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 117: goto st235;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st235:
+ if ( ++p == pe )
+ goto _test_eof235;
+case 235:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 115: goto st236;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st236:
+ if ( ++p == pe )
+ goto _test_eof236;
+case 236:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto tr445;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st237:
+ if ( ++p == pe )
+ goto _test_eof237;
+case 237:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 111: goto tr446;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st238:
+ if ( ++p == pe )
+ goto _test_eof238;
+case 238:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 97: goto st239;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st239:
+ if ( ++p == pe )
+ goto _test_eof239;
+case 239:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 114: goto st240;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st240:
+ if ( ++p == pe )
+ goto _test_eof240;
+case 240:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 105: goto st241;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st241:
+ if ( ++p == pe )
+ goto _test_eof241;
+case 241:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 97: goto st242;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 98 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st242:
+ if ( ++p == pe )
+ goto _test_eof242;
+case 242:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 98: goto st243;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st243:
+ if ( ++p == pe )
+ goto _test_eof243;
+case 243:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 108: goto st244;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st244:
+ if ( ++p == pe )
+ goto _test_eof244;
+case 244:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto tr453;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st245:
+ if ( ++p == pe )
+ goto _test_eof245;
+case 245:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 104: goto st246;
+ case 114: goto st248;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st246:
+ if ( ++p == pe )
+ goto _test_eof246;
+case 246:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto st247;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st247:
+ if ( ++p == pe )
+ goto _test_eof247;
+case 247:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 110: goto tr457;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st248:
+ if ( ++p == pe )
+ goto _test_eof248;
+case 248:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 105: goto st249;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st249:
+ if ( ++p == pe )
+ goto _test_eof249;
+case 249:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 116: goto st250;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st250:
+ if ( ++p == pe )
+ goto _test_eof250;
+case 250:
+ switch( (*p) ) {
+ case 95: goto tr297;
+ case 101: goto tr460;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr297;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr297;
+ } else
+ goto tr297;
+ goto tr370;
+st251:
+ if ( ++p == pe )
+ goto _test_eof251;
+case 251:
+ if ( (*p) == 42 )
+ goto tr461;
+ goto tr315;
+tr313:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st252;
+st252:
+ if ( ++p == pe )
+ goto _test_eof252;
+case 252:
+#line 6374 "rlscan.cpp"
+ if ( (*p) == 37 )
+ goto st30;
+ goto tr315;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+ if ( (*p) == 37 )
+ goto tr57;
+ goto tr45;
+tr58:
+#line 1146 "rlscan.rl"
+ {{p = ((te))-1;}{ pass( *ts, 0, 0 ); }}
+ goto st253;
+tr61:
+#line 1130 "rlscan.rl"
+ {te = p+1;{ pass( IMP_Literal, ts, te ); }}
+ goto st253;
+tr64:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+#line 1128 "rlscan.rl"
+ {te = p+1;{ pass(); }}
+ goto st253;
+tr463:
+#line 1146 "rlscan.rl"
+ {te = p+1;{ pass( *ts, 0, 0 ); }}
+ goto st253;
+tr464:
+#line 1145 "rlscan.rl"
+ {te = p+1;}
+ goto st253;
+tr474:
+#line 1144 "rlscan.rl"
+ {te = p;p--;{ pass(); }}
+ goto st253;
+tr475:
+#line 1146 "rlscan.rl"
+ {te = p;p--;{ pass( *ts, 0, 0 ); }}
+ goto st253;
+tr477:
+#line 1138 "rlscan.rl"
+ {te = p;p--;{
+ updateCol();
+ singleLineSpec = true;
+ startSection();
+ {stack[top++] = 253; goto st146;}
+ }}
+ goto st253;
+tr478:
+#line 1132 "rlscan.rl"
+ {te = p+1;{
+ updateCol();
+ singleLineSpec = false;
+ startSection();
+ {stack[top++] = 253; goto st146;}
+ }}
+ goto st253;
+tr479:
+#line 1127 "rlscan.rl"
+ {te = p;p--;{ pass( IMP_UInt, ts, te ); }}
+ goto st253;
+tr480:
+#line 1126 "rlscan.rl"
+ {te = p;p--;{ pass( IMP_Word, ts, te ); }}
+ goto st253;
+st253:
+#line 1 "NONE"
+ {ts = 0;}
+ if ( ++p == pe )
+ goto _test_eof253;
+case 253:
+#line 1 "NONE"
+ {ts = p;}
+#line 6453 "rlscan.cpp"
+ switch( (*p) ) {
+ case 0: goto tr464;
+ case 9: goto st254;
+ case 10: goto tr466;
+ case 32: goto st254;
+ case 34: goto tr467;
+ case 35: goto tr468;
+ case 37: goto st257;
+ case 39: goto tr470;
+ case 47: goto tr471;
+ case 95: goto st262;
+ }
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st261;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st262;
+ } else
+ goto st262;
+ goto tr463;
+tr466:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st254;
+st254:
+ if ( ++p == pe )
+ goto _test_eof254;
+case 254:
+#line 6487 "rlscan.cpp"
+ switch( (*p) ) {
+ case 9: goto st254;
+ case 10: goto tr466;
+ case 32: goto st254;
+ }
+ goto tr474;
+tr467:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st255;
+st255:
+ if ( ++p == pe )
+ goto _test_eof255;
+case 255:
+#line 6502 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr60;
+ case 34: goto tr61;
+ case 92: goto st32;
+ }
+ goto st31;
+tr60:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st31;
+st31:
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+#line 6521 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr60;
+ case 34: goto tr61;
+ case 92: goto st32;
+ }
+ goto st31;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+ if ( (*p) == 10 )
+ goto tr60;
+ goto st31;
+tr468:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st256;
+st256:
+ if ( ++p == pe )
+ goto _test_eof256;
+case 256:
+#line 6543 "rlscan.cpp"
+ if ( (*p) == 10 )
+ goto tr64;
+ goto st33;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+ if ( (*p) == 10 )
+ goto tr64;
+ goto st33;
+st257:
+ if ( ++p == pe )
+ goto _test_eof257;
+case 257:
+ if ( (*p) == 37 )
+ goto st258;
+ goto tr475;
+st258:
+ if ( ++p == pe )
+ goto _test_eof258;
+case 258:
+ if ( (*p) == 123 )
+ goto tr478;
+ goto tr477;
+tr470:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st259;
+st259:
+ if ( ++p == pe )
+ goto _test_eof259;
+case 259:
+#line 6576 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr66;
+ case 39: goto tr61;
+ case 92: goto st35;
+ }
+ goto st34;
+tr66:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st34;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+#line 6595 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr66;
+ case 39: goto tr61;
+ case 92: goto st35;
+ }
+ goto st34;
+st35:
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+ if ( (*p) == 10 )
+ goto tr66;
+ goto st34;
+tr471:
+#line 1 "NONE"
+ {te = p+1;}
+ goto st260;
+st260:
+ if ( ++p == pe )
+ goto _test_eof260;
+case 260:
+#line 6617 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr69;
+ case 47: goto tr61;
+ case 92: goto st37;
+ }
+ goto st36;
+tr69:
+#line 641 "rlscan.rl"
+ {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ goto st36;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+#line 6636 "rlscan.cpp"
+ switch( (*p) ) {
+ case 10: goto tr69;
+ case 47: goto tr61;
+ case 92: goto st37;
+ }
+ goto st36;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+ if ( (*p) == 10 )
+ goto tr69;
+ goto st36;
+st261:
+ if ( ++p == pe )
+ goto _test_eof261;
+case 261:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st261;
+ goto tr479;
+st262:
+ if ( ++p == pe )
+ goto _test_eof262;
+case 262:
+ if ( (*p) == 95 )
+ goto st262;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st262;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st262;
+ } else
+ goto st262;
+ goto tr480;
+ }
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+ _test_eof40: cs = 40; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof41: cs = 41; goto _test_eof;
+ _test_eof42: cs = 42; goto _test_eof;
+ _test_eof43: cs = 43; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof44: cs = 44; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof45: cs = 45; goto _test_eof;
+ _test_eof46: cs = 46; goto _test_eof;
+ _test_eof47: cs = 47; goto _test_eof;
+ _test_eof48: cs = 48; goto _test_eof;
+ _test_eof49: cs = 49; goto _test_eof;
+ _test_eof50: cs = 50; goto _test_eof;
+ _test_eof51: cs = 51; goto _test_eof;
+ _test_eof52: cs = 52; goto _test_eof;
+ _test_eof53: cs = 53; goto _test_eof;
+ _test_eof54: cs = 54; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof55: cs = 55; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof56: cs = 56; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof57: cs = 57; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof58: cs = 58; goto _test_eof;
+ _test_eof59: cs = 59; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof60: cs = 60; goto _test_eof;
+ _test_eof61: cs = 61; goto _test_eof;
+ _test_eof62: cs = 62; goto _test_eof;
+ _test_eof63: cs = 63; goto _test_eof;
+ _test_eof64: cs = 64; goto _test_eof;
+ _test_eof65: cs = 65; goto _test_eof;
+ _test_eof66: cs = 66; goto _test_eof;
+ _test_eof67: cs = 67; goto _test_eof;
+ _test_eof68: cs = 68; goto _test_eof;
+ _test_eof69: cs = 69; goto _test_eof;
+ _test_eof70: cs = 70; goto _test_eof;
+ _test_eof71: cs = 71; goto _test_eof;
+ _test_eof72: cs = 72; goto _test_eof;
+ _test_eof73: cs = 73; goto _test_eof;
+ _test_eof74: cs = 74; goto _test_eof;
+ _test_eof75: cs = 75; goto _test_eof;
+ _test_eof76: cs = 76; goto _test_eof;
+ _test_eof77: cs = 77; goto _test_eof;
+ _test_eof78: cs = 78; goto _test_eof;
+ _test_eof79: cs = 79; goto _test_eof;
+ _test_eof80: cs = 80; goto _test_eof;
+ _test_eof81: cs = 81; goto _test_eof;
+ _test_eof82: cs = 82; goto _test_eof;
+ _test_eof83: cs = 83; goto _test_eof;
+ _test_eof84: cs = 84; goto _test_eof;
+ _test_eof85: cs = 85; goto _test_eof;
+ _test_eof86: cs = 86; goto _test_eof;
+ _test_eof87: cs = 87; goto _test_eof;
+ _test_eof88: cs = 88; goto _test_eof;
+ _test_eof89: cs = 89; goto _test_eof;
+ _test_eof90: cs = 90; goto _test_eof;
+ _test_eof91: cs = 91; goto _test_eof;
+ _test_eof92: cs = 92; goto _test_eof;
+ _test_eof93: cs = 93; goto _test_eof;
+ _test_eof94: cs = 94; goto _test_eof;
+ _test_eof95: cs = 95; goto _test_eof;
+ _test_eof96: cs = 96; goto _test_eof;
+ _test_eof97: cs = 97; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof98: cs = 98; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof99: cs = 99; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof100: cs = 100; goto _test_eof;
+ _test_eof101: cs = 101; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof102: cs = 102; goto _test_eof;
+ _test_eof103: cs = 103; goto _test_eof;
+ _test_eof104: cs = 104; goto _test_eof;
+ _test_eof105: cs = 105; goto _test_eof;
+ _test_eof106: cs = 106; goto _test_eof;
+ _test_eof107: cs = 107; goto _test_eof;
+ _test_eof108: cs = 108; goto _test_eof;
+ _test_eof109: cs = 109; goto _test_eof;
+ _test_eof110: cs = 110; goto _test_eof;
+ _test_eof111: cs = 111; goto _test_eof;
+ _test_eof112: cs = 112; goto _test_eof;
+ _test_eof113: cs = 113; goto _test_eof;
+ _test_eof114: cs = 114; goto _test_eof;
+ _test_eof115: cs = 115; goto _test_eof;
+ _test_eof116: cs = 116; goto _test_eof;
+ _test_eof117: cs = 117; goto _test_eof;
+ _test_eof118: cs = 118; goto _test_eof;
+ _test_eof119: cs = 119; goto _test_eof;
+ _test_eof120: cs = 120; goto _test_eof;
+ _test_eof121: cs = 121; goto _test_eof;
+ _test_eof122: cs = 122; goto _test_eof;
+ _test_eof123: cs = 123; goto _test_eof;
+ _test_eof124: cs = 124; goto _test_eof;
+ _test_eof125: cs = 125; goto _test_eof;
+ _test_eof126: cs = 126; goto _test_eof;
+ _test_eof127: cs = 127; goto _test_eof;
+ _test_eof128: cs = 128; goto _test_eof;
+ _test_eof129: cs = 129; goto _test_eof;
+ _test_eof130: cs = 130; goto _test_eof;
+ _test_eof131: cs = 131; goto _test_eof;
+ _test_eof132: cs = 132; goto _test_eof;
+ _test_eof133: cs = 133; goto _test_eof;
+ _test_eof134: cs = 134; goto _test_eof;
+ _test_eof135: cs = 135; goto _test_eof;
+ _test_eof136: cs = 136; goto _test_eof;
+ _test_eof137: cs = 137; goto _test_eof;
+ _test_eof138: cs = 138; goto _test_eof;
+ _test_eof139: cs = 139; goto _test_eof;
+ _test_eof140: cs = 140; goto _test_eof;
+ _test_eof141: cs = 141; goto _test_eof;
+ _test_eof142: cs = 142; goto _test_eof;
+ _test_eof143: cs = 143; goto _test_eof;
+ _test_eof144: cs = 144; goto _test_eof;
+ _test_eof145: cs = 145; goto _test_eof;
+ _test_eof146: cs = 146; goto _test_eof;
+ _test_eof147: cs = 147; goto _test_eof;
+ _test_eof148: cs = 148; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof149: cs = 149; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof150: cs = 150; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof151: cs = 151; goto _test_eof;
+ _test_eof152: cs = 152; goto _test_eof;
+ _test_eof153: cs = 153; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof154: cs = 154; goto _test_eof;
+ _test_eof155: cs = 155; goto _test_eof;
+ _test_eof156: cs = 156; goto _test_eof;
+ _test_eof157: cs = 157; goto _test_eof;
+ _test_eof158: cs = 158; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof159: cs = 159; goto _test_eof;
+ _test_eof160: cs = 160; goto _test_eof;
+ _test_eof161: cs = 161; goto _test_eof;
+ _test_eof162: cs = 162; goto _test_eof;
+ _test_eof163: cs = 163; goto _test_eof;
+ _test_eof164: cs = 164; goto _test_eof;
+ _test_eof165: cs = 165; goto _test_eof;
+ _test_eof166: cs = 166; goto _test_eof;
+ _test_eof167: cs = 167; goto _test_eof;
+ _test_eof168: cs = 168; goto _test_eof;
+ _test_eof169: cs = 169; goto _test_eof;
+ _test_eof170: cs = 170; goto _test_eof;
+ _test_eof171: cs = 171; goto _test_eof;
+ _test_eof172: cs = 172; goto _test_eof;
+ _test_eof173: cs = 173; goto _test_eof;
+ _test_eof174: cs = 174; goto _test_eof;
+ _test_eof175: cs = 175; goto _test_eof;
+ _test_eof176: cs = 176; goto _test_eof;
+ _test_eof177: cs = 177; goto _test_eof;
+ _test_eof178: cs = 178; goto _test_eof;
+ _test_eof179: cs = 179; goto _test_eof;
+ _test_eof180: cs = 180; goto _test_eof;
+ _test_eof181: cs = 181; goto _test_eof;
+ _test_eof182: cs = 182; goto _test_eof;
+ _test_eof183: cs = 183; goto _test_eof;
+ _test_eof184: cs = 184; goto _test_eof;
+ _test_eof185: cs = 185; goto _test_eof;
+ _test_eof186: cs = 186; goto _test_eof;
+ _test_eof187: cs = 187; goto _test_eof;
+ _test_eof188: cs = 188; goto _test_eof;
+ _test_eof189: cs = 189; goto _test_eof;
+ _test_eof190: cs = 190; goto _test_eof;
+ _test_eof191: cs = 191; goto _test_eof;
+ _test_eof192: cs = 192; goto _test_eof;
+ _test_eof193: cs = 193; goto _test_eof;
+ _test_eof194: cs = 194; goto _test_eof;
+ _test_eof195: cs = 195; goto _test_eof;
+ _test_eof196: cs = 196; goto _test_eof;
+ _test_eof197: cs = 197; goto _test_eof;
+ _test_eof198: cs = 198; goto _test_eof;
+ _test_eof199: cs = 199; goto _test_eof;
+ _test_eof200: cs = 200; goto _test_eof;
+ _test_eof201: cs = 201; goto _test_eof;
+ _test_eof202: cs = 202; goto _test_eof;
+ _test_eof203: cs = 203; goto _test_eof;
+ _test_eof204: cs = 204; goto _test_eof;
+ _test_eof205: cs = 205; goto _test_eof;
+ _test_eof206: cs = 206; goto _test_eof;
+ _test_eof207: cs = 207; goto _test_eof;
+ _test_eof208: cs = 208; goto _test_eof;
+ _test_eof209: cs = 209; goto _test_eof;
+ _test_eof210: cs = 210; goto _test_eof;
+ _test_eof211: cs = 211; goto _test_eof;
+ _test_eof212: cs = 212; goto _test_eof;
+ _test_eof213: cs = 213; goto _test_eof;
+ _test_eof214: cs = 214; goto _test_eof;
+ _test_eof215: cs = 215; goto _test_eof;
+ _test_eof216: cs = 216; goto _test_eof;
+ _test_eof217: cs = 217; goto _test_eof;
+ _test_eof218: cs = 218; goto _test_eof;
+ _test_eof219: cs = 219; goto _test_eof;
+ _test_eof220: cs = 220; goto _test_eof;
+ _test_eof221: cs = 221; goto _test_eof;
+ _test_eof222: cs = 222; goto _test_eof;
+ _test_eof223: cs = 223; goto _test_eof;
+ _test_eof224: cs = 224; goto _test_eof;
+ _test_eof225: cs = 225; goto _test_eof;
+ _test_eof226: cs = 226; goto _test_eof;
+ _test_eof227: cs = 227; goto _test_eof;
+ _test_eof228: cs = 228; goto _test_eof;
+ _test_eof229: cs = 229; goto _test_eof;
+ _test_eof230: cs = 230; goto _test_eof;
+ _test_eof231: cs = 231; goto _test_eof;
+ _test_eof232: cs = 232; goto _test_eof;
+ _test_eof233: cs = 233; goto _test_eof;
+ _test_eof234: cs = 234; goto _test_eof;
+ _test_eof235: cs = 235; goto _test_eof;
+ _test_eof236: cs = 236; goto _test_eof;
+ _test_eof237: cs = 237; goto _test_eof;
+ _test_eof238: cs = 238; goto _test_eof;
+ _test_eof239: cs = 239; goto _test_eof;
+ _test_eof240: cs = 240; goto _test_eof;
+ _test_eof241: cs = 241; goto _test_eof;
+ _test_eof242: cs = 242; goto _test_eof;
+ _test_eof243: cs = 243; goto _test_eof;
+ _test_eof244: cs = 244; goto _test_eof;
+ _test_eof245: cs = 245; goto _test_eof;
+ _test_eof246: cs = 246; goto _test_eof;
+ _test_eof247: cs = 247; goto _test_eof;
+ _test_eof248: cs = 248; goto _test_eof;
+ _test_eof249: cs = 249; goto _test_eof;
+ _test_eof250: cs = 250; goto _test_eof;
+ _test_eof251: cs = 251; goto _test_eof;
+ _test_eof252: cs = 252; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof253: cs = 253; goto _test_eof;
+ _test_eof254: cs = 254; goto _test_eof;
+ _test_eof255: cs = 255; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof256: cs = 256; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof257: cs = 257; goto _test_eof;
+ _test_eof258: cs = 258; goto _test_eof;
+ _test_eof259: cs = 259; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof260: cs = 260; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof261: cs = 261; goto _test_eof;
+ _test_eof262: cs = 262; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 39: goto tr82;
+ case 40: goto tr83;
+ case 1: goto tr0;
+ case 2: goto tr0;
+ case 41: goto tr83;
+ case 42: goto tr85;
+ case 43: goto tr83;
+ case 3: goto tr0;
+ case 4: goto tr0;
+ case 44: goto tr83;
+ case 5: goto tr0;
+ case 6: goto tr0;
+ case 7: goto tr0;
+ case 45: goto tr87;
+ case 46: goto tr88;
+ case 47: goto tr89;
+ case 48: goto tr89;
+ case 49: goto tr89;
+ case 50: goto tr89;
+ case 51: goto tr89;
+ case 53: goto tr113;
+ case 54: goto tr114;
+ case 8: goto tr14;
+ case 9: goto tr14;
+ case 55: goto tr114;
+ case 10: goto tr14;
+ case 56: goto tr114;
+ case 11: goto tr14;
+ case 12: goto tr14;
+ case 57: goto tr114;
+ case 13: goto tr14;
+ case 14: goto tr14;
+ case 58: goto tr115;
+ case 59: goto tr115;
+ case 15: goto tr27;
+ case 60: goto tr117;
+ case 61: goto tr114;
+ case 62: goto tr119;
+ case 63: goto tr120;
+ case 64: goto tr120;
+ case 65: goto tr120;
+ case 66: goto tr120;
+ case 67: goto tr120;
+ case 68: goto tr134;
+ case 69: goto tr120;
+ case 70: goto tr120;
+ case 71: goto tr120;
+ case 72: goto tr120;
+ case 73: goto tr120;
+ case 74: goto tr120;
+ case 75: goto tr120;
+ case 76: goto tr120;
+ case 77: goto tr120;
+ case 78: goto tr120;
+ case 79: goto tr120;
+ case 80: goto tr120;
+ case 81: goto tr120;
+ case 82: goto tr120;
+ case 83: goto tr120;
+ case 84: goto tr120;
+ case 85: goto tr120;
+ case 86: goto tr120;
+ case 87: goto tr120;
+ case 88: goto tr120;
+ case 89: goto tr120;
+ case 90: goto tr120;
+ case 91: goto tr120;
+ case 92: goto tr120;
+ case 93: goto tr120;
+ case 94: goto tr120;
+ case 96: goto tr181;
+ case 97: goto tr182;
+ case 16: goto tr29;
+ case 17: goto tr29;
+ case 98: goto tr182;
+ case 18: goto tr29;
+ case 19: goto tr29;
+ case 99: goto tr182;
+ case 20: goto tr29;
+ case 21: goto tr29;
+ case 22: goto tr29;
+ case 100: goto tr183;
+ case 101: goto tr183;
+ case 23: goto tr43;
+ case 102: goto tr185;
+ case 103: goto tr182;
+ case 104: goto tr187;
+ case 105: goto tr188;
+ case 106: goto tr188;
+ case 107: goto tr188;
+ case 108: goto tr188;
+ case 109: goto tr188;
+ case 110: goto tr202;
+ case 111: goto tr188;
+ case 112: goto tr188;
+ case 113: goto tr188;
+ case 114: goto tr188;
+ case 115: goto tr188;
+ case 116: goto tr188;
+ case 117: goto tr188;
+ case 118: goto tr188;
+ case 119: goto tr188;
+ case 120: goto tr188;
+ case 121: goto tr188;
+ case 122: goto tr188;
+ case 123: goto tr188;
+ case 124: goto tr188;
+ case 125: goto tr188;
+ case 126: goto tr188;
+ case 127: goto tr188;
+ case 128: goto tr188;
+ case 129: goto tr188;
+ case 130: goto tr188;
+ case 131: goto tr188;
+ case 132: goto tr188;
+ case 133: goto tr188;
+ case 134: goto tr188;
+ case 135: goto tr188;
+ case 136: goto tr188;
+ case 138: goto tr237;
+ case 140: goto tr255;
+ case 141: goto tr257;
+ case 142: goto tr259;
+ case 144: goto tr275;
+ case 145: goto tr276;
+ case 147: goto tr314;
+ case 148: goto tr315;
+ case 24: goto tr45;
+ case 149: goto tr316;
+ case 25: goto tr45;
+ case 150: goto tr315;
+ case 26: goto tr45;
+ case 151: goto tr315;
+ case 152: goto tr315;
+ case 153: goto tr315;
+ case 27: goto tr45;
+ case 28: goto tr45;
+ case 154: goto tr315;
+ case 155: goto tr315;
+ case 156: goto tr315;
+ case 157: goto tr334;
+ case 158: goto tr334;
+ case 29: goto tr55;
+ case 159: goto tr336;
+ case 160: goto tr315;
+ case 161: goto tr340;
+ case 162: goto tr315;
+ case 163: goto tr349;
+ case 164: goto tr315;
+ case 165: goto tr315;
+ case 166: goto tr315;
+ case 167: goto tr367;
+ case 168: goto tr368;
+ case 169: goto tr370;
+ case 170: goto tr370;
+ case 171: goto tr370;
+ case 172: goto tr370;
+ case 173: goto tr370;
+ case 174: goto tr370;
+ case 175: goto tr370;
+ case 176: goto tr370;
+ case 177: goto tr370;
+ case 178: goto tr370;
+ case 179: goto tr370;
+ case 180: goto tr370;
+ case 181: goto tr370;
+ case 182: goto tr370;
+ case 183: goto tr370;
+ case 184: goto tr370;
+ case 185: goto tr370;
+ case 186: goto tr370;
+ case 187: goto tr370;
+ case 188: goto tr370;
+ case 189: goto tr370;
+ case 190: goto tr370;
+ case 191: goto tr370;
+ case 192: goto tr370;
+ case 193: goto tr370;
+ case 194: goto tr370;
+ case 195: goto tr370;
+ case 196: goto tr370;
+ case 197: goto tr370;
+ case 198: goto tr370;
+ case 199: goto tr370;
+ case 200: goto tr370;
+ case 201: goto tr370;
+ case 202: goto tr370;
+ case 203: goto tr370;
+ case 204: goto tr370;
+ case 205: goto tr370;
+ case 206: goto tr370;
+ case 207: goto tr370;
+ case 208: goto tr370;
+ case 209: goto tr370;
+ case 210: goto tr370;
+ case 211: goto tr370;
+ case 212: goto tr370;
+ case 213: goto tr370;
+ case 214: goto tr370;
+ case 215: goto tr370;
+ case 216: goto tr370;
+ case 217: goto tr370;
+ case 218: goto tr370;
+ case 219: goto tr370;
+ case 220: goto tr370;
+ case 221: goto tr370;
+ case 222: goto tr370;
+ case 223: goto tr370;
+ case 224: goto tr370;
+ case 225: goto tr370;
+ case 226: goto tr370;
+ case 227: goto tr370;
+ case 228: goto tr370;
+ case 229: goto tr370;
+ case 230: goto tr370;
+ case 231: goto tr370;
+ case 232: goto tr370;
+ case 233: goto tr370;
+ case 234: goto tr370;
+ case 235: goto tr370;
+ case 236: goto tr370;
+ case 237: goto tr370;
+ case 238: goto tr370;
+ case 239: goto tr370;
+ case 240: goto tr370;
+ case 241: goto tr370;
+ case 242: goto tr370;
+ case 243: goto tr370;
+ case 244: goto tr370;
+ case 245: goto tr370;
+ case 246: goto tr370;
+ case 247: goto tr370;
+ case 248: goto tr370;
+ case 249: goto tr370;
+ case 250: goto tr370;
+ case 251: goto tr315;
+ case 252: goto tr315;
+ case 30: goto tr45;
+ case 254: goto tr474;
+ case 255: goto tr475;
+ case 31: goto tr58;
+ case 32: goto tr58;
+ case 256: goto tr475;
+ case 33: goto tr58;
+ case 257: goto tr475;
+ case 258: goto tr477;
+ case 259: goto tr475;
+ case 34: goto tr58;
+ case 35: goto tr58;
+ case 260: goto tr475;
+ case 36: goto tr58;
+ case 37: goto tr58;
+ case 261: goto tr479;
+ case 262: goto tr480;
+ }
+ }
+
+ _out: {}
+ }
+
+#line 1241 "rlscan.rl"
+
+ /* 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 = ts;
+
+ /* 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 ( ts != 0 )
+ ts -= shiftback;
+ te -= shiftback;
+
+ preserve = buf;
+ }
+ }
+
+ delete[] buf;
+}
diff --git a/ragel/rlscan.h b/ragel/rlscan.h
new file mode 100644
index 0000000..b56bd60
--- /dev/null
+++ b/ragel/rlscan.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 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
+ */
+
+#ifndef _RLSCAN_H
+#define _RLSCAN_H
+
+#include <iostream>
+#include "rlscan.h"
+#include "vector.h"
+#include "rlparse.h"
+#include "parsedata.h"
+#include "avltree.h"
+#include "vector.h"
+
+using std::istream;
+using std::ostream;
+
+extern char *Parser_lelNames[];
+
+struct Scanner
+{
+ Scanner( InputData &id, const char *fileName, istream &input,
+ Parser *inclToParser, char *inclSectionTarg,
+ int includeDepth, bool importMachines )
+ :
+ id(id), fileName(fileName),
+ input(input),
+ inclToParser(inclToParser),
+ inclSectionTarg(inclSectionTarg),
+ includeDepth(includeDepth),
+ importMachines(importMachines),
+ cur_token(0),
+ line(1), column(1), lastnl(0),
+ parser(0), ignoreSection(false),
+ parserExistsError(false),
+ whitespaceOn(true),
+ lastToken(0)
+ {}
+
+ bool duplicateInclude( char *inclFileName, char *inclSectionName );
+
+ /* Make a list of places to look for an included file. */
+ char **makeIncludePathChecks( const char *curFileName, const char *fileName, int len );
+ std::ifstream *tryOpenInclude( char **pathChecks, long &found );
+
+ void handleMachine();
+ void handleInclude();
+ void handleImport();
+
+ void init();
+ void token( int type, char *start, char *end );
+ void token( int type, char c );
+ void token( int type );
+ void processToken( int type, char *tokdata, int toklen );
+ void directToParser( Parser *toParser, const char *tokFileName, int tokLine,
+ int tokColumn, int type, char *tokdata, int toklen );
+ void flushImport( );
+ void importToken( int type, char *start, char *end );
+ void pass( int token, char *start, char *end );
+ void pass();
+ void updateCol();
+ void startSection();
+ void endSection();
+ void do_scan();
+ bool active();
+ ostream &scan_error();
+
+ InputData &id;
+ const char *fileName;
+ istream &input;
+ Parser *inclToParser;
+ char *inclSectionTarg;
+ int includeDepth;
+ bool importMachines;
+
+ /* For import parsing. */
+ int tok_cs, tok_act;
+ int *tok_ts, *tok_te;
+ int cur_token;
+ static const int max_tokens = 32;
+ int token_data[max_tokens];
+ char *token_strings[max_tokens];
+ int token_lens[max_tokens];
+
+ /* For section processing. */
+ int cs;
+ char *word, *lit;
+ int word_len, lit_len;
+
+ /* For character scanning. */
+ int line;
+ InputLoc sectionLoc;
+ char *ts, *te;
+ int column;
+ char *lastnl;
+
+ /* Set by machine statements, these persist from section to section
+ * allowing for unnamed sections. */
+ Parser *parser;
+ bool ignoreSection;
+
+ /* This is set if ragel has already emitted an error stating that
+ * no section name has been seen and thus no parser exists. */
+ bool parserExistsError;
+
+ /* This is for inline code. By default it is on. It goes off for
+ * statements and values in inline blocks which are parsed. */
+ bool whitespaceOn;
+
+ /* Keeps a record of the previous token sent to the section parser. */
+ int lastToken;
+};
+
+#endif
diff --git a/ragel/rlscan.rl b/ragel/rlscan.rl
new file mode 100644
index 0000000..a676b7e
--- /dev/null
+++ b/ragel/rlscan.rl
@@ -0,0 +1,1270 @@
+/*
+ * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
+ * Copyright 2011 Josef Goettgens
+ */
+
+/* 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 "ragel.h"
+#include "rlscan.h"
+#include "inputdata.h"
+
+//#define LOG_TOKENS
+
+using std::ifstream;
+using std::istream;
+using std::ostream;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+enum InlineBlockType
+{
+ CurlyDelimited,
+ SemiTerminated
+};
+
+#ifdef _WIN32
+#define PATH_SEP '\\'
+#else
+#define PATH_SEP '/'
+#endif
+
+
+/*
+ * The Scanner for Importing
+ */
+
+%%{
+ machine inline_token_scan;
+ alphtype int;
+ access tok_;
+
+ # Import scanner tokens.
+ import "rlparse.h";
+
+ main := |*
+ # Define of number.
+ IMP_Define IMP_Word IMP_UInt => {
+ int base = tok_ts - token_data;
+ int nameOff = 1;
+ int numOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_UInt,
+ token_strings[base+numOff], token_lens[base+numOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ };
+
+ # Assignment of number.
+ IMP_Word '=' IMP_UInt => {
+ int base = tok_ts - token_data;
+ int nameOff = 0;
+ int numOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_UInt,
+ token_strings[base+numOff], token_lens[base+numOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ };
+
+ # Define of literal.
+ IMP_Define IMP_Word IMP_Literal => {
+ int base = tok_ts - token_data;
+ int nameOff = 1;
+ int litOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_Literal,
+ token_strings[base+litOff], token_lens[base+litOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ };
+
+ # Assignment of literal.
+ IMP_Word '=' IMP_Literal => {
+ int base = tok_ts - token_data;
+ int nameOff = 0;
+ int litOff = 2;
+
+ directToParser( inclToParser, fileName, line, column, TK_Word,
+ token_strings[base+nameOff], token_lens[base+nameOff] );
+ directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
+ directToParser( inclToParser, fileName, line, column, TK_Literal,
+ token_strings[base+litOff], token_lens[base+litOff] );
+ directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
+ };
+
+ # Catch everything else.
+ any;
+ *|;
+}%%
+
+%% write data;
+
+void Scanner::flushImport()
+{
+ int *p = token_data;
+ int *pe = token_data + cur_token;
+ int *eof = 0;
+
+ %%{
+ machine inline_token_scan;
+ write init;
+ write exec;
+ }%%
+
+ if ( tok_ts == 0 )
+ cur_token = 0;
+ else {
+ cur_token = pe - tok_ts;
+ int ts_offset = tok_ts - token_data;
+ memmove( token_data, token_data+ts_offset, cur_token*sizeof(token_data[0]) );
+ memmove( token_strings, token_strings+ts_offset, cur_token*sizeof(token_strings[0]) );
+ memmove( token_lens, token_lens+ts_offset, cur_token*sizeof(token_lens[0]) );
+ }
+}
+
+void Scanner::directToParser( Parser *toParser, const char *tokFileName, int tokLine,
+ int tokColumn, int type, char *tokdata, int toklen )
+{
+ InputLoc loc;
+
+ #ifdef LOG_TOKENS
+ cerr << "scanner:" << tokLine << ":" << tokColumn <<
+ ": sending token to the parser " << Parser_lelNames[type];
+ cerr << " " << toklen;
+ if ( tokdata != 0 )
+ cerr << " " << tokdata;
+ cerr << endl;
+ #endif
+
+ loc.fileName = tokFileName;
+ loc.line = tokLine;
+ loc.col = tokColumn;
+
+ toParser->token( loc, type, tokdata, toklen );
+}
+
+void Scanner::importToken( int token, char *start, char *end )
+{
+ if ( cur_token == max_tokens )
+ flushImport();
+
+ token_data[cur_token] = token;
+ if ( start == 0 ) {
+ token_strings[cur_token] = 0;
+ token_lens[cur_token] = 0;
+ }
+ else {
+ int toklen = end-start;
+ token_lens[cur_token] = toklen;
+ token_strings[cur_token] = new char[toklen+1];
+ memcpy( token_strings[cur_token], start, toklen );
+ token_strings[cur_token][toklen] = 0;
+ }
+ cur_token++;
+}
+
+void Scanner::pass( int token, char *start, char *end )
+{
+ if ( importMachines )
+ importToken( token, start, end );
+ pass();
+}
+
+void Scanner::pass()
+{
+ updateCol();
+
+ /* If no errors and we are at the bottom of the include stack (the
+ * source file listed on the command line) then write out the data. */
+ if ( includeDepth == 0 && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->data.write( ts, te-ts );
+}
+
+/*
+ * The scanner for processing sections, includes, imports, etc.
+ */
+
+%%{
+ machine section_parse;
+ alphtype int;
+ write data;
+}%%
+
+
+void Scanner::init( )
+{
+ %% write init;
+}
+
+bool Scanner::active()
+{
+ if ( ignoreSection )
+ return false;
+
+ if ( parser == 0 && ! parserExistsError ) {
+ scan_error() << "this specification has no name, nor does any previous"
+ " specification" << endl;
+ parserExistsError = true;
+ }
+
+ if ( parser == 0 )
+ return false;
+
+ return true;
+}
+
+ostream &Scanner::scan_error()
+{
+ /* Maintain the error count. */
+ gblErrorCount += 1;
+ cerr << makeInputLoc( fileName, line, column ) << ": ";
+ return cerr;
+}
+
+/* An approximate check for duplicate includes. Due to aliasing of files it's
+ * possible for duplicates to creep in. */
+bool Scanner::duplicateInclude( char *inclFileName, char *inclSectionName )
+{
+ for ( IncludeHistory::Iter hi = parser->includeHistory; hi.lte(); hi++ ) {
+ if ( strcmp( hi->fileName, inclFileName ) == 0 &&
+ strcmp( hi->sectionName, inclSectionName ) == 0 )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Scanner::updateCol()
+{
+ char *from = lastnl;
+ if ( from == 0 )
+ from = ts;
+ //cerr << "adding " << te - from << " to column" << endl;
+ column += te - from;
+ lastnl = 0;
+}
+
+void Scanner::handleMachine()
+{
+ /* Assign a name to the machine. */
+ char *machine = word;
+
+ if ( !importMachines && inclSectionTarg == 0 ) {
+ ignoreSection = false;
+
+ ParserDictEl *pdEl = id.parserDict.find( machine );
+ if ( pdEl == 0 ) {
+ pdEl = new ParserDictEl( machine );
+ pdEl->value = new Parser( fileName, machine, sectionLoc );
+ pdEl->value->init();
+ id.parserDict.insert( pdEl );
+ id.parserList.append( pdEl->value );
+ }
+
+ parser = pdEl->value;
+ }
+ else if ( !importMachines && strcmp( inclSectionTarg, machine ) == 0 ) {
+ /* found include target */
+ ignoreSection = false;
+ parser = inclToParser;
+ }
+ else {
+ /* ignoring section */
+ ignoreSection = true;
+ parser = 0;
+ }
+}
+
+void Scanner::handleInclude()
+{
+ if ( active() ) {
+ char *inclSectionName = word;
+ char **includeChecks = 0;
+
+ /* Implement defaults for the input file and section name. */
+ if ( inclSectionName == 0 )
+ inclSectionName = parser->sectionName;
+
+ if ( lit != 0 )
+ includeChecks = makeIncludePathChecks( fileName, lit, lit_len );
+ else {
+ char *test = new char[strlen(fileName)+1];
+ strcpy( test, fileName );
+
+ includeChecks = new char*[2];
+
+ includeChecks[0] = test;
+ includeChecks[1] = 0;
+ }
+
+ long found = 0;
+ ifstream *inFile = tryOpenInclude( includeChecks, found );
+ if ( inFile == 0 ) {
+ scan_error() << "include: failed to locate file" << endl;
+ char **tried = includeChecks;
+ while ( *tried != 0 )
+ scan_error() << "include: attempted: \"" << *tried++ << '\"' << endl;
+ }
+ else {
+ /* Don't include anything that's already been included. */
+ if ( !duplicateInclude( includeChecks[found], inclSectionName ) ) {
+ parser->includeHistory.append( IncludeHistoryItem(
+ includeChecks[found], inclSectionName ) );
+
+ Scanner scanner( id, includeChecks[found], *inFile, parser,
+ inclSectionName, includeDepth+1, false );
+ scanner.do_scan( );
+ delete inFile;
+ }
+ }
+ }
+}
+
+void Scanner::handleImport()
+{
+ if ( active() ) {
+ char **importChecks = makeIncludePathChecks( fileName, lit, lit_len );
+
+ /* Open the input file for reading. */
+ long found = 0;
+ ifstream *inFile = tryOpenInclude( importChecks, found );
+ if ( inFile == 0 ) {
+ scan_error() << "import: could not open import file " <<
+ "for reading" << endl;
+ char **tried = importChecks;
+ while ( *tried != 0 )
+ scan_error() << "import: attempted: \"" << *tried++ << '\"' << endl;
+ }
+
+ Scanner scanner( id, importChecks[found], *inFile, parser,
+ 0, includeDepth+1, true );
+ scanner.do_scan( );
+ scanner.importToken( 0, 0, 0 );
+ scanner.flushImport();
+ delete inFile;
+ }
+}
+
+%%{
+ machine section_parse;
+
+ # Need the defines representing tokens.
+ import "rlparse.h";
+
+ action clear_words { word = lit = 0; word_len = lit_len = 0; }
+ action store_word { word = tokdata; word_len = toklen; }
+ action store_lit { lit = tokdata; lit_len = toklen; }
+
+ action mach_err { scan_error() << "bad machine statement" << endl; }
+ action incl_err { scan_error() << "bad include statement" << endl; }
+ action import_err { scan_error() << "bad import statement" << endl; }
+ action write_err { scan_error() << "bad write statement" << endl; }
+
+ action handle_machine { handleMachine(); }
+ action handle_include { handleInclude(); }
+ action handle_import { handleImport(); }
+
+ machine_stmt =
+ ( KW_Machine TK_Word @store_word ';' ) @handle_machine
+ <>err mach_err <>eof mach_err;
+
+ include_names = (
+ TK_Word @store_word ( TK_Literal @store_lit )? |
+ TK_Literal @store_lit
+ ) >clear_words;
+
+ include_stmt =
+ ( KW_Include include_names ';' ) @handle_include
+ <>err incl_err <>eof incl_err;
+
+ import_stmt =
+ ( KW_Import TK_Literal @store_lit ';' ) @handle_import
+ <>err import_err <>eof import_err;
+
+ action write_command
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 ) {
+ InputItem *inputItem = new InputItem;
+ inputItem->type = InputItem::Write;
+ inputItem->loc.fileName = fileName;
+ inputItem->loc.line = line;
+ inputItem->loc.col = column;
+ inputItem->name = parser->sectionName;
+ inputItem->pd = parser->pd;
+ id.inputItems.append( inputItem );
+ }
+ }
+
+ action write_arg
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->writeArgs.append( strdup(tokdata) );
+ }
+
+ action write_close
+ {
+ if ( active() && machineSpec == 0 && machineName == 0 )
+ id.inputItems.tail->writeArgs.append( 0 );
+ }
+
+ write_stmt =
+ ( KW_Write @write_command
+ ( TK_Word @write_arg )+ ';' @write_close )
+ <>err write_err <>eof write_err;
+
+ action handle_token
+ {
+ /* Send the token off to the parser. */
+ if ( active() )
+ directToParser( parser, fileName, line, column, type, tokdata, toklen );
+ }
+
+ # Catch everything else.
+ everything_else =
+ ^( KW_Machine | KW_Include | KW_Import | KW_Write ) @handle_token;
+
+ main := (
+ machine_stmt |
+ include_stmt |
+ import_stmt |
+ write_stmt |
+ everything_else
+ )*;
+}%%
+
+void Scanner::token( int type, char c )
+{
+ token( type, &c, &c + 1 );
+}
+
+void Scanner::token( int type )
+{
+ token( type, 0, 0 );
+}
+
+void Scanner::token( int type, char *start, char *end )
+{
+ char *tokdata = 0;
+ int toklen = 0;
+ if ( start != 0 ) {
+ toklen = end-start;
+ tokdata = new char[toklen+1];
+ memcpy( tokdata, start, toklen );
+ tokdata[toklen] = 0;
+ }
+
+ processToken( type, tokdata, toklen );
+}
+
+void Scanner::processToken( int type, char *tokdata, int toklen )
+{
+ int *p, *pe, *eof;
+
+ if ( type < 0 )
+ p = pe = eof = 0;
+ else {
+ p = &type;
+ pe = &type + 1;
+ eof = 0;
+ }
+
+ %%{
+ machine section_parse;
+ write exec;
+ }%%
+
+ updateCol();
+
+ /* Record the last token for use in controlling the scan of subsequent
+ * tokens. */
+ lastToken = type;
+}
+
+void Scanner::startSection( )
+{
+ parserExistsError = false;
+
+ sectionLoc.fileName = fileName;
+ sectionLoc.line = line;
+ sectionLoc.col = column;
+}
+
+void Scanner::endSection( )
+{
+ /* Execute the eof actions for the section parser. */
+ processToken( -1, 0, 0 );
+
+ /* Close off the section with the parser. */
+ if ( active() ) {
+ InputLoc loc;
+ loc.fileName = fileName;
+ loc.line = line;
+ loc.col = column;
+
+ parser->token( loc, TK_EndSection, 0, 0 );
+ }
+
+ if ( includeDepth == 0 ) {
+ if ( machineSpec == 0 && machineName == 0 ) {
+ /* The end section may include a newline on the end, so
+ * we use the last line, which will count the newline. */
+ InputItem *inputItem = new InputItem;
+ inputItem->type = InputItem::HostData;
+ inputItem->loc.line = line;
+ inputItem->loc.col = column;
+ id.inputItems.append( inputItem );
+ }
+ }
+}
+
+bool isAbsolutePath( const char *path )
+{
+#ifdef _WIN32
+ return isalpha( path[0] ) && path[1] == ':' && path[2] == '\\';
+#else
+ return path[0] == '/';
+#endif
+}
+
+char **Scanner::makeIncludePathChecks( const char *thisFileName,
+ const char *fileName, int fnlen )
+{
+ char **checks = 0;
+ long nextCheck = 0;
+ long length = 0;
+ bool caseInsensitive = false;
+ char *data = prepareLitString( InputLoc(), fileName, fnlen,
+ length, caseInsensitive );
+
+ /* Absolute path? */
+ if ( isAbsolutePath( data ) ) {
+ checks = new char*[2];
+ checks[nextCheck++] = data;
+ }
+ else {
+ checks = new char*[2 + id.includePaths.length()];
+
+ /* Search from the the location of the current file. */
+ const char *lastSlash = strrchr( thisFileName, PATH_SEP );
+ if ( lastSlash == 0 )
+ checks[nextCheck++] = data;
+ else {
+ long givenPathLen = (lastSlash - thisFileName) + 1;
+ long checklen = givenPathLen + length;
+ char *check = new char[checklen+1];
+ memcpy( check, thisFileName, givenPathLen );
+ memcpy( check+givenPathLen, data, length );
+ check[checklen] = 0;
+ checks[nextCheck++] = check;
+ }
+
+ /* Search from the include paths given on the command line. */
+ for ( ArgsVector::Iter incp = id.includePaths; incp.lte(); incp++ ) {
+ long pathLen = strlen( *incp );
+ long checkLen = pathLen + 1 + length;
+ char *check = new char[checkLen+1];
+ memcpy( check, *incp, pathLen );
+ check[pathLen] = PATH_SEP;
+ memcpy( check+pathLen+1, data, length );
+ check[checkLen] = 0;
+ checks[nextCheck++] = check;
+ }
+ }
+
+ checks[nextCheck] = 0;
+ return checks;
+}
+
+ifstream *Scanner::tryOpenInclude( char **pathChecks, long &found )
+{
+ char **check = pathChecks;
+ ifstream *inFile = new ifstream;
+
+ while ( *check != 0 ) {
+ inFile->open( *check );
+ if ( inFile->is_open() ) {
+ found = check - pathChecks;
+ return inFile;
+ }
+
+ /*
+ * 03/26/2011 jg:
+ * Don't rely on sloppy runtime behaviour: reset the state of the stream explicitly.
+ * If inFile->open() fails, which happens when include dirs are tested, the fail bit
+ * is set by the runtime library. Currently the VS runtime library opens new files,
+ * but when it comes to reading it refuses to work.
+ */
+ inFile->clear();
+
+ check += 1;
+ }
+
+ found = -1;
+ delete inFile;
+ return 0;
+}
+
+%%{
+ machine rlscan;
+
+ # This is sent by the driver code.
+ EOF = 0;
+
+ action inc_nl {
+ lastnl = p;
+ column = 0;
+ line++;
+ }
+ NL = '\n' @inc_nl;
+
+ # Identifiers, numbers, commetns, and other common things.
+ ident = ( alpha | '_' ) ( alpha |digit |'_' )*;
+ number = digit+;
+ hex_number = '0x' [0-9a-fA-F]+;
+
+ c_comment =
+ '/*' ( any | NL )* :>> '*/';
+
+ cpp_comment =
+ '//' [^\n]* NL;
+
+ c_cpp_comment = c_comment | cpp_comment;
+
+ ruby_comment = '#' [^\n]* NL;
+
+ # These literal forms are common to host code and ragel.
+ s_literal = "'" ([^'\\] | NL | '\\' (any | NL))* "'";
+ d_literal = '"' ([^"\\] | NL | '\\' (any | NL))* '"';
+ host_re_literal = '/' ([^/\\] | NL | '\\' (any | NL))* '/';
+
+ whitespace = [ \t] | NL;
+ pound_comment = '#' [^\n]* NL;
+
+ # An inline block of code for Ruby.
+ inline_code_ruby := |*
+ # Inline expression keywords.
+ "fpc" => { token( KW_PChar ); };
+ "fc" => { token( KW_Char ); };
+ "fcurs" => { token( KW_CurState ); };
+ "ftargs" => { token( KW_TargState ); };
+ "fentry" => {
+ whitespaceOn = false;
+ token( KW_Entry );
+ };
+
+ # Inline statement keywords.
+ "fhold" => {
+ whitespaceOn = false;
+ token( KW_Hold );
+ };
+ "fexec" => { token( KW_Exec, 0, 0 ); };
+ "fgoto" => {
+ whitespaceOn = false;
+ token( KW_Goto );
+ };
+ "fnext" => {
+ whitespaceOn = false;
+ token( KW_Next );
+ };
+ "fcall" => {
+ whitespaceOn = false;
+ token( KW_Call );
+ };
+ "fret" => {
+ whitespaceOn = false;
+ token( KW_Ret );
+ };
+ "fbreak" => {
+ whitespaceOn = false;
+ token( KW_Break );
+ };
+
+ ident => { token( TK_Word, ts, te ); };
+
+ number => { token( TK_UInt, ts, te ); };
+ hex_number => { token( TK_Hex, ts, te ); };
+
+ ( s_literal | d_literal | host_re_literal )
+ => { token( IL_Literal, ts, te ); };
+
+ whitespace+ => {
+ if ( whitespaceOn )
+ token( IL_WhiteSpace, ts, te );
+ };
+
+ ruby_comment => { token( IL_Comment, ts, te ); };
+
+ "::" => { token( TK_NameSep, ts, te ); };
+
+ # Some symbols need to go to the parser as with their cardinal value as
+ # the token type (as opposed to being sent as anonymous symbols)
+ # because they are part of the sequences which we interpret. The * ) ;
+ # symbols cause whitespace parsing to come back on. This gets turned
+ # off by some keywords.
+
+ ";" => {
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ if ( inlineBlockType == SemiTerminated )
+ fret;
+ };
+
+ [*)] => {
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ };
+
+ [,(] => { token( *ts, ts, te ); };
+
+ '{' => {
+ token( IL_Symbol, ts, te );
+ curly_count += 1;
+ };
+
+ '}' => {
+ if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
+ /* Inline code block ends. */
+ token( '}' );
+ fret;
+ }
+ else {
+ /* Either a semi terminated inline block or only the closing
+ * brace of some inner scope, not the block's closing brace. */
+ token( IL_Symbol, ts, te );
+ }
+ };
+
+ EOF => {
+ scan_error() << "unterminated code block" << endl;
+ };
+
+ # Send every other character as a symbol.
+ any => { token( IL_Symbol, ts, te ); };
+ *|;
+
+
+ # An inline block of code for languages other than Ruby.
+ inline_code := |*
+ # Inline expression keywords.
+ "fpc" => { token( KW_PChar ); };
+ "fc" => { token( KW_Char ); };
+ "fcurs" => { token( KW_CurState ); };
+ "ftargs" => { token( KW_TargState ); };
+ "fentry" => {
+ whitespaceOn = false;
+ token( KW_Entry );
+ };
+
+ # Inline statement keywords.
+ "fhold" => {
+ whitespaceOn = false;
+ token( KW_Hold );
+ };
+ "fexec" => { token( KW_Exec, 0, 0 ); };
+ "fgoto" => {
+ whitespaceOn = false;
+ token( KW_Goto );
+ };
+ "fnext" => {
+ whitespaceOn = false;
+ token( KW_Next );
+ };
+ "fcall" => {
+ whitespaceOn = false;
+ token( KW_Call );
+ };
+ "fret" => {
+ whitespaceOn = false;
+ token( KW_Ret );
+ };
+ "fbreak" => {
+ whitespaceOn = false;
+ token( KW_Break );
+ };
+
+ ident => { token( TK_Word, ts, te ); };
+
+ number => { token( TK_UInt, ts, te ); };
+ hex_number => { token( TK_Hex, ts, te ); };
+
+ ( s_literal | d_literal )
+ => { token( IL_Literal, ts, te ); };
+
+ whitespace+ => {
+ if ( whitespaceOn )
+ token( IL_WhiteSpace, ts, te );
+ };
+
+ c_cpp_comment => { token( IL_Comment, ts, te ); };
+
+ "::" => { token( TK_NameSep, ts, te ); };
+
+ # Some symbols need to go to the parser as with their cardinal value as
+ # the token type (as opposed to being sent as anonymous symbols)
+ # because they are part of the sequences which we interpret. The * ) ;
+ # symbols cause whitespace parsing to come back on. This gets turned
+ # off by some keywords.
+
+ ";" => {
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ if ( inlineBlockType == SemiTerminated )
+ fret;
+ };
+
+ [*)] => {
+ whitespaceOn = true;
+ token( *ts, ts, te );
+ };
+
+ [,(] => { token( *ts, ts, te ); };
+
+ '{' => {
+ token( IL_Symbol, ts, te );
+ curly_count += 1;
+ };
+
+ '}' => {
+ if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
+ /* Inline code block ends. */
+ token( '}' );
+ fret;
+ }
+ else {
+ /* Either a semi terminated inline block or only the closing
+ * brace of some inner scope, not the block's closing brace. */
+ token( IL_Symbol, ts, te );
+ }
+ };
+
+ EOF => {
+ scan_error() << "unterminated code block" << endl;
+ };
+
+ # Send every other character as a symbol.
+ any => { token( IL_Symbol, ts, te ); };
+ *|;
+
+ or_literal := |*
+ # Escape sequences in OR expressions.
+ '\\0' => { token( RE_Char, '\0' ); };
+ '\\a' => { token( RE_Char, '\a' ); };
+ '\\b' => { token( RE_Char, '\b' ); };
+ '\\t' => { token( RE_Char, '\t' ); };
+ '\\n' => { token( RE_Char, '\n' ); };
+ '\\v' => { token( RE_Char, '\v' ); };
+ '\\f' => { token( RE_Char, '\f' ); };
+ '\\r' => { token( RE_Char, '\r' ); };
+ '\\\n' => { updateCol(); };
+ '\\' any => { token( RE_Char, ts+1, te ); };
+
+ # Range dash in an OR expression.
+ '-' => { token( RE_Dash, 0, 0 ); };
+
+ # Terminate an OR expression.
+ ']' => { token( RE_SqClose ); fret; };
+
+ EOF => {
+ scan_error() << "unterminated OR literal" << endl;
+ };
+
+ # Characters in an OR expression.
+ [^\]] => { token( RE_Char, ts, te ); };
+
+ *|;
+
+ ragel_re_literal := |*
+ # Escape sequences in regular expressions.
+ '\\0' => { token( RE_Char, '\0' ); };
+ '\\a' => { token( RE_Char, '\a' ); };
+ '\\b' => { token( RE_Char, '\b' ); };
+ '\\t' => { token( RE_Char, '\t' ); };
+ '\\n' => { token( RE_Char, '\n' ); };
+ '\\v' => { token( RE_Char, '\v' ); };
+ '\\f' => { token( RE_Char, '\f' ); };
+ '\\r' => { token( RE_Char, '\r' ); };
+ '\\\n' => { updateCol(); };
+ '\\' any => { token( RE_Char, ts+1, te ); };
+
+ # Terminate an OR expression.
+ '/' [i]? => {
+ token( RE_Slash, ts, te );
+ fgoto parser_def;
+ };
+
+ # Special characters.
+ '.' => { token( RE_Dot ); };
+ '*' => { token( RE_Star ); };
+
+ '[' => { token( RE_SqOpen ); fcall or_literal; };
+ '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
+
+ EOF => {
+ scan_error() << "unterminated regular expression" << endl;
+ };
+
+ # Characters in an OR expression.
+ [^\/] => { token( RE_Char, ts, te ); };
+ *|;
+
+ # We need a separate token space here to avoid the ragel keywords.
+ write_statement := |*
+ ident => { token( TK_Word, ts, te ); } ;
+ [ \t\n]+ => { updateCol(); };
+ ';' => { token( ';' ); fgoto parser_def; };
+
+ EOF => {
+ scan_error() << "unterminated write statement" << endl;
+ };
+ *|;
+
+ # Parser definitions.
+ parser_def := |*
+ #'length_cond' => { token( KW_Length ); };
+ 'machine' => { token( KW_Machine ); };
+ 'include' => { token( KW_Include ); };
+ 'import' => { token( KW_Import ); };
+ 'write' => {
+ token( KW_Write );
+ fgoto write_statement;
+ };
+ 'action' => { token( KW_Action ); };
+ 'alphtype' => { token( KW_AlphType ); };
+ 'prepush' => { token( KW_PrePush ); };
+ 'postpop' => { token( KW_PostPop ); };
+
+ # FIXME: Enable this post 5.17.
+ # 'range' => { token( KW_Range ); };
+
+ 'getkey' => {
+ token( KW_GetKey );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ fcall inline_code_ruby;
+ else
+ fcall inline_code;
+ };
+ 'access' => {
+ token( KW_Access );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ fcall inline_code_ruby;
+ else
+ fcall inline_code;
+ };
+ 'variable' => {
+ token( KW_Variable );
+ inlineBlockType = SemiTerminated;
+ if ( hostLang->lang == HostLang::Ruby )
+ fcall inline_code_ruby;
+ else
+ fcall inline_code;
+ };
+ 'when' => { token( KW_When ); };
+ 'inwhen' => { token( KW_InWhen ); };
+ 'outwhen' => { token( KW_OutWhen ); };
+ 'eof' => { token( KW_Eof ); };
+ 'err' => { token( KW_Err ); };
+ 'lerr' => { token( KW_Lerr ); };
+ 'to' => { token( KW_To ); };
+ 'from' => { token( KW_From ); };
+ 'export' => { token( KW_Export ); };
+
+ # Identifiers.
+ ident => { token( TK_Word, ts, te ); } ;
+
+ # Numbers
+ number => { token( TK_UInt, ts, te ); };
+ hex_number => { token( TK_Hex, ts, te ); };
+
+ # Literals, with optionals.
+ ( s_literal | d_literal ) [i]?
+ => { token( TK_Literal, ts, te ); };
+
+ '[' => { token( RE_SqOpen ); fcall or_literal; };
+ '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
+
+ '/' => { token( RE_Slash ); fgoto ragel_re_literal; };
+
+ # Ignore.
+ pound_comment => { updateCol(); };
+
+ ':=' => { token( TK_ColonEquals ); };
+
+ # To State Actions.
+ ">~" => { token( TK_StartToState ); };
+ "$~" => { token( TK_AllToState ); };
+ "%~" => { token( TK_FinalToState ); };
+ "<~" => { token( TK_NotStartToState ); };
+ "@~" => { token( TK_NotFinalToState ); };
+ "<>~" => { token( TK_MiddleToState ); };
+
+ # From State actions
+ ">*" => { token( TK_StartFromState ); };
+ "$*" => { token( TK_AllFromState ); };
+ "%*" => { token( TK_FinalFromState ); };
+ "<*" => { token( TK_NotStartFromState ); };
+ "@*" => { token( TK_NotFinalFromState ); };
+ "<>*" => { token( TK_MiddleFromState ); };
+
+ # EOF Actions.
+ ">/" => { token( TK_StartEOF ); };
+ "$/" => { token( TK_AllEOF ); };
+ "%/" => { token( TK_FinalEOF ); };
+ "</" => { token( TK_NotStartEOF ); };
+ "@/" => { token( TK_NotFinalEOF ); };
+ "<>/" => { token( TK_MiddleEOF ); };
+
+ # Global Error actions.
+ ">!" => { token( TK_StartGblError ); };
+ "$!" => { token( TK_AllGblError ); };
+ "%!" => { token( TK_FinalGblError ); };
+ "<!" => { token( TK_NotStartGblError ); };
+ "@!" => { token( TK_NotFinalGblError ); };
+ "<>!" => { token( TK_MiddleGblError ); };
+
+ # Local error actions.
+ ">^" => { token( TK_StartLocalError ); };
+ "$^" => { token( TK_AllLocalError ); };
+ "%^" => { token( TK_FinalLocalError ); };
+ "<^" => { token( TK_NotStartLocalError ); };
+ "@^" => { token( TK_NotFinalLocalError ); };
+ "<>^" => { token( TK_MiddleLocalError ); };
+
+ # Middle.
+ "<>" => { token( TK_Middle ); };
+
+ # Conditions.
+ '>?' => { token( TK_StartCond ); };
+ '$?' => { token( TK_AllCond ); };
+ '%?' => { token( TK_LeavingCond ); };
+
+ '..' => { token( TK_DotDot ); };
+ '**' => { token( TK_StarStar ); };
+ '--' => { token( TK_DashDash ); };
+ '->' => { token( TK_Arrow ); };
+ '=>' => { token( TK_DoubleArrow ); };
+
+ ":>" => { token( TK_ColonGt ); };
+ ":>>" => { token( TK_ColonGtGt ); };
+ "<:" => { token( TK_LtColon ); };
+
+ # Opening of longest match.
+ "|*" => { token( TK_BarStar ); };
+
+ # Separater for name references.
+ "::" => { token( TK_NameSep, ts, te ); };
+
+ '}%%' => {
+ updateCol();
+ endSection();
+ fret;
+ };
+
+ [ \t\r]+ => { updateCol(); };
+
+ # If we are in a single line machine then newline may end the spec.
+ NL => {
+ updateCol();
+ if ( singleLineSpec ) {
+ endSection();
+ fret;
+ }
+ };
+
+ '{' => {
+ if ( lastToken == KW_Export || lastToken == KW_Entry )
+ token( '{' );
+ else {
+ token( '{' );
+ curly_count = 1;
+ inlineBlockType = CurlyDelimited;
+ if ( hostLang->lang == HostLang::Ruby )
+ fcall inline_code_ruby;
+ else
+ fcall inline_code;
+ }
+ };
+
+ EOF => {
+ scan_error() << "unterminated ragel section" << endl;
+ };
+
+ any => { token( *ts ); } ;
+ *|;
+
+ # Outside code scanner. These tokens get passed through.
+ main_ruby := |*
+ ident => { pass( IMP_Word, ts, te ); };
+ number => { pass( IMP_UInt, ts, te ); };
+ ruby_comment => { pass(); };
+ ( s_literal | d_literal | host_re_literal )
+ => { pass( IMP_Literal, ts, te ); };
+
+ '%%{' => {
+ updateCol();
+ singleLineSpec = false;
+ startSection();
+ fcall parser_def;
+ };
+ '%%' => {
+ updateCol();
+ singleLineSpec = true;
+ startSection();
+ fcall parser_def;
+ };
+ whitespace+ => { pass(); };
+ EOF;
+ any => { pass( *ts, 0, 0 ); };
+ *|;
+
+ # Outside code scanner. These tokens get passed through.
+ main := |*
+ 'define' => { pass( IMP_Define, 0, 0 ); };
+ ident => { pass( IMP_Word, ts, te ); };
+ number => { pass( IMP_UInt, ts, te ); };
+ c_cpp_comment => { pass(); };
+ ( s_literal | d_literal ) => { pass( IMP_Literal, ts, te ); };
+
+ '%%{' => {
+ updateCol();
+ singleLineSpec = false;
+ startSection();
+ fcall parser_def;
+ };
+ '%%' => {
+ updateCol();
+ singleLineSpec = true;
+ startSection();
+ fcall parser_def;
+ };
+ whitespace+ => { pass(); };
+ EOF;
+ any => { pass( *ts, 0, 0 ); };
+ *|;
+}%%
+
+%% write data;
+
+void Scanner::do_scan()
+{
+ int bufsize = 8;
+ char *buf = new char[bufsize];
+ int cs, act, have = 0;
+ int top;
+
+ /* The stack is two deep, one level for going into ragel defs from the main
+ * machines which process outside code, and another for going into or literals
+ * from either a ragel spec, or a regular expression. */
+ int stack[2];
+ int curly_count = 0;
+ bool execute = true;
+ bool singleLineSpec = false;
+ InlineBlockType inlineBlockType = CurlyDelimited;
+
+ /* Init the section parser and the character scanner. */
+ init();
+ %% write init;
+
+ /* Set up the start state. FIXME: After 5.20 is released the nocs write
+ * init option should be used, the main machine eliminated and this statement moved
+ * above the write init. */
+ if ( hostLang->lang == HostLang::Ruby )
+ cs = rlscan_en_main_ruby;
+ else
+ cs = rlscan_en_main;
+
+ 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 ( ts != 0 )
+ ts = newbuf + ( ts - buf );
+ te = newbuf + ( te - buf );
+
+ /* Copy the new buffer in. */
+ memcpy( newbuf, buf, have );
+ delete[] buf;
+ buf = newbuf;
+ }
+
+ input.read( p, space );
+ int len = input.gcount();
+ char *pe = p + len;
+
+ /* If we see eof then append the eof var. */
+ char *eof = 0;
+ if ( len == 0 ) {
+ eof = pe;
+ execute = false;
+ }
+
+ %% write exec;
+
+ /* 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 = ts;
+
+ /* 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 ( ts != 0 )
+ ts -= shiftback;
+ te -= shiftback;
+
+ preserve = buf;
+ }
+ }
+
+ delete[] buf;
+}
diff --git a/ragel/rubycodegen.cpp b/ragel/rubycodegen.cpp
new file mode 100644
index 0000000..ff25ada
--- /dev/null
+++ b/ragel/rubycodegen.cpp
@@ -0,0 +1,831 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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 <iomanip>
+#include <sstream>
+#include "redfsm.h"
+#include "gendata.h"
+#include "ragel.h"
+#include "rubycodegen.h"
+#include "pcheck.h"
+#include "vector.h"
+#include "version.h"
+#include "common.h"
+
+#include "ragel.h"
+#include "rubytable.h"
+#include "rubyftable.h"
+#include "rubyflat.h"
+#include "rubyfflat.h"
+#include "rbxgoto.h"
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/* Target ruby impl */
+
+/* Target language and output style. */
+extern CodeStyle codeStyle;
+
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
+/*
+ * Callbacks invoked by the XML data parser.
+ */
+
+
+void rubyLineDirective( ostream &out, const char *fileName, int line )
+{
+ if ( noLineDirectives )
+ return;
+
+ /* Write a comment containing line info. */
+ out << "# line " << line << " \"";
+ for ( const char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+ out << "\"\n";
+}
+
+void RubyCodeGen::genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ rubyLineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+string RubyCodeGen::DATA_PREFIX()
+{
+ if ( !noPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
+{
+ out <<
+ "class << self\n"
+ " attr_accessor :" << name << "\n"
+ "end\n"
+ "self." << name;
+ return out;
+}
+
+
+std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
+{
+ out <<
+ "class << self\n"
+ " attr_accessor :" << name << "\n"
+ " private :" << name << ", :" << name << "=\n"
+ "end\n"
+ "self." << name << " = [\n";
+ return out;
+}
+
+std::ostream &RubyCodeGen::CLOSE_ARRAY()
+{
+ out << "]\n";
+ return out;
+}
+
+
+string RubyCodeGen::ARR_OFF( string ptr, string offset )
+{
+ return ptr + "[" + offset + "]";
+}
+
+string RubyCodeGen::NULL_ITEM()
+{
+ return "nil";
+}
+
+
+string RubyCodeGen::P()
+{
+ ostringstream ret;
+ if ( pExpr == 0 )
+ ret << "p";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, pExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::PE()
+{
+ ostringstream ret;
+ if ( peExpr == 0 )
+ ret << "pe";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, peExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::vEOF()
+{
+ ostringstream ret;
+ if ( eofExpr == 0 )
+ ret << "eof";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, eofExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::vCS()
+{
+ ostringstream ret;
+ if ( csExpr == 0 )
+ ret << ACCESS() << "cs";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, csExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::TOP()
+{
+ ostringstream ret;
+ if ( topExpr == 0 )
+ ret << ACCESS() + "top";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, topExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::STACK()
+{
+ ostringstream ret;
+ if ( stackExpr == 0 )
+ ret << ACCESS() + "stack";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, stackExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::ACT()
+{
+ ostringstream ret;
+ if ( actExpr == 0 )
+ ret << ACCESS() + "act";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, actExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::TOKSTART()
+{
+ ostringstream ret;
+ if ( tokstartExpr == 0 )
+ ret << ACCESS() + "ts";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, tokstartExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::TOKEND()
+{
+ ostringstream ret;
+ if ( tokendExpr == 0 )
+ ret << ACCESS() + "te";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, tokendExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::DATA()
+{
+ ostringstream ret;
+ if ( dataExpr == 0 )
+ ret << ACCESS() + "data";
+ else {
+ //ret << "(";
+ INLINE_LIST( ret, dataExpr, 0, false );
+ //ret << ")";
+ }
+ return ret.str();
+}
+
+/* Write out the fsm name. */
+string RubyCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+
+void RubyCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ rubyLineDirective( ret, action->loc.fileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << " begin\n";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish );
+ ret << " end\n";
+}
+
+
+
+string RubyCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string RubyCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use dereference and read ordinal,
+ * for compatibility with Ruby 1.9. */
+ ret << DATA() << "[" << P() << "].ord";
+ }
+ return ret.str();
+}
+
+string RubyCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal();
+ return ret.str();
+}
+
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string RubyCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+string RubyCodeGen::INT( int i )
+{
+ ostringstream ret;
+ ret << i;
+ return ret.str();
+}
+
+void RubyCodeGen::CONDITION( ostream &ret, GenAction *condition )
+{
+ ret << "\n";
+ rubyLineDirective( ret, condition->loc.fileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+/* Emit the alphabet data type. */
+string RubyCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string RubyCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+
+string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+/* Write out the array of actions. */
+std::ostream &RubyCodeGen::ACTIONS_ARRAY()
+{
+ START_ARRAY_LINE();
+ int totalActions = 0;
+ ARRAY_ITEM( INT(0), ++totalActions, false );
+ for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
+
+ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
+ ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
+ }
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+void RubyCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
+
+ if ( !noFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
+
+ if ( !noError )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+std::ostream &RubyCodeGen::START_ARRAY_LINE()
+{
+ out << "\t";
+ return out;
+}
+
+std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
+{
+ out << item;
+ if ( !last )
+ {
+ out << ", ";
+ if ( count % IALL == 0 )
+ {
+ END_ARRAY_LINE();
+ START_ARRAY_LINE();
+ }
+ }
+ return out;
+}
+
+std::ostream &RubyCodeGen::END_ARRAY_LINE()
+{
+ out << "\n";
+ return out;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string RubyCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+string RubyCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string RubyCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+string RubyCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false );
+ return ret.str();
+}
+
+/* Write out an inline tree structure. Walks the list and possibly calls out
+ * to virtual functions than handle language specific items in the tree. */
+void RubyCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
+ int targState, bool inFinish )
+{
+ for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case GenInlineItem::Text:
+ ret << item->data;
+ break;
+ case GenInlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case GenInlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case GenInlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case GenInlineItem::PChar:
+ ret << P();
+ break;
+ case GenInlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case GenInlineItem::Hold:
+ ret << P() << " = " << P() << " - 1;";
+ break;
+ case GenInlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Curs:
+ ret << "(_ps)";
+ break;
+ case GenInlineItem::Targs:
+ ret << "(" << vCS() << ")";
+ break;
+ case GenInlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case GenInlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case GenInlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case GenInlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case GenInlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case GenInlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish );
+ break;
+ case GenInlineItem::Break:
+ BREAK( ret, targState );
+ break;
+ }
+ }
+}
+
+
+void RubyCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
+{
+ /* The parser gives fexec two children. The double brackets are for D
+ * code. If the inline list is a single word it will get interpreted as a
+ * C-style cast by the D compiler. */
+ ret << " begin " << P() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "))-1; end\n";
+}
+
+void RubyCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
+ int targState, int inFinish )
+{
+ ret <<
+ " case " << ACT() << "\n";
+
+ for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ if ( lma->lmId < 0 )
+ ret << " else\n";
+ else
+ ret << " when " << lma->lmId << " then\n";
+
+
+ /* Write the block and close it off. */
+ ret << " begin";
+ INLINE_LIST( ret, lma->children, targState, inFinish );
+ ret << "end\n";
+ }
+
+ ret << "end \n\t";
+}
+
+void RubyCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void RubyCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void RubyCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
+{
+ ret << ACT() << " = 0\n";
+}
+
+void RubyCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << "\n";
+}
+
+void RubyCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << "\n";
+}
+
+void RubyCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void RubyCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << " begin ";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << " end\n";
+ }
+}
+
+int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ return act;
+}
+
+ostream &RubyCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &RubyCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
+void RubyCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+
+/* Determine if we should use indicies or not. */
+void RubyCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+
+void RubyCodeGen::writeInit()
+{
+ out << "begin\n";
+
+ out << " " << P() << " ||= 0\n";
+
+ if ( !noEnd )
+ out << " " << PE() << " ||= " << DATA() << ".length\n";
+
+ if ( !noCS )
+ out << " " << vCS() << " = " << START() << "\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << " " << TOP() << " = 0\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << "\n"
+ " " << TOKEND() << " = " << NULL_ITEM() << "\n"
+ " " << ACT() << " = 0\n";
+ }
+
+ out << "end\n";
+}
+
+void RubyCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
+ << " = " << KEY(ex->key) << "\n";
+ }
+ out << "\n";
+ }
+}
+
+void RubyCodeGen::writeStart()
+{
+ out << START_STATE_ID();
+}
+
+void RubyCodeGen::writeFirstFinal()
+{
+ out << FIRST_FINAL_STATE();
+}
+
+void RubyCodeGen::writeError()
+{
+ out << ERROR_STATE();
+}
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/rubycodegen.h b/ragel/rubycodegen.h
new file mode 100644
index 0000000..4e3a30d
--- /dev/null
+++ b/ragel/rubycodegen.h
@@ -0,0 +1,174 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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
+ */
+
+#ifndef _RUBY_CODEGEN_H
+#define _RUBY_CODEGEN_H
+
+#include "common.h"
+#include "gendata.h"
+
+/* Integer array line length. */
+#define IALL 8
+
+
+class RubyCodeGen : public CodeGenData
+{
+public:
+ RubyCodeGen( ostream &out ) : CodeGenData(out) { }
+ virtual ~RubyCodeGen() {}
+protected:
+ ostream &START_ARRAY_LINE();
+ ostream &ARRAY_ITEM( string item, int count, bool last );
+ ostream &END_ARRAY_LINE();
+
+
+ string FSM_NAME();
+
+ string START_STATE_ID();
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+ void INLINE_LIST(ostream &ret, GenInlineList *inlineList, int targState, bool inFinish);
+ string ACCESS();
+
+ void ACTION( ostream &ret, GenAction *action, int targState, bool inFinish );
+ string GET_KEY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string KEY( Key key );
+ string TABS( int level );
+ string INT( int i );
+ void CONDITION( ostream &ret, GenAction *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+ ostream &ACTIONS_ARRAY();
+ void STATE_IDS();
+
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string ET() { return "_" + DATA_PREFIX() + "eof_trans"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+public:
+ string NULL_ITEM();
+ ostream &OPEN_ARRAY( string type, string name );
+ ostream &CLOSE_ARRAY();
+ ostream &STATIC_VAR( string type, string name );
+ string ARR_OFF( string ptr, string offset );
+
+ string P();
+ string PE();
+ string vEOF();
+
+ string vCS();
+ string TOP();
+ string STACK();
+ string ACT();
+ string TOKSTART();
+ string TOKEND();
+ string DATA();
+
+
+ void finishRagelDef();
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+protected:
+ virtual void writeExports();
+ virtual void writeInit();
+ virtual void writeStart();
+ virtual void writeFirstFinal();
+ virtual void writeError();
+
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize();
+
+ virtual void BREAK( ostream &ret, int targState ) = 0;
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+
+
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0;
+
+ virtual int TO_STATE_ACTION( RedStateAp *state ) = 0;
+ virtual int FROM_STATE_ACTION( RedStateAp *state ) = 0;
+ virtual int EOF_ACTION( RedStateAp *state ) = 0;
+
+ virtual int TRANS_ACTION( RedTransAp *trans );
+
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ void SUB_ACTION( ostream &ret, GenInlineItem *item, int targState, bool inFinish );
+
+protected:
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+
+ /* fields */
+ bool outLabelUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+ void genLineDirective( ostream &out );
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif
diff --git a/ragel/rubyfflat.cpp b/ragel/rubyfflat.cpp
new file mode 100644
index 0000000..53c7896
--- /dev/null
+++ b/ragel/rubyfflat.cpp
@@ -0,0 +1,488 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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 "rubyfflat.h"
+
+void RubyFFlatCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = " << gotoDest << "\n"
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFFlatCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, 0, inFinish );
+ out << ")\n";
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << "+= 1\n"
+ " " << vCS() << " = " << callDest << "\n"
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFFlatCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem,
+ int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << " += 1\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, targState, inFinish );
+ out << ")\n";
+
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFFlatCodeGen::RET( ostream &out, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << TOP() << " -= 1\n"
+ " " << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+ if ( postPopExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, postPopExpr, 0, false );
+ out << "end\n";
+ }
+
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFFlatCodeGen::BREAK( ostream &out, int targState )
+{
+ out <<
+ " begin\n"
+ " " << P() << " += 1\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+}
+
+
+int RubyFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+int RubyFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+int RubyFFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+/* Write out the function for a transition. */
+int RubyFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ return action;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyFFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void RubyFFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void RubyFFlatCodeGen::writeExec()
+{
+ out <<
+ "begin\n"
+ " testEof = false\n"
+ " _slen, _trans, _keys, _inds";
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+ if ( redFsm->anyConditions() )
+ out << ", _cond, _conds, _widec";
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ out << ", _acts, _nacts";
+
+ out << " = nil\n";
+
+ out <<
+ " _goto_level = 0\n"
+ " _resume = 10\n"
+ " _eof_trans = 15\n"
+ " _again = 20\n"
+ " _test_eof = 30\n"
+ " _out = 40\n";
+
+ out <<
+ " while true\n"
+ " if _goto_level <= 0\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " == " << PE() << "\n"
+ " _goto_level = _test_eof\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The resume label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _resume\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " case " << FSA() << "[" << vCS() << "] \n";
+ FROM_STATE_ACTION_SWITCH() <<
+ " end\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " end\n"
+ " if _goto_level <= _eof_trans\n";
+ }
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << "\n";
+
+ out << " " << vCS() << " = " << TT() << "[_trans]\n";
+
+ if ( redFsm->anyRegActions() ) {
+ /* break _again */
+ out <<
+ " if " << TA() << "[_trans] != 0\n"
+ " case " << TA() << "[_trans]" << "\n";
+ ACTION_SWITCH() <<
+ " end\n"
+ " end\n";
+ }
+
+ /* The again label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _again\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " case " << TSA() << "[" << vCS() << "] \n";
+ TO_STATE_ACTION_SWITCH() <<
+ " end\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ out << " " << P() << " += 1\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " != " << PE() << "\n"
+ " _goto_level = _resume\n"
+ " next\n"
+ " end\n";
+ }
+ else {
+ out <<
+ " _goto_level = _resume\n"
+ " next\n";
+ }
+
+ /* The test eof label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _test_eof\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << "\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " _goto_level = _eof_trans\n"
+ " next;\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " case " << EA() << "[" << vCS() << "]\n";
+ EOF_ACTION_SWITCH() <<
+ " end\n";
+ }
+
+ out <<
+ " end\n"
+ "\n";
+ }
+
+ out <<
+ " end\n"
+ " if _goto_level <= _out\n"
+ " break\n"
+ " end\n"
+ "end\n";
+
+ /* Wrapping the execute block. */
+ out << " end\n";
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
diff --git a/ragel/rubyfflat.h b/ragel/rubyfflat.h
new file mode 100644
index 0000000..4ac412f
--- /dev/null
+++ b/ragel/rubyfflat.h
@@ -0,0 +1,65 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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
+ */
+
+#ifndef _RUBY_FFLATCODEGEN_H
+#define _RUBY_FFLATCODEGEN_H
+
+#include <iostream>
+#include "rubyflat.h"
+
+class RubyFFlatCodeGen : public RubyFlatCodeGen
+{
+public:
+ RubyFFlatCodeGen( ostream &out ) :
+ RubyFlatCodeGen(out) {}
+protected:
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ void GOTO( ostream &out, int gotoDest, bool inFinish );
+ void GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish );
+ void CALL( ostream &out, int callDest, int targState, bool inFinish );
+ void CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &out, bool inFinish );
+ void BREAK( ostream &out, int targState );
+
+ virtual int TO_STATE_ACTION( RedStateAp *state );
+ virtual int FROM_STATE_ACTION( RedStateAp *state );
+ virtual int EOF_ACTION( RedStateAp *state );
+ virtual int TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif
diff --git a/ragel/rubyflat.cpp b/ragel/rubyflat.cpp
new file mode 100644
index 0000000..827084d
--- /dev/null
+++ b/ragel/rubyflat.cpp
@@ -0,0 +1,873 @@
+/*
+ * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
+ * Copyright 2007 Victor Hugo Borja <vic@rubyforge.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 "rubyflat.h"
+#include "ragel.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::ostream;
+using std::string;
+
+std::ostream &RubyFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, true );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\twhen " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &RubyFlatCodeGen::KEYS()
+{
+ START_ARRAY_LINE();
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ ARRAY_ITEM( KEY( st->lowKey ), ++totalTrans, false );
+ ARRAY_ITEM( KEY( st->highKey ), ++totalTrans, false );
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ START_ARRAY_LINE();
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ ARRAY_ITEM( KEY( st->transList[pos]->id ), ++totalTrans, false );
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 )
+ ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ ARRAY_ITEM( INT( curIndOffset ), ++totalStateNum, st.last() );
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::KEY_SPANS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ ARRAY_ITEM( INT( span ), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::TO_STATE_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT( TO_STATE_ACTION(st) ), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::FROM_STATE_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT( FROM_STATE_ACTION(st) ), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::EOF_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT( EOF_ACTION(st) ), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::EOF_TRANS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(trans), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ START_ARRAY_LINE();
+
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Save the position. Needed for eofTargs. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ ARRAY_ITEM( INT( trans->targ->id ), ++totalStates, t >= redFsm->transSet.length()-1 );
+ }
+ END_ARRAY_LINE();
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &RubyFlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ START_ARRAY_LINE();
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ ARRAY_ITEM( INT( TRANS_ACTION( trans ) ), ++totalAct, t >= redFsm->transSet.length()-1 );
+ }
+ END_ARRAY_LINE();
+ delete[] transPtrs;
+ return out;
+}
+
+
+void RubyFlatCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << vCS() << " << 1\n"
+ " _inds = " << IO() << "[" << vCS() << "]\n"
+ " _slen = " << SP() << "[" << vCS() << "]\n"
+ " _wide = " << GET_WIDE_KEY() << "\n"
+ " _trans = if ( _slen > 0 && \n"
+ " " << K() << "[_keys] <= _wide && \n"
+ " " << "_wide <= " << K() << "[_keys + 1] \n"
+ " ) then\n"
+ " " << I() << "[ _inds + _wide - " << K() << "[_keys] ] \n"
+ " else \n"
+ " " << I() << "[ _inds + _slen ]\n"
+ " end\n"
+ "";
+
+}
+
+std::ostream &RubyFlatCodeGen::COND_INDEX_OFFSET()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ ARRAY_ITEM( INT( curIndOffset ), ++totalStateNum, st.last() );
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+void RubyFlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << "\n"
+ " _keys = " << vCS() << " << 1\n"
+ " _conds = " << CO() << "[" << vCS() << "]\n"
+ " _slen = " << CSP() << "[" << vCS() << "]\n"
+ " _wide = " << GET_WIDE_KEY() << "\n"
+ " _cond = if ( _slen > 0 && \n"
+ " " << CK() << "[_keys] <= _wide &&\n"
+ " " << "_wide <= " << CK() << "[_keys + 1]\n"
+ " ) then \n"
+ " " << C() << "[ _conds + _wide - " << CK() << "[_keys]" << " ]\n"
+ " else\n"
+ " 0\n"
+ " end\n";
+ out <<
+ " case _cond \n";
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " when " << condSpace->condSpaceId + 1 << " then\n";
+ out << TABS(2) << "_widec = " << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "))\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out <<
+ " ) then \n" <<
+ TABS(3) << " _widec += " << condValOffset << "\n"
+ "end\n";
+ }
+ }
+
+ out <<
+ " end # _cond switch \n";
+}
+
+std::ostream &RubyFlatCodeGen::CONDS()
+{
+ int totalTrans = 0;
+ START_ARRAY_LINE();
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ ARRAY_ITEM( INT( st->condList[pos]->condSpaceId + 1 ), ++totalTrans, false );
+ else
+ ARRAY_ITEM( INT( 0 ), ++totalTrans, false );
+ }
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::COND_KEYS()
+{
+ START_ARRAY_LINE();
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ ARRAY_ITEM( KEY( st->condLowKey ), ++totalTrans, false );
+ ARRAY_ITEM( KEY( st->condHighKey ), ++totalTrans, false );
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyFlatCodeGen::COND_KEY_SPANS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ ARRAY_ITEM( INT( span ), ++totalStateNum, false );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+
+void RubyFlatCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = " << gotoDest << "\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << "+= 1\n"
+ " " << vCS() << " = " << callDest << "\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFlatCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << " += 1\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, targState, inFinish );
+ out << ")\n";
+
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFlatCodeGen::RET( ostream &out, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << TOP() << " -= 1\n"
+ " " << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+ if ( postPopExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, postPopExpr, 0, false );
+ out << "end\n";
+ }
+
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyFlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void RubyFlatCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, 0, inFinish );
+ out << ")\n";
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyFlatCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+
+void RubyFlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void RubyFlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << vCS() << ")";
+}
+
+void RubyFlatCodeGen::BREAK( ostream &out, int targState )
+{
+ out <<
+ " begin\n"
+ " " << P() << " += 1\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _out\n"
+ " break\n"
+ " end\n";
+}
+
+int RubyFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+int RubyFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+int RubyFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+int RubyFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ return act;
+}
+
+void RubyFlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void RubyFlatCodeGen::writeExec()
+{
+ out <<
+ "begin # ragel flat\n"
+ " testEof = false\n"
+ " _slen, _trans, _keys, _inds";
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+ if ( redFsm->anyConditions() )
+ out << ", _cond, _conds, _widec";
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ out << ", _acts, _nacts";
+
+ out << " = nil\n";
+
+ out <<
+ " _goto_level = 0\n"
+ " _resume = 10\n"
+ " _eof_trans = 15\n"
+ " _again = 20\n"
+ " _test_eof = 30\n"
+ " _out = 40\n";
+
+ out <<
+ " while true\n"
+ " _trigger_goto = false\n"
+ " if _goto_level <= 0\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " == " << PE() << "\n"
+ " _goto_level = _test_eof\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The resume label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _resume\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" << vCS() << "]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ FROM_STATE_ACTION_SWITCH();
+ out <<
+ " end # from state action switch\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " end\n"
+ " if _goto_level <= _eof_trans\n";
+ }
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << "\n";
+
+ out << " " << vCS() << " = " << TT() << "[_trans]\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] != 0\n"
+ " _acts = " << TA() << "[_trans]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ ACTION_SWITCH();
+ out <<
+ " end # action switch\n"
+ " end\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The again label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _again\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ TO_STATE_ACTION_SWITCH() <<
+ " end # to state action switch\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ out << " " << P() << " += 1\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " != " << PE() << "\n"
+ " _goto_level = _resume\n"
+ " next\n"
+ " end\n";
+ }
+ else {
+ out <<
+ " _goto_level = _resume\n"
+ " next\n";
+ }
+
+ /* The test_eof label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _test_eof\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << "\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " _goto_level = _eof_trans\n"
+ " next;\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " begin\n"
+ " __acts = " << EA() << "[" << vCS() << "]\n"
+ " __nacts = " << A() << "[__acts]\n" <<
+ " __acts += 1\n"
+ " while ( __nacts > 0 ) \n"
+ " __nacts -= 1\n"
+ " __acts += 1\n"
+ " case ( "<< A() << "[__acts-1] ) \n";
+ EOF_ACTION_SWITCH() <<
+ " end\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n"
+ " end\n";
+ }
+
+ out <<
+ " end\n";
+ }
+
+ out <<
+ " end\n"
+ " if _goto_level <= _out\n"
+ " break\n"
+ " end\n";
+
+ /* The loop for faking goto. */
+ out <<
+ " end\n";
+
+ /* Wrapping the execute block. */
+ out <<
+ " end\n";
+}
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/rubyflat.h b/ragel/rubyflat.h
new file mode 100644
index 0000000..5136791
--- /dev/null
+++ b/ragel/rubyflat.h
@@ -0,0 +1,99 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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
+ */
+
+#ifndef _RUBY_FLATCODEGEN_H
+#define _RUBY_FLATCODEGEN_H
+
+#include <iostream>
+#include "rubycodegen.h"
+
+using std::string;
+using std::ostream;
+
+
+/*
+ * FlatCodeGen
+ */
+class RubyFlatCodeGen : public RubyCodeGen
+{
+public:
+ RubyFlatCodeGen( ostream &out ) :
+ RubyCodeGen(out) {};
+ virtual ~RubyFlatCodeGen() {}
+protected:
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+
+ virtual int TO_STATE_ACTION( RedStateAp *state );
+ virtual int FROM_STATE_ACTION( RedStateAp *state );
+ virtual int EOF_ACTION( RedStateAp *state );
+ virtual int TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeExec();
+
+};
+
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/rubyftable.cpp b/ragel/rubyftable.cpp
new file mode 100644
index 0000000..b90ffa7
--- /dev/null
+++ b/ragel/rubyftable.cpp
@@ -0,0 +1,563 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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 <iomanip>
+#include <sstream>
+#include "redfsm.h"
+#include "gendata.h"
+#include "ragel.h"
+#include "rubyftable.h"
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+void RubyFTabCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = " << gotoDest << "\n"
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFTabCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, 0, inFinish );
+ out << ")\n";
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << "+= 1\n"
+ " " << vCS() << " = " << callDest << "\n"
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFTabCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem,
+ int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << " += 1\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, targState, inFinish );
+ out << ")\n";
+
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyFTabCodeGen::RET( ostream &out, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << TOP() << " -= 1\n"
+ " " << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+ if ( postPopExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, postPopExpr, 0, false );
+ out << "end\n";
+ }
+
+ out <<
+ " _goto_level = _again\n"
+ " next\n"
+ " end\n";
+}
+
+void RubyFTabCodeGen::BREAK( ostream &out, int targState )
+{
+ out <<
+ " begin\n"
+ " " << P() << " += 1\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+}
+
+
+std::ostream &RubyFTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyFTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFTabCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\twhen " << redAct->actListId+1 << " then\n";
+
+ /* Write each action in the list of action items. */
+ for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+int RubyFTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+int RubyFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+int RubyFTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+
+/* Write out the function for a transition. */
+int RubyFTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ return action;
+}
+
+void RubyFTabCodeGen::writeData()
+{
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void RubyFTabCodeGen::writeExec()
+{
+ out <<
+ "begin\n"
+ " testEof = false\n"
+ " _klen, _trans, _keys";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ if ( redFsm->anyConditions() )
+ out << ", _widec";
+
+ out << " = nil\n";
+
+ out <<
+ " _goto_level = 0\n"
+ " _resume = 10\n"
+ " _eof_trans = 15\n"
+ " _again = 20\n"
+ " _test_eof = 30\n"
+ " _out = 40\n";
+
+ out <<
+ " while true\n"
+ " if _goto_level <= 0\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " == " << PE() << "\n"
+ " _goto_level = _test_eof\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The resume label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _resume\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " case " << FSA() << "[" << vCS() << "] \n";
+ FROM_STATE_ACTION_SWITCH() <<
+ " end # from state action switch \n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " end\n"
+ " if _goto_level <= _eof_trans\n";
+ }
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << ";\n";
+
+ out <<
+ " " << vCS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] != 0\n"
+ "\n"
+ " case " << TA() << "[_trans] \n";
+ ACTION_SWITCH() <<
+ " end # action switch \n"
+ " end\n"
+ "\n";
+ }
+
+ /* The again label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _again\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " case " << TSA() << "[" << vCS() << "] \n";
+ TO_STATE_ACTION_SWITCH() <<
+ " end\n"
+ "\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ out << " " << P() << " += 1\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " != " << PE() << "\n"
+ " _goto_level = _resume\n"
+ " next\n"
+ " end\n";
+ }
+ else {
+ out <<
+ " _goto_level = _resume\n"
+ " next\n";
+ }
+
+ /* The test eof label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _test_eof\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << "\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " _goto_level = _eof_trans\n"
+ " next;\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " begin\n"
+ " case ( " << EA() << "[" << vCS() << "] )\n";
+ EOF_ACTION_SWITCH() <<
+ " end\n"
+ " end\n";
+ }
+
+ out <<
+ " end\n"
+ "\n";
+ }
+
+ out <<
+ " end\n"
+ " if _goto_level <= _out\n"
+ " break\n"
+ " end\n"
+ "end\n";
+
+ /* Wrapping the execute block. */
+ out << " end\n";
+}
+
+
+void RubyFTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/rubyftable.h b/ragel/rubyftable.h
new file mode 100644
index 0000000..91d7fe5
--- /dev/null
+++ b/ragel/rubyftable.h
@@ -0,0 +1,64 @@
+/*
+ * 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * Copyright 2001-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
+ */
+
+#ifndef _RUBY_FTABCODEGEN_H
+#define _RUBY_FTABCODEGEN_H
+
+#include "rubytable.h"
+
+class RubyFTabCodeGen : public RubyTabCodeGen
+{
+public:
+ RubyFTabCodeGen( ostream &out ): RubyTabCodeGen(out) {}
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ void GOTO( ostream &out, int gotoDest, bool inFinish );
+ void GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish );
+ void CALL( ostream &out, int callDest, int targState, bool inFinish );
+ void CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &out, bool inFinish );
+ void BREAK( ostream &out, int targState );
+
+ int TO_STATE_ACTION( RedStateAp *state );
+ int FROM_STATE_ACTION( RedStateAp *state );
+ int EOF_ACTION( RedStateAp *state );
+ virtual int TRANS_ACTION( RedTransAp *trans );
+
+ void writeData();
+ void writeExec();
+ void calcIndexSize();
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif
+
diff --git a/ragel/rubytable.cpp b/ragel/rubytable.cpp
new file mode 100644
index 0000000..eb5dfd5
--- /dev/null
+++ b/ragel/rubytable.cpp
@@ -0,0 +1,1033 @@
+/*
+ * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * 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 <iomanip>
+#include <sstream>
+#include "redfsm.h"
+#include "gendata.h"
+#include "ragel.h"
+#include "rubytable.h"
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+
+
+void RubyTabCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = " << gotoDest << "\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyTabCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, 0, inFinish );
+ out << ")\n";
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << "+= 1\n"
+ " " << vCS() << " = " << callDest << "\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyTabCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish )
+{
+ if ( prePushExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, prePushExpr, 0, false );
+ }
+
+ out <<
+ " begin\n"
+ " " << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
+ " " << TOP() << " += 1\n"
+ " " << vCS() << " = (";
+ INLINE_LIST( out, ilItem->children, targState, inFinish );
+ out << ")\n";
+
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+
+ if ( prePushExpr != 0 )
+ out << "end\n";
+}
+
+void RubyTabCodeGen::RET( ostream &out, bool inFinish )
+{
+ out <<
+ " begin\n"
+ " " << TOP() << " -= 1\n"
+ " " << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+ if ( postPopExpr != 0 ) {
+ out << "begin\n";
+ INLINE_LIST( out, postPopExpr, 0, false );
+ out << "end\n";
+ }
+
+ out <<
+ " _trigger_goto = true\n"
+ " _goto_level = _again\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyTabCodeGen::BREAK( ostream &out, int targState )
+{
+ out <<
+ " begin\n"
+ " " << P() << " += 1\n"
+ " _trigger_goto = true\n"
+ " _goto_level = _out\n"
+ " break\n"
+ " end\n";
+}
+
+void RubyTabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << "\n"
+ " _keys = " << CO() << "[" << vCS() << "]*2\n"
+ " _klen = " << CL() << "[" << vCS() << "]\n"
+ " if _klen > 0\n"
+ " _lower = _keys\n"
+ " _upper = _keys + (_klen<<1) - 2\n"
+ " loop do\n"
+ " break if _upper < _lower\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
+ " if " << GET_WIDE_KEY() << " < " << CK() << "[_mid]\n"
+ " _upper = _mid - 2\n"
+ " elsif " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1]\n"
+ " _lower = _mid + 2\n"
+ " else\n"
+ " case " << C() << "[" << CO() << "[" << vCS() << "]"
+ " + ((_mid - _keys)>>1)]\n";
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ GenCondSpace *condSpace = csi;
+ out << " when " << condSpace->condSpaceId << " then" ;
+ out << " _widec = " << KEY(condSpace->baseKey) <<
+ "+ (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ")\n";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " _widec += " << condValOffset << " if ( ";
+ CONDITION( out, *csi );
+ out << " )\n";
+ }
+ }
+
+ out <<
+ " end # case\n"
+ " end\n"
+ " end # loop\n"
+ " end\n";
+}
+
+
+void RubyTabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << KO() << "[" << vCS() << "]\n"
+ " _trans = " << IO() << "[" << vCS() << "]\n"
+ " _klen = " << SL() << "[" << vCS() << "]\n"
+ " _break_match = false\n"
+ " \n"
+ " begin\n"
+ " if _klen > 0\n"
+ " _lower = _keys\n"
+ " _upper = _keys + _klen - 1\n"
+ "\n"
+ " loop do\n"
+ " break if _upper < _lower\n"
+ " _mid = _lower + ( (_upper - _lower) >> 1 )\n"
+ "\n"
+ " if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
+ " _upper = _mid - 1\n"
+ " elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid]\n"
+ " _lower = _mid + 1\n"
+ " else\n"
+ " _trans += (_mid - _keys)\n"
+ " _break_match = true\n"
+ " break\n"
+ " end\n"
+ " end # loop\n"
+ " break if _break_match\n"
+ " _keys += _klen\n"
+ " _trans += _klen\n"
+ " end"
+ "\n"
+ " _klen = " << RL() << "[" << vCS() << "]\n"
+ " if _klen > 0\n"
+ " _lower = _keys\n"
+ " _upper = _keys + (_klen << 1) - 2\n"
+ " loop do\n"
+ " break if _upper < _lower\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
+ " if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
+ " _upper = _mid - 2\n"
+ " elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid+1]\n"
+ " _lower = _mid + 2\n"
+ " else\n"
+ " _trans += ((_mid - _keys) >> 1)\n"
+ " _break_match = true\n"
+ " break\n"
+ " end\n"
+ " end # loop\n"
+ " break if _break_match\n"
+ " _trans += _klen\n"
+ " end\n"
+ " end while false\n";
+}
+
+void RubyTabCodeGen::writeExec()
+{
+ out <<
+ "begin\n"
+ " _klen, _trans, _keys";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+ if ( redFsm->anyConditions() )
+ out << ", _widec";
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ out << ", _acts, _nacts";
+
+ out << " = nil\n";
+
+ out <<
+ " _goto_level = 0\n"
+ " _resume = 10\n"
+ " _eof_trans = 15\n"
+ " _again = 20\n"
+ " _test_eof = 30\n"
+ " _out = 40\n";
+
+ out <<
+ " while true\n"
+ " _trigger_goto = false\n"
+ " if _goto_level <= 0\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " == " << PE() << "\n"
+ " _goto_level = _test_eof\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The resume label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _resume\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << FSA() << "[" << vCS() << "]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ FROM_STATE_ACTION_SWITCH();
+ out <<
+ " end # from state action switch\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans]\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " end\n"
+ " if _goto_level <= _eof_trans\n";
+ }
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << vCS() << "\n";
+
+ out << " " << vCS() << " = " << TT() << "[_trans]\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if " << TA() << "[_trans] != 0\n"
+ " _acts = " << TA() << "[_trans]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ ACTION_SWITCH();
+ out <<
+ " end # action switch\n"
+ " end\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ /* The again label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _again\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << TSA() << "[" << vCS() << "]\n"
+ " _nacts = " << A() << "[_acts]\n"
+ " _acts += 1\n"
+ " while _nacts > 0\n"
+ " _nacts -= 1\n"
+ " _acts += 1\n"
+ " case " << A() << "[_acts - 1]\n";
+ TO_STATE_ACTION_SWITCH();
+ out <<
+ " end # to state action switch\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ if ( redFsm->errState != 0 ) {
+ out <<
+ " if " << vCS() << " == " << redFsm->errState->id << "\n"
+ " _goto_level = _out\n"
+ " next\n"
+ " end\n";
+ }
+
+ out << " " << P() << " += 1\n";
+
+ if ( !noEnd ) {
+ out <<
+ " if " << P() << " != " << PE() << "\n"
+ " _goto_level = _resume\n"
+ " next\n"
+ " end\n";
+ }
+ else {
+ out <<
+ " _goto_level = _resume\n"
+ " next\n";
+ }
+
+ /* The test_eof label. */
+ out <<
+ " end\n"
+ " if _goto_level <= _test_eof\n";
+
+ if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
+ out <<
+ " if " << P() << " == " << vEOF() << "\n";
+
+ if ( redFsm->anyEofTrans() ) {
+ out <<
+ " if " << ET() << "[" << vCS() << "] > 0\n"
+ " _trans = " << ET() << "[" << vCS() << "] - 1;\n"
+ " _goto_level = _eof_trans\n"
+ " next;\n"
+ " end\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " __acts = " << EA() << "[" << vCS() << "]\n"
+ " __nacts = " << " " << A() << "[__acts]\n"
+ " __acts += 1\n"
+ " while __nacts > 0\n"
+ " __nacts -= 1\n"
+ " __acts += 1\n"
+ " case " << A() << "[__acts - 1]\n";
+ EOF_ACTION_SWITCH() <<
+ " end # eof action switch\n"
+ " end\n"
+ " if _trigger_goto\n"
+ " next\n"
+ " end\n";
+ }
+
+ out <<
+ "end\n";
+ }
+
+ out <<
+ " end\n"
+ " if _goto_level <= _out\n"
+ " break\n"
+ " end\n";
+
+ /* The loop for next. */
+ out <<
+ " end\n";
+
+ /* Wrapping the execute block. */
+ out <<
+ " end\n";
+}
+
+std::ostream &RubyTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action */
+ out << " when " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &RubyTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "when " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "when " << act->actionId << " then\n";
+ ACTION( out, act, 0, true );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "when " << act->actionId << " then\n";
+ ACTION( out, act, 0, false );
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+void RubyTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << vCS() << " = " << nextDest << ";";
+}
+
+void RubyTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
+{
+ ret << vCS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+
+int RubyTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+int RubyTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+int RubyTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+
+std::ostream &RubyTabCodeGen::COND_OFFSETS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::KEY_OFFSETS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+
+std::ostream &RubyTabCodeGen::INDEX_OFFSETS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ ARRAY_ITEM( INT(curIndOffset), ++totalStateNum, st.last() );
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::COND_LENS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ ARRAY_ITEM( INT(st->stateCondList.length()), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+
+std::ostream &RubyTabCodeGen::SINGLE_LENS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ ARRAY_ITEM( INT(st->outSingle.length()), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::RANGE_LENS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ ARRAY_ITEM( INT(st->outRange.length()), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::TO_STATE_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(TO_STATE_ACTION(st)), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::FROM_STATE_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::EOF_ACTIONS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(EOF_ACTION(st)), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::EOF_TRANS()
+{
+ START_ARRAY_LINE();
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ long trans = 0;
+ if ( st->eofTrans != 0 ) {
+ assert( st->eofTrans->pos >= 0 );
+ trans = st->eofTrans->pos+1;
+ }
+
+ /* Write any eof action. */
+ ARRAY_ITEM( INT(trans), ++totalStateNum, st.last() );
+ }
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::COND_KEYS()
+{
+ START_ARRAY_LINE();
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
+ ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::COND_SPACES()
+{
+ START_ARRAY_LINE();
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::KEYS()
+{
+ START_ARRAY_LINE();
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ ARRAY_ITEM( KEY( stel->lowKey ), ++totalTrans, false );
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
+
+ /* Upper key. */
+ ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ START_ARRAY_LINE();
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ ARRAY_ITEM( KEY( stel->value->id ), ++totalTrans, false );
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ START_ARRAY_LINE();
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ trans->pos = totalTrans;
+ ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+
+std::ostream &RubyTabCodeGen::TRANS_ACTIONS()
+{
+ int totalTrans = 0;
+ START_ARRAY_LINE();
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 ) {
+ RedTransAp *trans = st->eofTrans;
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ ARRAY_ITEM( INT(0), ++totalTrans, true );
+ END_ARRAY_LINE();
+ return out;
+}
+
+std::ostream &RubyTabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ START_ARRAY_LINE();
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Save the position. Needed for eofTargs. */
+ RedTransAp *trans = transPtrs[t];
+ trans->pos = t;
+
+ /* Write out the target state. */
+ ARRAY_ITEM( INT(trans->targ->id), ++totalStates, ( t >= redFsm->transSet.length()-1 ) );
+ }
+ END_ARRAY_LINE();
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &RubyTabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ START_ARRAY_LINE();
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalAct,
+ ( t >= redFsm->transSet.length()-1 ) );
+ }
+ END_ARRAY_LINE();
+ delete[] transPtrs;
+ return out;
+}
+
+
+void RubyTabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofTrans() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
+ EOF_TRANS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+/*
+ Local Variables:
+ mode: c++
+ indent-tabs-mode: 1
+ c-file-style: "bsd"
+ End:
+ */
diff --git a/ragel/rubytable.h b/ragel/rubytable.h
new file mode 100644
index 0000000..76b847f
--- /dev/null
+++ b/ragel/rubytable.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ * 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
+ */
+
+#ifndef _RUBY_TABCODEGEN_H
+#define _RUBY_TABCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+#include "rubycodegen.h"
+
+
+using std::string;
+using std::ostream;
+
+/*
+ * RubyCodeGen
+ */
+class RubyTabCodeGen : public RubyCodeGen
+{
+public:
+ RubyTabCodeGen( ostream &out ) :
+ RubyCodeGen(out) {}
+ virtual ~RubyTabCodeGen() {}
+
+public:
+ void BREAK( ostream &ret, int targState );
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+
+ void COND_TRANSLATE();
+ void LOCATE_TRANS();
+
+ virtual void writeExec();
+ virtual void writeData();
+
+ protected:
+ virtual std::ostream &TO_STATE_ACTION_SWITCH();
+ virtual std::ostream &FROM_STATE_ACTION_SWITCH();
+ virtual std::ostream &EOF_ACTION_SWITCH();
+ virtual std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &EOF_TRANS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+
+
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish );
+
+ virtual int TO_STATE_ACTION( RedStateAp *state );
+ virtual int FROM_STATE_ACTION( RedStateAp *state );
+ virtual int EOF_ACTION( RedStateAp *state );
+
+private:
+ string array_type;
+ string array_name;
+
+public:
+
+ void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void EXECTE( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, GenInlineItem *item );
+ void INIT_TOKSTART( ostream &ret, GenInlineItem *item );
+ void INIT_ACT( ostream &ret, GenInlineItem *item );
+ void SET_TOKSTART( ostream &ret, GenInlineItem *item );
+ void SET_TOKEND( ostream &ret, GenInlineItem *item );
+ void GET_TOKEND( ostream &ret, GenInlineItem *item );
+ void SUB_ACTION( ostream &ret, GenInlineItem *item,
+ int targState, bool inFinish );
+
+
+};
+
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/ragel/version.h b/ragel/version.h
new file mode 100644
index 0000000..87d9750
--- /dev/null
+++ b/ragel/version.h
@@ -0,0 +1,2 @@
+#define VERSION "6.9"
+#define PUBDATE "Oct 2014"
diff --git a/ragel/xmlcodegen.cpp b/ragel/xmlcodegen.cpp
new file mode 100644
index 0000000..e4b14bc
--- /dev/null
+++ b/ragel/xmlcodegen.cpp
@@ -0,0 +1,1429 @@
+/*
+ * Copyright 2005-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 "ragel.h"
+#include "xmlcodegen.h"
+#include "parsedata.h"
+#include "fsmgraph.h"
+#include "gendata.h"
+#include "inputdata.h"
+#include <string.h>
+#include "rlparse.h"
+#include "version.h"
+
+using namespace std;
+
+GenBase::GenBase( char *fsmName, ParseData *pd, FsmAp *fsm )
+:
+ fsmName(fsmName),
+ pd(pd),
+ fsm(fsm),
+ nextActionTableId(0)
+{
+}
+
+void GenBase::appendTrans( TransListVect &outList, Key lowKey,
+ Key highKey, TransAp *trans )
+{
+ if ( trans->toState != 0 || trans->actionTable.length() > 0 )
+ outList.append( TransEl( lowKey, highKey, trans ) );
+}
+
+void GenBase::reduceActionTables()
+{
+ /* Reduce the actions tables to a set. */
+ for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
+ RedActionTable *actionTable = 0;
+
+ /* Reduce To State Actions. */
+ if ( st->toStateActionTable.length() > 0 ) {
+ if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
+ actionTable->id = nextActionTableId++;
+ }
+
+ /* Reduce From State Actions. */
+ if ( st->fromStateActionTable.length() > 0 ) {
+ if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
+ actionTable->id = nextActionTableId++;
+ }
+
+ /* Reduce EOF actions. */
+ if ( st->eofActionTable.length() > 0 ) {
+ if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
+ actionTable->id = nextActionTableId++;
+ }
+
+ /* Loop the transitions and reduce their actions. */
+ for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
+ if ( trans->actionTable.length() > 0 ) {
+ if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
+ actionTable->id = nextActionTableId++;
+ }
+ }
+ }
+}
+
+XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, std::ostream &out )
+:
+ GenBase(fsmName, pd, fsm),
+ out(out)
+{
+}
+
+
+void XMLCodeGen::writeActionList()
+{
+ /* Determine which actions to write. */
+ int nextActionId = 0;
+ for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
+ if ( act->numRefs() > 0 || act->numCondRefs > 0 )
+ act->actionId = nextActionId++;
+ }
+
+ /* Write the list. */
+ out << " <action_list length=\"" << nextActionId << "\">\n";
+ for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
+ if ( act->actionId >= 0 )
+ writeAction( act );
+ }
+ out << " </action_list>\n";
+}
+
+void XMLCodeGen::writeActionTableList()
+{
+ /* Must first order the action tables based on their id. */
+ int numTables = nextActionTableId;
+ RedActionTable **tables = new RedActionTable*[numTables];
+ for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
+ tables[at->id] = at;
+
+ out << " <action_table_list length=\"" << numTables << "\">\n";
+ for ( int t = 0; t < numTables; t++ ) {
+ out << " <action_table id=\"" << t << "\" length=\"" <<
+ tables[t]->key.length() << "\">";
+ for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
+ out << atel->value->actionId;
+ if ( ! atel.last() )
+ out << " ";
+ }
+ out << "</action_table>\n";
+ }
+ out << " </action_table_list>\n";
+
+ delete[] tables;
+}
+
+void XMLCodeGen::writeKey( Key key )
+{
+ if ( keyOps->isSigned )
+ out << key.getVal();
+ else
+ out << (unsigned long) key.getVal();
+}
+
+void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
+{
+ /* First reduce the action. */
+ RedActionTable *actionTable = 0;
+ if ( trans->actionTable.length() > 0 )
+ actionTable = actionTableMap.find( trans->actionTable );
+
+ /* Write the transition. */
+ out << " <t>";
+ writeKey( lowKey );
+ out << " ";
+ writeKey( highKey );
+
+ if ( trans->toState != 0 )
+ out << " " << trans->toState->alg.stateNum;
+ else
+ out << " x";
+
+ if ( actionTable != 0 )
+ out << " " << actionTable->id;
+ else
+ out << " x";
+ out << "</t>\n";
+}
+
+void XMLCodeGen::writeTransList( StateAp *state )
+{
+ TransListVect outList;
+
+ /* If there is only are no ranges the task is simple. */
+ if ( state->outList.length() > 0 ) {
+ /* Loop each source range. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ /* Reduce the transition. If it reduced to anything then add it. */
+ appendTrans( outList, trans->lowKey, trans->highKey, trans );
+ }
+ }
+
+ out << " <trans_list length=\"" << outList.length() << "\">\n";
+ for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
+ writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
+ out << " </trans_list>\n";
+}
+
+void XMLCodeGen::writeEofTrans( StateAp *state )
+{
+ RedActionTable *eofActions = 0;
+ if ( state->eofActionTable.length() > 0 )
+ eofActions = actionTableMap.find( state->eofActionTable );
+
+ /* The <eof_t> is used when there is an eof target, otherwise the eof
+ * action goes into state actions. */
+ if ( state->eofTarget != 0 ) {
+ out << " <eof_t>" << state->eofTarget->alg.stateNum;
+
+ if ( eofActions != 0 )
+ out << " " << eofActions->id;
+ else
+ out << " x";
+
+ out << "</eof_t>" << endl;
+ }
+}
+
+void XMLCodeGen::writeText( InlineItem *item )
+{
+ if ( item->prev == 0 || item->prev->type != InlineItem::Text )
+ out << "<text>";
+ xmlEscapeHost( out, item->data, strlen(item->data) );
+ if ( item->next == 0 || item->next->type != InlineItem::Text )
+ out << "</text>";
+}
+
+void XMLCodeGen::writeGoto( InlineItem *item )
+{
+ if ( pd->generatingSectionSubset )
+ out << "<goto>-1</goto>";
+ else {
+ EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
+ out << "<goto>" << targ->value->alg.stateNum << "</goto>";
+ }
+}
+
+void XMLCodeGen::writeCall( InlineItem *item )
+{
+ if ( pd->generatingSectionSubset )
+ out << "<call>-1</call>";
+ else {
+ EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
+ out << "<call>" << targ->value->alg.stateNum << "</call>";
+ }
+}
+
+void XMLCodeGen::writeNext( InlineItem *item )
+{
+ if ( pd->generatingSectionSubset )
+ out << "<next>-1</next>";
+ else {
+ EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
+ out << "<next>" << targ->value->alg.stateNum << "</next>";
+ }
+}
+
+void XMLCodeGen::writeGotoExpr( InlineItem *item )
+{
+ out << "<goto_expr>";
+ writeInlineList( item->children );
+ out << "</goto_expr>";
+}
+
+void XMLCodeGen::writeCallExpr( InlineItem *item )
+{
+ out << "<call_expr>";
+ writeInlineList( item->children );
+ out << "</call_expr>";
+}
+
+void XMLCodeGen::writeNextExpr( InlineItem *item )
+{
+ out << "<next_expr>";
+ writeInlineList( item->children );
+ out << "</next_expr>";
+}
+
+void XMLCodeGen::writeEntry( InlineItem *item )
+{
+ if ( pd->generatingSectionSubset )
+ out << "<entry>-1</entry>";
+ else {
+ EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
+ out << "<entry>" << targ->value->alg.stateNum << "</entry>";
+ }
+}
+
+void XMLCodeGen::writeActionExec( InlineItem *item )
+{
+ out << "<exec>";
+ writeInlineList( item->children );
+ out << "</exec>";
+}
+
+void XMLCodeGen::writeLmOnLast( InlineItem *item )
+{
+ out << "<set_tokend>1</set_tokend>";
+
+ if ( item->longestMatchPart->action != 0 ) {
+ out << "<sub_action>";
+ writeInlineList( item->longestMatchPart->action->inlineList );
+ out << "</sub_action>";
+ }
+}
+
+void XMLCodeGen::writeLmOnNext( InlineItem *item )
+{
+ out << "<set_tokend>0</set_tokend>";
+ out << "<hold></hold>";
+
+ if ( item->longestMatchPart->action != 0 ) {
+ out << "<sub_action>";
+ writeInlineList( item->longestMatchPart->action->inlineList );
+ out << "</sub_action>";
+ }
+}
+
+void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
+{
+ out << "<exec><get_tokend></get_tokend></exec>";
+
+ if ( item->longestMatchPart->action != 0 ) {
+ out << "<sub_action>";
+ writeInlineList( item->longestMatchPart->action->inlineList );
+ out << "</sub_action>";
+ }
+}
+
+void XMLCodeGen::writeLmSwitch( InlineItem *item )
+{
+ LongestMatch *longestMatch = item->longestMatch;
+ out << "<lm_switch>\n";
+
+ /* We can't put the <exec> here because we may need to handle the error
+ * case and in that case p should not be changed. Instead use a default
+ * label in the switch to adjust p when user actions are not set. An id of
+ * -1 indicates the default. */
+
+ if ( longestMatch->lmSwitchHandlesError ) {
+ /* If the switch handles error then we should have also forced the
+ * error state. */
+ assert( fsm->errState != 0 );
+
+ out << " <sub_action id=\"0\">";
+ out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
+ out << "</sub_action>\n";
+ }
+
+ bool needDefault = false;
+ for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
+ if ( lmi->inLmSelect ) {
+ if ( lmi->action == 0 )
+ needDefault = true;
+ else {
+ /* Open the action. Write it with the context that sets up _p
+ * when doing control flow changes from inside the machine. */
+ out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
+ out << "<exec><get_tokend></get_tokend></exec>";
+ writeInlineList( lmi->action->inlineList );
+ out << "</sub_action>\n";
+ }
+ }
+ }
+
+ if ( needDefault ) {
+ out << " <sub_action id=\"-1\"><exec><get_tokend>"
+ "</get_tokend></exec></sub_action>\n";
+ }
+
+ out << " </lm_switch>";
+}
+
+void XMLCodeGen::writeInlineList( InlineList *inlineList )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Text:
+ writeText( item );
+ break;
+ case InlineItem::Goto:
+ writeGoto( item );
+ break;
+ case InlineItem::GotoExpr:
+ writeGotoExpr( item );
+ break;
+ case InlineItem::Call:
+ writeCall( item );
+ break;
+ case InlineItem::CallExpr:
+ writeCallExpr( item );
+ break;
+ case InlineItem::Next:
+ writeNext( item );
+ break;
+ case InlineItem::NextExpr:
+ writeNextExpr( item );
+ break;
+ case InlineItem::Break:
+ out << "<break></break>";
+ break;
+ case InlineItem::Ret:
+ out << "<ret></ret>";
+ break;
+ case InlineItem::PChar:
+ out << "<pchar></pchar>";
+ break;
+ case InlineItem::Char:
+ out << "<char></char>";
+ break;
+ case InlineItem::Curs:
+ out << "<curs></curs>";
+ break;
+ case InlineItem::Targs:
+ out << "<targs></targs>";
+ break;
+ case InlineItem::Entry:
+ writeEntry( item );
+ break;
+
+ case InlineItem::Hold:
+ out << "<hold></hold>";
+ break;
+ case InlineItem::Exec:
+ writeActionExec( item );
+ break;
+
+ case InlineItem::LmSetActId:
+ out << "<set_act>" <<
+ item->longestMatchPart->longestMatchId <<
+ "</set_act>";
+ break;
+ case InlineItem::LmSetTokEnd:
+ out << "<set_tokend>1</set_tokend>";
+ break;
+
+ case InlineItem::LmOnLast:
+ writeLmOnLast( item );
+ break;
+ case InlineItem::LmOnNext:
+ writeLmOnNext( item );
+ break;
+ case InlineItem::LmOnLagBehind:
+ writeLmOnLagBehind( item );
+ break;
+ case InlineItem::LmSwitch:
+ writeLmSwitch( item );
+ break;
+
+ case InlineItem::LmInitAct:
+ out << "<init_act></init_act>";
+ break;
+ case InlineItem::LmInitTokStart:
+ out << "<init_tokstart></init_tokstart>";
+ break;
+ case InlineItem::LmSetTokStart:
+ out << "<set_tokstart></set_tokstart>";
+ break;
+ }
+ }
+}
+
+BackendGen::BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, CodeGenData *cgd )
+:
+ GenBase(fsmName, pd, fsm),
+ cgd(cgd)
+{
+}
+
+
+void BackendGen::makeText( GenInlineList *outList, InlineItem *item )
+{
+ GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text );
+ inlineItem->data = item->data;
+
+ outList->append( inlineItem );
+}
+
+void BackendGen::makeTargetItem( GenInlineList *outList, NameInst *nameTarg,
+ GenInlineItem::Type type )
+{
+ long targetState;
+ if ( pd->generatingSectionSubset )
+ targetState = -1;
+ else {
+ EntryMapEl *targ = fsm->entryPoints.find( nameTarg->id );
+ targetState = targ->value->alg.stateNum;
+ }
+
+ /* Make the item. */
+ GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
+ inlineItem->targId = targetState;
+ outList->append( inlineItem );
+}
+
+/* Make a sublist item with a given type. */
+void BackendGen::makeSubList( GenInlineList *outList,
+ InlineList *inlineList, GenInlineItem::Type type )
+{
+ /* Fill the sub list. */
+ GenInlineList *subList = new GenInlineList;
+ makeGenInlineList( subList, inlineList );
+
+ /* Make the item. */
+ GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
+ inlineItem->children = subList;
+ outList->append( inlineItem );
+}
+
+void BackendGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
+{
+ makeSetTokend( outList, 1 );
+
+ if ( item->longestMatchPart->action != 0 ) {
+ makeSubList( outList,
+ item->longestMatchPart->action->inlineList,
+ GenInlineItem::SubAction );
+ }
+}
+
+void BackendGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
+{
+ makeSetTokend( outList, 0 );
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
+
+ if ( item->longestMatchPart->action != 0 ) {
+ makeSubList( outList,
+ item->longestMatchPart->action->inlineList,
+ GenInlineItem::SubAction );
+ }
+}
+
+void BackendGen::makeExecGetTokend( GenInlineList *outList )
+{
+ /* Make the Exec item. */
+ GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
+ execItem->children = new GenInlineList;
+
+ /* Make the GetTokEnd */
+ GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
+ execItem->children->append( getTokend );
+
+ outList->append( execItem );
+}
+
+void BackendGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
+{
+ /* Jump to the tokend. */
+ makeExecGetTokend( outList );
+
+ if ( item->longestMatchPart->action != 0 ) {
+ makeSubList( outList,
+ item->longestMatchPart->action->inlineList,
+ GenInlineItem::SubAction );
+ }
+}
+
+void BackendGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
+{
+ GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
+ GenInlineList *lmList = lmSwitch->children = new GenInlineList;
+ LongestMatch *longestMatch = item->longestMatch;
+
+ /* We can't put the <exec> here because we may need to handle the error
+ * case and in that case p should not be changed. Instead use a default
+ * label in the switch to adjust p when user actions are not set. An id of
+ * -1 indicates the default. */
+
+ if ( longestMatch->lmSwitchHandlesError ) {
+ /* If the switch handles error then we should have also forced the
+ * error state. */
+ assert( fsm->errState != 0 );
+
+ GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
+ errCase->lmId = 0;
+ errCase->children = new GenInlineList;
+
+ /* Make the item. */
+ GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
+ gotoItem->targId = fsm->errState->alg.stateNum;
+ errCase->children->append( gotoItem );
+
+ lmList->append( errCase );
+ }
+
+ bool needDefault = false;
+ for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
+ if ( lmi->inLmSelect ) {
+ if ( lmi->action == 0 )
+ needDefault = true;
+ else {
+ /* Open the action. Write it with the context that sets up _p
+ * when doing control flow changes from inside the machine. */
+ GenInlineItem *lmCase = new GenInlineItem( InputLoc(),
+ GenInlineItem::SubAction );
+ lmCase->lmId = lmi->longestMatchId;
+ lmCase->children = new GenInlineList;
+
+ makeExecGetTokend( lmCase->children );
+ makeGenInlineList( lmCase->children, lmi->action->inlineList );
+
+ lmList->append( lmCase );
+ }
+ }
+ }
+
+ if ( needDefault ) {
+ GenInlineItem *defCase = new GenInlineItem( InputLoc(),
+ GenInlineItem::SubAction );
+ defCase->lmId = -1;
+ defCase->children = new GenInlineList;
+
+ makeExecGetTokend( defCase->children );
+
+ lmList->append( defCase );
+ }
+
+ outList->append( lmSwitch );
+}
+
+void BackendGen::makeSetTokend( GenInlineList *outList, long offset )
+{
+ GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
+ inlineItem->offset = offset;
+ outList->append( inlineItem );
+}
+
+void BackendGen::makeSetAct( GenInlineList *outList, long lmId )
+{
+ GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
+ inlineItem->lmId = lmId;
+ outList->append( inlineItem );
+}
+
+void BackendGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
+{
+ for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Text:
+ makeText( outList, item );
+ break;
+ case InlineItem::Goto:
+ makeTargetItem( outList, item->nameTarg, GenInlineItem::Goto );
+ break;
+ case InlineItem::GotoExpr:
+ makeSubList( outList, item->children, GenInlineItem::GotoExpr );
+ break;
+ case InlineItem::Call:
+ makeTargetItem( outList, item->nameTarg, GenInlineItem::Call );
+ break;
+ case InlineItem::CallExpr:
+ makeSubList( outList, item->children, GenInlineItem::CallExpr );
+ break;
+ case InlineItem::Next:
+ makeTargetItem( outList, item->nameTarg, GenInlineItem::Next );
+ break;
+ case InlineItem::NextExpr:
+ makeSubList( outList, item->children, GenInlineItem::NextExpr );
+ break;
+ case InlineItem::Break:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) );
+ break;
+ case InlineItem::Ret:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) );
+ break;
+ case InlineItem::PChar:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) );
+ break;
+ case InlineItem::Char:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) );
+ break;
+ case InlineItem::Curs:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) );
+ break;
+ case InlineItem::Targs:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) );
+ break;
+ case InlineItem::Entry:
+ makeTargetItem( outList, item->nameTarg, GenInlineItem::Entry );
+ break;
+
+ case InlineItem::Hold:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
+ break;
+ case InlineItem::Exec:
+ makeSubList( outList, item->children, GenInlineItem::Exec );
+ break;
+
+ case InlineItem::LmSetActId:
+ makeSetAct( outList, item->longestMatchPart->longestMatchId );
+ break;
+ case InlineItem::LmSetTokEnd:
+ makeSetTokend( outList, 1 );
+ break;
+
+ case InlineItem::LmOnLast:
+ makeLmOnLast( outList, item );
+ break;
+ case InlineItem::LmOnNext:
+ makeLmOnNext( outList, item );
+ break;
+ case InlineItem::LmOnLagBehind:
+ makeLmOnLagBehind( outList, item );
+ break;
+ case InlineItem::LmSwitch:
+ makeLmSwitch( outList, item );
+ break;
+
+ case InlineItem::LmInitAct:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) );
+ break;
+ case InlineItem::LmInitTokStart:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) );
+ break;
+ case InlineItem::LmSetTokStart:
+ outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) );
+ cgd->hasLongestMatch = true;
+ break;
+ }
+ }
+}
+
+
+void XMLCodeGen::writeAction( Action *action )
+{
+ out << " <action id=\"" << action->actionId << "\"";
+ if ( action->name != 0 )
+ out << " name=\"" << action->name << "\"";
+ out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
+ writeInlineList( action->inlineList );
+ out << "</action>\n";
+}
+
+void xmlEscapeHost( std::ostream &out, char *data, long len )
+{
+ char *end = data + len;
+ while ( data != end ) {
+ switch ( *data ) {
+ case '<': out << "&lt;"; break;
+ case '>': out << "&gt;"; break;
+ case '&': out << "&amp;"; break;
+ default: out << *data; break;
+ }
+ data += 1;
+ }
+}
+
+void XMLCodeGen::writeStateActions( StateAp *state )
+{
+ RedActionTable *toStateActions = 0;
+ if ( state->toStateActionTable.length() > 0 )
+ toStateActions = actionTableMap.find( state->toStateActionTable );
+
+ RedActionTable *fromStateActions = 0;
+ if ( state->fromStateActionTable.length() > 0 )
+ fromStateActions = actionTableMap.find( state->fromStateActionTable );
+
+ /* EOF actions go out here only if the state has no eof target. If it has
+ * an eof target then an eof transition will be used instead. */
+ RedActionTable *eofActions = 0;
+ if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
+ eofActions = actionTableMap.find( state->eofActionTable );
+
+ if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
+ out << " <state_actions>";
+ if ( toStateActions != 0 )
+ out << toStateActions->id;
+ else
+ out << "x";
+
+ if ( fromStateActions != 0 )
+ out << " " << fromStateActions->id;
+ else
+ out << " x";
+
+ if ( eofActions != 0 )
+ out << " " << eofActions->id;
+ else
+ out << " x";
+
+ out << "</state_actions>\n";
+ }
+}
+
+void XMLCodeGen::writeStateConditions( StateAp *state )
+{
+ if ( state->stateCondList.length() > 0 ) {
+ out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
+ for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
+ out << " <c>";
+ writeKey( scdi->lowKey );
+ out << " ";
+ writeKey( scdi->highKey );
+ out << " ";
+ out << scdi->condSpace->condSpaceId;
+ out << "</c>\n";
+ }
+ out << " </cond_list>\n";
+ }
+}
+
+void XMLCodeGen::writeStateList()
+{
+ /* Write the list of states. */
+ out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
+ for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
+ out << " <state id=\"" << st->alg.stateNum << "\"";
+ if ( st->isFinState() )
+ out << " final=\"t\"";
+ out << ">\n";
+
+ writeStateActions( st );
+ writeEofTrans( st );
+ writeStateConditions( st );
+ writeTransList( st );
+
+ out << " </state>\n";
+
+ if ( !st.last() )
+ out << "\n";
+ }
+ out << " </state_list>\n";
+}
+
+bool XMLCodeGen::writeNameInst( NameInst *nameInst )
+{
+ bool written = false;
+ if ( nameInst->parent != 0 )
+ written = writeNameInst( nameInst->parent );
+
+ if ( nameInst->name != 0 ) {
+ if ( written )
+ out << '_';
+ out << nameInst->name;
+ written = true;
+ }
+
+ return written;
+}
+
+void XMLCodeGen::writeEntryPoints()
+{
+ /* List of entry points other than start state. */
+ if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
+ out << " <entry_points";
+ if ( pd->lmRequiresErrorState )
+ out << " error=\"t\"";
+ out << ">\n";
+ for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
+ /* Get the name instantiation from nameIndex. */
+ NameInst *nameInst = pd->nameIndex[en->key];
+ StateAp *state = en->value;
+ out << " <entry name=\"";
+ writeNameInst( nameInst );
+ out << "\">" << state->alg.stateNum << "</entry>\n";
+ }
+ out << " </entry_points>\n";
+ }
+}
+
+void XMLCodeGen::writeMachine()
+{
+ /* Open the machine. */
+ out << " <machine>\n";
+
+ /* Action tables. */
+ reduceActionTables();
+
+ writeActionList();
+ writeActionTableList();
+ writeConditions();
+
+ /* Start state. */
+ out << " <start_state>" << fsm->startState->alg.stateNum <<
+ "</start_state>\n";
+
+ /* Error state. */
+ if ( fsm->errState != 0 ) {
+ out << " <error_state>" << fsm->errState->alg.stateNum <<
+ "</error_state>\n";
+ }
+
+ writeEntryPoints();
+ writeStateList();
+
+ out << " </machine>\n";
+}
+
+
+void XMLCodeGen::writeConditions()
+{
+ if ( condData->condSpaceMap.length() > 0 ) {
+ long nextCondSpaceId = 0;
+ for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
+ cs->condSpaceId = nextCondSpaceId++;
+
+ out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
+ for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
+ out << " <cond_space id=\"" << cs->condSpaceId <<
+ "\" length=\"" << cs->condSet.length() << "\">";
+ writeKey( cs->baseKey );
+ for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
+ out << " " << (*csi)->actionId;
+ out << "</cond_space>\n";
+ }
+ out << " </cond_space_list>\n";
+ }
+}
+
+void XMLCodeGen::writeExports()
+{
+ if ( pd->exportList.length() > 0 ) {
+ out << " <exports>\n";
+ for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
+ out << " <ex name=\"" << exp->name << "\">";
+ writeKey( exp->key );
+ out << "</ex>\n";
+ }
+ out << " </exports>\n";
+ }
+}
+
+void XMLCodeGen::writeXML()
+{
+ /* Open the definition. */
+ out << "<ragel_def name=\"" << fsmName << "\">\n";
+
+ /* Alphabet type. */
+ out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
+
+ /* Getkey expression. */
+ if ( pd->getKeyExpr != 0 ) {
+ out << " <getkey>";
+ writeInlineList( pd->getKeyExpr );
+ out << "</getkey>\n";
+ }
+
+ /* Access expression. */
+ if ( pd->accessExpr != 0 ) {
+ out << " <access>";
+ writeInlineList( pd->accessExpr );
+ out << "</access>\n";
+ }
+
+ /* PrePush expression. */
+ if ( pd->prePushExpr != 0 ) {
+ out << " <prepush>";
+ writeInlineList( pd->prePushExpr );
+ out << "</prepush>\n";
+ }
+
+ /* PostPop expression. */
+ if ( pd->postPopExpr != 0 ) {
+ out << " <postpop>";
+ writeInlineList( pd->postPopExpr );
+ out << "</postpop>\n";
+ }
+
+ /*
+ * Variable expressions.
+ */
+
+ if ( pd->pExpr != 0 ) {
+ out << " <p_expr>";
+ writeInlineList( pd->pExpr );
+ out << "</p_expr>\n";
+ }
+
+ if ( pd->peExpr != 0 ) {
+ out << " <pe_expr>";
+ writeInlineList( pd->peExpr );
+ out << "</pe_expr>\n";
+ }
+
+ if ( pd->eofExpr != 0 ) {
+ out << " <eof_expr>";
+ writeInlineList( pd->eofExpr );
+ out << "</eof_expr>\n";
+ }
+
+ if ( pd->csExpr != 0 ) {
+ out << " <cs_expr>";
+ writeInlineList( pd->csExpr );
+ out << "</cs_expr>\n";
+ }
+
+ if ( pd->topExpr != 0 ) {
+ out << " <top_expr>";
+ writeInlineList( pd->topExpr );
+ out << "</top_expr>\n";
+ }
+
+ if ( pd->stackExpr != 0 ) {
+ out << " <stack_expr>";
+ writeInlineList( pd->stackExpr );
+ out << "</stack_expr>\n";
+ }
+
+ if ( pd->actExpr != 0 ) {
+ out << " <act_expr>";
+ writeInlineList( pd->actExpr );
+ out << "</act_expr>\n";
+ }
+
+ if ( pd->tokstartExpr != 0 ) {
+ out << " <tokstart_expr>";
+ writeInlineList( pd->tokstartExpr );
+ out << "</tokstart_expr>\n";
+ }
+
+ if ( pd->tokendExpr != 0 ) {
+ out << " <tokend_expr>";
+ writeInlineList( pd->tokendExpr );
+ out << "</tokend_expr>\n";
+ }
+
+ if ( pd->dataExpr != 0 ) {
+ out << " <data_expr>";
+ writeInlineList( pd->dataExpr );
+ out << "</data_expr>\n";
+ }
+
+ writeExports();
+
+ writeMachine();
+
+ out <<
+ "</ragel_def>\n";
+}
+
+void BackendGen::makeExports()
+{
+ for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ )
+ cgd->exportList.append( new Export( exp->name, exp->key ) );
+}
+
+void BackendGen::makeAction( Action *action )
+{
+ GenInlineList *genList = new GenInlineList;
+ makeGenInlineList( genList, action->inlineList );
+
+ cgd->newAction( curAction++, action->name, action->loc, genList );
+}
+
+
+void BackendGen::makeActionList()
+{
+ /* Determine which actions to write. */
+ int nextActionId = 0;
+ for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
+ if ( act->numRefs() > 0 || act->numCondRefs > 0 )
+ act->actionId = nextActionId++;
+ }
+
+ /* Write the list. */
+ cgd->initActionList( nextActionId );
+ curAction = 0;
+
+ for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
+ if ( act->actionId >= 0 )
+ makeAction( act );
+ }
+}
+
+void BackendGen::makeActionTableList()
+{
+ /* Must first order the action tables based on their id. */
+ int numTables = nextActionTableId;
+ RedActionTable **tables = new RedActionTable*[numTables];
+ for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
+ tables[at->id] = at;
+
+ cgd->initActionTableList( numTables );
+ curActionTable = 0;
+
+ for ( int t = 0; t < numTables; t++ ) {
+ long length = tables[t]->key.length();
+
+ /* Collect the action table. */
+ RedAction *redAct = cgd->allActionTables + curActionTable;
+ redAct->actListId = curActionTable;
+ redAct->key.setAsNew( length );
+
+ for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
+ redAct->key[atel.pos()].key = 0;
+ redAct->key[atel.pos()].value = cgd->allActions +
+ atel->value->actionId;
+ }
+
+ /* Insert into the action table map. */
+ cgd->redFsm->actionMap.insert( redAct );
+
+ curActionTable += 1;
+ }
+
+ delete[] tables;
+}
+
+void BackendGen::makeConditions()
+{
+ if ( condData->condSpaceMap.length() > 0 ) {
+ long nextCondSpaceId = 0;
+ for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
+ cs->condSpaceId = nextCondSpaceId++;
+
+ long listLength = condData->condSpaceMap.length();
+ cgd->initCondSpaceList( listLength );
+ curCondSpace = 0;
+
+ for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
+ long id = cs->condSpaceId;
+ cgd->newCondSpace( curCondSpace, id, cs->baseKey );
+ for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
+ cgd->condSpaceItem( curCondSpace, (*csi)->actionId );
+ curCondSpace += 1;
+ }
+ }
+}
+
+bool BackendGen::makeNameInst( std::string &res, NameInst *nameInst )
+{
+ bool written = false;
+ if ( nameInst->parent != 0 )
+ written = makeNameInst( res, nameInst->parent );
+
+ if ( nameInst->name != 0 ) {
+ if ( written )
+ res += '_';
+ res += nameInst->name;
+ written = true;
+ }
+
+ return written;
+}
+
+void BackendGen::makeEntryPoints()
+{
+ /* List of entry points other than start state. */
+ if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
+ if ( pd->lmRequiresErrorState )
+ cgd->setForcedErrorState();
+
+ for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
+ /* Get the name instantiation from nameIndex. */
+ NameInst *nameInst = pd->nameIndex[en->key];
+ std::string name;
+ makeNameInst( name, nameInst );
+ StateAp *state = en->value;
+ cgd->addEntryPoint( strdup(name.c_str()), state->alg.stateNum );
+ }
+ }
+}
+
+void BackendGen::makeStateActions( StateAp *state )
+{
+ RedActionTable *toStateActions = 0;
+ if ( state->toStateActionTable.length() > 0 )
+ toStateActions = actionTableMap.find( state->toStateActionTable );
+
+ RedActionTable *fromStateActions = 0;
+ if ( state->fromStateActionTable.length() > 0 )
+ fromStateActions = actionTableMap.find( state->fromStateActionTable );
+
+ /* EOF actions go out here only if the state has no eof target. If it has
+ * an eof target then an eof transition will be used instead. */
+ RedActionTable *eofActions = 0;
+ if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
+ eofActions = actionTableMap.find( state->eofActionTable );
+
+ if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
+ long to = -1;
+ if ( toStateActions != 0 )
+ to = toStateActions->id;
+
+ long from = -1;
+ if ( fromStateActions != 0 )
+ from = fromStateActions->id;
+
+ long eof = -1;
+ if ( eofActions != 0 )
+ eof = eofActions->id;
+
+ cgd->setStateActions( curState, to, from, eof );
+ }
+}
+
+void BackendGen::makeEofTrans( StateAp *state )
+{
+ RedActionTable *eofActions = 0;
+ if ( state->eofActionTable.length() > 0 )
+ eofActions = actionTableMap.find( state->eofActionTable );
+
+ /* The EOF trans is used when there is an eof target, otherwise the eof
+ * action goes into state actions. */
+ if ( state->eofTarget != 0 ) {
+ long targ = state->eofTarget->alg.stateNum;
+ long action = -1;
+ if ( eofActions != 0 )
+ action = eofActions->id;
+
+ cgd->setEofTrans( curState, targ, action );
+ }
+}
+
+void BackendGen::makeStateConditions( StateAp *state )
+{
+ if ( state->stateCondList.length() > 0 ) {
+ long length = state->stateCondList.length();
+ cgd->initStateCondList( curState, length );
+ curStateCond = 0;
+
+ for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
+ cgd->addStateCond( curState, scdi->lowKey, scdi->highKey,
+ scdi->condSpace->condSpaceId );
+ }
+ }
+}
+
+void BackendGen::makeTrans( Key lowKey, Key highKey, TransAp *trans )
+{
+ /* First reduce the action. */
+ RedActionTable *actionTable = 0;
+ if ( trans->actionTable.length() > 0 )
+ actionTable = actionTableMap.find( trans->actionTable );
+
+ long targ = -1;
+ if ( trans->toState != 0 )
+ targ = trans->toState->alg.stateNum;
+
+ long action = -1;
+ if ( actionTable != 0 )
+ action = actionTable->id;
+
+ cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
+}
+
+void BackendGen::makeTransList( StateAp *state )
+{
+ TransListVect outList;
+
+ /* If there is only are no ranges the task is simple. */
+ if ( state->outList.length() > 0 ) {
+ /* Loop each source range. */
+ for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
+ /* Reduce the transition. If it reduced to anything then add it. */
+ appendTrans( outList, trans->lowKey, trans->highKey, trans );
+ }
+ }
+
+ cgd->initTransList( curState, outList.length() );
+ curTrans = 0;
+
+ for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
+ makeTrans( tvi->lowKey, tvi->highKey, tvi->value );
+
+ cgd->finishTransList( curState );
+}
+
+
+void BackendGen::makeStateList()
+{
+ /* Write the list of states. */
+ long length = fsm->stateList.length();
+ cgd->initStateList( length );
+ curState = 0;
+ for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
+ makeStateActions( st );
+ makeEofTrans( st );
+ makeStateConditions( st );
+ makeTransList( st );
+
+ long id = st->alg.stateNum;
+ cgd->setId( curState, id );
+
+ if ( st->isFinState() )
+ cgd->setFinal( curState );
+
+ curState += 1;
+ }
+}
+
+
+void BackendGen::makeMachine()
+{
+ cgd->createMachine();
+
+ /* Action tables. */
+ reduceActionTables();
+
+ makeActionList();
+ makeActionTableList();
+ makeConditions();
+
+ /* Start State. */
+ cgd->setStartState( fsm->startState->alg.stateNum );
+
+ /* Error state. */
+ if ( fsm->errState != 0 )
+ cgd->setErrorState( fsm->errState->alg.stateNum );
+
+ makeEntryPoints();
+ makeStateList();
+
+ cgd->closeMachine();
+}
+
+void BackendGen::close_ragel_def()
+{
+ /* Do this before distributing transitions out to singles and defaults
+ * makes life easier. */
+ cgd->redFsm->maxKey = cgd->findMaxKey();
+
+ cgd->redFsm->assignActionLocs();
+
+ /* Find the first final state (The final state with the lowest id). */
+ cgd->redFsm->findFirstFinState();
+
+ /* Call the user's callback. */
+ cgd->finishRagelDef();
+}
+
+
+void BackendGen::makeBackend()
+{
+ /* Alphabet type. */
+ cgd->setAlphType( keyOps->alphType->internalName );
+
+ /* Getkey expression. */
+ if ( pd->getKeyExpr != 0 ) {
+ cgd->getKeyExpr = new GenInlineList;
+ makeGenInlineList( cgd->getKeyExpr, pd->getKeyExpr );
+ }
+
+ /* Access expression. */
+ if ( pd->accessExpr != 0 ) {
+ cgd->accessExpr = new GenInlineList;
+ makeGenInlineList( cgd->accessExpr, pd->accessExpr );
+ }
+
+ /* PrePush expression. */
+ if ( pd->prePushExpr != 0 ) {
+ cgd->prePushExpr = new GenInlineList;
+ makeGenInlineList( cgd->prePushExpr, pd->prePushExpr );
+ }
+
+ /* PostPop expression. */
+ if ( pd->postPopExpr != 0 ) {
+ cgd->postPopExpr = new GenInlineList;
+ makeGenInlineList( cgd->postPopExpr, pd->postPopExpr );
+ }
+
+ /*
+ * Variable expressions.
+ */
+
+ if ( pd->pExpr != 0 ) {
+ cgd->pExpr = new GenInlineList;
+ makeGenInlineList( cgd->pExpr, pd->pExpr );
+ }
+
+ if ( pd->peExpr != 0 ) {
+ cgd->peExpr = new GenInlineList;
+ makeGenInlineList( cgd->peExpr, pd->peExpr );
+ }
+
+ if ( pd->eofExpr != 0 ) {
+ cgd->eofExpr = new GenInlineList;
+ makeGenInlineList( cgd->eofExpr, pd->eofExpr );
+ }
+
+ if ( pd->csExpr != 0 ) {
+ cgd->csExpr = new GenInlineList;
+ makeGenInlineList( cgd->csExpr, pd->csExpr );
+ }
+
+ if ( pd->topExpr != 0 ) {
+ cgd->topExpr = new GenInlineList;
+ makeGenInlineList( cgd->topExpr, pd->topExpr );
+ }
+
+ if ( pd->stackExpr != 0 ) {
+ cgd->stackExpr = new GenInlineList;
+ makeGenInlineList( cgd->stackExpr, pd->stackExpr );
+ }
+
+ if ( pd->actExpr != 0 ) {
+ cgd->actExpr = new GenInlineList;
+ makeGenInlineList( cgd->actExpr, pd->actExpr );
+ }
+
+ if ( pd->tokstartExpr != 0 ) {
+ cgd->tokstartExpr = new GenInlineList;
+ makeGenInlineList( cgd->tokstartExpr, pd->tokstartExpr );
+ }
+
+ if ( pd->tokendExpr != 0 ) {
+ cgd->tokendExpr = new GenInlineList;
+ makeGenInlineList( cgd->tokendExpr, pd->tokendExpr );
+ }
+
+ if ( pd->dataExpr != 0 ) {
+ cgd->dataExpr = new GenInlineList;
+ makeGenInlineList( cgd->dataExpr, pd->dataExpr );
+ }
+
+ makeExports();
+ makeMachine();
+
+ close_ragel_def();
+}
+
+void InputData::writeLanguage( std::ostream &out )
+{
+ out << " lang=\"";
+ switch ( hostLang->lang ) {
+ case HostLang::C: out << "C"; break;
+ case HostLang::D: out << "D"; break;
+ case HostLang::D2: out << "D2"; break;
+ case HostLang::Go: out << "Go"; break;
+ case HostLang::Java: out << "Java"; break;
+ case HostLang::Ruby: out << "Ruby"; break;
+ case HostLang::CSharp: out << "C#"; break;
+ case HostLang::OCaml: out << "OCaml"; break;
+ }
+ out << "\"";
+}
+
+void InputData::writeXML( std::ostream &out )
+{
+ out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
+ writeLanguage( out );
+ out << ">\n";
+
+ for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
+ ParseData *pd = parser->value->pd;
+ if ( pd->instanceList.length() > 0 )
+ pd->generateXML( *outStream );
+ }
+
+ out << "</ragel>\n";
+}
diff --git a/ragel/xmlcodegen.h b/ragel/xmlcodegen.h
new file mode 100644
index 0000000..d20d6ea
--- /dev/null
+++ b/ragel/xmlcodegen.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2005-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
+ */
+
+#ifndef _XMLCODEGEN_H
+#define _XMLCODEGEN_H
+
+#include <iostream>
+#include "avltree.h"
+#include "fsmgraph.h"
+#include "parsedata.h"
+#include "redfsm.h"
+
+/* Forwards. */
+struct TransAp;
+struct FsmAp;
+struct ParseData;
+struct GenInlineList;
+struct CodeGenData;
+
+struct RedActionTable
+:
+ public AvlTreeEl<RedActionTable>
+{
+ RedActionTable( const ActionTable &key )
+ :
+ key(key),
+ id(0)
+ { }
+
+ const ActionTable &getKey()
+ { return key; }
+
+ ActionTable key;
+ int id;
+};
+
+typedef AvlTree<RedActionTable, ActionTable, CmpActionTable> ActionTableMap;
+
+struct NextRedTrans
+{
+ Key lowKey, highKey;
+ TransAp *trans;
+ TransAp *next;
+
+ void load() {
+ if ( trans != 0 ) {
+ next = trans->next;
+ lowKey = trans->lowKey;
+ highKey = trans->highKey;
+ }
+ }
+
+ NextRedTrans( TransAp *t ) {
+ trans = t;
+ load();
+ }
+
+ void increment() {
+ trans = next;
+ load();
+ }
+};
+
+struct GenBase
+{
+ GenBase( char *fsmName, ParseData *pd, FsmAp *fsm );
+
+ void appendTrans( TransListVect &outList, Key lowKey, Key highKey, TransAp *trans );
+ void reduceActionTables();
+
+ char *fsmName;
+ ParseData *pd;
+ FsmAp *fsm;
+
+ ActionTableMap actionTableMap;
+ int nextActionTableId;
+};
+
+class XMLCodeGen : protected GenBase
+{
+public:
+ XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, std::ostream &out );
+
+ void writeXML( );
+
+private:
+ void writeStateActions( StateAp *state );
+ void writeStateList();
+ void writeStateConditions( StateAp *state );
+
+ void writeKey( Key key );
+ void writeText( InlineItem *item );
+ void writeGoto( InlineItem *item );
+ void writeGotoExpr( InlineItem *item );
+ void writeCall( InlineItem *item );
+ void writeCallExpr( InlineItem *item );
+ void writeNext( InlineItem *item );
+ void writeNextExpr( InlineItem *item );
+ void writeEntry( InlineItem *item );
+ void writeLmOnLast( InlineItem *item );
+ void writeLmOnNext( InlineItem *item );
+ void writeLmOnLagBehind( InlineItem *item );
+
+ void writeExports();
+ bool writeNameInst( NameInst *nameInst );
+ void writeEntryPoints();
+ void writeConditions();
+ void writeInlineList( InlineList *inlineList );
+ void writeActionList();
+ void writeActionTableList();
+ void reduceTrans( TransAp *trans );
+ void writeTransList( StateAp *state );
+ void writeEofTrans( StateAp *state );
+ void writeTrans( Key lowKey, Key highKey, TransAp *defTrans );
+ void writeAction( Action *action );
+ void writeLmSwitch( InlineItem *item );
+ void writeMachine();
+ void writeActionExec( InlineItem *item );
+
+ std::ostream &out;
+};
+
+class BackendGen : protected GenBase
+{
+public:
+ BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, CodeGenData *cgd );
+ void makeBackend( );
+
+private:
+ void makeGenInlineList( GenInlineList *outList, InlineList *inList );
+ void makeKey( GenInlineList *outList, Key key );
+ void makeText( GenInlineList *outList, InlineItem *item );
+ void makeLmOnLast( GenInlineList *outList, InlineItem *item );
+ void makeLmOnNext( GenInlineList *outList, InlineItem *item );
+ void makeLmOnLagBehind( GenInlineList *outList, InlineItem *item );
+ void makeActionExec( GenInlineList *outList, InlineItem *item );
+ void makeLmSwitch( GenInlineList *outList, InlineItem *item );
+ void makeSetTokend( GenInlineList *outList, long offset );
+ void makeSetAct( GenInlineList *outList, long lmId );
+ void makeSubList( GenInlineList *outList, InlineList *inlineList,
+ GenInlineItem::Type type );
+ void makeTargetItem( GenInlineList *outList, NameInst *nameTarg, GenInlineItem::Type type );
+ void makeExecGetTokend( GenInlineList *outList );
+ void makeExports();
+ void makeMachine();
+ void makeActionList();
+ void makeAction( Action *action );
+ void makeActionTableList();
+ void makeConditions();
+ void makeEntryPoints();
+ bool makeNameInst( std::string &out, NameInst *nameInst );
+ void makeStateList();
+
+ void makeStateActions( StateAp *state );
+ void makeEofTrans( StateAp *state );
+ void makeStateConditions( StateAp *state );
+ void makeTransList( StateAp *state );
+ void makeTrans( Key lowKey, Key highKey, TransAp *trans );
+
+ void close_ragel_def();
+
+ CodeGenData *cgd;
+
+ /* Collected during parsing. */
+ int curAction;
+ int curActionTable;
+ int curTrans;
+ int curState;
+ int curCondSpace;
+ int curStateCond;
+
+};
+
+#endif
diff --git a/test-driver b/test-driver
new file mode 100755
index 0000000..d306056
--- /dev/null
+++ b/test-driver
@@ -0,0 +1,139 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error. This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+ echo "$0: $*" >&2
+ print_usage >&2
+ exit 2
+}
+
+print_usage ()
+{
+ cat <<END
+Usage:
+ test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+ [--expect-failure={yes|no}] [--color-tests={yes|no}]
+ [--enable-hard-errors={yes|no}] [--]
+ TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file= # Where to save the output of the test script.
+trs_file= # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+ case $1 in
+ --help) print_usage; exit $?;;
+ --version) echo "test-driver $scriptversion"; exit $?;;
+ --test-name) test_name=$2; shift;;
+ --log-file) log_file=$2; shift;;
+ --trs-file) trs_file=$2; shift;;
+ --color-tests) color_tests=$2; shift;;
+ --expect-failure) expect_failure=$2; shift;;
+ --enable-hard-errors) enable_hard_errors=$2; shift;;
+ --) shift; break;;
+ -*) usage_error "invalid option: '$1'";;
+ *) break;;
+ esac
+ shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file" = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+ usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+ usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+ # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+ red='' # Red.
+ grn='' # Green.
+ lgn='' # Light green.
+ blu='' # Blue.
+ mgn='' # Magenta.
+ std='' # No color.
+else
+ red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+ estatus=1
+fi
+
+case $estatus:$expect_failure in
+ 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+ 0:*) col=$grn res=PASS recheck=no gcopy=no;;
+ 77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
+ 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
+ *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
+ *:*) col=$red res=FAIL recheck=yes gcopy=yes;;
+esac
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..e27bd5b
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,46 @@
+#
+# Copyright 2002-2009 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
+
+
+TESTS = runtests
+
+EXTRA_DIST = \
+ atoi1.rl clang2.rl cond7.rl element3.rl erract8.rl forder3.rl java1.rl \
+ range.rl scan3.rl xml.rl atoi2.rl clang3.rl cppscan1.rl eofact.rl \
+ erract9.rl gotocallret1.rl java2.rl recdescent1.rl scan4.rl atoi3.rl \
+ clang4.rl cppscan2.rl erract1.rl export1.rl gotocallret2.rl keller1.rl \
+ recdescent2.rl stateact1.rl awkemu.rl cond1.rl cppscan3.rl erract2.rl \
+ export2.rl high1.rl lmgoto.rl recdescent3.rl statechart1.rl builtin.rl \
+ cond2.rl cppscan4.rl erract3.rl export3.rl high2.rl mailbox1.rl \
+ repetition.rl strings1.rl call1.rl cond3.rl cppscan5.rl erract4.rl \
+ export4.rl high3.rl mailbox2.rl rlscan.rl strings2.rl call2.rl cond4.rl \
+ cppscan6.rl erract5.rl fnext1.rl import1.rl mailbox3.rl ruby1.rl \
+ tokstart1.rl call3.rl cond5.rl element1.rl erract6.rl forder1.rl \
+ include1.rl minimize1.rl scan1.rl union.rl clang1.rl cond6.rl \
+ element2.rl erract7.rl forder2.rl include2.rl patact.rl scan2.rl \
+ xmlcommon.rl langtrans_c.sh langtrans_csharp.sh langtrans_d.sh \
+ langtrans_java.sh langtrans_ruby.sh checkeofact.txl \
+ langtrans_csharp.txl langtrans_c.txl langtrans_d.txl langtrans_java.txl \
+ langtrans_ruby.txl testcase.txl cppscan1.h eofact.h mailbox1.h strings2.h
+
+CLEANFILES = \
+ *.c *.cpp *.m *.d *.java *.bin *.class *.exp \
+ *.out *_c.rl *_d.rl *_java.rl *_ruby.rl *_csharp.rl *.cs \
+ *_go.rl *.go *.exe
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644
index 0000000..77c3a38
--- /dev/null
+++ b/test/Makefile.in
@@ -0,0 +1,818 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright 2002-2009 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
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = test
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/runtests.in $(top_srcdir)/test-driver README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/ragel/config.h
+CONFIG_CLEAN_FILES = runtests
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FIG2DEV = @FIG2DEV@
+GDC = @GDC@
+GMCS = @GMCS@
+GOBIN = @GOBIN@
+GOBJC = @GOBJC@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVAC = @JAVAC@
+KELBT = @KELBT@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PUBDATE = @PUBDATE@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TXL = @TXL@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+TESTS = runtests
+EXTRA_DIST = \
+ atoi1.rl clang2.rl cond7.rl element3.rl erract8.rl forder3.rl java1.rl \
+ range.rl scan3.rl xml.rl atoi2.rl clang3.rl cppscan1.rl eofact.rl \
+ erract9.rl gotocallret1.rl java2.rl recdescent1.rl scan4.rl atoi3.rl \
+ clang4.rl cppscan2.rl erract1.rl export1.rl gotocallret2.rl keller1.rl \
+ recdescent2.rl stateact1.rl awkemu.rl cond1.rl cppscan3.rl erract2.rl \
+ export2.rl high1.rl lmgoto.rl recdescent3.rl statechart1.rl builtin.rl \
+ cond2.rl cppscan4.rl erract3.rl export3.rl high2.rl mailbox1.rl \
+ repetition.rl strings1.rl call1.rl cond3.rl cppscan5.rl erract4.rl \
+ export4.rl high3.rl mailbox2.rl rlscan.rl strings2.rl call2.rl cond4.rl \
+ cppscan6.rl erract5.rl fnext1.rl import1.rl mailbox3.rl ruby1.rl \
+ tokstart1.rl call3.rl cond5.rl element1.rl erract6.rl forder1.rl \
+ include1.rl minimize1.rl scan1.rl union.rl clang1.rl cond6.rl \
+ element2.rl erract7.rl forder2.rl include2.rl patact.rl scan2.rl \
+ xmlcommon.rl langtrans_c.sh langtrans_csharp.sh langtrans_d.sh \
+ langtrans_java.sh langtrans_ruby.sh checkeofact.txl \
+ langtrans_csharp.txl langtrans_c.txl langtrans_d.txl langtrans_java.txl \
+ langtrans_ruby.txl testcase.txl cppscan1.h eofact.h mailbox1.h strings2.h
+
+CLEANFILES = \
+ *.c *.cpp *.m *.d *.java *.bin *.class *.exp \
+ *.out *_c.rl *_d.rl *_java.rl *_ruby.rl *_csharp.rl *.cs \
+ *_go.rl *.go *.exe
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .log .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+runtests: $(top_builddir)/config.status $(srcdir)/runtests.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+runtests.log: runtests
+ @p='runtests'; \
+ b='runtests'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+ cscopelist-am ctags-am distclean distclean-generic distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am recheck tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..beb0c03
--- /dev/null
+++ b/test/README
@@ -0,0 +1,13 @@
+
+The test suite now depends on TXL. Since the trend in Ragel is towards
+independence of the host-language, tests are now being written in a fictional
+mini-language designed for the purpose of testing ragel. The host language
+test-cases are then generated using a TXL transformation. This allows one test
+case to be run against all host languages in addition to all code generation
+styles.
+
+TXL is not open source, but a free download is available from the homepage.
+
+http://www.txl.ca/
+
+-Adrian
diff --git a/test/atoi1.rl b/test/atoi1.rl
new file mode 100644
index 0000000..013348e
--- /dev/null
+++ b/test/atoi1.rl
@@ -0,0 +1,69 @@
+/*
+ * @LANG: indep
+ */
+bool neg;
+int val;
+%%
+val = 0;
+neg = false;
+%%{
+ machine AtoI;
+
+ action begin {
+ neg = false;
+ val = 0;
+ }
+
+ action see_neg {
+ neg = true;
+ }
+
+ action add_digit {
+ val = val * 10 + <int>(fc - 48);
+ }
+
+ action finish {
+ if ( neg ) {
+ val = -1 * val;
+ }
+ }
+ action print {
+ printi val;
+ prints "\n";
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ main := atoi '\n' @print;
+}%%
+/* _____INPUT_____
+"1\n"
+"12\n"
+"222222\n"
+"+2123\n"
+"213 3213\n"
+"-12321\n"
+"--123\n"
+"-99\n"
+" -3000\n"
+_____INPUT_____ */
+
+/* _____OUTPUT_____
+1
+ACCEPT
+12
+ACCEPT
+222222
+ACCEPT
+2123
+ACCEPT
+FAIL
+-12321
+ACCEPT
+FAIL
+-99
+ACCEPT
+FAIL
+_____OUTPUT_____ */
diff --git a/test/atoi2.rl b/test/atoi2.rl
new file mode 100644
index 0000000..9f17c69
--- /dev/null
+++ b/test/atoi2.rl
@@ -0,0 +1,81 @@
+/*
+ * @LANG: indep
+ * This implementes an atoi machine using the statechart paradigm.
+ */
+bool neg;
+int val;
+%%
+val = 0;
+neg = false;
+%%{
+ machine StateChart;
+
+ action begin {
+ neg = false;
+ val = 0;
+ }
+
+ action see_neg {
+ neg = true;
+ }
+
+ action add_digit {
+ val = val * 10 + <int>(fc - 48);
+ }
+
+ action finish {
+ if ( neg )
+ val = -1 * val;
+ }
+
+ atoi = (
+ start: (
+ '-' @see_neg ->om_num |
+ '+' ->om_num |
+ [0-9] @add_digit ->more_nums
+ ),
+
+ # One or more nums.
+ om_num: (
+ [0-9] @add_digit ->more_nums
+ ),
+
+ # Zero ore more nums.
+ more_nums: (
+ [0-9] @add_digit ->more_nums |
+ '' -> final
+ )
+ ) >begin %finish;
+
+ action oneof { printi val; prints "\n"; }
+ main := ( atoi '\n' @oneof )*;
+}%%
+/* _____INPUT_____
+"1\n"
+"12\n"
+"222222\n"
+"+2123\n"
+"213 3213\n"
+"-12321\n"
+"--123\n"
+"-99\n"
+" -3000\n"
+_____INPUT_____ */
+
+/* _____OUTPUT_____
+1
+ACCEPT
+12
+ACCEPT
+222222
+ACCEPT
+2123
+ACCEPT
+FAIL
+-12321
+ACCEPT
+FAIL
+-99
+ACCEPT
+FAIL
+_____OUTPUT_____ */
diff --git a/test/atoi3.rl b/test/atoi3.rl
new file mode 100644
index 0000000..fcd4a41
--- /dev/null
+++ b/test/atoi3.rl
@@ -0,0 +1,75 @@
+#
+# @LANG: ruby
+#
+
+%%{
+ machine atoi3;
+ action begin {
+ neg = false;
+ val = 0;
+ }
+ action see_neg {
+ neg = true;
+ }
+ action add_digit {
+ val = val * 10 + (fc - "0"[0]);
+ }
+ action finish {
+ val = -1 * val if neg
+ }
+ action print {
+ puts val;
+ }
+ atoi = (('-' @ see_neg | '+') ? (digit @ add_digit) +) > begin % finish;
+ main := atoi '\n' @ print;
+}%%
+
+%% write data;
+
+def run_machine( data )
+ p = 0;
+ pe = data.length
+ cs = 0
+ val = 0;
+ neg = false;
+
+ %% write init;
+ %% write exec;
+ if cs >= atoi3_first_final
+ puts "ACCEPT"
+ else
+ puts "FAIL"
+ end
+end
+
+inp = [
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+]
+
+inp.each { |str| run_machine(str) }
+
+=begin _____OUTPUT_____
+1
+ACCEPT
+12
+ACCEPT
+222222
+ACCEPT
+2123
+ACCEPT
+FAIL
+-12321
+ACCEPT
+FAIL
+-99
+ACCEPT
+FAIL
+=end _____OUTPUT_____
diff --git a/test/awkemu.rl b/test/awkemu.rl
new file mode 100644
index 0000000..343f3e6
--- /dev/null
+++ b/test/awkemu.rl
@@ -0,0 +1,155 @@
+/*
+ * @LANG: c
+ */
+
+/*
+ * Emulate the basic parser of the awk program. Breaks lines up into
+ * words and prints the words.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define LINEBUF 2048
+static char lineBuf[LINEBUF];
+static char blineBuf[LINEBUF];
+static int lineLen;
+static int blineLen;
+static int words;
+
+void finishLine();
+
+struct awkemu
+{
+ int cs;
+};
+
+%%{
+ machine awkemu;
+
+ variable cs fsm->cs;
+
+ # Starts a line. Will initialize all the data necessary for capturing the line.
+ action startline {
+ lineLen = 0;
+ blineLen = 0;
+ words = 0;
+ }
+
+ # Will be executed on every character seen in a word. Captures the word
+ # to the broken up line buffer.
+ action wordchar {
+ blineBuf[blineLen++] = fc;
+ }
+
+ # Terminate a word. Adds the null after the word and increments the word count
+ # for the line.
+ action termword {
+ blineBuf[blineLen++] = 0;
+ words += 1;
+ }
+
+ # Will be executed on every character seen in a line (not including
+ # the newline itself.
+ action linechar {
+ lineBuf[lineLen++] = fc;
+ }
+
+ # This section of the machine deals with breaking up lines into fields.
+ # Lines are separed by the whitespace and put in an array of words.
+
+ # Words in a line.
+ word = (extend - [ \t\n])+;
+
+ # The whitespace separating words in a line.
+ whitespace = [ \t];
+
+ # The components in a line to break up. Either a word or a single char of
+ # whitespace. On the word capture characters.
+ blineElements = word $wordchar %termword | whitespace;
+
+ # Star the break line elements. Just be careful to decrement the leaving
+ # priority as we don't want multiple character identifiers to be treated as
+ # multiple single char identifiers.
+ breakLine = ( blineElements $1 %0 )* . '\n';
+
+ # This machine lets us capture entire lines. We do it separate from the words
+ # in a line.
+ bufLine = (extend - '\n')* $linechar %{ finishLine(); } . '\n';
+
+ # A line can then consist of the machine that will break up the line into
+ # words and a machine that will buffer the entire line.
+ line = ( breakLine | bufLine ) > startline;
+
+ # Any number of lines.
+ main := line*;
+}%%
+
+void finishLine()
+{
+ int i;
+ char *pword = blineBuf;
+ lineBuf[lineLen] = 0;
+ printf("endline(%i): %s\n", words, lineBuf );
+ for ( i = 0; i < words; i++ ) {
+ printf(" word: %s\n", pword );
+ pword += strlen(pword) + 1;
+ }
+}
+
+%% write data;
+
+void awkemu_init( struct awkemu *fsm )
+{
+ %% write init;
+}
+
+void awkemu_execute( struct awkemu *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+ %% write exec;
+}
+
+int awkemu_finish( struct awkemu *fsm )
+{
+ if ( fsm->cs == awkemu_error )
+ return -1;
+ if ( fsm->cs >= awkemu_first_final )
+ return 1;
+ return 0;
+}
+
+#include <stdio.h>
+#define BUFSIZE 2048
+
+struct awkemu fsm;
+char buf[BUFSIZE];
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ awkemu_init( &fsm );
+ awkemu_execute( &fsm, buf, len );
+ if ( awkemu_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test( "" );
+ test( "one line with no newline" );
+ test( "one line\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+FAIL
+endline(2): one line
+ word: one
+ word: line
+ACCEPT
+#endif
diff --git a/test/builtin.rl b/test/builtin.rl
new file mode 100644
index 0000000..816b441
--- /dev/null
+++ b/test/builtin.rl
@@ -0,0 +1,1209 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+
+void alph(const char *type)
+{
+ printf("%s\n", type);
+}
+
+struct builtin
+{
+ int cs;
+};
+
+%%{
+ machine builtin;
+ alphtype unsigned int;
+ variable cs fsm->cs;
+
+ main := (
+ any @{alph("any");} |
+ ascii @{alph("ascii");} |
+ extend @{alph("extend");} |
+ alpha @{alph("alpha");} |
+ digit @{alph("digit");} |
+ alnum @{alph("alnum");} |
+ lower @{alph("lower");} |
+ upper @{alph("upper");} |
+ cntrl @{alph("cntrl");} |
+ graph @{alph("graph");} |
+ print @{alph("print");} |
+ punct @{alph("punct");} |
+ space @{alph("space");} |
+ xdigit @{alph("xdigit");}
+ )*;
+}%%
+
+%% write data;
+
+void builtin_init( struct builtin *fsm )
+{
+ %% write init;
+}
+
+void builtin_execute( struct builtin *fsm, const unsigned int *data, int len )
+{
+ const unsigned int *p = data;
+ const unsigned int *pe = data+len;
+ %% write exec;
+}
+
+int builtin_finish( struct builtin *fsm )
+{
+ if ( fsm->cs == builtin_error )
+ return -1;
+ else if ( fsm->cs >= builtin_first_final )
+ return 1;
+ return 0;
+}
+
+#include <stdio.h>
+#define BUFSIZE 2048
+
+struct builtin fsm;
+char buf[BUFSIZE];
+unsigned int i;
+
+int test( const unsigned int *data, int len )
+{
+ builtin_init( &fsm );
+ builtin_execute( &fsm, data, len );
+ if ( builtin_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+ return 0;
+}
+
+#define DLEN 258
+unsigned int data[DLEN] = {
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
+ 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216,
+ 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256
+};
+
+int main()
+{
+ test( data, DLEN );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+any
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+space
+any
+ascii
+extend
+cntrl
+space
+any
+ascii
+extend
+cntrl
+space
+any
+ascii
+extend
+cntrl
+space
+any
+ascii
+extend
+cntrl
+space
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+cntrl
+any
+ascii
+extend
+print
+space
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+digit
+alnum
+graph
+print
+xdigit
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+upper
+graph
+print
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+xdigit
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+alpha
+alnum
+lower
+graph
+print
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+graph
+print
+punct
+any
+ascii
+extend
+cntrl
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+extend
+any
+ACCEPT
+#endif
diff --git a/test/call1.rl b/test/call1.rl
new file mode 100644
index 0000000..ddd552a
--- /dev/null
+++ b/test/call1.rl
@@ -0,0 +1,101 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int num = 0;
+
+struct test
+{
+ int cs, top, stack[32];
+};
+
+%%{
+ machine test;
+ access fsm->;
+
+ action check_num {
+ if ( num & 1 )
+ fcall *fentry(odd);
+ else
+ fcall even;
+ }
+
+ # Test call and return functionality.
+ even := 'even' any @{fhold; fret;};
+ odd := 'odd' any @{fhold; fret;};
+ num = [0-9]+ ${ num = num * 10 + (fc - '0'); };
+ even_odd = num ' ' @check_num "\n";
+
+ # Test calls in out actions.
+ fail := !(any*);
+ out_acts = 'OA ok\n' |
+ 'OA error1\n' |
+ 'OA error2\n';
+
+ main := even_odd | out_acts;
+}%%
+
+%% write data;
+
+void test_init( struct test *fsm )
+{
+ num = 0;
+ %% write init;
+}
+
+void test_execute( struct test *fsm, const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data+len;
+
+ %% write exec;
+}
+
+int test_finish( struct test *fsm )
+{
+ if ( fsm->cs == test_error )
+ return -1;
+ if ( fsm->cs >= test_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 1024
+
+void test( char *buf )
+{
+ struct test test;
+ test_init( &test );
+ test_execute( &test, buf, strlen(buf) );
+ if ( test_finish( &test ) > 0 )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+}
+
+int main()
+{
+ test( "78 even\n" );
+ test( "89 odd\n" );
+ test( "1 even\n" );
+ test( "0 odd\n" );
+ test( "OA ok\n" );
+ test( "OA error1\n" );
+ test( "OA error2\n" );
+
+ return 0;
+}
+
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+ACCEPT
+ACCEPT
+ACCEPT
+#endif
diff --git a/test/call2.rl b/test/call2.rl
new file mode 100644
index 0000000..a553855
--- /dev/null
+++ b/test/call2.rl
@@ -0,0 +1,116 @@
+/*
+ * @LANG: c++
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int num = 0;
+
+struct CallTest
+{
+ int cs, top, stack[32];
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ void execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine CallTest;
+
+ action check_num {
+ if ( num & 1 )
+ fcall *fentry(odd);
+ else
+ fcall even;
+ }
+
+ # Test call and return functionality.
+ even := 'even' any @{fhold; fret;};
+ odd := 'odd' any @{fhold; fret;};
+ num = [0-9]+ ${ num = num * 10 + (fc - '0'); };
+ even_odd = num ' ' @check_num "\n";
+
+ # Test calls in out actions.
+ fail := !(any*);
+ out_acts = 'OA ok\n' |
+ 'OA error1\n' |
+ 'OA error2\n';
+
+ main := even_odd | out_acts;
+}%%
+
+%% write data;
+
+void CallTest::init( )
+{
+ num = 0;
+ %% write init;
+}
+
+void CallTest::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data+len;
+
+ %% write exec;
+}
+
+int CallTest::finish( )
+{
+ if ( this->cs == CallTest_error )
+ return -1;
+ if ( this->cs >= CallTest_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 1024
+
+void test( const char *buf )
+{
+ CallTest test;
+
+ test.init();
+ test.execute( buf, strlen(buf) );
+ if ( test.finish() > 0 )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+}
+
+int main()
+{
+ test( "78 even\n" );
+ test( "89 odd\n" );
+ test( "1 even\n" );
+ test( "0 odd\n" );
+ test( "OA ok\n" );
+ test( "OA error1\n" );
+ test( "OA error2\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+ACCEPT
+ACCEPT
+ACCEPT
+#endif
diff --git a/test/call3.rl b/test/call3.rl
new file mode 100644
index 0000000..b19b96c
--- /dev/null
+++ b/test/call3.rl
@@ -0,0 +1,122 @@
+/*
+ * @LANG: obj-c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <objc/Object.h>
+
+
+int num = 0;
+
+@interface CallTest : Object
+{
+@public
+ /* State machine operation data. */
+ int cs, top, stack[32];
+};
+
+// Initialize the machine. Invokes any init statement blocks. Returns 0
+// if the machine begins in a non-accepting state and 1 if the machine
+// begins in an accepting state.
+- (void) initFsm;
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (void) executeWithData:(const char *)data len:(int)len;
+
+// Indicate that there is no more data. Returns -1 if the machine finishes
+// in the error state and does not accept, 0 if the machine finishes
+// in any other non-accepting state and 1 if the machine finishes in an
+// accepting state.
+- (int) finish;
+
+@end
+
+@implementation CallTest
+
+%%{
+ machine CallTest;
+
+ action check_num {
+ if ( num & 1 )
+ fcall odd;
+ else
+ fcall even;
+ }
+
+ # Test call and return functionality.
+ even := 'even' any @{fhold; fret;};
+ odd := 'odd' any @{fhold; fret;};
+ num = [0-9]+ ${ num = num * 10 + (fc - '0'); };
+ even_odd = num ' ' @check_num "\n";
+
+ # Test calls in out actions.
+ fail := !(any*);
+ out_acts = 'OA ok\n' |
+ 'OA error1\n' |
+ 'OA error2\n';
+
+ main := even_odd | out_acts;
+}%%
+
+%% write data;
+
+- (void) initFsm;
+{
+ num = 0;
+ %% write init;
+}
+
+- (void) executeWithData:(const char *)data len:(int)len;
+{
+ const char *p = data;
+ const char *pe = data + len;
+ %% write exec;
+}
+
+- (int) finish;
+{
+ if ( cs == CallTest_error )
+ return -1;
+ return ( cs >= CallTest_first_final ) ? 1 : 0;
+}
+
+@end
+
+#define BUFSIZE 1024
+
+void test( char *buf )
+{
+ CallTest *test = [[CallTest alloc] init];
+ [test initFsm];
+ [test executeWithData:buf len:strlen(buf)];
+ if ( [test finish] > 0 )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+}
+
+int main()
+{
+ test( "78 even\n" );
+ test( "89 odd\n" );
+ test( "1 even\n" );
+ test( "0 odd\n" );
+ test( "OA ok\n" );
+ test( "OA error1\n" );
+ test( "OA error2\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+ACCEPT
+ACCEPT
+ACCEPT
+#endif
diff --git a/test/checkeofact.txl b/test/checkeofact.txl
new file mode 100644
index 0000000..8189013
--- /dev/null
+++ b/test/checkeofact.txl
@@ -0,0 +1,95 @@
+include "testcase.txl"
+
+define program
+ [lang_indep]
+ | 'yes
+ | 'no
+end define
+
+rule findEof1
+ match [machine_expr_item]
+ '>/
+end rule
+
+rule findEof2
+ match [machine_expr_item]
+ '</
+end rule
+
+rule findEof3
+ match [machine_expr_item]
+ '$/
+end rule
+
+rule findEof4
+ match [machine_expr_item]
+ '%/
+end rule
+
+rule findEof5
+ match [machine_expr_item]
+ '@/
+end rule
+
+rule findEof6
+ match [machine_expr_item]
+ '<>/
+end rule
+
+rule findEof7
+ match [repeat machine_expr_item]
+ '> 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findEof8
+ match [repeat machine_expr_item]
+ '< 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findEof9
+ match [repeat machine_expr_item]
+ '$ 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findEof10
+ match [repeat machine_expr_item]
+ '% 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findEof11
+ match [repeat machine_expr_item]
+ '@ 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findEof12
+ match [repeat machine_expr_item]
+ '<> 'eof _ [repeat machine_expr_item]
+end rule
+
+rule findScanner
+ match [machine_expr_item]
+ '|* _ [repeat scanner_item] '*|
+end rule
+
+function findEof P [program]
+ replace [program]
+ _ [program]
+ where
+ P
+ [findEof1] [findEof2] [findEof3]
+ [findEof4] [findEof5] [findEof6]
+ [findEof7] [findEof8] [findEof9]
+ [findEof10] [findEof11] [findEof12]
+ [findScanner]
+ by
+ 'yes
+end function
+
+function main
+ replace [program]
+ P [program]
+ construct NewP [program]
+ 'no
+ by
+ NewP [findEof P]
+end function
diff --git a/test/clang1.rl b/test/clang1.rl
new file mode 100644
index 0000000..85532c6
--- /dev/null
+++ b/test/clang1.rl
@@ -0,0 +1,283 @@
+/*
+ * @LANG: c
+ * A mini C-like language scanner.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#define IDENT_BUFLEN 256
+
+%%{
+ machine clang;
+
+ # Function to buffer a character.
+ action bufChar {
+ if ( identLen < IDENT_BUFLEN ) {
+ identBuf[identLen] = fc;
+ identLen += 1;
+ }
+ }
+
+ # Function to clear the buffer.
+ action clearBuf {
+ identLen = 0;
+ }
+
+ # Functions to dump tokens as they are matched.
+ action ident {
+ identBuf[identLen] = 0;
+ printf("ident(%i): %s\n", curLine, identBuf);
+ }
+ action literal {
+ identBuf[identLen] = 0;
+ printf("literal(%i): %s\n", curLine, identBuf);
+ }
+ action float {
+ identBuf[identLen] = 0;
+ printf("float(%i): %s\n", curLine, identBuf);
+ }
+ action int {
+ identBuf[identLen] = 0;
+ printf("int(%i): %s\n", curLine, identBuf);
+ }
+ action hex {
+ identBuf[identLen] = 0;
+ printf("hex(%i): 0x%s\n", curLine, identBuf);
+ }
+ action symbol {
+ identBuf[identLen] = 0;
+ printf("symbol(%i): %s\n", curLine, identBuf);
+ }
+
+ # Alpha numberic characters or underscore.
+ alnumu = alnum | '_';
+
+ # Alpha charactres or underscore.
+ alphau = alpha | '_';
+
+ # Symbols. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving dump the symbol.
+ symbol = ( punct - [_'"] ) >clearBuf $bufChar %symbol;
+
+ # Identifier. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving, dump the identifier.
+ ident = (alphau . alnumu*) >clearBuf $bufChar %ident;
+
+ # Match single characters inside literal strings. Or match
+ # an escape sequence. Buffers the charater matched.
+ sliteralChar =
+ ( extend - ['\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+ dliteralChar =
+ ( extend - ["\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+
+ # Single quote and double quota literals. At the start clear
+ # the buffer. Upon leaving dump the literal.
+ sliteral = ('\'' @clearBuf . sliteralChar* . '\'' ) %literal;
+ dliteral = ('"' @clearBuf . dliteralChar* . '"' ) %literal;
+ literal = sliteral | dliteral;
+
+ # Whitespace is standard ws, newlines and control codes.
+ whitespace = any - 0x21..0x7e;
+
+ # Describe both c style comments and c++ style comments. The
+ # priority bump on tne terminator of the comments brings us
+ # out of the extend* which matches everything.
+ ccComment = '//' . extend* $0 . '\n' @1;
+ cComment = '/*' . extend* $0 . '*/' @1;
+
+ # Match an integer. We don't bother clearing the buf or filling it.
+ # The float machine overlaps with int and it will do it.
+ int = digit+ %int;
+
+ # Match a float. Upon entering the machine clear the buf, buffer
+ # characters on every trans and dump the float upon leaving.
+ float = ( digit+ . '.' . digit+ ) >clearBuf $bufChar %float;
+
+ # Match a hex. Upon entering the hex part, clear the buf, buffer characters
+ # on every trans and dump the hex on leaving transitions.
+ hex = '0x' . xdigit+ >clearBuf $bufChar %hex;
+
+ # Or together all the lanuage elements.
+ fin = ( ccComment |
+ cComment |
+ symbol |
+ ident |
+ literal |
+ whitespace |
+ int |
+ float |
+ hex );
+
+ # Star the language elements. It is critical in this type of application
+ # that we decrease the priority of out transitions before doing so. This
+ # is so that when we see 'aa' we stay in the fin machine to match an ident
+ # of length two and not wrap around to the front to match two idents of
+ # length one.
+ clang_main = ( fin $1 %0 )*;
+
+ # This machine matches everything, taking note of newlines.
+ newline = ( any | '\n' @{ curLine += 1; } )*;
+
+ # The final fsm is the lexer intersected with the newline machine which
+ # will count lines for us. Since the newline machine accepts everything,
+ # the strings accepted is goverened by the clang_main machine, onto which
+ # the newline machine overlays line counting.
+ main := clang_main & newline;
+}%%
+
+#include <stdio.h>
+
+%% write data noerror;
+
+
+char data[] =
+ "/*\n"
+ " * Copyright\n"
+ " */\n"
+ "\n"
+ "/* Aapl.\n"
+ " */\n"
+ " \n"
+ "#define _AAPL_RESIZE_H\n"
+ "\n"
+ "#include <assert.h>\n"
+ "\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "namespace Aapl {\n"
+ "#endif\n"
+ "#define LIN_DEFAULT_STEP 256\n"
+ "#define EXPN_UP( existing, needed ) \\\n"
+ " need > eng ? (ned<<1) : eing\n"
+ " \n"
+ "\n"
+ "/*@}*/\n"
+ "#undef EXPN_UP\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "#endif /* _AAPL_RESIZE_H */\n";
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ char *p = buf, *pe = buf + len;
+ char *eof = pe;
+ char identBuf[IDENT_BUFLEN+1];
+ int identLen;
+ int curLine;
+ int cs;
+
+ identLen = 0;
+ curLine = 1;
+
+ %% write init;
+ %% write exec;
+
+ if ( cs >= clang_first_final )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test(
+ "999 0xaAFF99 99.99 /*\n"
+ "*/ 'lksdj' //\n"
+ "\"\n"
+ "\n"
+ "literal\n"
+ "\n"
+ "\n"
+ "\"0x00aba foobardd.ddsf 0x0.9\n" );
+ test(
+ "wordwithnum00asdf\n"
+ "000wordfollowsnum,makes new symbol\n"
+ "\n"
+ "finishing early /* unfinished ...\n" );
+ test( data );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+int(1): 999
+hex(1): 0xaAFF99
+float(1): 99.99
+literal(2): lksdj
+literal(8):
+
+literal
+
+
+
+hex(8): 0x00aba
+ident(8): foobardd
+symbol(8): .
+ident(8): ddsf
+hex(8): 0x0
+symbol(8): .
+int(8): 9
+ACCEPT
+ident(1): wordwithnum00asdf
+int(2): 000
+ident(2): wordfollowsnum
+symbol(2): ,
+ident(2): makes
+ident(2): new
+ident(2): symbol
+ident(4): finishing
+ident(4): early
+FAIL
+symbol(8): #
+ident(8): define
+ident(8): _AAPL_RESIZE_H
+symbol(10): #
+ident(10): include
+symbol(10): <
+ident(10): assert
+symbol(10): .
+ident(10): h
+symbol(10): >
+symbol(12): #
+ident(12): ifdef
+ident(12): AAPL_NAMESPACE
+ident(13): namespace
+ident(13): Aapl
+symbol(13): {
+symbol(14): #
+ident(14): endif
+symbol(15): #
+ident(15): define
+ident(15): LIN_DEFAULT_STEP
+int(15): 256
+symbol(16): #
+ident(16): define
+ident(16): EXPN_UP
+symbol(16): (
+ident(16): existing
+symbol(16): ,
+ident(16): needed
+symbol(16): )
+symbol(16): \
+ident(17): need
+symbol(17): >
+ident(17): eng
+symbol(17): ?
+symbol(17): (
+ident(17): ned
+symbol(17): <
+symbol(17): <
+int(17): 1
+symbol(17): )
+symbol(17): :
+ident(17): eing
+symbol(21): #
+ident(21): undef
+ident(21): EXPN_UP
+symbol(22): #
+ident(22): ifdef
+ident(22): AAPL_NAMESPACE
+symbol(23): #
+ident(23): endif
+ACCEPT
+#endif
diff --git a/test/clang2.rl b/test/clang2.rl
new file mode 100644
index 0000000..3b22e4b
--- /dev/null
+++ b/test/clang2.rl
@@ -0,0 +1,324 @@
+/*
+ * @LANG: obj-c
+ * A mini C-like language scanner.
+ */
+
+#include <stdio.h>
+#include <objc/Object.h>
+#include <string.h>
+
+#define IDENT_BUFLEN 256
+
+@interface Clang : Object
+{
+@public
+ /* State machine operation data. */
+ int cs;
+
+ /* Parsing data. */
+ char identBuf[IDENT_BUFLEN+1];
+ int identLen;
+ int curLine;
+};
+
+- (void) initFsm;
+- (void) executeWithData:(const char *)data len:(int)len;
+- (int) finish;
+
+@end
+
+%%{
+ machine Clang;
+
+ # Function to buffer a character.
+ action bufChar {
+ if ( identLen < IDENT_BUFLEN ) {
+ identBuf[identLen] = fc;
+ identLen += 1;
+ }
+ }
+
+ # Function to clear the buffer.
+ action clearBuf {
+ identLen = 0;
+ }
+
+ # Functions to dump tokens as they are matched.
+ action ident {
+ identBuf[identLen] = 0;
+ printf("ident(%i): %s\n", curLine, identBuf);
+ }
+ action literal {
+ identBuf[identLen] = 0;
+ printf("literal(%i): %s\n", curLine, identBuf);
+ }
+ action float {
+ identBuf[identLen] = 0;
+ printf("float(%i): %s\n", curLine, identBuf);
+ }
+ action int {
+ identBuf[identLen] = 0;
+ printf("int(%i): %s\n", curLine, identBuf);
+ }
+ action hex {
+ identBuf[identLen] = 0;
+ printf("hex(%i): 0x%s\n", curLine, identBuf);
+ }
+ action symbol {
+ identBuf[identLen] = 0;
+ printf("symbol(%i): %s\n", curLine, identBuf);
+ }
+
+ # Alpha numberic characters or underscore.
+ alnumu = alnum | '_';
+
+ # Alpha charactres or underscore.
+ alphau = alpha | '_';
+
+ # Symbols. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving dump the symbol.
+ symbol = ( punct - [_'"] ) >clearBuf $bufChar %symbol;
+
+ # Identifier. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving, dump the identifier.
+ ident = (alphau . alnumu*) >clearBuf $bufChar %ident;
+
+ # Match single characters inside literal strings. Or match
+ # an escape sequence. Buffers the charater matched.
+ sliteralChar =
+ ( extend - ['\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+ dliteralChar =
+ ( extend - ["\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+
+ # Single quote and double quota literals. At the start clear
+ # the buffer. Upon leaving dump the literal.
+ sliteral = ('\'' @clearBuf . sliteralChar* . '\'' ) %literal;
+ dliteral = ('"' @clearBuf . dliteralChar* . '"' ) %literal;
+ literal = sliteral | dliteral;
+
+ # Whitespace is standard ws, newlines and control codes.
+ whitespace = any - 0x21..0x7e;
+
+ # Describe both c style comments and c++ style comments. The
+ # priority bump on tne terminator of the comments brings us
+ # out of the extend* which matches everything.
+ ccComment = '//' . extend* $0 . '\n' @1;
+ cComment = '/*' . extend* $0 . '*/' @1;
+
+ # Match an integer. We don't bother clearing the buf or filling it.
+ # The float machine overlaps with int and it will do it.
+ int = digit+ %int;
+
+ # Match a float. Upon entering the machine clear the buf, buffer
+ # characters on every trans and dump the float upon leaving.
+ float = ( digit+ . '.' . digit+ ) >clearBuf $bufChar %float;
+
+ # Match a hex. Upon entering the hex part, clear the buf, buffer characters
+ # on every trans and dump the hex on leaving transitions.
+ hex = '0x' . xdigit+ >clearBuf $bufChar %hex;
+
+ # Or together all the lanuage elements.
+ fin = ( ccComment |
+ cComment |
+ symbol |
+ ident |
+ literal |
+ whitespace |
+ int |
+ float |
+ hex );
+
+ # Star the language elements. It is critical in this type of application
+ # that we decrease the priority of out transitions before doing so. This
+ # is so that when we see 'aa' we stay in the fin machine to match an ident
+ # of length two and not wrap around to the front to match two idents of
+ # length one.
+ clang_main = ( fin $1 %0 )*;
+
+ # This machine matches everything, taking note of newlines.
+ newline = ( any | '\n' @{ curLine += 1; } )*;
+
+ # The final fsm is the lexer intersected with the newline machine which
+ # will count lines for us. Since the newline machine accepts everything,
+ # the strings accepted is goverened by the clang_main machine, onto which
+ # the newline machine overlays line counting.
+ main := clang_main & newline;
+}%%
+
+@implementation Clang
+
+%% write data;
+
+- (void) initFsm;
+{
+ identLen = 0;
+ curLine = 1;
+ %% write init;
+}
+
+- (void) executeWithData:(const char *)data len:(int)len;
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = pe;
+
+ %% write exec;
+}
+
+- (int) finish;
+{
+ if ( cs == Clang_error )
+ return -1;
+ if ( cs >= Clang_first_final )
+ return 1;
+ return 0;
+}
+
+@end
+
+#define BUFSIZE 2048
+
+Clang *fsm;
+char buf[BUFSIZE];
+
+void test( char *buf )
+{
+ int len = strlen(buf);
+ fsm = [[Clang alloc] init];
+ [fsm initFsm];
+ [fsm executeWithData:buf len:len];
+ if ( [fsm finish] > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test(
+ "999 0xaAFF99 99.99 /*\n"
+ "*/ 'lksdj' //\n"
+ "\"\n"
+ "\n"
+ "literal\n"
+ "\n"
+ "\n"
+ "\"0x00aba foobardd.ddsf 0x0.9\n" );
+
+ test(
+ "wordwithnum00asdf\n"
+ "000wordfollowsnum,makes new symbol\n"
+ "\n"
+ "finishing early /* unfinished ...\n" );
+
+ test(
+ "/*\n"
+ " * Copyright\n"
+ " */\n"
+ "\n"
+ "/* Aapl.\n"
+ " */\n"
+ " \n"
+ "#define _AAPL_RESIZE_H\n"
+ "\n"
+ "#include <assert.h>\n"
+ "\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "namespace Aapl {\n"
+ "#endif\n"
+ "#define LIN_DEFAULT_STEP 256\n"
+ "#define EXPN_UP( existing, needed ) \\\n"
+ " need > eng ? (ned<<1) : eing\n"
+ " \n"
+ "\n"
+ "/*@}*/\n"
+ "#undef EXPN_UP\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "#endif /* _AAPL_RESIZE_H */\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+int(1): 999
+hex(1): 0xaAFF99
+float(1): 99.99
+literal(2): lksdj
+literal(8):
+
+literal
+
+
+
+hex(8): 0x00aba
+ident(8): foobardd
+symbol(8): .
+ident(8): ddsf
+hex(8): 0x0
+symbol(8): .
+int(8): 9
+ACCEPT
+ident(1): wordwithnum00asdf
+int(2): 000
+ident(2): wordfollowsnum
+symbol(2): ,
+ident(2): makes
+ident(2): new
+ident(2): symbol
+ident(4): finishing
+ident(4): early
+FAIL
+symbol(8): #
+ident(8): define
+ident(8): _AAPL_RESIZE_H
+symbol(10): #
+ident(10): include
+symbol(10): <
+ident(10): assert
+symbol(10): .
+ident(10): h
+symbol(10): >
+symbol(12): #
+ident(12): ifdef
+ident(12): AAPL_NAMESPACE
+ident(13): namespace
+ident(13): Aapl
+symbol(13): {
+symbol(14): #
+ident(14): endif
+symbol(15): #
+ident(15): define
+ident(15): LIN_DEFAULT_STEP
+int(15): 256
+symbol(16): #
+ident(16): define
+ident(16): EXPN_UP
+symbol(16): (
+ident(16): existing
+symbol(16): ,
+ident(16): needed
+symbol(16): )
+symbol(16): \
+ident(17): need
+symbol(17): >
+ident(17): eng
+symbol(17): ?
+symbol(17): (
+ident(17): ned
+symbol(17): <
+symbol(17): <
+int(17): 1
+symbol(17): )
+symbol(17): :
+ident(17): eing
+symbol(21): #
+ident(21): undef
+ident(21): EXPN_UP
+symbol(22): #
+ident(22): ifdef
+ident(22): AAPL_NAMESPACE
+symbol(23): #
+ident(23): endif
+ACCEPT
+#endif
diff --git a/test/clang3.rl b/test/clang3.rl
new file mode 100644
index 0000000..82f5eed
--- /dev/null
+++ b/test/clang3.rl
@@ -0,0 +1,321 @@
+/*
+ * @LANG: d
+ * A mini C-like language scanner.
+ */
+
+module clang;
+
+import std.c.stdio;
+
+char[] string(char c)
+{
+ char[] result = new char[2];
+ result[0] = c;
+ result[1] = 0;
+ return result[0 .. 1];
+}
+
+class CLang
+{
+ /* Parsing data. */
+ char[] identBuf;
+ int curLine;
+
+ this()
+ {
+ }
+
+ /* State machine operation data. */
+ int cs;
+
+ %%{
+ machine clang;
+
+ # Function to buffer a character.
+ action bufChar {
+ identBuf ~= fc;
+ }
+
+ # Function to clear the buffer.
+ action clearBuf {
+
+ identBuf = null;
+ }
+
+ # Functions to dump tokens as they are matched.
+ action ident {
+ printf("ident(%i): %.*s\n", curLine, identBuf);
+ }
+ action literal {
+ printf("literal(%i): %.*s\n", curLine, identBuf);
+ }
+ action float {
+ printf("float(%i): %.*s\n", curLine, identBuf);
+ }
+ action int {
+ printf("int(%i): %.*s\n", curLine, identBuf);
+ }
+ action hex {
+ printf("hex(%i): 0x%.*s\n", curLine, identBuf);
+ }
+ action symbol {
+ printf("symbol(%i): %.*s\n", curLine, identBuf);
+ }
+
+ # Alpha numberic characters or underscore.
+ alnumu = alnum | '_';
+
+ # Alpha charactres or underscore.
+ alphau = alpha | '_';
+
+ # Symbols. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving dump the symbol.
+ symbol = ( punct - [_'"] ) >clearBuf $bufChar %symbol;
+
+ # Identifier. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving, dump the identifier.
+ ident = (alphau . alnumu*) >clearBuf $bufChar %ident;
+
+ # Match single characters inside literal strings. Or match
+ # an escape sequence. Buffers the charater matched.
+ sliteralChar =
+ ( extend - ['\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+ dliteralChar =
+ ( extend - ["\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+
+ # Single quote and double quota literals. At the start clear
+ # the buffer. Upon leaving dump the literal.
+ sliteral = ('\'' @clearBuf . sliteralChar* . '\'' ) %literal;
+ dliteral = ('"' @clearBuf . dliteralChar* . '"' ) %literal;
+ literal = sliteral | dliteral;
+
+ # Whitespace is standard ws, newlines and control codes.
+ whitespace = any - 0x21..0x7e;
+
+ # Describe both c style comments and c++ style comments. The
+ # priority bump on tne terminator of the comments brings us
+ # out of the extend* which matches everything.
+ ccComment = '//' . extend* $0 . '\n' @1;
+ cComment = '/*' . extend* $0 . '*/' @1;
+
+ # Match an integer. We don't bother clearing the buf or filling it.
+ # The float machine overlaps with int and it will do it.
+ int = digit+ %int;
+
+ # Match a float. Upon entering the machine clear the buf, buffer
+ # characters on every trans and dump the float upon leaving.
+ float = ( digit+ . '.' . digit+ ) >clearBuf $bufChar %float;
+
+ # Match a hex. Upon entering the hex part, clear the buf, buffer characters
+ # on every trans and dump the hex on leaving transitions.
+ hex = '0x' . xdigit+ >clearBuf $bufChar %hex;
+
+ # Or together all the lanuage elements.
+ fin = ( ccComment |
+ cComment |
+ symbol |
+ ident |
+ literal |
+ whitespace |
+ int |
+ float |
+ hex );
+
+ # Star the language elements. It is critical in this type of application
+ # that we decrease the priority of out transitions before doing so. This
+ # is so that when we see 'aa' we stay in the fin machine to match an ident
+ # of length two and not wrap around to the front to match two idents of
+ # length one.
+ clang_main = ( fin $1 %0 )*;
+
+ # This machine matches everything, taking note of newlines.
+ newline = ( any | '\n' @{ curLine++; } )*;
+
+ # The final fsm is the lexer intersected with the newline machine which
+ # will count lines for us. Since the newline machine accepts everything,
+ # the strings accepted is goverened by the clang_main machine, onto which
+ # the newline machine overlays line counting.
+ main := clang_main & newline;
+ }%%
+
+ %% write data noprefix;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( )
+ {
+ curLine = 1;
+ %% write init;
+ }
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ void execute( char* _data, int _len )
+ {
+ char *p = _data;
+ char *pe = _data + _len;
+ char *eof = pe;
+ %% write exec;
+ }
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( )
+ {
+ if ( cs == error )
+ return -1;
+ if ( cs >= first_final )
+ return 1;
+ return 0;
+ }
+}
+
+static const int BUFSIZE = 1024;
+
+void test( char buf[] )
+{
+ CLang scanner = new CLang();
+ scanner.init();
+ scanner.execute( buf.ptr, buf.length );
+ if ( scanner.finish() > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+
+ return 0;
+}
+
+int main()
+{
+ test(
+ "999 0xaAFF99 99.99 /*\n"
+ "*/ 'lksdj' //\n"
+ "\"\n"
+ "\n"
+ "literal\n"
+ "\n"
+ "\n"
+ "\"0x00aba foobardd.ddsf 0x0.9\n" );
+
+ test(
+ "wordwithnum00asdf\n"
+ "000wordfollowsnum,makes new symbol\n"
+ "\n"
+ "finishing early /* unfinished ...\n" );
+
+ test(
+ "/*\n"
+ " * Copyright\n"
+ " */\n"
+ "\n"
+ "/* Aapl.\n"
+ " */\n"
+ " \n"
+ "#define _AAPL_RESIZE_H\n"
+ "\n"
+ "#include <assert.h>\n"
+ "\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "namespace Aapl {\n"
+ "#endif\n"
+ "#define LIN_DEFAULT_STEP 256\n"
+ "#define EXPN_UP( existing, needed ) \\\n"
+ " need > eng ? (ned<<1) : eing\n"
+ " \n"
+ "\n"
+ "/*@}*/\n"
+ "#undef EXPN_UP\n"
+ "#ifdef AAPL_NAMESPACE\n"
+ "#endif /* _AAPL_RESIZE_H */\n" );
+ return 0;
+}
+
+/+ _____OUTPUT_____
+int(1): 999
+hex(1): 0xaAFF99
+float(1): 99.99
+literal(2): lksdj
+literal(8):
+
+literal
+
+
+
+hex(8): 0x00aba
+ident(8): foobardd
+symbol(8): .
+ident(8): ddsf
+hex(8): 0x0
+symbol(8): .
+int(8): 9
+ACCEPT
+ident(1): wordwithnum00asdf
+int(2): 000
+ident(2): wordfollowsnum
+symbol(2): ,
+ident(2): makes
+ident(2): new
+ident(2): symbol
+ident(4): finishing
+ident(4): early
+FAIL
+symbol(8): #
+ident(8): define
+ident(8): _AAPL_RESIZE_H
+symbol(10): #
+ident(10): include
+symbol(10): <
+ident(10): assert
+symbol(10): .
+ident(10): h
+symbol(10): >
+symbol(12): #
+ident(12): ifdef
+ident(12): AAPL_NAMESPACE
+ident(13): namespace
+ident(13): Aapl
+symbol(13): {
+symbol(14): #
+ident(14): endif
+symbol(15): #
+ident(15): define
+ident(15): LIN_DEFAULT_STEP
+int(15): 256
+symbol(16): #
+ident(16): define
+ident(16): EXPN_UP
+symbol(16): (
+ident(16): existing
+symbol(16): ,
+ident(16): needed
+symbol(16): )
+symbol(16): \
+ident(17): need
+symbol(17): >
+ident(17): eng
+symbol(17): ?
+symbol(17): (
+ident(17): ned
+symbol(17): <
+symbol(17): <
+int(17): 1
+symbol(17): )
+symbol(17): :
+ident(17): eing
+symbol(21): #
+ident(21): undef
+ident(21): EXPN_UP
+symbol(22): #
+ident(22): ifdef
+ident(22): AAPL_NAMESPACE
+symbol(23): #
+ident(23): endif
+ACCEPT
+++++++++++++++++/
diff --git a/test/clang4.rl b/test/clang4.rl
new file mode 100644
index 0000000..c3bb399
--- /dev/null
+++ b/test/clang4.rl
@@ -0,0 +1,188 @@
+/*
+ * @LANG: indep
+ * @NEEDS_EOF: yes
+ */
+
+char array[32];
+int pos;
+int line;
+%%
+pos = 0;
+line = 1;
+%%{
+ machine clang;
+
+ # Function to buffer a character.
+ action bufChar { array[pos] = fc; pos = pos + 1; }
+
+ # Function to clear the buffer.
+ action clearBuf { pos = 0; }
+
+ # Functions to dump tokens as they are matched.
+ action ident {
+ prints "ident(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+ action literal {
+ prints "literal(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+ action float {
+ prints "float(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+ action integer {
+ prints "int(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+ action hex {
+ prints "hex(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+ action symbol {
+ prints "symbol(";
+ printi line;
+ prints ",";
+ printi pos;
+ prints "): ";
+ printb array;
+ prints "\n";
+ }
+
+ # Alpha numberic characters or underscore.
+ alnumu = alnum | '_';
+
+ # Alpha charactres or underscore.
+ alphau = alpha | '_';
+
+ # Symbols. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving dump the symbol.
+ symbol = ( punct - [_'"] ) >clearBuf $bufChar %symbol;
+
+ # Identifier. Upon entering clear the buffer. On all transitions
+ # buffer a character. Upon leaving, dump the identifier.
+ ident = (alphau . alnumu*) >clearBuf $bufChar %ident;
+
+ # Match single characters inside literal strings. Or match
+ # an escape sequence. Buffers the charater matched.
+ sliteralChar =
+ ( extend - ['\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+ dliteralChar =
+ ( extend - ["\\] ) @bufChar |
+ ( '\\' . extend @bufChar );
+
+ # Single quote and double quota literals. At the start clear
+ # the buffer. Upon leaving dump the literal.
+ sliteral = ('\'' @clearBuf . sliteralChar* . '\'' ) %literal;
+ dliteral = ('"' @clearBuf . dliteralChar* . '"' ) %literal;
+ literal = sliteral | dliteral;
+
+ # Whitespace is standard ws, newlines and control codes.
+ whitespace = any - 33 .. 126;
+
+ # Describe both c style comments and c++ style comments. The
+ # priority bump on tne terminator of the comments brings us
+ # out of the extend* which matches everything.
+ ccComment = '//' . extend* $0 . '\n' @1;
+ cComment = '/!' . extend* $0 . '!/' @1;
+
+ # Match an integer. We don't bother clearing the buf or filling it.
+ # The float machine overlaps with int and it will do it.
+ integer = digit+ %integer;
+
+ # Match a float. Upon entering the machine clear the buf, buffer
+ # characters on every trans and dump the float upon leaving.
+ float = ( digit+ . '.' . digit+ ) >clearBuf $bufChar %float;
+
+ # Match a hex. Upon entering the hex part, clear the buf, buffer characters
+ # on every trans and dump the hex on leaving transitions.
+ hex = '0x' . xdigit+ >clearBuf $bufChar %hex;
+
+ # Or together all the lanuage elements.
+ fin = ( ccComment |
+ cComment |
+ symbol |
+ ident |
+ literal |
+ whitespace |
+ integer |
+ float |
+ hex );
+
+ # Star the language elements. It is critical in this type of application
+ # that we decrease the priority of out transitions before doing so. This
+ # is so that when we see 'aa' we stay in the fin machine to match an ident
+ # of length two and not wrap around to the front to match two idents of
+ # length one.
+ clang_main = ( fin $1 %0 )*;
+
+ # This machine matches everything, taking note of newlines.
+ newline = ( any | '\n' @{ line = line + 1; } )*;
+
+ # The final fsm is the lexer intersected with the newline machine which
+ # will count lines for us. Since the newline machine accepts everything,
+ # the strings accepted is goverened by the clang_main machine, onto which
+ # the newline machine overlays line counting.
+ main := clang_main & newline;
+}%%
+/* _____INPUT_____
+"999 0xaAFF99 99.99 /!\n!/ 'lksdj' //\n\"\n\nliteral\n\n\n\"0x00aba foobardd.ddsf 0x0.9\n"
+"wordwithnum00asdf\n000wordfollowsnum,makes new symbol\n\nfinishing early /! unfinished ...\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+int(1,3): 999
+hex(1,6): aAFF99
+float(1,5): 99.99
+literal(2,5): lksdj
+literal(8,12):
+
+literal
+
+
+
+hex(8,5): 00aba
+ident(8,8): foobardd
+symbol(8,1): .
+ident(8,4): ddsf
+hex(8,1): 0
+symbol(8,1): .
+int(8,1): 9
+ACCEPT
+ident(1,17): wordwithnum00asdf
+int(2,3): 000
+ident(2,14): wordfollowsnum
+symbol(2,1): ,
+ident(2,5): makes
+ident(2,3): new
+ident(2,6): symbol
+ident(4,9): finishing
+ident(4,5): early
+FAIL
+_____OUTPUT_____ */
+
diff --git a/test/cond1.rl b/test/cond1.rl
new file mode 100644
index 0000000..7c3ffff
--- /dev/null
+++ b/test/cond1.rl
@@ -0,0 +1,69 @@
+/*
+ * @LANG: indep
+ * @ALLOW_GENFLAGS: -T0 -T1 -G0 -G1 -G2
+ */
+bool i;
+bool j;
+bool k;
+%%
+
+%%{
+ machine foo;
+
+ action c1 {i}
+ action c2 {j}
+ action c3 {k}
+ action one { prints " one\n";}
+ action two { prints " two\n";}
+ action three { prints " three\n";}
+
+ action seti { if ( fc == 48 ) i = false; else i = true; }
+ action setj { if ( fc == 48 ) j = false; else j = true; }
+ action setk { if ( fc == 48 ) k = false; else k = true; }
+
+ action break {fbreak;}
+
+ one = 'a' 'b' when c1 'c' @one;
+ two = 'a'* 'b' when c2 'c' @two;
+ three = 'a'+ 'b' when c3 'c' @three;
+
+ main :=
+ [01] @seti
+ [01] @setj
+ [01] @setk
+ ( one | two | three ) '\n' @break;
+
+}%%
+
+/* _____INPUT_____
+"000abc\n"
+"100abc\n"
+"010abc\n"
+"110abc\n"
+"001abc\n"
+"101abc\n"
+"011abc\n"
+"111abc\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+FAIL
+ one
+ACCEPT
+ two
+ACCEPT
+ one
+ two
+ACCEPT
+ three
+ACCEPT
+ one
+ three
+ACCEPT
+ two
+ three
+ACCEPT
+ one
+ two
+ three
+ACCEPT
+_____OUTPUT_____ */
diff --git a/test/cond2.rl b/test/cond2.rl
new file mode 100644
index 0000000..7e49ab8
--- /dev/null
+++ b/test/cond2.rl
@@ -0,0 +1,91 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using std::cout;
+using std::endl;
+
+%%{
+ machine foo;
+
+ action c1 {i}
+ action c2 {j}
+
+ action one { cout << " one" << endl;}
+ action two { cout << " two" << endl;}
+
+ main := (
+ [a-z] |
+ ('\n' when c1 @one)
+ )*
+ ('\n' when c2 @two);
+}%%
+
+%% write data noerror;
+
+void test( int i, int j, const char *str )
+{
+ int cs = foo_start;
+ const char *p = str;
+ const char *pe = str + strlen( str );
+
+ cout << "run:" << endl;
+ %% write exec;
+ if ( cs >= foo_first_final )
+ cout << " success" << endl;
+ else
+ cout << " failure" << endl;
+ cout << endl;
+}
+
+int main()
+{
+ test( 0, 0, "hi\n\n" );
+ test( 1, 0, "hi\n\n" );
+ test( 0, 1, "hi\n" );
+ test( 0, 1, "hi\n\n" );
+ test( 1, 1, "hi\n" );
+ test( 1, 1, "hi\n\n" );
+ test( 1, 1, "hi\n\nx" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+run:
+ failure
+
+run:
+ one
+ one
+ failure
+
+run:
+ two
+ success
+
+run:
+ two
+ failure
+
+run:
+ one
+ two
+ success
+
+run:
+ one
+ two
+ one
+ two
+ success
+
+run:
+ one
+ two
+ one
+ two
+ failure
+
+#endif
diff --git a/test/cond3.rl b/test/cond3.rl
new file mode 100644
index 0000000..80904b5
--- /dev/null
+++ b/test/cond3.rl
@@ -0,0 +1,59 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using std::cout;
+using std::endl;
+
+%%{
+ machine foo;
+
+ action hit_5 {c == 5}
+ action done { cout << " done" << endl; }
+ action inc {c++;}
+
+ # The any* includes '\n' when hit_5 is true, so use guarded concatenation.
+ main := (any @inc)* :> '\n' when hit_5 @done;
+}%%
+
+%% write data noerror;
+
+void test( const char *str )
+{
+ int cs = foo_start;
+ int c = 0;
+ const char *p = str;
+ const char *pe = str + strlen( str );
+
+ cout << "run:" << endl;
+ %% write exec;
+ if ( cs >= foo_first_final )
+ cout << " success" << endl;
+ else
+ cout << " failure" << endl;
+ cout << endl;
+}
+
+int main()
+{
+ test( "12345\n" ); // success
+ test( "\n2345\n" ); // success, first newline ignored
+ test( "1234\n" ); // failure, didn't get 5 chars before newline.
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+run:
+ done
+ success
+
+run:
+ done
+ success
+
+run:
+ failure
+
+#endif
diff --git a/test/cond4.rl b/test/cond4.rl
new file mode 100644
index 0000000..380c5ff
--- /dev/null
+++ b/test/cond4.rl
@@ -0,0 +1,54 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using std::cout;
+using std::endl;
+
+%%{
+ machine foo;
+
+ action c1 {(cout << "c1 ", true)}
+ action c2 {(cout << "c2 ", true)}
+ action c3 {(cout << "c3 ", true)}
+ action c4 {(cout << "c4 ", true)}
+
+ main := (
+ 10 .. 60 when c1 |
+ 20 .. 40 when c2 |
+ 30 .. 50 when c3 |
+ 32 .. 38 when c4 |
+ 0 .. 70 )* ${cout << "char: " << (int)*p << endl;};
+}%%
+
+%% write data noerror nofinal;
+
+void test( char *str )
+{
+ int len = strlen( str );
+ int cs = foo_start;
+ char *p = str, *pe = str+len;
+ %% write exec;
+}
+
+char data[] = { 5, 15, 25, 31, 35, 39, 45, 55, 65, 0 };
+
+int main()
+{
+ test( data );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+char: 5
+c1 char: 15
+c1 c2 char: 25
+c1 c2 c3 char: 31
+c1 c2 c3 c4 char: 35
+c1 c2 c3 char: 39
+c1 c3 char: 45
+c1 char: 55
+char: 65
+#endif
diff --git a/test/cond5.rl b/test/cond5.rl
new file mode 100644
index 0000000..b6ab4ae
--- /dev/null
+++ b/test/cond5.rl
@@ -0,0 +1,59 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using std::cout;
+using std::endl;
+
+%%{
+ machine foo;
+ write data noerror;
+}%%
+
+void test( const char *str )
+{
+ int cs = foo_start;
+ int c = 0;
+ const char *p = str;
+ const char *pe = str + strlen( str );
+ char last = '0';
+
+ cout << "run:";
+ %%{
+ action d1 { cout << " d1"; }
+ action see_five { cout << " see_five"; }
+
+ see_five = ([0-9] when{c++ < 5} @d1)* '\n' @see_five;
+
+ action in_sequence { cout << " in_sequence"; }
+ action d2 { last = *p; cout << " d2"; }
+ in_sequence = ( [0-9] when { *p == last+1 } @d2 )* '\n' @in_sequence;
+
+ main := ( see_five | in_sequence ) ${cout << " |";};
+
+ write exec;
+ }%%
+ if ( cs < foo_first_final )
+ cout << " failure";
+ cout << endl;
+}
+
+int main()
+{
+ test( "123456789012\n" ); // fails both
+ test( "123456789\n" ); // fails five
+ test( "1234\n" ); // fails five
+ test( "13245\n" ); // fails sequence
+ test( "12345\n" ); // succeeds in both
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+run: d1 d2 | d1 d2 | d1 d2 | d1 d2 | d1 d2 | d2 | d2 | d2 | d2 | failure
+run: d1 d2 | d1 d2 | d1 d2 | d1 d2 | d1 d2 | d2 | d2 | d2 | d2 | in_sequence |
+run: d1 d2 | d1 d2 | d1 d2 | d1 d2 | see_five in_sequence |
+run: d1 d2 | d1 | d1 | d1 | d1 | see_five |
+run: d1 d2 | d1 d2 | d1 d2 | d1 d2 | d1 d2 | see_five in_sequence |
+#endif
diff --git a/test/cond6.rl b/test/cond6.rl
new file mode 100644
index 0000000..ede9ed8
--- /dev/null
+++ b/test/cond6.rl
@@ -0,0 +1,61 @@
+/*
+ * @LANG: c++
+ */
+
+/* Balanced parenthesis with conditions. */
+
+#include <iostream>
+#include <string.h>
+using std::cout;
+using std::endl;
+
+%%{
+ machine cond;
+ write data noerror;
+}%%
+
+void test( const char *str )
+{
+ int cs = cond_start, n = 0;
+ const char *p = str;
+ const char *pe = str + strlen( str );
+
+ %%{
+ comment = '(' @{n=0;}
+ ( '('@{n++;} | ')'@{n--;} | [^()] )*
+ :> ')' when{!n};
+
+ main := ' '* comment ' '* '\n' @{cout << "success";};
+
+ write exec;
+ }%%
+ if ( cs < cond_first_final )
+ cout << "failure";
+ cout << endl;
+}
+
+int main()
+{
+ test( "( ( )\n" );
+ test( "()()\n" );
+ test( "(((\n" );
+ test( "((()\n" );
+ test( "((())\n" );
+ test( "()\n" );
+ test( "((()))\n" );
+ test( "(()())\n" );
+ test( "((())()(((()))))\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+failure
+failure
+failure
+failure
+failure
+success
+success
+success
+success
+#endif
diff --git a/test/cond7.rl b/test/cond7.rl
new file mode 100644
index 0000000..a88e67c
--- /dev/null
+++ b/test/cond7.rl
@@ -0,0 +1,82 @@
+/*
+ * @LANG: indep
+ */
+int i;
+int c;
+%%
+
+%%{
+ machine foo;
+
+ action testi {i > 0}
+ action inc {
+ i = i - 1;
+ c = <int>(fc);
+ prints "item: ";
+ printi c;
+ prints "\n";
+ }
+
+ count = [0-9] @{
+ i = <int>(fc - '0');
+ prints "count: ";
+ printi i;
+ prints "\n";
+ };
+
+ sub =
+ count # record the number of digits
+ ( digit when testi @inc )* outwhen !testi;
+
+ main := sub sub '\n';
+}%%
+
+/* _____INPUT_____
+"00\n"
+"019\n"
+"190\n"
+"1719\n"
+"1040000\n"
+"104000a\n"
+"104000\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+count: 0
+count: 0
+ACCEPT
+count: 0
+count: 1
+item: 57
+ACCEPT
+count: 1
+item: 57
+count: 0
+ACCEPT
+count: 1
+item: 55
+count: 1
+item: 57
+ACCEPT
+count: 1
+item: 48
+count: 4
+item: 48
+item: 48
+item: 48
+item: 48
+ACCEPT
+count: 1
+item: 48
+count: 4
+item: 48
+item: 48
+item: 48
+FAIL
+count: 1
+item: 48
+count: 4
+item: 48
+item: 48
+item: 48
+FAIL
+_____OUTPUT_____ */
diff --git a/test/cppscan1.h b/test/cppscan1.h
new file mode 100644
index 0000000..346dd9b
--- /dev/null
+++ b/test/cppscan1.h
@@ -0,0 +1,112 @@
+#ifndef _CPPSCAN1_H
+#define _CPPSCAN1_H
+
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+#define TK_Dlit 192
+#define TK_Slit 193
+#define TK_Float 194
+#define TK_Id 195
+#define TK_NameSep 197
+#define TK_Arrow 211
+#define TK_PlusPlus 212
+#define TK_MinusMinus 213
+#define TK_ArrowStar 214
+#define TK_DotStar 215
+#define TK_ShiftLeft 216
+#define TK_ShiftRight 217
+#define TK_IntegerDecimal 218
+#define TK_IntegerOctal 219
+#define TK_IntegerHex 220
+#define TK_EqualsEquals 223
+#define TK_NotEquals 224
+#define TK_AndAnd 225
+#define TK_OrOr 226
+#define TK_MultAssign 227
+#define TK_DivAssign 228
+#define TK_PercentAssign 229
+#define TK_PlusAssign 230
+#define TK_MinusAssign 231
+#define TK_AmpAssign 232
+#define TK_CaretAssign 233
+#define TK_BarAssign 234
+#define TK_DotDotDot 240
+
+/* A growable buffer for collecting headers. */
+struct Buffer
+{
+ Buffer() : data(0), allocated(0), length(0) { }
+ Buffer( const Buffer &other ) {
+ data = (char*)malloc( other.allocated );
+ memcpy( data, other.data, other.length );
+ allocated = other.allocated;
+ length = other.length;
+ }
+ ~Buffer() { empty(); }
+
+ void append( char p ) {
+ if ( ++length > allocated )
+ upAllocate( length*2 );
+ data[length-1] = p;
+ }
+ void append( char *str, int len ) {
+ if ( (length += len) > allocated )
+ upAllocate( length*2 );
+ memcpy( data+length-len, str, len );
+ }
+
+ void clear() { length = 0; }
+ void upAllocate( int len );
+ void empty();
+
+ char *data;
+ int allocated;
+ int length;
+};
+
+
+struct Scanner
+{
+ Scanner( std::ostream &out )
+ : out(out) { }
+
+ std::ostream &out;
+
+ int line, col;
+ int tokStart;
+ int inlineDepth;
+ int count;
+ Buffer tokBuf;
+ Buffer nonTokBuf;
+
+ void pass(char c) { nonTokBuf.append(c); }
+ void buf(char c) { tokBuf.append(c); }
+ void token( int id );
+
+ int cs, stack, top;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+#endif
diff --git a/test/cppscan1.rl b/test/cppscan1.rl
new file mode 100644
index 0000000..92869f7
--- /dev/null
+++ b/test/cppscan1.rl
@@ -0,0 +1,283 @@
+/*
+ * @LANG: c++
+ *
+ * Test works with split code gen.
+ */
+
+#include "cppscan1.h"
+
+%%{
+ machine Scanner;
+ access fsm->;
+
+ action pass { fsm->pass(fc); }
+ action buf { fsm->buf(fc); }
+
+ action emit_slit { fsm->token( TK_Slit ); }
+ action emit_dlit { fsm->token( TK_Dlit ); }
+ action emit_id { fsm->token( TK_Id ); }
+ action emit_integer_decimal { fsm->token( TK_IntegerDecimal ); }
+ action emit_integer_octal { fsm->token( TK_IntegerOctal ); }
+ action emit_integer_hex { fsm->token( TK_IntegerHex ); }
+ action emit_float { fsm->token( TK_Float ); }
+ action emit_symbol { fsm->token( fsm->tokBuf.data[0] ); }
+ action tokst { fsm->tokStart = fsm->col; }
+
+ # Single and double literals.
+ slit = ( 'L'? ( "'" ( [^'\\\n] | /\\./ )* "'" ) $buf ) >tokst %emit_slit;
+ dlit = ( 'L'? ( '"' ( [^"\\\n] | /\\./ )* '"' ) $buf ) >tokst %emit_dlit;
+
+ # Identifiers
+ id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) >tokst $buf %emit_id;
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+ float =
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? ) >tokst $buf %emit_float;
+
+ # Integer decimal. Leading part buffered by float.
+ integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} $buf ) %emit_integer_decimal;
+
+ # Integer octal. Leading part buffered by float.
+ integer_octal = ( '0' [0-9]+ [ulUL]{0,2} $buf ) %emit_integer_octal;
+
+ # Integer hex. Leading 0 buffered by float.
+ integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) $buf ) %emit_integer_hex;
+
+ # Only buffer the second item, first buffered by symbol. */
+ namesep = '::' @buf %{fsm->token( TK_NameSep );};
+ deqs = '==' @buf %{fsm->token( TK_EqualsEquals );};
+ neqs = '!=' @buf %{fsm->token( TK_NotEquals );};
+ and_and = '&&' @buf %{fsm->token( TK_AndAnd );};
+ or_or = '||' @buf %{fsm->token( TK_OrOr );};
+ mult_assign = '*=' @buf %{fsm->token( TK_MultAssign );};
+ percent_assign = '%=' @buf %{fsm->token( TK_PercentAssign );};
+ plus_assign = '+=' @buf %{fsm->token( TK_PlusAssign );};
+ minus_assign = '-=' @buf %{fsm->token( TK_MinusAssign );};
+ amp_assign = '&=' @buf %{fsm->token( TK_AmpAssign );};
+ caret_assign = '^=' @buf %{fsm->token( TK_CaretAssign );};
+ bar_assign = '|=' @buf %{fsm->token( TK_BarAssign );};
+ plus_plus = '++' @buf %{fsm->token( TK_PlusPlus );};
+ minus_minus = '--' @buf %{fsm->token( TK_MinusMinus );};
+ arrow = '->' @buf %{fsm->token( TK_Arrow );};
+ arrow_star = '->*' @buf %{fsm->token( TK_ArrowStar );};
+ dot_star = '.*' @buf %{fsm->token( TK_DotStar );};
+
+ # Buffer both items. *
+ div_assign = '/=' @{fsm->buf('/');fsm->buf(fc);} %{fsm->token( TK_DivAssign );};
+
+ # Double dot is sent as two dots.
+ dot_dot = '..' %{fsm->token('.'); fsm->buf('.'); fsm->token('.');};
+
+ # Three char compounds, first item already buffered. */
+ dot_dot_dot = '...' %{fsm->buf('.'); fsm->buf('.'); fsm->token( TK_DotDotDot );};
+
+ # All compunds
+ compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
+ div_assign | percent_assign | plus_assign | minus_assign |
+ amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
+ arrow | arrow_star | dot_star | dot_dot | dot_dot_dot;
+
+ # Single char symbols.
+ symbol =
+ ( punct - [./_"'] ) >tokst $buf %emit_symbol |
+ # Do not immediately buffer slash, may be start of comment.
+ '/' >tokst %{ fsm->buf('/'); fsm->token( '/' ); } |
+ # Dot covered by float.
+ '.' %emit_symbol;
+
+ # Comments and whitespace.
+ commc = '/*' @{fsm->pass('/'); fsm->pass('*');} ( any* $0 '*/' @1 ) $pass;
+ commcc = '//' @{fsm->pass('/'); fsm->pass('/');} ( any* $0 '\n' @1 ) $pass;
+ whitespace = ( any - ( 0 | 33..126 ) )+ $pass;
+
+ action onEOFChar {
+ /* On EOF char, write out the non token buffer. */
+ fsm->nonTokBuf.append(0);
+ cout << fsm->nonTokBuf.data;
+ fsm->nonTokBuf.clear();
+ }
+
+ # Using 0 as eof. If seeingAs a result all null characters get ignored.
+ EOF = 0 @onEOFChar;
+
+ # All outside code tokens.
+ tokens = (
+ id | slit | dlit | float | integer_decimal |
+ integer_octal | integer_hex | compound | symbol );
+ nontok = ( commc | commcc | whitespace | EOF );
+
+ position = (
+ '\n' @{ fsm->line += 1; fsm->col = 1; } |
+ [^\n] @{ fsm->col += 1; } )*;
+
+ main := ( ( tokens | nontok )** ) & position;
+}%%
+
+%% write data;
+
+void Scanner::init( )
+{
+ Scanner *fsm = this;
+ /* A count of the number of characters in
+ * a token. Used for % sequences. */
+ count = 0;
+ line = 1;
+ col = 1;
+
+ %% write init;
+}
+
+int Scanner::execute( const char *data, int len )
+{
+ Scanner *fsm = this;
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = pe;
+
+ %% write exec;
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+int Scanner::finish( )
+{
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+void Scanner::token( int id )
+{
+ /* Leader. */
+ if ( nonTokBuf.length > 0 ) {
+ nonTokBuf.append(0);
+ cout << nonTokBuf.data;
+ nonTokBuf.clear();
+ }
+
+ /* Token data. */
+ tokBuf.append(0);
+ cout << '<' << id << '>' << tokBuf.data;
+ tokBuf.clear();
+}
+
+void Buffer::empty()
+{
+ if ( data != 0 ) {
+ free( data );
+
+ data = 0;
+ length = 0;
+ allocated = 0;
+ }
+}
+
+void Buffer::upAllocate( int len )
+{
+ if ( data == 0 )
+ data = (char*) malloc( len );
+ else
+ data = (char*) realloc( data, len );
+ allocated = len;
+}
+
+void test( const char *buf )
+{
+ Scanner scanner(cout);
+ scanner.init();
+ scanner.execute( buf, strlen(buf) );
+
+ /* The last token is ignored (because there is no next token). Send
+ * trailing null to force the last token into whitespace. */
+ char eof = 0;
+ if ( scanner.execute( &eof, 1 ) <= 0 ) {
+ cerr << "cppscan: scan failed" << endl;
+ return;
+ }
+ cout.flush();
+}
+
+int main()
+{
+ test(
+ "/*\n"
+ " * Copyright \n"
+ " */\n"
+ "\n"
+ "/* Construct an fsmmachine from a graph. */\n"
+ "RedFsmAp::RedFsmAp( FsmAp *graph, bool complete )\n"
+ ":\n"
+ " graph(graph),\n"
+ "{\n"
+ " assert( sizeof(RedTransAp) <= sizeof(TransAp) );\n"
+ "\n"
+ " reduceMachine();\n"
+ "}\n"
+ "\n"
+ "{\n"
+ " /* Get the transition that we want to extend. */\n"
+ " RedTransAp *extendTrans = list[pos].value;\n"
+ "\n"
+ " /* Look ahead in the transition list. */\n"
+ " for ( int next = pos + 1; next < list.length(); pos++, next++ ) {\n"
+ " if ( ! keyOps->eq( list[pos].highKey, nextKey ) )\n"
+ " break;\n"
+ " }\n"
+ " return false;\n"
+ "}\n"
+ "\n" );
+
+ test(
+ "->*\n"
+ ".*\n"
+ "/*\"*/\n"
+ "\"/*\"\n"
+ "L'\"'\n"
+ "L\"'\"\n" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+/*
+ * Copyright
+ */
+
+/* Construct an fsmmachine from a graph. */
+<195>RedFsmAp<197>::<195>RedFsmAp<40>( <195>FsmAp <42>*<195>graph<44>, <195>bool <195>complete <41>)
+<58>:
+ <195>graph<40>(<195>graph<41>)<44>,
+<123>{
+ <195>assert<40>( <195>sizeof<40>(<195>RedTransAp<41>) <60><<61>= <195>sizeof<40>(<195>TransAp<41>) <41>)<59>;
+
+ <195>reduceMachine<40>(<41>)<59>;
+<125>}
+
+<123>{
+ /* Get the transition that we want to extend. */
+ <195>RedTransAp <42>*<195>extendTrans <61>= <195>list<91>[<195>pos<93>]<46>.<195>value<59>;
+
+ /* Look ahead in the transition list. */
+ <195>for <40>( <195>int <195>next <61>= <195>pos <43>+ <218>1<59>; <195>next <60>< <195>list<46>.<195>length<40>(<41>)<59>; <195>pos<212>++<44>, <195>next<212>++ <41>) <123>{
+ <195>if <40>( <33>! <195>keyOps<211>-><195>eq<40>( <195>list<91>[<195>pos<93>]<46>.<195>highKey<44>, <195>nextKey <41>) <41>)
+ <195>break<59>;
+ <125>}
+ <195>return <195>false<59>;
+<125>}
+
+<214>->*
+<215>.*
+/*"*/
+<192>"/*"
+<193>L'"'
+<192>L"'"
+#endif
diff --git a/test/cppscan2.rl b/test/cppscan2.rl
new file mode 100644
index 0000000..a609bba
--- /dev/null
+++ b/test/cppscan2.rl
@@ -0,0 +1,404 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using namespace std;
+
+#define TK_Dlit 192
+#define TK_Slit 193
+#define TK_Float 194
+#define TK_Id 195
+#define TK_NameSep 197
+#define TK_Arrow 211
+#define TK_PlusPlus 212
+#define TK_MinusMinus 213
+#define TK_ArrowStar 214
+#define TK_DotStar 215
+#define TK_ShiftLeft 216
+#define TK_ShiftRight 217
+#define TK_IntegerDecimal 218
+#define TK_IntegerOctal 219
+#define TK_IntegerHex 220
+#define TK_EqualsEquals 223
+#define TK_NotEquals 224
+#define TK_AndAnd 225
+#define TK_OrOr 226
+#define TK_MultAssign 227
+#define TK_DivAssign 228
+#define TK_PercentAssign 229
+#define TK_PlusAssign 230
+#define TK_MinusAssign 231
+#define TK_AmpAssign 232
+#define TK_CaretAssign 233
+#define TK_BarAssign 234
+#define TK_DotDotDot 240
+#define TK_Whitespace 241
+#define TK_Comment 242
+
+#define BUFSIZE 4096
+
+int tok;
+char buf[BUFSIZE];
+const char *ts, *te;
+void token( const char *data, int len );
+bool discard = false;
+
+struct Scanner
+{
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ int init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine Scanner;
+
+ # Single and double literals.
+ slit = ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" ) @{tok = TK_Slit;};
+ dlit = ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' ) @{tok = TK_Dlit;};
+
+ # Identifiers
+ id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) @{tok = TK_Id;};
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+ float =
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? ) @{tok = TK_Float;};
+
+ # Integer decimal. Leading part buffered by float.
+ integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} ) @{tok = TK_IntegerDecimal;};
+
+ # Integer octal. Leading part buffered by float.
+ integer_octal = ( '0' [0-9]+ [ulUL]{0,2} ) @{tok = TK_IntegerOctal;};
+
+ # Integer hex. Leading 0 buffered by float.
+ integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) ) @{tok = TK_IntegerHex;};
+
+ # Only buffer the second item, first buffered by symbol. */
+ namesep = '::' @{tok = TK_NameSep;};
+ deqs = '==' @{tok = TK_EqualsEquals;};
+ neqs = '!=' @{tok = TK_NotEquals;};
+ and_and = '&&' @{tok = TK_AndAnd;};
+ or_or = '||' @{tok = TK_OrOr;};
+ mult_assign = '*=' @{tok = TK_MultAssign;};
+ div_assign = '/=' @{tok = TK_DivAssign;};
+ percent_assign = '%=' @{tok = TK_PercentAssign;};
+ plus_assign = '+=' @{tok = TK_PlusAssign;};
+ minus_assign = '-=' @{tok = TK_MinusAssign;};
+ amp_assign = '&=' @{tok = TK_AmpAssign;};
+ caret_assign = '^=' @{tok = TK_CaretAssign;};
+ bar_assign = '|=' @{tok = TK_BarAssign;};
+ plus_plus = '++' @{tok = TK_PlusPlus;};
+ minus_minus = '--' @{tok = TK_MinusMinus;};
+ arrow = '->' @{tok = TK_Arrow;};
+ arrow_star = '->*' @{tok = TK_ArrowStar;};
+ dot_star = '.*' @{tok = TK_DotStar;};
+
+ # Three char compounds, first item already buffered. */
+ dot_dot_dot = '...' @{tok = TK_DotDotDot;};
+
+ # All compunds
+ compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
+ div_assign | percent_assign | plus_assign | minus_assign |
+ amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
+ arrow | arrow_star | dot_star | dot_dot_dot;
+
+ # Single char symbols.
+ symbol = ( punct - [_"'] ) @{tok = fc;};
+
+ action discard {
+ discard = true;
+ }
+
+ # Comments and whitespace.
+ commc = '/*' @discard ( any* $0 '*/' @1 ) @{tok = TK_Comment;};
+ commcc = '//' @discard ( any* $0 '\n' @1 ) @{tok = TK_Comment;};
+ whitespace = ( any - 33..126 )+ >discard @{tok = TK_Whitespace;};
+
+ # All outside code tokens.
+ tokens = (
+ id | slit | dlit | float | integer_decimal |
+ integer_octal | integer_hex | compound | symbol |
+ commc | commcc | whitespace );
+
+ action onError {
+ if ( tok != 0 ) {
+ const char *rst_data;
+
+ if ( tok == TK_Comment || tok == TK_Whitespace ) {
+ /* Reset comment status, don't send. */
+ discard = false;
+
+ /* Restart right at the error point if consuming whitespace or
+ * a comment. Consume may have spanned multiple buffers. */
+ rst_data = fpc;
+ }
+ else {
+ /* Send the token. */
+ token( ts, te - ts + 1 );
+
+ /* Restart right after the token. */
+ rst_data = te+1;
+ }
+
+ ts = 0;
+ fexec rst_data;
+ fgoto main;
+ }
+ }
+
+ main := tokens >{ts=fpc;} @{te=fpc;} $!onError;
+}%%
+
+%% write data;
+
+int Scanner::init( )
+{
+ tok = 0;
+ ts = 0;
+ te = 0;
+
+ %% write init;
+ return 1;
+}
+
+int Scanner::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = pe;
+
+ %% write exec;
+
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+int Scanner::finish( )
+{
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+
+void token( const char *data, int len )
+{
+ cout << "<" << tok << "> ";
+ for ( int i = 0; i < len; i++ )
+ cout << data[i];
+ cout << '\n';
+}
+
+void test( const char * data )
+{
+ Scanner scanner;
+ scanner.init();
+ scanner.execute( data, strlen(data) );
+ scanner.finish();
+ if ( tok != 0 && tok != TK_Comment && tok != TK_Whitespace )
+ token( ts, te - ts + 1 );
+}
+
+int main()
+{
+ test(
+ "/*\n"
+ " * Copyright \n"
+ " */\n"
+ "\n"
+ "\n"
+ "/* Move ranges to the singles list. */\n"
+ "void RedFsmAp::move( RedStateAp *state )\n"
+ "{\n"
+ " RedTranst &range = state->outRange;\n"
+ " for ( int rpos = 0; rpos < range.length(); ) {\n"
+ " if ( can( range, rpos ) ) {\n"
+ " while ( range[rpos].value != range[rpos+1].value ) {\n"
+ " single.append( range[rpos+1] );\n"
+ " }\n"
+ " \n"
+ " range[rpos].highKey = range[rpos+1].highKey;\n"
+ " }\n"
+ " else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {\n"
+ " single.append( range[rpos] );\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "\n" );
+
+ test(
+ "->*\n"
+ ".*\n"
+ "/*\"*/\n"
+ "\"/*\"\n"
+ "L'\"'\n"
+ "L\"'\"\n"
+ "...\n" );
+}
+
+#ifdef _____OUTPUT_____
+<195> void
+<195> RedFsmAp
+<197> ::
+<195> move
+<40> (
+<195> RedStateAp
+<42> *
+<195> state
+<41> )
+<123> {
+<195> RedTranst
+<38> &
+<195> range
+<61> =
+<195> state
+<211> ->
+<195> outRange
+<59> ;
+<195> for
+<40> (
+<195> int
+<195> rpos
+<61> =
+<218> 0
+<59> ;
+<195> rpos
+<60> <
+<195> range
+<46> .
+<195> length
+<40> (
+<41> )
+<59> ;
+<41> )
+<123> {
+<195> if
+<40> (
+<195> can
+<40> (
+<195> range
+<44> ,
+<195> rpos
+<41> )
+<41> )
+<123> {
+<195> while
+<40> (
+<195> range
+<91> [
+<195> rpos
+<93> ]
+<46> .
+<195> value
+<224> !=
+<195> range
+<91> [
+<195> rpos
+<43> +
+<218> 1
+<93> ]
+<46> .
+<195> value
+<41> )
+<123> {
+<195> single
+<46> .
+<195> append
+<40> (
+<195> range
+<91> [
+<195> rpos
+<43> +
+<218> 1
+<93> ]
+<41> )
+<59> ;
+<125> }
+<195> range
+<91> [
+<195> rpos
+<93> ]
+<46> .
+<195> highKey
+<61> =
+<195> range
+<91> [
+<195> rpos
+<43> +
+<218> 1
+<93> ]
+<46> .
+<195> highKey
+<59> ;
+<125> }
+<195> else
+<195> if
+<40> (
+<195> keyOps
+<211> ->
+<195> span
+<40> (
+<195> range
+<91> [
+<195> rpos
+<93> ]
+<46> .
+<195> lowKey
+<44> ,
+<195> range
+<91> [
+<195> rpos
+<93> ]
+<46> .
+<195> highKey
+<41> )
+<223> ==
+<218> 1
+<41> )
+<123> {
+<195> single
+<46> .
+<195> append
+<40> (
+<195> range
+<91> [
+<195> rpos
+<93> ]
+<41> )
+<59> ;
+<125> }
+<125> }
+<125> }
+<214> ->*
+<215> .*
+<192> "/*"
+<193> L'"'
+<192> L"'"
+<240> ...
+#endif
diff --git a/test/cppscan3.rl b/test/cppscan3.rl
new file mode 100644
index 0000000..67b8624
--- /dev/null
+++ b/test/cppscan3.rl
@@ -0,0 +1,285 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using namespace std;
+
+#define TK_Dlit 192
+#define TK_Slit 193
+#define TK_Float 194
+#define TK_Id 195
+#define TK_NameSep 197
+#define TK_Arrow 211
+#define TK_PlusPlus 212
+#define TK_MinusMinus 213
+#define TK_ArrowStar 214
+#define TK_DotStar 215
+#define TK_ShiftLeft 216
+#define TK_ShiftRight 217
+#define TK_IntegerDecimal 218
+#define TK_IntegerOctal 219
+#define TK_IntegerHex 220
+#define TK_EqualsEquals 223
+#define TK_NotEquals 224
+#define TK_AndAnd 225
+#define TK_OrOr 226
+#define TK_MultAssign 227
+#define TK_DivAssign 228
+#define TK_PercentAssign 229
+#define TK_PlusAssign 230
+#define TK_MinusAssign 231
+#define TK_AmpAssign 232
+#define TK_CaretAssign 233
+#define TK_BarAssign 234
+#define TK_DotDotDot 240
+#define TK_Whitespace 241
+#define TK_Comment 242
+
+#define BUFSIZE 4096
+
+char buf[BUFSIZE];
+
+struct Scanner
+{
+ int cs, act;
+ const char *ts, *te;
+
+ void token( int tok );
+ void run();
+
+ void init( );
+ void execute( const char *data, int len );
+ int finish( );
+};
+
+%%{
+ machine Scanner;
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" )
+ => { token( TK_Slit );};
+ ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' )
+ => { token( TK_Dlit );};
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* )
+ =>{ token( TK_Id );};
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? )
+ => { token( TK_Float );};
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )
+ => { token( TK_IntegerDecimal );};
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]{0,2} )
+ => { token( TK_IntegerOctal );};
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) )
+ => { token( TK_IntegerHex );};
+
+ # Only buffer the second item, first buffered by symbol. */
+ '::' => {token( TK_NameSep );};
+ '==' => {token( TK_EqualsEquals );};
+ '!=' => {token( TK_NotEquals );};
+ '&&' => {token( TK_AndAnd );};
+ '||' => {token( TK_OrOr );};
+ '*=' => {token( TK_MultAssign );};
+ '/=' => {token( TK_DivAssign );};
+ '%=' => {token( TK_PercentAssign );};
+ '+=' => {token( TK_PlusAssign );};
+ '-=' => {token( TK_MinusAssign );};
+ '&=' => {token( TK_AmpAssign );};
+ '^=' => {token( TK_CaretAssign );};
+ '|=' => {token( TK_BarAssign );};
+ '++' => {token( TK_PlusPlus );};
+ '--' => {token( TK_MinusMinus );};
+ '->' => {token( TK_Arrow );};
+ '->*' => {token( TK_ArrowStar );};
+ '.*' => {token( TK_DotStar );};
+
+ # Three char compounds, first item already buffered. */
+ '...' => { token( TK_DotDotDot );};
+
+ # Single char symbols.
+ ( punct - [_"'] ) => { token( ts[0] );};
+
+ action comment {
+ token( TK_Comment );
+ }
+
+ # Comments and whitespace.
+ '/*' ( any* $0 '*/' @1 ) => comment;
+ '//' ( any* $0 '\n' @1 ) => comment;
+ ( any - 33..126 )+ => { token( TK_Whitespace );};
+
+ *|;
+}%%
+
+%% write data;
+
+void Scanner::init( )
+{
+ %% write init;
+}
+
+/* Returns the count of bytes still in the buffer
+ * (shifted to the biginning) */
+void Scanner::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = pe;
+
+ %% write exec;
+
+ cout << "P: " << (p - data) << endl;
+}
+
+int Scanner::finish( )
+{
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+
+void Scanner::token( int tok )
+{
+ const char *data = ts;
+ int len = te - ts;
+ cout << "<" << tok << "> ";
+ for ( int i = 0; i < len; i++ )
+ cout << data[i];
+ cout << '\n';
+}
+
+void test( const char *buf )
+{
+ int len = strlen( buf );
+ std::ios::sync_with_stdio(false);
+ Scanner scanner;
+ scanner.init();
+
+ scanner.execute( buf, len );
+ if ( scanner.cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cout << "PARSE ERROR" << endl;
+ }
+
+ /* FIXME: Last token may get lost. */
+ scanner.finish();
+}
+
+int main()
+{
+ test(
+ "\"\\\"hi\" /*\n"
+ "*/\n"
+ "44 .44\n"
+ "44. 44\n"
+ "44 . 44\n"
+ "44.44\n"
+ "_hithere22"
+ );
+
+ test(
+ "'\\''\"\\n\\d'\\\"\"\n"
+ "hi\n"
+ "99\n"
+ ".99\n"
+ "99e-4\n"
+ "->*\n"
+ "||\n"
+ "0x98\n"
+ "0x\n"
+ "//\n"
+ "/* * */"
+ );
+
+ test(
+ "'\n"
+ "'\n"
+ );
+
+}
+
+#ifdef _____OUTPUT_____
+<192> "\"hi"
+<241>
+<242> /*
+*/
+<241>
+
+<218> 44
+<241>
+<194> .44
+<241>
+
+<194> 44.
+<241>
+<218> 44
+<241>
+
+<218> 44
+<241>
+<46> .
+<241>
+<218> 44
+<241>
+
+<194> 44.44
+<241>
+
+<195> _hithere22
+P: 51
+<193> '\''
+<192> "\n\d'\""
+<241>
+
+<195> hi
+<241>
+
+<218> 99
+<241>
+
+<194> .99
+<241>
+
+<194> 99e-4
+<241>
+
+<214> ->*
+<241>
+
+<226> ||
+<241>
+
+<220> 0x98
+<241>
+
+<218> 0
+<195> x
+<241>
+
+<242> //
+
+<242> /* * */
+P: 55
+P: 1
+PARSE ERROR
+#endif
diff --git a/test/cppscan4.rl b/test/cppscan4.rl
new file mode 100644
index 0000000..42a97f1
--- /dev/null
+++ b/test/cppscan4.rl
@@ -0,0 +1,302 @@
+/*
+ * @LANG: d
+ */
+
+module cppscan;
+
+import std.c.stdio;
+import std.string;
+
+const int BUFSIZE = 2048;
+
+const int TK_Dlit = 192;
+const int TK_Slit = 193;
+const int TK_Float = 194;
+const int TK_Id = 195;
+const int TK_NameSep = 197;
+const int TK_Arrow = 211;
+const int TK_PlusPlus = 212;
+const int TK_MinusMinus = 213;
+const int TK_ArrowStar = 214;
+const int TK_DotStar = 215;
+const int TK_ShiftLeft = 216;
+const int TK_ShiftRight = 217;
+const int TK_IntegerDecimal = 218;
+const int TK_IntegerOctal = 219;
+const int TK_IntegerHex = 220;
+const int TK_EqualsEquals = 223;
+const int TK_NotEquals = 224;
+const int TK_AndAnd = 225;
+const int TK_OrOr = 226;
+const int TK_MultAssign = 227;
+const int TK_DivAssign = 228;
+const int TK_PercentAssign = 229;
+const int TK_PlusAssign = 230;
+const int TK_MinusAssign = 231;
+const int TK_AmpAssign = 232;
+const int TK_CaretAssign = 233;
+const int TK_BarAssign = 234;
+const int TK_DotDotDot = 240;
+
+
+class Scanner
+{
+ int line, col;
+ int tokStart;
+ int inlineDepth;
+ int count;
+ char[] tokBuf;
+ char[] nonTokBuf;
+
+ void pass(char c) { nonTokBuf ~= c; }
+ void buf(char c) { tokBuf ~= c; }
+ void token( int id )
+ {
+ /* Leader. */
+ if ( nonTokBuf.length > 0 ) {
+ printf("%.*s", nonTokBuf);
+ nonTokBuf = "";
+ }
+
+ /* Token data. */
+ printf("<%d>%.*s", id, tokBuf);
+
+ tokBuf = "";
+ }
+
+ int cs, stack, top;
+
+ %%{
+ machine Scanner;
+
+ action pass { pass(fc); }
+ action buf { buf(fc); }
+
+ action emit_slit { token( TK_Slit ); }
+ action emit_dlit { token( TK_Dlit ); }
+ action emit_id { token( TK_Id ); }
+ action emit_integer_decimal { token( TK_IntegerDecimal ); }
+ action emit_integer_octal { token( TK_IntegerOctal ); }
+ action emit_integer_hex { token( TK_IntegerHex ); }
+ action emit_float { token( TK_Float ); }
+ action emit_symbol { token( tokBuf[0] ); }
+ action tokst { tokStart = col; }
+
+ # Single and double literals.
+ slit = ( 'L'? ( "'" ( [^'\\\n] | /\\./ )* "'" ) $buf ) >tokst %emit_slit;
+ dlit = ( 'L'? ( '"' ( [^"\\\n] | /\\./ )* '"' ) $buf ) >tokst %emit_dlit;
+
+ # Identifiers
+ id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) >tokst $buf %emit_id;
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+ float =
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? ) >tokst $buf %emit_float;
+
+ # Integer decimal. Leading part buffered by float.
+ integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} $buf ) %emit_integer_decimal;
+
+ # Integer octal. Leading part buffered by float.
+ integer_octal = ( '0' [0-9]+ [ulUL]{0,2} $buf ) %emit_integer_octal;
+
+ # Integer hex. Leading 0 buffered by float.
+ integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) $buf ) %emit_integer_hex;
+
+ # Only buffer the second item, first buffered by symbol. */
+ namesep = '::' @buf %{token( TK_NameSep );};
+ deqs = '==' @buf %{token( TK_EqualsEquals );};
+ neqs = '!=' @buf %{token( TK_NotEquals );};
+ and_and = '&&' @buf %{token( TK_AndAnd );};
+ or_or = '||' @buf %{token( TK_OrOr );};
+ mult_assign = '*=' @buf %{token( TK_MultAssign );};
+ percent_assign = '%=' @buf %{token( TK_PercentAssign );};
+ plus_assign = '+=' @buf %{token( TK_PlusAssign );};
+ minus_assign = '-=' @buf %{token( TK_MinusAssign );};
+ amp_assign = '&=' @buf %{token( TK_AmpAssign );};
+ caret_assign = '^=' @buf %{token( TK_CaretAssign );};
+ bar_assign = '|=' @buf %{token( TK_BarAssign );};
+ plus_plus = '++' @buf %{token( TK_PlusPlus );};
+ minus_minus = '--' @buf %{token( TK_MinusMinus );};
+ arrow = '->' @buf %{token( TK_Arrow );};
+ arrow_star = '->*' @buf %{token( TK_ArrowStar );};
+ dot_star = '.*' @buf %{token( TK_DotStar );};
+
+ # Buffer both items. *
+ div_assign = '/=' @{buf('/');buf(fc);} %{token( TK_DivAssign );};
+
+ # Double dot is sent as two dots.
+ dot_dot = '..' %{token('.'); buf('.'); token('.');};
+
+ # Three char compounds, first item already buffered. */
+ dot_dot_dot = '...' %{buf('.'); buf('.'); token( TK_DotDotDot );};
+
+ # All compunds
+ compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
+ div_assign | percent_assign | plus_assign | minus_assign |
+ amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
+ arrow | arrow_star | dot_star | dot_dot | dot_dot_dot;
+
+ # Single char symbols.
+ symbol =
+ ( punct - [./_"'] ) >tokst $buf %emit_symbol |
+ # Do not immediately buffer slash, may be start of comment.
+ '/' >tokst %{ buf('/'); token( '/' ); } |
+ # Dot covered by float.
+ '.' %emit_symbol;
+
+ # Comments and whitespace.
+ commc = '/*' @{pass('/'); pass('*');} ( any* $0 '*/' @1 ) $pass;
+ commcc = '//' @{pass('/'); pass('/');} ( any* $0 '\n' @1 ) $pass;
+ whitespace = ( any - ( 0 | 33..126 ) )+ $pass;
+
+ action onEOFChar {
+ /* On EOF char, write out the non token buffer. */
+ printf("%.*s", nonTokBuf);
+ nonTokBuf = "";
+ }
+
+ # Using 0 as eof. If seeingAs a result all null characters get ignored.
+ EOF = 0 @onEOFChar;
+
+ # All outside code tokens.
+ tokens = (
+ id | slit | dlit | float | integer_decimal |
+ integer_octal | integer_hex | compound | symbol );
+ nontok = ( commc | commcc | whitespace | EOF );
+
+ position = (
+ '\n' @{ line += 1; col = 1; } |
+ [^\n] @{ col += 1; } )*;
+
+ main := ( ( tokens | nontok )** ) & position;
+ }%%
+
+ %% write data noprefix;
+
+ void init( )
+ {
+ /* A count of the number of characters in
+ * a token. Used for % sequences. */
+ count = 0;
+ line = 1;
+ col = 1;
+ %% write init;
+ return 1;
+ }
+
+ int execute( char* _data, int _len )
+ {
+ char *p = _data;
+ char *pe = _data + _len;
+ char *eof = null;
+
+ %% write exec;
+
+ if ( cs == error )
+ return -1;
+ if ( cs >= first_final )
+ return 1;
+ return 0;
+ }
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( )
+ {
+ if ( cs == error )
+ return -1;
+ if ( cs >= first_final )
+ return 1;
+ return 0;
+ }
+};
+
+void test(char[] buf)
+{
+ Scanner scanner = new Scanner();
+ scanner.init();
+ scanner.execute( buf.ptr, buf.length );
+
+ /* The last token is ignored (because there is no next token). Send
+ * trailing null to force the last token into whitespace. */
+ char eof_char = 0;
+ if ( scanner.execute( &eof_char, 1 ) <= 0 ) {
+ fprintf(stderr, "cppscan: scan failed\n");
+ }
+}
+
+int main()
+{
+ test(
+ "/*\n"
+ " * Copyright \n"
+ " */\n"
+ "\n"
+ "RedTransAp *RedFsmAp::reduceTrans( TransAp *trans )\n"
+ "{\n"
+ " RedAction *action = 0;\n"
+ " if ( trans->actionTable.length() > 0 ) {\n"
+ " if ( actionMap.insert( trans->actionTable, &action ) )\n"
+ " action->id = nextActionId++;\n"
+ " }\n"
+ " \n"
+ " RedStateAp *targ = (RedStateAp*)trans->toState;\n"
+ " if ( action == 0 ) {\n"
+ " delete trans;\n"
+ " return 0;\n"
+ " }\n"
+ "\n"
+ " trans->~TransAp();\n"
+ " inDict = new(trans) RedTransAp( targ, action, nextTransId++ );\n"
+ " transSet.insert( inDict );\n"
+ "}\n"
+ );
+
+ test(
+ "->*\n"
+ ".*\n"
+ "/*\"*/\n"
+ "\"/*\"\n"
+ "L'\"'\n"
+ "L\"'\"\n"
+ );
+
+ return 0;
+}
+
+/+ _____OUTPUT_____
+/*
+ * Copyright
+ */
+
+<195>RedTransAp <42>*<195>RedFsmAp<197>::<195>reduceTrans<40>( <195>TransAp <42>*<195>trans <41>)
+<123>{
+ <195>RedAction <42>*<195>action <61>= <218>0<59>;
+ <195>if <40>( <195>trans<211>-><195>actionTable<46>.<195>length<40>(<41>) <62>> <218>0 <41>) <123>{
+ <195>if <40>( <195>actionMap<46>.<195>insert<40>( <195>trans<211>-><195>actionTable<44>, <38>&<195>action <41>) <41>)
+ <195>action<211>-><195>id <61>= <195>nextActionId<212>++<59>;
+ <125>}
+
+ <195>RedStateAp <42>*<195>targ <61>= <40>(<195>RedStateAp<42>*<41>)<195>trans<211>-><195>toState<59>;
+ <195>if <40>( <195>action <223>== <218>0 <41>) <123>{
+ <195>delete <195>trans<59>;
+ <195>return <218>0<59>;
+ <125>}
+
+ <195>trans<211>-><126>~<195>TransAp<40>(<41>)<59>;
+ <195>inDict <61>= <195>new<40>(<195>trans<41>) <195>RedTransAp<40>( <195>targ<44>, <195>action<44>, <195>nextTransId<212>++ <41>)<59>;
+ <195>transSet<46>.<195>insert<40>( <195>inDict <41>)<59>;
+<125>}
+<214>->*
+<215>.*
+/*"*/
+<192>"/*"
+<193>L'"'
+<192>L"'"
++++++++++++++++++/
diff --git a/test/cppscan5.rl b/test/cppscan5.rl
new file mode 100644
index 0000000..057725a
--- /dev/null
+++ b/test/cppscan5.rl
@@ -0,0 +1,275 @@
+/*
+ * @LANG: d
+ */
+
+/*
+ * Test in and out state actions.
+ */
+
+import std.c.stdio;
+import std.string;
+
+static const int TK_Dlit = 192;
+static const int TK_Slit = 193;
+static const int TK_Float = 194;
+static const int TK_Id = 195;
+static const int TK_NameSep = 197;
+static const int TK_Arrow = 211;
+static const int TK_PlusPlus = 212;
+static const int TK_MinusMinus = 213;
+static const int TK_ArrowStar = 214;
+static const int TK_DotStar = 215;
+static const int TK_ShiftLeft = 216;
+static const int TK_ShiftRight = 217;
+static const int TK_IntegerDecimal = 218;
+static const int TK_IntegerOctal = 219;
+static const int TK_IntegerHex = 220;
+static const int TK_EqualsEquals = 223;
+static const int TK_NotEquals = 224;
+static const int TK_AndAnd = 225;
+static const int TK_OrOr = 226;
+static const int TK_MultAssign = 227;
+static const int TK_DivAssign = 228;
+static const int TK_PercentAssign = 229;
+static const int TK_PlusAssign = 230;
+static const int TK_MinusAssign = 231;
+static const int TK_AmpAssign = 232;
+static const int TK_CaretAssign = 233;
+static const int TK_BarAssign = 234;
+static const int TK_DotDotDot = 240;
+static const int TK_Whitespace = 241;
+static const int TK_Comment = 242;
+
+class Scanner
+{
+ int cs, act;
+ char *ts, te;
+
+ void token( int tok )
+ {
+ char *data = ts;
+ int len = te - ts;
+ printf( "<%i> ", tok );
+ for ( int i = 0; i < len; i++ )
+ printf( "%c", data[i] );
+ printf( "\n" );
+ }
+
+ %%{
+
+ machine Scanner;
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" )
+ => { token( TK_Slit );};
+ ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' )
+ => { token( TK_Dlit );};
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* )
+ =>{ token( TK_Id );};
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? )
+ => { token( TK_Float );};
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )
+ => { token( TK_IntegerDecimal );};
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]{0,2} )
+ => { token( TK_IntegerOctal );};
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) )
+ => { token( TK_IntegerHex );};
+
+ # Only buffer the second item, first buffered by symbol. */
+ '::' => {token( TK_NameSep );};
+ '==' => {token( TK_EqualsEquals );};
+ '!=' => {token( TK_NotEquals );};
+ '&&' => {token( TK_AndAnd );};
+ '||' => {token( TK_OrOr );};
+ '*=' => {token( TK_MultAssign );};
+ '/=' => {token( TK_DivAssign );};
+ '%=' => {token( TK_PercentAssign );};
+ '+=' => {token( TK_PlusAssign );};
+ '-=' => {token( TK_MinusAssign );};
+ '&=' => {token( TK_AmpAssign );};
+ '^=' => {token( TK_CaretAssign );};
+ '|=' => {token( TK_BarAssign );};
+ '++' => {token( TK_PlusPlus );};
+ '--' => {token( TK_MinusMinus );};
+ '->' => {token( TK_Arrow );};
+ '->*' => {token( TK_ArrowStar );};
+ '.*' => {token( TK_DotStar );};
+
+ # Three char compounds, first item already buffered. */
+ '...' => { token( TK_DotDotDot );};
+
+ # Single char symbols.
+ ( punct - [_"'] ) => { token( ts[0] );};
+
+ action comment {
+ token( TK_Comment );
+ }
+
+ # Comments and whitespace.
+ '/*' ( any* $0 '*/' @1 ) => comment;
+ '//' ( any* $0 '\n' @1 ) => comment;
+ ( any - 33..126 )+ => { token( TK_Whitespace );};
+
+ *|;
+
+ }%%
+
+ %% write data noprefix;
+
+ void init( )
+ {
+ %% write init;
+ }
+
+ void execute( char* data, int len )
+ {
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+
+ %% write exec;
+ }
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( )
+ {
+ if ( cs == error )
+ return -1;
+ if ( cs >= first_final )
+ return 1;
+ return 0;
+ }
+};
+
+static const int BUFSIZE = 12;
+
+void test( char buf[] )
+{
+ Scanner scanner = new Scanner();
+ scanner.init();
+
+ scanner.execute( buf.ptr, buf.length );
+ if ( scanner.cs == Scanner.error ) {
+ /* Machine failed before finding a token. */
+ printf("PARSE ERROR\n");
+ }
+ scanner.finish();
+ return 0;
+}
+
+int main()
+{
+ test(
+ "\"\\\"hi\" /*\n"
+ "*/\n"
+ "44 .44\n"
+ "44. 44\n"
+ "44 . 44\n"
+ "44.44\n"
+ "_hithere22"
+ );
+
+ test(
+ "'\\''\"\\n\\d'\\\"\"\n"
+ "hi\n"
+ "99\n"
+ ".99\n"
+ "99e-4\n"
+ "->*\n"
+ "||\n"
+ "0x98\n"
+ "0x\n"
+ "//\n"
+ "/* * */"
+ );
+
+ test(
+ "'\n"
+ "'\n"
+ );
+
+ return 0;
+}
+
+/+ _____OUTPUT_____
+<192> "\"hi"
+<241>
+<242> /*
+*/
+<241>
+
+<218> 44
+<241>
+<194> .44
+<241>
+
+<194> 44.
+<241>
+<218> 44
+<241>
+
+<218> 44
+<241>
+<46> .
+<241>
+<218> 44
+<241>
+
+<194> 44.44
+<241>
+
+<195> _hithere22
+<193> '\''
+<192> "\n\d'\""
+<241>
+
+<195> hi
+<241>
+
+<218> 99
+<241>
+
+<194> .99
+<241>
+
+<194> 99e-4
+<241>
+
+<214> ->*
+<241>
+
+<226> ||
+<241>
+
+<220> 0x98
+<241>
+
+<218> 0
+<195> x
+<241>
+
+<242> //
+
+<242> /* * */
+PARSE ERROR
++++++++++++++++++++/
diff --git a/test/cppscan6.rl b/test/cppscan6.rl
new file mode 100644
index 0000000..ad2d266
--- /dev/null
+++ b/test/cppscan6.rl
@@ -0,0 +1,358 @@
+/*
+ * @LANG: indep
+ *
+ * const char *data = ts;
+ * int len = te - ts;
+ * cout << "<" << tok << "> ";
+ * for ( int i = 0; i < len; i++ )
+ * cout << data[i];
+ * cout << '\n';
+ */
+ptr ts;
+ptr te;
+int act;
+int token;
+%%
+%%{
+ machine scanner;
+
+ action comment {
+ token = 242;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ }
+
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | '\\' any )* "'" )
+ => {
+ token = 193;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ ( 'L'? '"' ( [^"\\\n] | '\\' any )* '"' )
+ => {
+ token = 192;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* )
+ =>{
+ token = 195;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? )
+ => {
+ token = 194;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]? )
+ => {
+ token = 218;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]? )
+ => {
+ token = 219;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]? ) )
+ => {
+ token = 220;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Only buffer the second item, first buffered by symbol.
+ '::' => {
+ token = 197;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '==' => {
+ token = 223;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '!=' => {
+ token = 224;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '&&' => {
+ token = 225;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '||' => {
+ token = 226;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '*=' => {
+ token = 227;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '/=' => {
+ token = 228;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '%=' => {
+ token = 229;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '+=' => {
+ token = 230;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '-=' => {
+ token = 231;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '&=' => {
+ token = 232;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '^=' => {
+ token = 233;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '|=' => {
+ token = 234;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '++' => {
+ token = 212;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '--' => {
+ token = 213;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '->' => {
+ token = 211;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '->*' => {
+ token = 214;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ '.*' => {
+ token = 215;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Three char compounds, first item already buffered.
+ '...' => {
+ token = 240;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Single char symbols.
+ ( punct - [_"'] ) => {
+ token = <int>(first_token_char);
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+
+ # Comments and whitespace.
+ '/!' ( any* $0 '!/' @1 ) => comment;
+ '//' ( any* $0 '\n' @1 ) => comment;
+ ( any - 33..126 )+ => {
+ token = 241;
+ prints "<";
+ printi token;
+ prints "> ";
+ print_token;
+ prints "\n";
+ };
+ *|;
+}%%
+/* _____INPUT_____
+"\"\\\"hi\" /!\n!/\n44 .44\n44. 44\n44 . 44\n44.44\n_hithere22"
+"'\\''\"\\n\\d'\\\"\"\nhi\n99\n.99\n99e-4\n->*\n||\n0x98\n0x\n//\n/! * !/"
+"'\n'\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+<192> "\"hi"
+<241>
+<242> /!
+!/
+<241>
+
+<218> 44
+<241>
+<194> .44
+<241>
+
+<194> 44.
+<241>
+<218> 44
+<241>
+
+<218> 44
+<241>
+<46> .
+<241>
+<218> 44
+<241>
+
+<194> 44.44
+<241>
+
+<195> _hithere22
+ACCEPT
+<193> '\''
+<192> "\n\d'\""
+<241>
+
+<195> hi
+<241>
+
+<218> 99
+<241>
+
+<194> .99
+<241>
+
+<194> 99e-4
+<241>
+
+<214> ->*
+<241>
+
+<226> ||
+<241>
+
+<220> 0x98
+<241>
+
+<218> 0
+<195> x
+<241>
+
+<242> //
+
+<242> /! * !/
+ACCEPT
+FAIL
+_____OUTPUT_____ */
diff --git a/test/element1.rl b/test/element1.rl
new file mode 100644
index 0000000..0795778
--- /dev/null
+++ b/test/element1.rl
@@ -0,0 +1,108 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+using namespace std;
+
+struct LangEl
+{
+ int key;
+ const char *name;
+};
+
+struct Fsm
+{
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ int init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( LangEl *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+
+};
+
+%%{
+ machine Fsm;
+
+ alphtype int;
+ getkey fpc->key;
+ variable eof eof_marker;
+
+ action a1 {}
+ action a2 {}
+ action a3 {}
+
+ main := ( 1 2* 3 )
+ ${cout << fpc->name << endl;}
+ %/{cout << "accept" << endl;};
+}%%
+
+%% write data;
+
+int Fsm::init( )
+{
+ %% write init;
+ return 0;
+}
+
+int Fsm::execute( LangEl *data, int len )
+{
+ LangEl *p = data;
+ LangEl *pe = data + len;
+ LangEl *eof_marker = pe;
+ %% write exec;
+
+ if ( cs == Fsm_error )
+ return -1;
+ if ( cs >= Fsm_first_final )
+ return 1;
+ return 0;
+}
+
+int Fsm::finish( )
+{
+ if ( cs == Fsm_error )
+ return -1;
+ if ( cs >= Fsm_first_final )
+ return 1;
+ return 0;
+}
+
+int main( )
+{
+ static Fsm fsm;
+ static LangEl lel[] = {
+ {1, "one"},
+ {2, "two-a"},
+ {2, "two-b"},
+ {2, "two-c"},
+ {3, "three"}
+ };
+
+ fsm.init();
+ fsm.execute( lel, 5 );
+ fsm.finish();
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+one
+two-a
+two-b
+two-c
+three
+accept
+#endif
diff --git a/test/element2.rl b/test/element2.rl
new file mode 100644
index 0000000..7aa6217
--- /dev/null
+++ b/test/element2.rl
@@ -0,0 +1,83 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+
+struct LangEl
+{
+ int key;
+ char *name;
+};
+
+struct fsm
+{
+ int cs;
+};
+
+%%{
+ machine fsm;
+ alphtype int;
+ getkey fpc->key;
+ variable cs fsm->cs;
+
+ action a1 {}
+ action a2 {}
+ action a3 {}
+
+ main := ( 1 2* 3 )
+ ${printf("%s\n", fpc->name);}
+ %/{printf("accept\n");};
+}%%
+
+%% write data;
+
+void fsm_init( struct fsm *fsm )
+{
+ %% write init;
+}
+
+void fsm_execute( struct fsm *fsm, struct LangEl *_data, int _len )
+{
+ struct LangEl *p = _data;
+ struct LangEl *pe = _data+_len;
+ struct LangEl *eof = pe;
+
+ %% write exec;
+}
+
+int fsm_finish( struct fsm *fsm )
+{
+ if ( fsm->cs == fsm_error )
+ return -1;
+ if ( fsm->cs >= fsm_first_final )
+ return 1;
+ return 0;
+}
+
+int main()
+{
+ static struct fsm fsm;
+ static struct LangEl lel[] = {
+ {1, "one"},
+ {2, "two-a"},
+ {2, "two-b"},
+ {2, "two-c"},
+ {3, "three"}
+ };
+
+ fsm_init( &fsm );
+ fsm_execute( &fsm, lel, 5 );
+ fsm_finish( &fsm );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+one
+two-a
+two-b
+two-c
+three
+accept
+#endif
diff --git a/test/element3.rl b/test/element3.rl
new file mode 100644
index 0000000..66435f4
--- /dev/null
+++ b/test/element3.rl
@@ -0,0 +1,144 @@
+/*
+ * @LANG: obj-c
+ */
+
+#include <stdio.h>
+#include <objc/Object.h>
+
+struct LangEl
+{
+ int key;
+ char *name;
+};
+
+@interface Fsm : Object
+{
+@public
+ int cs;
+};
+
+// Initialize the machine. Invokes any init statement blocks. Returns 0
+// if the machine begins in a non-accepting state and 1 if the machine
+// begins in an accepting state.
+- (int) initFsm;
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (int) executeWithData:( struct LangEl *)data len:(int)len;
+
+// Indicate that there is no more data. Returns -1 if the machine finishes
+// in the error state and does not accept, 0 if the machine finishes
+// in any other non-accepting state and 1 if the machine finishes in an
+// accepting state.
+- (int) finish;
+
+@end;
+
+
+@implementation Fsm
+
+%%{
+ machine Fsm;
+
+ alphtype int;
+ getkey fpc->key;
+
+ action a1 {}
+ action a2 {}
+ action a3 {}
+
+ main := ( 1 2* 3 )
+ ${printf("%s\n", fpc->name);}
+ %/{printf("accept\n");};
+}%%
+
+%% write data;
+
+- (int) initFsm;
+{
+ %% write init;
+ return 0;
+}
+
+- (int) executeWithData:( struct LangEl *)_data len:(int)_len;
+{
+ struct LangEl *p = _data;
+ struct LangEl *pe = _data + _len;
+ struct LangEl *eof = pe;
+ %% write exec;
+
+ if ( self->cs == Fsm_error )
+ return -1;
+ return ( self->cs >= Fsm_first_final ) ? 1 : 0;
+}
+
+- (int) finish;
+{
+ if ( self->cs == Fsm_error )
+ return -1;
+ return ( self->cs >= Fsm_first_final ) ? 1 : 0;
+}
+
+
+@end
+
+int main()
+{
+ static Fsm *fsm;
+ static struct LangEl lel[] = {
+ {1, "one"},
+ {2, "two-a"},
+ {2, "two-b"},
+ {2, "two-c"},
+ {3, "three"}
+ };
+
+ fsm = [[Fsm alloc] init];
+ [fsm initFsm];
+ [fsm executeWithData:lel len:5];
+ [fsm finish];
+
+ return 0;
+}
+
+@interface Fsm2 : Object
+{
+ // The current state may be read and written to from outside of the
+ // machine. From within action code, curs is -1 and writing to it has no
+ // effect.
+ @public
+ int cs;
+
+ @protected
+
+}
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (int)
+executeWithElements:(int) elements
+length:(unsigned)length;
+
+@end
+
+@implementation Fsm2
+- (int)
+executeWithElements:(int)elements
+length:(unsigned)length;
+{
+ return 0;
+}
+@end
+
+#ifdef _____OUTPUT_____
+one
+two-a
+two-b
+two-c
+three
+accept
+#endif
diff --git a/test/eofact.h b/test/eofact.h
new file mode 100644
index 0000000..d547f87
--- /dev/null
+++ b/test/eofact.h
@@ -0,0 +1,9 @@
+#ifndef _EOFACT_H
+#define _EOFACT_H
+
+struct eofact
+{
+ int cs;
+};
+
+#endif
diff --git a/test/eofact.rl b/test/eofact.rl
new file mode 100644
index 0000000..eeb91b8
--- /dev/null
+++ b/test/eofact.rl
@@ -0,0 +1,51 @@
+/*
+ * @LANG: indep
+ *
+ * Test works with split code gen.
+ */
+%%
+%%{
+ machine eofact;
+
+ action a1 { prints "a1\n"; }
+ action a2 { prints "a2\n"; }
+ action a3 { prints "a3\n"; }
+ action a4 { prints "a4\n"; }
+
+
+ main := (
+ 'hello' @eof a1 %eof a2 '\n'? |
+ 'there' @eof a3 %eof a4
+ );
+
+}%%
+/* _____INPUT_____
+""
+"h"
+"hell"
+"hello"
+"hello\n"
+"t"
+"ther"
+"there"
+"friend"
+_____INPUT_____ */
+/* _____OUTPUT_____
+a1
+a3
+FAIL
+a1
+FAIL
+a1
+FAIL
+a2
+ACCEPT
+ACCEPT
+a3
+FAIL
+a3
+FAIL
+a4
+ACCEPT
+FAIL
+_____OUTPUT_____ */
diff --git a/test/erract1.rl b/test/erract1.rl
new file mode 100644
index 0000000..d5c01ea
--- /dev/null
+++ b/test/erract1.rl
@@ -0,0 +1,145 @@
+/*
+ * @LANG: c++
+ */
+
+/*
+ * Test error actions.
+ */
+
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct ErrAct
+{
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ int init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine ErrAct;
+
+ action expect_digit_plus_minus { printf(" DIGIT PLUS MINUS\n"); }
+ action expect_digit { printf(" DIGIT\n"); }
+ action expect_digit_decimal { printf(" DIGIT DECIMAL\n"); }
+
+ float = (
+ (
+ [\-+] >err expect_digit_plus_minus %err expect_digit |
+ ""
+ )
+ ( [0-9] [0-9]* $err expect_digit_decimal )
+ ( '.' [0-9]+ $err expect_digit )?
+ );
+
+ main := float '\n';
+}%%
+
+%% write data;
+
+int ErrAct::init( )
+{
+ %% write init;
+ return 0;
+}
+
+int ErrAct::execute( const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+ const char *eof = pe;
+ %% write exec;
+
+ if ( cs == ErrAct_error )
+ return -1;
+ if ( cs >= ErrAct_first_final )
+ return 1;
+ return 0;
+}
+
+int ErrAct::finish( )
+{
+ if ( cs == ErrAct_error )
+ return -1;
+ if ( cs >= ErrAct_first_final )
+ return 1;
+ return 0;
+}
+
+#define BUFSIZE 1024
+
+void test( const char *buf )
+{
+ ErrAct errAct;
+ errAct.init();
+ errAct.execute( buf, strlen(buf) );
+ if ( errAct.finish() > 0 )
+ cout << "ACCEPT" << endl;
+ else
+ cout << "FAIL" << endl;
+}
+
+int main()
+{
+ test( "1\n" );
+ test( "+1\n" );
+ test( "-1\n" );
+ test( "1.1\n" );
+ test( "+1.1\n" );
+ test( "-1.1\n" );
+ test( "a\n" );
+ test( "-\n" );
+ test( "+\n" );
+ test( "-a\n" );
+ test( "+b\n" );
+ test( "1.\n" );
+ test( "1d\n" );
+ test( "1.d\n" );
+ test( "1.1d\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ DIGIT PLUS MINUS
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT DECIMAL
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+#endif
diff --git a/test/erract2.rl b/test/erract2.rl
new file mode 100644
index 0000000..b1fbfbf
--- /dev/null
+++ b/test/erract2.rl
@@ -0,0 +1,92 @@
+/*
+ * @LANG: indep
+ *
+ * Test error actions.
+ */
+%%
+%%{
+ machine ErrAct;
+
+ action err_start { prints "err_start\n"; }
+ action err_all { prints "err_all\n"; }
+ action err_middle { prints "err_middle\n"; }
+ action err_out { prints "err_out\n"; }
+
+ action eof_start { prints "eof_start\n"; }
+ action eof_all { prints "eof_all\n"; }
+ action eof_middle { prints "eof_middle\n"; }
+ action eof_out { prints "eof_out\n"; }
+
+ main := ( 'hello'
+ >err err_start $err err_all <>err err_middle %err err_out
+ >eof eof_start $eof eof_all <>eof eof_middle %eof eof_out
+ ) '\n';
+}%%
+
+/* _____INPUT_____
+""
+"h"
+"x"
+"he"
+"hx"
+"hel"
+"hex"
+"hell"
+"helx"
+"hello"
+"hellx"
+"hello\n"
+"hellox"
+_____INPUT_____ */
+
+/* _____OUTPUT_____
+err_start
+eof_start
+err_all
+eof_all
+FAIL
+err_all
+err_middle
+eof_all
+eof_middle
+FAIL
+err_start
+err_all
+FAIL
+err_all
+err_middle
+eof_all
+eof_middle
+FAIL
+err_all
+err_middle
+FAIL
+err_all
+err_middle
+eof_all
+eof_middle
+FAIL
+err_all
+err_middle
+FAIL
+err_all
+err_middle
+eof_all
+eof_middle
+FAIL
+err_all
+err_middle
+FAIL
+err_all
+err_out
+eof_all
+eof_out
+FAIL
+err_all
+err_middle
+FAIL
+ACCEPT
+err_all
+err_out
+FAIL
+_____OUTPUT_____ */
diff --git a/test/erract3.rl b/test/erract3.rl
new file mode 100644
index 0000000..adfe76c
--- /dev/null
+++ b/test/erract3.rl
@@ -0,0 +1,104 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#define IDENT_BUFLEN 256
+
+struct erract
+{
+ int cs;
+};
+
+%%{
+ machine erract;
+ variable cs fsm->cs;
+
+ # The data that is to go into the fsm structure.
+ action hello_fails { printf("hello fails\n");}
+
+ newline = ( any | '\n' @{printf("newline\n");} )*;
+ hello = 'hello\n'* $lerr hello_fails @eof hello_fails;
+ main := newline | hello;
+}%%
+
+%% write data;
+
+void erract_init( struct erract *fsm )
+{
+ %% write init;
+}
+
+void erract_execute( struct erract *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+ const char *eof = pe;
+ %% write exec;
+}
+
+int erract_finish( struct erract *fsm )
+{
+ if ( fsm->cs == erract_error )
+ return -1;
+ else if ( fsm->cs >= erract_first_final )
+ return 1;
+ return 0;
+}
+
+#include <stdio.h>
+#include <string.h>
+
+struct erract fsm;
+
+void test( char *buf )
+{
+ int len = strlen(buf);
+ erract_init( &fsm );
+ erract_execute( &fsm, buf, len );
+ if ( erract_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test(
+ "hello\n"
+ "hello\n"
+ "hello\n"
+ );
+
+ test(
+ "hello\n"
+ "hello\n"
+ "hello there\n"
+ );
+
+ test(
+ "hello\n"
+ "hello\n"
+ "he" );
+
+ test( "" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+newline
+newline
+newline
+ACCEPT
+newline
+newline
+hello fails
+newline
+ACCEPT
+newline
+newline
+hello fails
+ACCEPT
+ACCEPT
+#endif
diff --git a/test/erract4.rl b/test/erract4.rl
new file mode 100644
index 0000000..bef1139
--- /dev/null
+++ b/test/erract4.rl
@@ -0,0 +1,135 @@
+/*
+ * @LANG: obj-c
+ */
+
+#include <stdio.h>
+#include <objc/Object.h>
+
+#define IDENT_BUFLEN 256
+
+@interface ErrAct : Object
+{
+@public
+ int cs;
+};
+
+// Initialize the machine. Invokes any init statement blocks. Returns 0
+// if the machine begins in a non-accepting state and 1 if the machine
+// begins in an accepting state.
+- (int) initFsm;
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (void) executeWithData:(const char *)data len:(int)len;
+
+// Indicate that there is no more data. Returns -1 if the machine finishes
+// in the error state and does not accept, 0 if the machine finishes
+// in any other non-accepting state and 1 if the machine finishes in an
+// accepting state.
+- (int) finish;
+
+@end
+
+@implementation ErrAct
+
+%%{
+ machine ErrAct;
+
+ # The data that is to go into the fsm structure.
+ action hello_fails { printf("hello fails\n");}
+
+ newline = ( any | '\n' @{printf("newline\n");} )*;
+ hello = 'hello\n'* $^hello_fails @/hello_fails;
+ main := newline | hello;
+}%%
+
+%% write data;
+
+- (int) initFsm;
+{
+ %% write init;
+ return 1;
+}
+
+- (void) executeWithData:(const char *)_data len:(int)_len;
+{
+ const char *p = _data;
+ const char *pe = _data + _len;
+ const char *eof = pe;
+ %% write exec;
+}
+
+- (int) finish;
+{
+ if ( cs == ErrAct_error )
+ return -1;
+ else if ( cs >= ErrAct_first_final )
+ return 1;
+ return 0;
+}
+
+@end
+
+#include <stdio.h>
+#include <string.h>
+#define BUFSIZE 2048
+
+ErrAct *fsm;
+char buf[BUFSIZE];
+
+void test( char *buf )
+{
+ int len = strlen(buf);
+ fsm = [[ErrAct alloc] init];
+
+ [fsm initFsm];
+ [fsm executeWithData:buf len:len];
+ if ( [fsm finish] > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test(
+ "hello\n"
+ "hello\n"
+ "hello\n"
+ );
+
+ test(
+ "hello\n"
+ "hello\n"
+ "hello there\n"
+ );
+
+ test(
+ "hello\n"
+ "hello\n"
+ "he" );
+
+ test( "" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+newline
+newline
+newline
+ACCEPT
+newline
+newline
+hello fails
+newline
+ACCEPT
+newline
+newline
+hello fails
+ACCEPT
+ACCEPT
+#endif
diff --git a/test/erract5.rl b/test/erract5.rl
new file mode 100644
index 0000000..0ea6e9a
--- /dev/null
+++ b/test/erract5.rl
@@ -0,0 +1,146 @@
+/*
+ * @LANG: obj-c
+ */
+
+/*
+ * Test error actions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <objc/Object.h>
+
+
+@interface ErrAct : Object
+{
+@public
+ int cs;
+};
+
+// Initialize the machine. Invokes any init statement blocks. Returns 0
+// if the machine begins in a non-accepting state and 1 if the machine
+// begins in an accepting state.
+- (int) initFsm;
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (void) executeWithData:(const char *)data len:(int)len;
+
+// Indicate that there is no more data. Returns -1 if the machine finishes
+// in the error state and does not accept, 0 if the machine finishes
+// in any other non-accepting state and 1 if the machine finishes in an
+// accepting state.
+- (int) finish;
+
+@end
+
+@implementation ErrAct
+
+%%{
+ machine ErrAct;
+
+ action expect_digit_plus_minus { printf(" DIGIT PLUS MINUS\n"); }
+ action expect_digit { printf(" DIGIT\n"); }
+ action expect_digit_decimal { printf(" DIGIT DECIMAL\n"); }
+
+ float = (
+ (
+ [\-+] >!expect_digit_plus_minus %!expect_digit |
+ ""
+ )
+ ( [0-9] [0-9]* $!expect_digit_decimal )
+ ( '.' [0-9]+ $!expect_digit )?
+ );
+
+ main := float '\n';
+}%%
+
+%% write data;
+
+- (int) initFsm;
+{
+ %% write init;
+ return 1;
+}
+
+- (void) executeWithData:(const char *)_data len:(int)_len;
+{
+ const char *p = _data;
+ const char *pe = _data + _len;
+ const char *eof = pe;
+ %% write exec;
+}
+
+- (int) finish;
+{
+ if ( cs == ErrAct_error )
+ return -1;
+ else if ( cs >= ErrAct_first_final )
+ return 1;
+ return 0;
+}
+
+
+@end
+
+#define BUFSIZE 1024
+
+void test( char *buf )
+{
+ ErrAct *errAct = [[ErrAct alloc] init];
+ [errAct initFsm];
+ [errAct executeWithData:buf len:strlen(buf)];
+ if ( [errAct finish] > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test( "1\n" );
+ test( "+1\n" );
+ test( "-1\n" );
+ test( "1.1\n" );
+ test( "+1.1\n" );
+ test( "-1.1\n" );
+ test( "a\n" );
+ test( "-\n" );
+ test( "+\n" );
+ test( "-a\n" );
+ test( "+b\n" );
+ test( "1.\n" );
+ test( "1d\n" );
+ test( "1.d\n" );
+ test( "1.1d\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ACCEPT
+ DIGIT PLUS MINUS
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+ DIGIT DECIMAL
+FAIL
+ DIGIT
+FAIL
+ DIGIT
+FAIL
+#endif
diff --git a/test/erract6.rl b/test/erract6.rl
new file mode 100644
index 0000000..688042f
--- /dev/null
+++ b/test/erract6.rl
@@ -0,0 +1,82 @@
+/*
+ * @LANG: c
+ */
+
+/*
+ * Test of a transition going to the error state.
+ */
+
+#include <stdio.h>
+#define BUFSIZE 2048
+
+struct errintrans
+{
+ int cs;
+};
+
+%%{
+ machine errintrans;
+ variable cs fsm->cs;
+
+ char = any - (digit | '\n');
+ line = char* "\n";
+ main := line+;
+}%%
+
+%% write data;
+
+void errintrans_init( struct errintrans *fsm )
+{
+ %% write init;
+}
+
+void errintrans_execute( struct errintrans *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int errintrans_finish( struct errintrans *fsm )
+{
+ if ( fsm->cs == errintrans_error )
+ return -1;
+ if ( fsm->cs >= errintrans_first_final )
+ return 1;
+ return 0;
+}
+
+
+struct errintrans fsm;
+#include <string.h>
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ errintrans_init( &fsm );
+ errintrans_execute( &fsm, buf, len );
+ if ( errintrans_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test(
+ "good, does not have numbers\n"
+ );
+
+ test(
+ "bad, has numbers 666\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+FAIL
+#endif
diff --git a/test/erract7.rl b/test/erract7.rl
new file mode 100644
index 0000000..040ad73
--- /dev/null
+++ b/test/erract7.rl
@@ -0,0 +1,42 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+%%{
+ machine foo;
+
+ action on_char { printf("char: %c\n", *p); }
+ action on_err { printf("err: %c\n", *p); }
+ action to_state { printf("to state: %c\n", *p); }
+
+ main := 'heXXX' $on_char $err(on_err) $to(to_state);
+}%%
+
+%% write data;
+
+int main()
+{
+ int cs;
+ char *p = "hello", *pe = p + strlen(p);
+ char *eof = pe;
+ %%{
+ write init;
+ write exec;
+ }%%
+
+ printf( "rest: %s\n", p );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+char: h
+to state: h
+char: e
+to state: e
+err: l
+rest: llo
+#endif
diff --git a/test/erract8.rl b/test/erract8.rl
new file mode 100644
index 0000000..7926186
--- /dev/null
+++ b/test/erract8.rl
@@ -0,0 +1,44 @@
+/*
+ * @LANG: java
+ */
+
+class erract8
+{
+ %%{
+ machine erract8;
+
+ action on_char { System.out.println("char: " + data[p]); }
+ action on_err { System.out.println("err: " + data[p]); }
+ action to_state { System.out.println("to state: " + data[p]); }
+
+ main := 'heXXX' $on_char $err(on_err) $to(to_state);
+ }%%
+
+ %% write data;
+
+ static void test( char data[] )
+ {
+ int cs, p = 0, pe = data.length;
+ int eof = pe;
+ int top;
+
+ %% write init;
+ %% write exec;
+
+ System.out.println("rest: " + data[p] + data[p+1] + data[p+2]);
+ }
+
+ public static void main( String args[] )
+ {
+ test( "hello".toCharArray() );
+ }
+}
+
+/* _____OUTPUT_____
+char: h
+to state: h
+char: e
+to state: e
+err: l
+rest: llo
+*/
diff --git a/test/erract9.rl b/test/erract9.rl
new file mode 100644
index 0000000..ccd848a
--- /dev/null
+++ b/test/erract9.rl
@@ -0,0 +1,43 @@
+#
+# @LANG: ruby
+#
+# Test the host language scanning for ruby.
+#
+
+%%{
+ machine erract9;
+
+ action on_char { print("char: ", data[p..p], "\n"); }
+ action on_err { print("err: ", data[p..p], "\n"); }
+ action to_state { print("to state: " , data[p..p], "\n"); }
+
+ main := 'heXXX' $on_char $err(on_err) $to(to_state);
+}%%
+
+%% write data;
+
+def run_machine( data )
+ p = 0;
+ pe = data.length
+ cs = 0
+
+ %% write init;
+ %% write exec;
+
+ print("rest: " , data[p..p+2], "\n")
+end
+
+inp = [
+ "hello\n",
+]
+
+inp.each { |str| run_machine(str) }
+
+=begin _____OUTPUT_____
+char: h
+to state: h
+char: e
+to state: e
+err: l
+rest: llo
+=end _____OUTPUT_____
diff --git a/test/export1.rl b/test/export1.rl
new file mode 100644
index 0000000..fe96141
--- /dev/null
+++ b/test/export1.rl
@@ -0,0 +1,59 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+%%{
+ machine test;
+
+ export c1 = 'c';
+ export c2 = 'z';
+ export c3 = 't';
+
+ commands := (
+ c1 . digit* '\n' @{ printf( "c1\n" );} |
+ c2 . alpha* '\n' @{ printf( "c2\n" );}|
+ c3 . '.'* '\n' @{ printf( "c3\n" );}
+ )*;
+
+ some_other := any*;
+}%%
+
+%% write exports;
+%% write data;
+
+int test( const char *data, int len )
+{
+ int cs = test_en_commands;
+ const char *p = data, *pe = data + len;
+
+ %% write init nocs;
+ %% write exec;
+
+ if ( cs >= test_first_final )
+ printf("ACCEPT\n");
+ else
+ printf("ERROR\n");
+ return 0;
+}
+
+char data[] = {
+ test_ex_c1, '1', '2', '\n',
+ test_ex_c2, 'a', 'b', '\n',
+ test_ex_c3, '.', '.', '\n', 0
+};
+
+int main()
+{
+ test( data, strlen( data ) );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+c1
+c2
+c3
+ACCEPT
+#endif
diff --git a/test/export2.rl b/test/export2.rl
new file mode 100644
index 0000000..881a4c9
--- /dev/null
+++ b/test/export2.rl
@@ -0,0 +1,57 @@
+/*
+ * @LANG: java
+ */
+
+class export2
+{
+ %%{
+ machine test;
+
+ export c1 = 'c';
+ export c2 = 'z';
+ export c3 = 't';
+
+ commands := (
+ c1 . digit* '\n' @{ System.out.println( "c1" );} |
+ c2 . alpha* '\n' @{ System.out.println( "c2" );}|
+ c3 . '.'* '\n' @{ System.out.println( "c3" );}
+ )*;
+
+ other := any*;
+ }%%
+
+ %% write exports;
+ %% write data;
+
+ static void test( char data[] )
+ {
+ int cs = test_en_commands, p = 0, pe = data.length;
+ int top;
+
+ %% write init nocs;
+ %% write exec;
+
+ if ( cs >= test_first_final )
+ System.out.println( "ACCEPT" );
+ else
+ System.out.println( "FAIL" );
+ }
+
+ public static void main( String args[] )
+ {
+ char data[] = {
+ test_ex_c1, '1', '2', '\n',
+ test_ex_c2, 'a', 'b', '\n',
+ test_ex_c3, '.', '.', '\n',
+ };
+ test( data );
+ }
+}
+
+
+/* _____OUTPUT_____
+c1
+c2
+c3
+ACCEPT
+*/
diff --git a/test/export3.rl b/test/export3.rl
new file mode 100644
index 0000000..dbf74b8
--- /dev/null
+++ b/test/export3.rl
@@ -0,0 +1,53 @@
+#
+# @LANG: ruby
+#
+
+%%{
+ machine test;
+
+ export c1 = 'c';
+ export c2 = 'z';
+ export c3 = 't';
+
+ commands := (
+ c1 . digit* '\n' @{ puts "c1"; } |
+ c2 . alpha* '\n' @{ puts "c2"; }|
+ c3 . '.'* '\n' @{ puts "c3"; }
+ )*;
+
+ other := any*;
+}%%
+
+%% write exports;
+%% write data;
+
+def run_machine( data )
+ p = 0;
+ pe = data.length
+ cs = test_en_commands
+ val = 0;
+ neg = false;
+
+ %% write init nocs;
+ %% write exec;
+ if cs >= test_first_final
+ puts "ACCEPT"
+ else
+ puts "FAIL"
+ end
+end
+
+inp = [
+ test_ex_c1, ?1, ?2, ?\n,
+ test_ex_c2, ?a, ?b, ?\n,
+ test_ex_c3, ?., ?., ?\n
+]
+
+run_machine( inp );
+
+=begin _____OUTPUT_____
+c1
+c2
+c3
+ACCEPT
+=end _____OUTPUT_____
diff --git a/test/export4.rl b/test/export4.rl
new file mode 100644
index 0000000..94d50e4
--- /dev/null
+++ b/test/export4.rl
@@ -0,0 +1,59 @@
+/*
+ * @LANG: d
+ */
+
+import std.c.stdio;
+import std.string;
+
+%%{
+ machine test;
+
+ export c1 = 'c';
+ export c2 = 'z';
+ export c3 = 't';
+
+ commands := (
+ c1 . digit* '\n' @{ printf( "c1\n" );} |
+ c2 . alpha* '\n' @{ printf( "c2\n" );}|
+ c3 . '.'* '\n' @{ printf( "c3\n" );}
+ )*;
+
+ some_other := any*;
+}%%
+
+%% write exports;
+%% write data;
+
+int test( char data[] )
+{
+ int cs = test_en_commands;
+ char *p = data.ptr, pe = data.ptr + data.length;
+
+ %% write init nocs;
+ %% write exec;
+
+ if ( cs >= test_first_final )
+ printf("ACCEPT\n");
+ else
+ printf("ERROR\n");
+ return 0;
+}
+
+char data[] = [
+ test_ex_c1, '1', '2', '\n',
+ test_ex_c2, 'a', 'b', '\n',
+ test_ex_c3, '.', '.', '\n'
+];
+
+int main()
+{
+ test( data );
+ return 0;
+}
+
+/+ _____OUTPUT_____
+c1
+c2
+c3
+ACCEPT
+++++++++++++++++++/
diff --git a/test/fnext1.rl b/test/fnext1.rl
new file mode 100644
index 0000000..a2925eb
--- /dev/null
+++ b/test/fnext1.rl
@@ -0,0 +1,81 @@
+/*
+ * @LANG: c
+ *
+ * Tests fnext in combination with fbreak.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+char comm;
+int top;
+int stack [32];
+
+%%{
+ machine fnext;
+ action break {fbreak;}
+
+ main := 'h' @{ /*h*/ fnext e; fbreak; };
+ e := 'e' @{ /*e*/ fnext l; } @{ fbreak; };
+ l := 'll' @{ /*ll*/ fnext o; } ${ fbreak; };
+ o := |* 'o' { /*o*/ fnext nl; fbreak; }; *|;
+ nl := '\n' @{ /*nl*/ fbreak; printf("ACCEPT\n"); };
+}%%
+
+int cs;
+char *ts, *te;
+int act;
+
+%% write data;
+
+void init()
+{
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+
+ while ( cs != fnext_error && p < pe ) {
+ printf( "%c\n", *p );
+ %% write exec;
+ }
+}
+
+void finish( )
+{
+ if ( cs >= fnext_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+}
+
+char *inp[] = {
+ "hello\n"
+};
+
+int inplen = 1;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+h
+e
+l
+l
+o
+
+
+ACCEPT
+#endif
diff --git a/test/forder1.rl b/test/forder1.rl
new file mode 100644
index 0000000..9873af4
--- /dev/null
+++ b/test/forder1.rl
@@ -0,0 +1,98 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct forder
+{
+ int cs;
+};
+
+%%{
+ machine forder;
+ variable cs fsm->cs;
+
+ second = 'b'
+ >{printf("enter b1\n");}
+ >{printf("enter b2\n");}
+ ;
+
+ first = 'a'
+ %{printf("leave a\n");}
+ @{printf("finish a\n");}
+ ;
+
+ main := first . second . '\n';
+}%%
+
+%% write data;
+
+void forder_init( struct forder *fsm )
+{
+ %% write init;
+}
+
+void forder_execute( struct forder *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int forder_finish( struct forder *fsm )
+{
+ if ( fsm->cs == forder_error )
+ return -1;
+ if ( fsm->cs >= forder_first_final )
+ return 1;
+ return 0;
+}
+
+struct forder fsm;
+
+void test( char *buf )
+{
+ int len = strlen(buf);
+ forder_init( &fsm );
+ forder_execute( &fsm, buf, len );
+ if ( forder_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test( "ab\n");
+ test( "abx\n");
+ test( "" );
+
+ test(
+ "ab\n"
+ "fail after newline\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+finish a
+leave a
+enter b1
+enter b2
+ACCEPT
+finish a
+leave a
+enter b1
+enter b2
+FAIL
+FAIL
+finish a
+leave a
+enter b1
+enter b2
+FAIL
+#endif
diff --git a/test/forder2.rl b/test/forder2.rl
new file mode 100644
index 0000000..d92f888
--- /dev/null
+++ b/test/forder2.rl
@@ -0,0 +1,133 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * After the fact start and ending transitions. Behaves like constructors of
+ * and destructors in c++.
+ */
+
+struct forder
+{
+ int cs;
+};
+
+%%{
+ machine forder;
+ variable cs fsm->cs;
+
+ inner = 'inner'
+ >{printf("enter inner\n");}
+ ${printf("inside inner\n");}
+ %{printf("leave inner\n");}
+ ;
+
+ outter = inner
+ >{printf("enter outter\n");}
+ ${printf("inside outter\n");}
+ %{printf("leave outter\n");}
+ ;
+
+ main := outter . '\n';
+}%%
+
+%% write data;
+
+void forder_init( struct forder *fsm )
+{
+ %% write init;
+}
+
+void forder_execute( struct forder *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int forder_finish( struct forder *fsm )
+{
+ if ( fsm->cs == forder_error )
+ return -1;
+ if ( fsm->cs >= forder_first_final )
+ return 1;
+ return 0;
+}
+
+struct forder fsm;
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ forder_init( &fsm );
+ forder_execute( &fsm, buf, len );
+ if ( forder_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test( "inner\n");
+
+ test(
+ "inner\n"
+ "foobar\n"
+ );
+
+ test( "" );
+ test( "\n" );
+ test( "inn\n" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+enter outter
+enter inner
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+leave inner
+leave outter
+ACCEPT
+enter outter
+enter inner
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+leave inner
+leave outter
+FAIL
+FAIL
+FAIL
+enter outter
+enter inner
+inside inner
+inside outter
+inside inner
+inside outter
+inside inner
+inside outter
+FAIL
+#endif
diff --git a/test/forder3.rl b/test/forder3.rl
new file mode 100644
index 0000000..5cb3725
--- /dev/null
+++ b/test/forder3.rl
@@ -0,0 +1,107 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct forder
+{
+ int cs;
+};
+
+%%{
+ machine forder;
+ variable cs fsm->cs;
+
+ m1 = ( "" %{printf("enter m1 aa\n");} |
+ 'aa'* >{printf("enter m1 aa\n");} %{printf("leave m1 aa\n");} )
+ 'b' @{printf("through m1 b\n");} . 'b'* . 'a'*;
+
+ m2 = 'bbb'* 'aa'*;
+
+ main := (
+ m1 %{printf("accept m1\n");} |
+ "" %{printf("enter m2\n");} |
+ m2 >{printf("enter m2\n");} %{printf("accept m2\n");}
+ ) . '\n';
+}%%
+
+%% write data;
+
+void forder_init( struct forder *fsm )
+{
+ %% write init;
+}
+
+void forder_execute( struct forder *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int forder_finish( struct forder *fsm )
+{
+ if ( fsm->cs == forder_error )
+ return -1;
+ if ( fsm->cs >= forder_first_final )
+ return 1;
+ return 0;
+}
+
+struct forder fsm;
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ forder_init( &fsm );
+ forder_execute( &fsm, buf, len );
+ if ( forder_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test( "aaaaaabbbaa\n" );
+ test( "\n" );
+ test( "bbbbbbaaaaaaa\n" );
+ test( "bbbbbbaaaaaa\n" );
+ test( "aaaaa\n" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+enter m1 aa
+enter m2
+leave m1 aa
+through m1 b
+accept m1
+ACCEPT
+enter m2
+enter m2
+accept m2
+ACCEPT
+enter m1 aa
+enter m1 aa
+leave m1 aa
+through m1 b
+enter m2
+accept m1
+ACCEPT
+enter m1 aa
+enter m1 aa
+leave m1 aa
+through m1 b
+enter m2
+accept m1
+accept m2
+ACCEPT
+enter m1 aa
+enter m2
+FAIL
+#endif
diff --git a/test/gotocallret1.rl b/test/gotocallret1.rl
new file mode 100644
index 0000000..8b294dd
--- /dev/null
+++ b/test/gotocallret1.rl
@@ -0,0 +1,114 @@
+/*
+ * @LANG: indep
+ */
+
+/*
+ * Demonstrate the use of goto, call and return. This machine expects either a
+ * lower case char or a digit as a command then a space followed by the command
+ * arg. If the command is a char, then the arg must be an a string of chars.
+ * If the command is a digit, then the arg must be a string of digits. This
+ * choice is determined by action code, rather than though transition
+ * desitinations.
+ */
+
+char comm;
+int top;
+int stack[32];
+%%
+%%{
+ machine GotoCallRet;
+
+ # A reference to a state in an unused action caused a segfault in 5.8. */
+ action unusedAction { fentry(garble_line); }
+
+ action err_garbling_line { prints "error: garbling line\n"; }
+ action goto_main { fgoto main; }
+ action recovery_failed { prints "error: failed to recover\n"; }
+
+ # Error machine, consumes to end of
+ # line, then starts the main line over.
+ garble_line := ( (any-'\n')*'\n')
+ >err_garbling_line
+ @goto_main
+ $/recovery_failed;
+
+ action hold_and_return {fhold; fret;}
+
+ # Look for a string of alphas or of digits,
+ # on anything else, hold the character and return.
+ alp_comm := alpha+ $!hold_and_return;
+ dig_comm := digit+ $!hold_and_return;
+
+ # Choose which to machine to call into based on the command.
+ action comm_arg {
+ if ( comm >= 'a' )
+ fcall alp_comm;
+ else
+ fcall dig_comm;
+ }
+
+ # Specifies command string. Note that the arg is left out.
+ command = (
+ [a-z0-9] @{comm = fc;} ' ' @comm_arg '\n'
+ ) @{prints "correct command\n";};
+
+ # Any number of commands. If there is an
+ # error anywhere, garble the line.
+ main := command* $!{fhold;fgoto garble_line;};
+}%%
+/* _____INPUT_____
+"lkajsdf\n"
+"2134\n"
+"(\n"
+"\n"
+"*234234()0909 092 -234aslkf09`1 11\n"
+"1\n"
+"909\n"
+"1 a\n"
+"11 1\n"
+"a 1\n"
+"aa a\n"
+"1 1\n"
+"1 123456\n"
+"a a\n"
+"a abcdef\n"
+"h"
+"a aa1"
+_____INPUT_____ */
+/* _____OUTPUT_____
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+error: garbling line
+ACCEPT
+correct command
+ACCEPT
+correct command
+ACCEPT
+correct command
+ACCEPT
+correct command
+ACCEPT
+error: failed to recover
+FAIL
+error: garbling line
+error: failed to recover
+FAIL
+_____OUTPUT_____ */
diff --git a/test/gotocallret2.rl b/test/gotocallret2.rl
new file mode 100644
index 0000000..5b4f740
--- /dev/null
+++ b/test/gotocallret2.rl
@@ -0,0 +1,77 @@
+/*
+ * @LANG: indep
+ */
+
+char comm;
+int top;
+int stack[32];
+ptr ts;
+ptr te;
+int act;
+int val;
+%%
+%%{
+ machine GotoCallRet;
+
+ sp = ' ';
+
+ handle := any @{
+ prints "handle ";
+ fhold;
+ if ( val == 1 ) fnext *fentry(one);
+ if ( val == 2 ) fnext *fentry(two);
+ if ( val == 3 ) fnext main;
+ };
+
+ one := |*
+ '{' => { prints "{ "; fcall *fentry(one); };
+ "[" => { prints "[ "; fcall *fentry(two); };
+ "}" sp* => { prints "} "; fret; };
+ [a-z]+ => { prints "word "; val = 1; fgoto *fentry(handle); };
+ ' ' => { prints "space "; };
+ *|;
+
+ two := |*
+ '{' => { prints "{ "; fcall *fentry(one); };
+ "[" => { prints "[ "; fcall *fentry(two); };
+ ']' sp* => { prints "] "; fret; };
+ [a-z]+ => { prints "word "; val = 2; fgoto *fentry(handle); };
+ ' ' => { prints "space "; };
+ *|;
+
+ main := |*
+ '{' => { prints "{ "; fcall one; };
+ "[" => { prints "[ "; fcall two; };
+ [a-z]+ => { prints "word "; val = 3; fgoto handle; };
+ [a-z] ' foil' => { prints "this is the foil";};
+ ' ' => { prints "space "; };
+ '\n';
+ *|;
+}%%
+/* _____INPUT_____
+"{a{b[c d]d}c}\n"
+"[a{b[c d]d}c}\n"
+"[a[b]c]d{ef{g{h}i}j}l\n"
+"{{[]}}\n"
+"a b c\n"
+"{a b c}\n"
+"[a b c]\n"
+"{]\n"
+"{{}\n"
+"[[[[[[]]]]]]\n"
+"[[[[[[]]}]]]\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+{ word handle { word handle [ word handle space word handle ] word handle } word handle } ACCEPT
+[ word handle { word handle [ word handle space word handle ] word handle } word handle FAIL
+[ word handle [ word handle ] word handle ] word handle { word handle { word handle { word handle } word handle } word handle } word handle ACCEPT
+{ { [ ] } } ACCEPT
+word handle space word handle space word handle ACCEPT
+{ word handle space word handle space word handle } ACCEPT
+[ word handle space word handle space word handle ] ACCEPT
+{ FAIL
+{ { } FAIL
+[ [ [ [ [ [ ] ] ] ] ] ] ACCEPT
+[ [ [ [ [ [ ] ] FAIL
+_____OUTPUT_____ */
+
diff --git a/test/high1.rl b/test/high1.rl
new file mode 100644
index 0000000..9179c89
--- /dev/null
+++ b/test/high1.rl
@@ -0,0 +1,180 @@
+/*
+ * @LANG: c
+ * @ALLOW_GENFLAGS: -T0 -T1 -G0 -G1 -G2
+ */
+
+/**
+ * Test a high character to make sure signedness
+ * isn't messing us up.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct high
+{
+ int cs;
+};
+
+%%{
+ machine high;
+ variable cs fsm->cs;
+
+ # We Want the header portion.
+ alphtype unsigned int;
+
+ main := (
+ 0x20 .. 0xefffffff @1 @{printf("gothigh1\n");} |
+ 0xf0000000 @1 @{printf("gothigh1\n");} |
+ 0x200 .. 0xfe000000 @1 @{printf("gothigh2\n");} |
+ any @0 @{printf("else\n");}
+ )*;
+}%%
+
+%% write data;
+
+void high_init( struct high *fsm )
+{
+ %% write init;
+}
+
+void high_execute( struct high *fsm, const unsigned int *_data, int _len )
+{
+ const unsigned int *p = _data;
+ const unsigned int *pe = _data+_len;
+
+ %% write exec;
+}
+
+int high_finish( struct high *fsm )
+{
+ if ( fsm->cs == high_error )
+ return -1;
+ if ( fsm->cs >= high_first_final )
+ return 1;
+ return 0;
+}
+
+struct high high;
+
+#define BUFSIZE 1024
+char cbuf[BUFSIZE];
+unsigned int buf[BUFSIZE];
+int buflen = 0;
+char numbuf[9];
+int numlen = 0;
+
+struct tokenizer
+{
+ int cs;
+};
+
+%%{
+ machine tokenizer;
+ variable cs fsm->cs;
+
+ action bufdigit {
+ if ( numlen < 8 )
+ numbuf[numlen++] = fc;
+ }
+
+ action writeDigit {
+ /* Null terminate the buffer storing the number and reset. */
+ numbuf[numlen] = 0;
+ numlen = 0;
+
+ /* Store the number in the buf. If the buf is full then
+ * flush and reset the buffer. */
+ buf[buflen++] = strtoul( numbuf, 0, 16 );
+ if ( buflen == BUFSIZE ) {
+ high_execute( &high, buf, BUFSIZE );
+ buflen = 0;
+ }
+ }
+
+ action finish {
+ if ( buflen > 0 )
+ high_execute( &high, buf, buflen );
+ if ( high_finish( &high ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+ }
+
+ num = ( digit | 'a'..'f' )+ $bufdigit %writeDigit;
+ main := ( num $1 %0 | space )* %/finish;
+}%%
+
+%% write data;
+
+void tokenizer_init( struct tokenizer *fsm )
+{
+ %% write init;
+}
+
+void tokenizer_execute( struct tokenizer *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+ const char *eof = pe;
+
+ %% write exec;
+}
+
+int tokenizer_finish( struct tokenizer *fsm )
+{
+ if ( fsm->cs == tokenizer_error )
+ return -1;
+ if ( fsm->cs >= tokenizer_first_final )
+ return 1;
+ return 0;
+}
+
+struct tokenizer tok;
+
+void test( char *cbuf )
+{
+ int len = strlen( cbuf );
+ high_init( &high );
+ tokenizer_init( &tok );
+ tokenizer_execute( &tok, cbuf, len );
+ if ( tokenizer_finish( &tok ) <= 0 )
+ printf("Tokenizer FAIL\n");
+}
+
+char data[] =
+ "10 20 30 40 50 200 300 400 \n"
+ "d0000000 f0000000 fd000000 fe000000\n"
+ "ff000000 ffffffffffffffffffffffffff\n"
+ "ff\n";
+
+int main()
+{
+ test( data );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+else
+gothigh1
+gothigh1
+gothigh1
+gothigh1
+gothigh1
+gothigh2
+gothigh1
+gothigh2
+gothigh1
+gothigh2
+gothigh1
+gothigh2
+gothigh1
+gothigh2
+gothigh2
+gothigh2
+else
+else
+gothigh1
+ACCEPT
+#endif
diff --git a/test/high2.rl b/test/high2.rl
new file mode 100644
index 0000000..53f1d80
--- /dev/null
+++ b/test/high2.rl
@@ -0,0 +1,103 @@
+/*
+ * @LANG: c++
+ */
+
+/**
+ * Test a high character to make sure signedness
+ * isn't messing us up.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct Fsm
+{
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ int init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( const unsigned char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine Fsm;
+
+ alphtype unsigned char;
+
+ # Indicate we got the high character.
+ action gothigh {
+ printf("yes\n");
+ }
+
+ main := 0xe8 @gothigh '\n';
+}%%
+
+%% write data;
+
+int Fsm::init( )
+{
+ %% write init;
+ return 0;
+}
+
+int Fsm::execute( const unsigned char *_data, int _len )
+{
+ const unsigned char *p = _data;
+ const unsigned char *pe = _data+_len;
+ %% write exec;
+ if ( cs == Fsm_error )
+ return -1;
+ if ( cs >= Fsm_first_final )
+ return 1;
+ return 0;
+}
+
+int Fsm::finish()
+{
+ if ( cs == Fsm_error )
+ return -1;
+ if ( cs >= Fsm_first_final )
+ return 1;
+ return 0;
+}
+
+Fsm fsm;
+
+void test( unsigned char *buf, int len )
+{
+ fsm.init();
+ fsm.execute( buf, len );
+ if ( fsm.finish() > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+unsigned char data1[] = { 0xe8, 10 };
+unsigned char data2[] = { 0xf8, 10 };
+
+int main()
+{
+ test( data1, 2 );
+ test( data2, 2 );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+yes
+ACCEPT
+FAIL
+#endif
diff --git a/test/high3.rl b/test/high3.rl
new file mode 100644
index 0000000..d915bff
--- /dev/null
+++ b/test/high3.rl
@@ -0,0 +1,111 @@
+/*
+ * @LANG: obj-c
+ */
+
+/**
+ * Test a high character to make sure signedness
+ * isn't messing us up.
+ */
+
+#include <stdio.h>
+#include <objc/Object.h>
+
+@interface Fsm : Object
+{
+@public
+ int cs;
+};
+
+// Initialize the machine. Invokes any init statement blocks. Returns 0
+// if the machine begins in a non-accepting state and 1 if the machine
+// begins in an accepting state.
+- (int) initFsm;
+
+// Execute the machine on a block of data. Returns -1 if after processing
+// the data, the machine is in the error state and can never accept, 0 if
+// the machine is in a non-accepting state and 1 if the machine is in an
+// accepting state.
+- (void) executeWithData:(const unsigned char *)data len:(int)len;
+
+// Indicate that there is no more data. Returns -1 if the machine finishes
+// in the error state and does not accept, 0 if the machine finishes
+// in any other non-accepting state and 1 if the machine finishes in an
+// accepting state.
+- (int) finish;
+
+@end
+
+@implementation Fsm
+
+%%{
+ machine Fsm;
+
+ alphtype unsigned char;
+
+ # Indicate we got the high character.
+ action gothigh {
+ printf("yes\n");
+ }
+
+ main := 0xe8 @gothigh '\n';
+}%%
+
+%% write data;
+
+- (int) initFsm;
+{
+ %% write init;
+ return 1;
+}
+
+- (void) executeWithData:(const unsigned char *)_data len:(int)_len;
+{
+ const unsigned char *p = _data;
+ const unsigned char *pe = _data + _len;
+ %% write exec;
+}
+
+- (int) finish;
+{
+ if ( cs == Fsm_error )
+ return -1;
+ else if ( cs >= Fsm_first_final )
+ return 1;
+ return 0;
+}
+
+
+@end
+
+
+#define BUFSIZE 2048
+
+Fsm *fsm;
+unsigned char buf[BUFSIZE];
+
+void test( unsigned char *buf, int len )
+{
+ fsm = [[Fsm alloc] init];
+ [fsm initFsm];
+ [fsm executeWithData:buf len:len];
+ if ( [fsm finish] > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+unsigned char data1[] = { 0xe8, 10 };
+unsigned char data2[] = { 0xf8, 10 };
+
+int main()
+{
+ test( data1, 2 );
+ test( data2, 2 );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+yes
+ACCEPT
+FAIL
+#endif
diff --git a/test/import1.rl b/test/import1.rl
new file mode 100644
index 0000000..e721f56
--- /dev/null
+++ b/test/import1.rl
@@ -0,0 +1,73 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+
+char *foo = "foo";
+
+char b = 98;
+char a = 97;
+char r = 114;
+
+#define SP 32
+#define NL '\n'
+
+%%{
+ machine tmp;
+ import "import1.rl";
+
+ foobar =
+ foo @{printf("foo\n"); } |
+ b a r @{printf("bar\n");};
+
+ main := ( foobar SP foobar NL )*;
+}%%
+
+%% write data;
+
+int cs;
+
+void exec_str( char *p, int len )
+{
+ char *pe = p + len;
+ %% write exec;
+}
+
+void exec_c( char c )
+{
+ exec_str( &c, 1 );
+}
+
+int main()
+{
+ %% write init;
+
+ exec_str( foo, 3 );
+ exec_c( SP );
+ exec_c( b );
+ exec_c( a );
+ exec_c( r );
+ exec_c( NL );
+
+ exec_c( b );
+ exec_c( a );
+ exec_c( r );
+ exec_c( SP );
+ exec_str( foo, 3 );
+ exec_c( NL );
+
+ if ( cs < tmp_first_final )
+ printf("FAIL\n");
+ else
+ printf("ACCEPT\n");
+
+ return 0;
+}
+#ifdef _____OUTPUT_____
+foo
+bar
+bar
+foo
+ACCEPT
+#endif
diff --git a/test/include1.rl b/test/include1.rl
new file mode 100644
index 0000000..30145de
--- /dev/null
+++ b/test/include1.rl
@@ -0,0 +1,28 @@
+/*
+ * @LANG: c
+ * @IGNORE: yes
+ *
+ * Provides definitions for include tests.
+ */
+
+%%{
+ machine include_test_1;
+
+ action A {printf(" a1");}
+ action B {printf(" b1");}
+
+ action NonRef1 {printf(" nr1");}
+
+ a1 = 'a' @A;
+ b1 = 'b' @B;
+}%%
+
+%%{
+ machine include_test_2;
+
+ action NonRef2 {printf(" nr2");}
+
+ a2 = 'a' @{printf(" a2");};
+ b2 = 'b' @{printf(" b2");};
+}%%
+
diff --git a/test/include2.rl b/test/include2.rl
new file mode 100644
index 0000000..68ab007
--- /dev/null
+++ b/test/include2.rl
@@ -0,0 +1,52 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+%%{
+ machine include_test_4;
+
+ action NonRef3 {printf(" nr3");}
+
+ a3 = 'a'@{printf(" a3");};
+ b3 = 'b'@{printf(" b3");};
+
+}%%
+
+%%{
+ machine include_test_1;
+
+ include "include1.rl";
+
+ include include_test_2 "include1.rl";
+
+ include include_test_4;
+
+ main :=
+ a1 b1 @NonRef1
+ a2 b2 @NonRef2
+ a3 b3 @NonRef3
+ 0 @{fbreak;};
+}%%
+
+%% write data;
+
+void test( char *p )
+{
+ int cs;
+ %% write init;
+ %% write exec noend;
+ printf("\n");
+}
+
+int main()
+{
+ test( "ababab" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ a1 b1 nr1 a2 b2 nr2 a3 b3 nr3
+#endif
diff --git a/test/java1.rl b/test/java1.rl
new file mode 100644
index 0000000..461d177
--- /dev/null
+++ b/test/java1.rl
@@ -0,0 +1,48 @@
+/*
+ * @LANG: java
+ */
+
+class java1
+{
+ %%{
+ machine java1;
+
+ one := 'one\n';
+ two := 'two\n';
+ four := 'four\n';
+
+ main :=
+ ( 'hello' | 'there' | 'friend' )
+ '\n' @{int s = fentry(one); fgoto *s; char c = fc;}
+ ( 'one' | 'two' | 'four' ) '\n';
+ }%%
+
+ %% write data;
+
+ static void test( char data[] )
+ {
+ int cs, p = 0, pe = data.length;
+ int top;
+
+ %% write init;
+ %% write exec;
+
+ if ( cs >= java1_first_final )
+ System.out.println( "ACCEPT" );
+ else
+ System.out.println( "FAIL" );
+ }
+
+ public static void main( String args[] )
+ {
+ test( "hello\none\n".toCharArray() );
+ test( "there\ntwo\n".toCharArray() );
+ test( "friend\nfour\n".toCharArray() );
+ }
+}
+
+/* _____OUTPUT_____
+ACCEPT
+FAIL
+FAIL
+*/
diff --git a/test/java2.rl b/test/java2.rl
new file mode 100644
index 0000000..f308902
--- /dev/null
+++ b/test/java2.rl
@@ -0,0 +1,50 @@
+/*
+ * @LANG: java
+ */
+
+class java2
+{
+ %%{
+ machine java1;
+ alphtype int;
+
+ main := 1 2 3 4 (
+ 5 6 7 8 |
+ 9 10 11 12
+ ) 1073741824;
+
+ }%%
+
+ %% write data;
+
+ static void test( int data[] )
+ {
+ int cs, p = 0, pe = data.length;
+ int top;
+
+ %% write init;
+ %% write exec;
+
+ if ( cs >= java1_first_final )
+ System.out.println( "ACCEPT" );
+ else
+ System.out.println( "FAIL" );
+ }
+
+ static final int t1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1073741824 };
+ static final int t2[] = { 1, 2, 3, 4, 9, 10, 11, 12, 1073741824 };
+ static final int t3[] = { 1, 2, 3, 4, 1073741824 };
+
+ public static void main( String args[] )
+ {
+ test( t1 );
+ test( t2 );
+ test( t3 );
+ }
+}
+
+/* _____OUTPUT_____
+ACCEPT
+ACCEPT
+FAIL
+*/
diff --git a/test/keller1.rl b/test/keller1.rl
new file mode 100644
index 0000000..646cec9
--- /dev/null
+++ b/test/keller1.rl
@@ -0,0 +1,1075 @@
+/*
+ * @LANG: c++
+ */
+
+/*
+ * Automatically generated by keller. Do not edit.
+ *
+ * Parts of this file are copied from Keller source covered by the GNU
+ * GPL. As a special exception, you may use the parts of this file copied
+ * from Keller source without restriction. The remainder is derived from
+ * "tmp.gmr" and inherits the copyright status of that file.
+ */
+
+#line 1 "tmp.gmr"
+#include <iostream>
+using std::cout;
+using std::endl;
+
+
+#line 16 "tmp.rl"
+enum token_type_e {
+ tt_id,
+ tt_equals,
+ tt_semi,
+ tt_pipe,
+ tt_amp,
+ tt_minus,
+ tt_dot,
+ tt_colon,
+ tt_percent,
+ tt_dollar,
+ tt_plus,
+ tt_number,
+ tt_star,
+ tt_question,
+ tt_not,
+ tt_andFSM,
+ tt_orFSM,
+ tt_open,
+ tt_close
+};
+
+struct LangEl
+{
+ int line, lineEnd;
+ int pos;
+
+ int type;
+ int state;
+ LangEl *prev, *next;
+};
+
+struct Token : public LangEl
+{
+ const char *value;
+};
+
+struct Lel_start : public LangEl
+{
+#line 32 "tmp.gmr"
+
+ int si;
+#line 59 "tmp.rl"
+};
+
+struct Lel_M : public LangEl
+{
+#line 36 "tmp.gmr"
+
+ int mi;
+#line 67 "tmp.rl"
+};
+
+#define l__error 19
+#define l_tt_id 0
+#define l_tt_equals 1
+#define l_tt_semi 2
+#define l_tt_pipe 3
+#define l_tt_amp 4
+#define l_tt_minus 5
+#define l_tt_dot 6
+#define l_tt_colon 7
+#define l_tt_percent 8
+#define l_tt_dollar 9
+#define l_tt_plus 10
+#define l_tt_number 11
+#define l_tt_star 12
+#define l_tt_question 13
+#define l_tt_not 14
+#define l_tt_andFSM 15
+#define l_tt_orFSM 16
+#define l_tt_open 17
+#define l_tt_close 18
+#define l_start 23
+#define l_M 24
+#define l_A 25
+#define l_E 26
+#define l_T 27
+#define l_N 28
+#define l_K 29
+#define l_F 30
+#define l__start 31
+#define l__eof 20
+
+struct LangEl;
+
+struct Parser
+{
+ Parser();
+
+ void parseLangEl( LangEl *langEl );
+ int done( );
+
+ void push( LangEl *lel ) {
+ lel->prev = stack;
+ stack = lel;
+ }
+ LangEl *pop() {
+ LangEl *ret = stack;
+ stack = stack->prev;
+ return ret;
+ }
+ int pop( int n );
+ void rem( LangEl *lel, int n );
+ LangEl *stack;
+ int next;
+ LangEl *redLel;
+ LangEl *rhs[10];
+
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ int init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( LangEl *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+
+%%{
+ machine Parser;
+
+ getkey fpc->type;
+
+ action shift {
+ fpc->state = fcurs;
+ push( fpc );
+ }
+
+ action pop1 { fnext *pop(1); }
+ action pop2 { fnext *pop(2); }
+ action pop3 { fnext *pop(3); }
+ action pop4 { fnext *pop(4); }
+
+ action new_error {
+ redLel = new LangEl();
+ redLel->type = 19;
+ }
+
+ action newstart {
+ redLel = new Lel_start();
+ redLel->type = 23;
+ }
+
+ action newM {
+ redLel = new Lel_M();
+ redLel->type = 24;
+ }
+
+ action newA {
+ redLel = new LangEl();
+ redLel->type = 25;
+ }
+
+ action newE {
+ redLel = new LangEl();
+ redLel->type = 26;
+ }
+
+ action newT {
+ redLel = new LangEl();
+ redLel->type = 27;
+ }
+
+ action newN {
+ redLel = new LangEl();
+ redLel->type = 28;
+ }
+
+ action newK {
+ redLel = new LangEl();
+ redLel->type = 29;
+ }
+
+ action newF {
+ redLel = new LangEl();
+ redLel->type = 30;
+ }
+
+ action new_eof {
+ redLel = new LangEl();
+ redLel->type = 20;
+ }
+
+ action new_epsilon {
+ redLel = new LangEl();
+ redLel->type = 21;
+ }
+
+ action new_null {
+ redLel = new LangEl();
+ redLel->type = 22;
+ }
+
+ action rem1 { rem(fpc, 1); }
+ action rem2 { rem(fpc, 2); }
+ action rem3 { rem(fpc, 3); }
+ action rem4 { rem(fpc, 4); }
+
+ action r_start_0
+ {
+#line 41 "tmp.gmr"
+
+ cout << "start = M;" << endl;
+ static_cast<Lel_start*>(redLel)->si = static_cast<Lel_M*>(rhs[0])->mi;
+
+#line 214 "tmp.rl"
+ }
+
+ action r_M_0
+ {
+#line 44 "tmp.gmr"
+ cout << "M = M A;" << endl;
+#line 221 "tmp.rl"
+ }
+
+ action r_M_1
+ {
+#line 45 "tmp.gmr"
+ cout << "M = A;" << endl;
+#line 228 "tmp.rl"
+ }
+
+ action r_A_0
+ {
+#line 46 "tmp.gmr"
+ cout << "A = tt_id tt_equals E tt_semi;" << endl;
+#line 235 "tmp.rl"
+ }
+
+ action r_E_0
+ {
+#line 47 "tmp.gmr"
+ cout << "E = E tt_pipe T;" << endl;
+#line 242 "tmp.rl"
+ }
+
+ action r_E_1
+ {
+#line 48 "tmp.gmr"
+ cout << "E = E tt_amp T;" << endl;
+#line 249 "tmp.rl"
+ }
+
+ action r_E_2
+ {
+#line 49 "tmp.gmr"
+ cout << "E = E tt_minus T;" << endl;
+#line 256 "tmp.rl"
+ }
+
+ action r_E_3
+ {
+#line 50 "tmp.gmr"
+ cout << "E = T;" << endl;
+#line 263 "tmp.rl"
+ }
+
+ action r_T_0
+ {
+#line 51 "tmp.gmr"
+ cout << "T = T tt_dot N;" << endl;
+#line 270 "tmp.rl"
+ }
+
+ action r_T_1
+ {
+#line 52 "tmp.gmr"
+ cout << "T = T N;" << endl;
+#line 277 "tmp.rl"
+ }
+
+ action r_T_2
+ {
+#line 53 "tmp.gmr"
+ cout << "T = N;" << endl;
+#line 284 "tmp.rl"
+ }
+
+ action r_N_0
+ {
+#line 54 "tmp.gmr"
+ cout << "N = N tt_colon tt_id;" << endl;
+#line 291 "tmp.rl"
+ }
+
+ action r_N_1
+ {
+#line 55 "tmp.gmr"
+ cout << "N = N tt_percent tt_id;" << endl;
+#line 298 "tmp.rl"
+ }
+
+ action r_N_2
+ {
+#line 56 "tmp.gmr"
+ cout << "N = N tt_dollar tt_id;" << endl;
+#line 305 "tmp.rl"
+ }
+
+ action r_N_3
+ {
+#line 57 "tmp.gmr"
+ cout << "N = N tt_colon tt_plus tt_number;" << endl;
+#line 312 "tmp.rl"
+ }
+
+ action r_N_4
+ {
+#line 58 "tmp.gmr"
+ cout << "N = N tt_colon tt_minus tt_number;" << endl;
+#line 319 "tmp.rl"
+ }
+
+ action r_N_5
+ {
+#line 59 "tmp.gmr"
+ cout << "N = N tt_percent tt_plus tt_number;" << endl;
+#line 326 "tmp.rl"
+ }
+
+ action r_N_6
+ {
+#line 60 "tmp.gmr"
+ cout << "N = N tt_percent tt_minus tt_number;" << endl;
+#line 333 "tmp.rl"
+ }
+
+ action r_N_7
+ {
+#line 61 "tmp.gmr"
+ cout << "N = N tt_dollar tt_plus tt_number;" << endl;
+#line 340 "tmp.rl"
+ }
+
+ action r_N_8
+ {
+#line 62 "tmp.gmr"
+ cout << "N = N tt_dollar tt_minus tt_number;" << endl;
+#line 347 "tmp.rl"
+ }
+
+ action r_N_9
+ {
+#line 63 "tmp.gmr"
+ cout << "N = K;" << endl;
+#line 354 "tmp.rl"
+ }
+
+ action r_K_0
+ {
+#line 64 "tmp.gmr"
+ cout << "K = F tt_star;" << endl;
+#line 361 "tmp.rl"
+ }
+
+ action r_K_1
+ {
+#line 65 "tmp.gmr"
+ cout << "K = F tt_question;" << endl;
+#line 368 "tmp.rl"
+ }
+
+ action r_K_2
+ {
+#line 66 "tmp.gmr"
+ cout << "K = F tt_plus;" << endl;
+#line 375 "tmp.rl"
+ }
+
+ action r_K_3
+ {
+#line 67 "tmp.gmr"
+ cout << "K = F;" << endl;
+#line 382 "tmp.rl"
+ }
+
+ action r_K_4
+ {
+#line 68 "tmp.gmr"
+ cout << "K = tt_not F tt_star;" << endl;
+#line 389 "tmp.rl"
+ }
+
+ action r_K_5
+ {
+#line 69 "tmp.gmr"
+ cout << "K = tt_not F tt_question;" << endl;
+#line 396 "tmp.rl"
+ }
+
+ action r_K_6
+ {
+#line 70 "tmp.gmr"
+ cout << "K = tt_not F tt_plus;" << endl;
+#line 403 "tmp.rl"
+ }
+
+ action r_K_7
+ {
+#line 71 "tmp.gmr"
+ cout << "K = tt_not F;" << endl;
+#line 410 "tmp.rl"
+ }
+
+ action r_F_0
+ {
+#line 72 "tmp.gmr"
+ cout << "F = tt_andFSM;" << endl;
+#line 417 "tmp.rl"
+ }
+
+ action r_F_1
+ {
+#line 73 "tmp.gmr"
+ cout << "F = tt_orFSM;" << endl;
+#line 424 "tmp.rl"
+ }
+
+ action r_F_2
+ {
+#line 74 "tmp.gmr"
+ cout << "F = tt_id;" << endl;
+#line 431 "tmp.rl"
+ }
+
+ action r_F_3
+ {
+#line 75 "tmp.gmr"
+ cout << "F = tt_open E tt_close;" << endl;
+#line 438 "tmp.rl"
+ }
+
+ main :=
+ s0: start: (
+ 23 @shift -> s1 |
+ 25 @shift -> s3 |
+ 24 @shift -> s4 |
+ 0 @shift -> s5
+ ),
+ s1: (
+ 20 @shift -> s54
+ ),
+ s2: (
+ (0|20) @pop2 @newM @r_M_0 @rem2 -> s54
+ ),
+ s3: (
+ (0|20) @pop1 @newM @r_M_1 @rem1 -> s54
+ ),
+ s4: (
+ 20 @pop1 @newstart @r_start_0 @rem1 -> s54 |
+ 25 @shift -> s2 |
+ 0 @shift -> s5
+ ),
+ s5: (
+ 1 @shift -> s6
+ ),
+ s6: (
+ 26 @shift -> s8 |
+ 27 @shift -> s9 |
+ 29 @shift -> s25 |
+ 28 @shift -> s26 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s7: (
+ (0|20) @pop4 @newA @r_A_0 @rem4 -> s54
+ ),
+ s8: (
+ 2 @shift -> s7 |
+ 3 @shift -> s37 |
+ 4 @shift -> s38 |
+ 5 @shift -> s39
+ ),
+ s9: (
+ (2..5|18) @pop1 @newE @r_E_3 @rem1 -> s54 |
+ 29 @shift -> s25 |
+ 30 @shift -> s33 |
+ 28 @shift -> s34 |
+ 17 @shift -> s35 |
+ 6 @shift -> s41 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s10: (
+ (0|2..9|14..18) @pop3 @newN @r_N_0 @rem3 -> s54
+ ),
+ s11: (
+ (0|2..9|14..18) @pop3 @newN @r_N_1 @rem3 -> s54
+ ),
+ s12: (
+ (0|2..9|14..18) @pop3 @newN @r_N_2 @rem3 -> s54
+ ),
+ s13: (
+ 11 @shift -> s14
+ ),
+ s14: (
+ (0|2..9|14..18) @pop4 @newN @r_N_3 @rem4 -> s54
+ ),
+ s15: (
+ 11 @shift -> s16
+ ),
+ s16: (
+ (0|2..9|14..18) @pop4 @newN @r_N_4 @rem4 -> s54
+ ),
+ s17: (
+ 11 @shift -> s18
+ ),
+ s18: (
+ (0|2..9|14..18) @pop4 @newN @r_N_5 @rem4 -> s54
+ ),
+ s19: (
+ 11 @shift -> s20
+ ),
+ s20: (
+ (0|2..9|14..18) @pop4 @newN @r_N_6 @rem4 -> s54
+ ),
+ s21: (
+ 11 @shift -> s22
+ ),
+ s22: (
+ (0|2..9|14..18) @pop4 @newN @r_N_7 @rem4 -> s54
+ ),
+ s23: (
+ 11 @shift -> s24
+ ),
+ s24: (
+ (0|2..9|14..18) @pop4 @newN @r_N_8 @rem4 -> s54
+ ),
+ s25: (
+ (0|2..9|14..18) @pop1 @newN @r_N_9 @rem1 -> s54
+ ),
+ s26: (
+ (0|2..6|14..18) @pop1 @newT @r_T_2 @rem1 -> s54 |
+ 7 @shift -> s27 |
+ 8 @shift -> s28 |
+ 9 @shift -> s29
+ ),
+ s27: (
+ 0 @shift -> s10 |
+ 10 @shift -> s13 |
+ 5 @shift -> s15
+ ),
+ s28: (
+ 0 @shift -> s11 |
+ 10 @shift -> s17 |
+ 5 @shift -> s19
+ ),
+ s29: (
+ 0 @shift -> s12 |
+ 10 @shift -> s21 |
+ 5 @shift -> s23
+ ),
+ s30: (
+ (0|2..9|14..18) @pop2 @newK @r_K_0 @rem2 -> s54
+ ),
+ s31: (
+ (0|2..9|14..18) @pop2 @newK @r_K_1 @rem2 -> s54
+ ),
+ s32: (
+ (0|2..9|14..18) @pop2 @newK @r_K_2 @rem2 -> s54
+ ),
+ s33: (
+ (0|2..9|14..18) @pop1 @newK @r_K_3 @rem1 -> s54 |
+ 12 @shift -> s30 |
+ 13 @shift -> s31 |
+ 10 @shift -> s32
+ ),
+ s34: (
+ (0|2..6|14..18) @pop2 @newT @r_T_1 @rem2 -> s54 |
+ 7 @shift -> s27 |
+ 8 @shift -> s28 |
+ 9 @shift -> s29
+ ),
+ s35: (
+ 27 @shift -> s9 |
+ 29 @shift -> s25 |
+ 28 @shift -> s26 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 26 @shift -> s40 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s36: (
+ (0|2..10|12..18) @pop3 @newF @r_F_3 @rem3 -> s54
+ ),
+ s37: (
+ 29 @shift -> s25 |
+ 28 @shift -> s26 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50 |
+ 27 @shift -> s53
+ ),
+ s38: (
+ 29 @shift -> s25 |
+ 28 @shift -> s26 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50 |
+ 27 @shift -> s52
+ ),
+ s39: (
+ 29 @shift -> s25 |
+ 28 @shift -> s26 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 27 @shift -> s42 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s40: (
+ 18 @shift -> s36 |
+ 3 @shift -> s37 |
+ 4 @shift -> s38 |
+ 5 @shift -> s39
+ ),
+ s41: (
+ 29 @shift -> s25 |
+ 30 @shift -> s33 |
+ 17 @shift -> s35 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50 |
+ 28 @shift -> s51
+ ),
+ s42: (
+ (2..5|18) @pop3 @newE @r_E_2 @rem3 -> s54 |
+ 29 @shift -> s25 |
+ 30 @shift -> s33 |
+ 28 @shift -> s34 |
+ 17 @shift -> s35 |
+ 6 @shift -> s41 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s43: (
+ (0|2..9|14..18) @pop3 @newK @r_K_4 @rem3 -> s54
+ ),
+ s44: (
+ (0|2..9|14..18) @pop3 @newK @r_K_5 @rem3 -> s54
+ ),
+ s45: (
+ (0|2..9|14..18) @pop3 @newK @r_K_6 @rem3 -> s54
+ ),
+ s46: (
+ 17 @shift -> s35 |
+ 30 @shift -> s47 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s47: (
+ (0|2..9|14..18) @pop2 @newK @r_K_7 @rem2 -> s54 |
+ 12 @shift -> s43 |
+ 13 @shift -> s44 |
+ 10 @shift -> s45
+ ),
+ s48: (
+ (0|2..10|12..18) @pop1 @newF @r_F_0 @rem1 -> s54
+ ),
+ s49: (
+ (0|2..10|12..18) @pop1 @newF @r_F_1 @rem1 -> s54
+ ),
+ s50: (
+ (0|2..10|12..18) @pop1 @newF @r_F_2 @rem1 -> s54
+ ),
+ s51: (
+ (0|2..6|14..18) @pop3 @newT @r_T_0 @rem3 -> s54 |
+ 7 @shift -> s27 |
+ 8 @shift -> s28 |
+ 9 @shift -> s29
+ ),
+ s52: (
+ (2..5|18) @pop3 @newE @r_E_1 @rem3 -> s54 |
+ 29 @shift -> s25 |
+ 30 @shift -> s33 |
+ 28 @shift -> s34 |
+ 17 @shift -> s35 |
+ 6 @shift -> s41 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s53: (
+ (2..5|18) @pop3 @newE @r_E_0 @rem3 -> s54 |
+ 29 @shift -> s25 |
+ 30 @shift -> s33 |
+ 28 @shift -> s34 |
+ 17 @shift -> s35 |
+ 6 @shift -> s41 |
+ 14 @shift -> s46 |
+ 15 @shift -> s48 |
+ 16 @shift -> s49 |
+ 0 @shift -> s50
+ ),
+ s54: (
+ '' -> final
+ )
+ ;
+}%%
+
+%% write data;
+
+Parser::Parser( )
+{ }
+
+int Parser::init( )
+{
+ %% write init;
+ return 0;
+}
+
+int Parser::execute( LangEl *_data, int _len )
+{
+ LangEl *p = _data;
+ LangEl *pe = _data+_len;
+ %% write exec;
+ if ( cs == Parser_error )
+ return -1;
+ if ( cs >= Parser_first_final )
+ return 1;
+ return 0;
+}
+
+int Parser::finish( )
+{
+ if ( cs == Parser_error )
+ return -1;
+ if ( cs >= Parser_first_final )
+ return 1;
+ return 0;
+}
+
+void Parser::parseLangEl( LangEl *lel )
+{
+ redLel = 0;
+ execute( lel, 1 );
+ while ( redLel != 0 ) {
+ execute( redLel, 1 );
+ redLel = 0;
+ execute( lel, 1 );
+ }
+}
+
+int Parser::pop( int n )
+{
+ for ( int i = n-1; i >= 0; i-- )
+ rhs[i] = pop();
+ return rhs[0]->state;
+}
+
+void Parser::rem( LangEl *lel, int n )
+{
+ for ( int i = n-1; i >= 0; i-- )
+ delete rhs[i];
+}
+
+int Parser::done( )
+{
+ Token *eof = new Token;
+ eof->type = l__eof;
+ eof->line = 0;
+ eof->pos = 0;
+ parseLangEl( eof );
+ return finish();
+}
+
+#line 77 "tmp.gmr"
+
+
+#include <assert.h>
+#define MAX_TOKS 10000
+
+struct TokList
+{
+ TokList() : numToks(0) { }
+
+ void append( int type );
+ int parse();
+
+ Token *toks[MAX_TOKS];
+ int numToks;
+};
+
+void TokList::append( int type )
+{
+ assert( numToks < MAX_TOKS );
+ toks[numToks] = new Token;
+ toks[numToks]->type = type;
+ numToks += 1;
+}
+
+int TokList::parse()
+{
+ Parser parser;
+ parser.init();
+ for ( int i = 0; i < numToks; i++ )
+ parser.parseLangEl( toks[i] );
+ return parser.done();
+}
+
+void test0()
+{
+ TokList tokList;
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_id );
+ tokList.append( tt_star );
+ tokList.append( tt_minus );
+ tokList.append( tt_andFSM );
+ tokList.append( tt_dot );
+ tokList.append( tt_id );
+ tokList.append( tt_semi );
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_id );
+ tokList.append( tt_andFSM );
+ tokList.append( tt_id );
+ tokList.append( tt_semi );
+ cout << tokList.parse() << endl;
+}
+
+void test1()
+{
+ TokList tokList;
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_open );
+ tokList.append( tt_orFSM );
+ tokList.append( tt_minus );
+ tokList.append( tt_andFSM );
+ tokList.append( tt_close );
+ tokList.append( tt_star );
+ tokList.append( tt_semi );
+ cout << tokList.parse() << endl;
+}
+void test2()
+{
+ TokList tokList;
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_not );
+ tokList.append( tt_open );
+ tokList.append( tt_orFSM );
+ tokList.append( tt_minus );
+ tokList.append( tt_not );
+ tokList.append( tt_andFSM );
+ tokList.append( tt_close );
+ tokList.append( tt_star );
+ tokList.append( tt_semi );
+ cout << tokList.parse() << endl;
+}
+void test3()
+{
+ TokList tokList;
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_id );
+ tokList.append( tt_colon );
+ tokList.append( tt_minus );
+ tokList.append( tt_number );
+ tokList.append( tt_id );
+ tokList.append( tt_colon );
+ tokList.append( tt_id );
+ tokList.append( tt_id );
+ tokList.append( tt_dollar );
+ tokList.append( tt_plus );
+ tokList.append( tt_number );
+ tokList.append( tt_id );
+ tokList.append( tt_percent );
+ tokList.append( tt_minus );
+ tokList.append( tt_number );
+ tokList.append( tt_semi );
+ cout << tokList.parse() << endl;
+}
+void test4()
+{
+ TokList tokList;
+ tokList.append( tt_id );
+ tokList.append( tt_equals );
+ tokList.append( tt_id );
+ tokList.append( tt_pipe );
+ tokList.append( tt_id );
+ tokList.append( tt_amp );
+ tokList.append( tt_id );
+ tokList.append( tt_minus );
+ tokList.append( tt_id );
+ tokList.append( tt_semi );
+ cout << tokList.parse() << endl;
+}
+
+int main()
+{
+ test0();
+ test1();
+ test2();
+ test3();
+ test4();
+}
+
+#ifdef _____OUTPUT_____
+F = tt_id;
+K = F tt_star;
+N = K;
+T = N;
+E = T;
+F = tt_andFSM;
+K = F;
+N = K;
+T = N;
+F = tt_id;
+K = F;
+N = K;
+T = T tt_dot N;
+E = E tt_minus T;
+A = tt_id tt_equals E tt_semi;
+M = A;
+F = tt_id;
+K = F;
+N = K;
+T = N;
+F = tt_andFSM;
+K = F;
+N = K;
+T = T N;
+F = tt_id;
+K = F;
+N = K;
+T = T N;
+E = T;
+A = tt_id tt_equals E tt_semi;
+M = M A;
+start = M;
+1
+F = tt_orFSM;
+K = F;
+N = K;
+T = N;
+E = T;
+F = tt_andFSM;
+K = F;
+N = K;
+T = N;
+E = E tt_minus T;
+F = tt_open E tt_close;
+K = F tt_star;
+N = K;
+T = N;
+E = T;
+A = tt_id tt_equals E tt_semi;
+M = A;
+start = M;
+1
+F = tt_orFSM;
+K = F;
+N = K;
+T = N;
+E = T;
+F = tt_andFSM;
+K = tt_not F;
+N = K;
+T = N;
+E = E tt_minus T;
+F = tt_open E tt_close;
+K = tt_not F tt_star;
+N = K;
+T = N;
+E = T;
+A = tt_id tt_equals E tt_semi;
+M = A;
+start = M;
+1
+F = tt_id;
+K = F;
+N = K;
+N = N tt_colon tt_minus tt_number;
+T = N;
+F = tt_id;
+K = F;
+N = K;
+N = N tt_colon tt_id;
+T = T N;
+F = tt_id;
+K = F;
+N = K;
+N = N tt_dollar tt_plus tt_number;
+T = T N;
+F = tt_id;
+K = F;
+N = K;
+N = N tt_percent tt_minus tt_number;
+T = T N;
+E = T;
+A = tt_id tt_equals E tt_semi;
+M = A;
+start = M;
+1
+F = tt_id;
+K = F;
+N = K;
+T = N;
+E = T;
+F = tt_id;
+K = F;
+N = K;
+T = N;
+E = E tt_pipe T;
+F = tt_id;
+K = F;
+N = K;
+T = N;
+E = E tt_amp T;
+F = tt_id;
+K = F;
+N = K;
+T = N;
+E = E tt_minus T;
+A = tt_id tt_equals E tt_semi;
+M = A;
+start = M;
+1
+#endif
diff --git a/test/langtrans_c.sh b/test/langtrans_c.sh
new file mode 100755
index 0000000..2523b0a
--- /dev/null
+++ b/test/langtrans_c.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+#
+
+file=$1
+
+[ -f $file ] || exit 1
+
+# Get the machine name.
+machine=`sed -n 's/^[\t ]*machine[\t ]*\([a-zA-Z_0-9]*\)[\t ]*;[\t ]*$/\1/p' $file`
+
+# Make a temporary version of the test case using the C language translations.
+sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin langtrans_c.txl > $file.pr
+
+needs_eof=`sed '/@NEEDS_EOF/s/^.*$/yes/p;d' $file`
+if [ "$needs_eof" != 'yes' ]; then
+ needs_eof=`sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin checkeofact.txl`
+fi
+
+# Begin writing out the test case.
+cat << EOF
+/*
+ * @LANG: c
+ * @GENERATED: yes
+EOF
+
+grep '@ALLOW_GENFLAGS:' $file
+grep '@ALLOW_MINFLAGS:' $file
+
+cat << EOF
+ */
+#include <string.h>
+#include <stdio.h>
+EOF
+
+# Write the data declarations
+sed -n '/^%%$/q;p' $file.pr
+
+# Write out the machine specification.
+sed -n '/^%%{$/,/^}%%/p' $file.pr
+
+# Write out the init and execute routines.
+cat << EOF
+int cs;
+%% write data;
+void init()
+{
+EOF
+
+sed -n '0,/^%%$/d; /^%%{$/q; {s/^/\t/;p}' $file.pr
+
+cat << EOF
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+EOF
+
+[ "$needs_eof" = "yes" ] && echo "char *eof = pe;"
+
+cat << EOF
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= ${machine}_first_final )
+ printf( "ACCEPT\\n" );
+ else
+ printf( "FAIL\\n" );
+}
+EOF
+
+# Write out the test data.
+sed -n '0,/\/\* _____INPUT_____/d; /_____INPUT_____ \*\//q; p;' $file | awk '
+BEGIN {
+ print "char *inp[] = {"
+}
+{
+ print " " $0 ","
+}
+END {
+ print "};"
+ print ""
+ print "int inplen = " NR ";"
+}'
+
+# Write out the main routine.
+cat << EOF
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+#ifdef _____OUTPUT_____
+EOF
+
+# Write out the expected output.
+sed -n '0,/\/\* _____OUTPUT_____/d; /_____OUTPUT_____ \*\//q; p;' $file
+echo "#endif"
+
+# Don't need this language-specific file anymore.
+rm $file.pr
diff --git a/test/langtrans_c.txl b/test/langtrans_c.txl
new file mode 100644
index 0000000..5a4971f
--- /dev/null
+++ b/test/langtrans_c.txl
@@ -0,0 +1,335 @@
+include "testcase.txl"
+
+define c_statements
+ [repeat c_lang_stmt]
+end define
+
+define c_lang_stmt
+ [al_ragel_stmt]
+ | [c_variable_decl]
+ | [c_expr_stmt]
+ | [c_if_stmt]
+ | [EX] '{ [IN] [NL] [c_statements] [EX] '} [IN] [NL]
+end define
+
+define c_variable_decl
+ [c_type_decl] [id] [opt union] '; [NL]
+end define
+
+define c_type_decl
+ [al_type_decl]
+ | 'char '*
+end define
+
+define c_expr_stmt
+ [c_expr] '; [NL]
+end define
+
+define c_expr
+ [c_term] [repeat c_expr_extend]
+end define
+
+define c_expr_extend
+ [al_expr_op] [c_term]
+end define
+
+define c_term
+ [al_term]
+ | [id] '( [c_args] ')
+end define
+
+define c_args
+ [list c_expr]
+end define
+
+define c_sign
+ '- | '+
+end define
+
+define c_if_stmt
+ 'if '( [c_expr] ') [NL] [IN]
+ [c_lang_stmt] [EX]
+ [opt c_else]
+end define
+
+define c_else
+ 'else [NL] [IN]
+ [c_lang_stmt] [EX]
+end define
+
+define c_lang
+ [c_statements]
+ '%% [NL]
+ [c_statements]
+ [ragel_def]
+end define
+
+define program
+ [lang_indep]
+ | [c_lang]
+end define
+
+redefine al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+ | '{ [NL] [IN] [c_statements] [EX] '} [NL]
+end define
+
+redefine cond_action_stmt
+ 'action [id] '{ [al_expr] '} [NL]
+ | 'action [id] '{ [c_expr] '} [NL]
+end redefine
+
+
+rule boolTypes
+ replace [al_type_decl]
+ 'bool
+ by
+ 'int
+end rule
+
+rule ptrTypes
+ replace [c_type_decl]
+ 'ptr
+ by
+ 'char '*
+end rule
+
+rule boolVals1
+ replace [al_term]
+ 'true
+ by
+ '1
+end rule
+
+rule boolVals2
+ replace [al_term]
+ 'false
+ by
+ '0
+end rule
+
+function alStmtToC1 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] OptUnion [opt union]';
+ construct CType [c_type_decl]
+ Type
+ construct Result [c_variable_decl]
+ CType [boolTypes] [ptrTypes] Id OptUnion ';
+ replace [repeat c_lang_stmt]
+ by
+ Result
+end function
+
+rule alTermToC1
+ replace [al_term]
+ 'first_token_char
+ by
+ 'ts '[0]
+end rule
+
+rule alTermToC2
+ replace [al_term]
+ '< _ [al_type_decl] '> '( AlExpr [al_expr] ')
+ by
+ '( AlExpr ')
+end rule
+
+function alTermToC
+ replace [al_term]
+ AlTerm [al_term]
+ by
+ AlTerm
+ [alTermToC1]
+ [alTermToC2]
+end function
+
+function alExprExtendToC AlExprExtend [repeat al_expr_extend]
+ deconstruct AlExprExtend
+ Op [al_expr_op] Term [al_term] Rest [repeat al_expr_extend]
+ construct RestC [repeat c_expr_extend]
+ _ [alExprExtendToC Rest]
+ replace [repeat c_expr_extend]
+ by
+ Op Term [alTermToC] RestC
+end function
+
+function alExprToC AlExpr [al_expr]
+ deconstruct AlExpr
+ ALTerm [al_term] AlExprExtend [repeat al_expr_extend]
+ construct CExprExtend [repeat c_expr_extend]
+ _ [alExprExtendToC AlExprExtend]
+ construct Result [opt c_expr]
+ ALTerm [alTermToC] CExprExtend
+ replace [opt c_expr]
+ by
+ Result [boolVals1] [boolVals2]
+end function
+
+function alStmtToC2 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ AlExpr [al_expr] ';
+ construct OptCExpr [opt c_expr]
+ _ [alExprToC AlExpr]
+ deconstruct OptCExpr
+ CExpr [c_expr]
+ replace [repeat c_lang_stmt]
+ by
+ CExpr ';
+end function
+
+function alOptElseC AlOptElse [opt al_else]
+ deconstruct AlOptElse
+ 'else
+ AlSubStmt [action_lang_stmt]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct CSubStmts [repeat c_lang_stmt]
+ _ [alToC AlSubStmts]
+ deconstruct CSubStmts
+ CSubStmt [c_lang_stmt]
+ replace [opt c_else]
+ by
+ 'else
+ CSubStmt
+end function
+
+function alStmtToC3 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'if '( AlExpr [al_expr] ')
+ AlSubStmt [action_lang_stmt]
+ AlOptElse [opt al_else]
+ construct OptCExpr [opt c_expr]
+ _ [alExprToC AlExpr]
+ deconstruct OptCExpr
+ CExpr [c_expr]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct CSubStmts [repeat c_lang_stmt]
+ _ [alToC AlSubStmts]
+ deconstruct CSubStmts
+ CSubStmt [c_lang_stmt]
+ construct OptCElse [opt c_else]
+ _ [alOptElseC AlOptElse]
+ replace [repeat c_lang_stmt]
+ by
+ 'if '( CExpr ')
+ CSubStmt
+ OptCElse
+end function
+
+function alStmtToC4a AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printi Id [id] ';
+ replace [repeat c_lang_stmt]
+ by
+ 'printf '( '"%i" ', Id ');
+end function
+
+function alStmtToC4b AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'prints String [stringlit] ';
+ replace [repeat c_lang_stmt]
+ by
+ 'fputs '( String , 'stdout ');
+end function
+
+function alStmtToC4c AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printb Id [id] ';
+ replace [repeat c_lang_stmt]
+ by
+ 'fwrite '( Id ', '1 ', 'pos ', 'stdout ');
+end function
+
+function alStmtToC4d AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'print_token ';
+ replace [repeat c_lang_stmt]
+ by
+ 'fwrite '( 'ts ', '1 ', 'te '- 'ts ', 'stdout ');
+end function
+
+function alStmtToC5 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ '{ AlSubStmts [repeat action_lang_stmt] '}
+ construct CSubStmts [repeat c_lang_stmt]
+ _ [alToC AlSubStmts]
+ replace [repeat c_lang_stmt]
+ by
+ '{ CSubStmts '}
+end function
+
+function alStmtToC6 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ RagelStmt [al_ragel_stmt]
+ replace [repeat c_lang_stmt]
+ by
+ RagelStmt
+end function
+
+function alToC AlStmts [repeat action_lang_stmt]
+ deconstruct AlStmts
+ FirstStmt [action_lang_stmt] Rest [repeat action_lang_stmt]
+ construct FirstC [repeat c_lang_stmt]
+ _
+ [alStmtToC1 FirstStmt]
+ [alStmtToC2 FirstStmt]
+ [alStmtToC3 FirstStmt]
+ [alStmtToC4a FirstStmt]
+ [alStmtToC4b FirstStmt]
+ [alStmtToC4c FirstStmt]
+ [alStmtToC4d FirstStmt]
+ [alStmtToC5 FirstStmt]
+ [alStmtToC6 FirstStmt]
+ construct RestC [repeat c_lang_stmt]
+ _ [alToC Rest]
+ replace [repeat c_lang_stmt]
+ by
+ FirstC [. RestC]
+end function
+
+rule actionTransC
+ replace [al_host_block]
+ '{ AlStmts [repeat action_lang_stmt] '}
+ construct CStmts [repeat c_lang_stmt]
+ _ [alToC AlStmts]
+ by
+ '{ CStmts '}
+end rule
+
+rule condTransC
+ replace [cond_action_stmt]
+ 'action Id [id] '{ AlExpr [al_expr] '}
+ construct OptCExpr [opt c_expr]
+ _ [alExprToC AlExpr]
+ deconstruct OptCExpr
+ CExpr [c_expr]
+ by
+ 'action Id '{ CExpr '}
+end rule
+
+function langTransC
+ replace [program]
+ Definitions [repeat action_lang_stmt]
+ '%%
+ Initializations [repeat action_lang_stmt]
+ RagelDef [ragel_def]
+ construct CDefinitions [repeat c_lang_stmt]
+ _ [alToC Definitions]
+ construct CInitializations [repeat c_lang_stmt]
+ _ [alToC Initializations]
+ by
+ CDefinitions
+ '%%
+ CInitializations
+ RagelDef [actionTransC] [condTransC]
+end function
+
+function main
+ replace [program]
+ P [program]
+ by
+ P [langTransC]
+end function
diff --git a/test/langtrans_csharp.sh b/test/langtrans_csharp.sh
new file mode 100755
index 0000000..3980f48
--- /dev/null
+++ b/test/langtrans_csharp.sh
@@ -0,0 +1,109 @@
+#!/bin/bash
+#
+
+file=$1
+
+[ -f $file ] || exit 1
+root=${file%.rl}
+class=${root}_csharp
+
+# Make a temporary version of the test case using the Java language translations.
+sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin langtrans_csharp.txl - $class > $file.pr
+
+# Begin writing out the test case.
+cat << EOF
+/*
+ * @LANG: csharp
+ * @GENERATED: yes
+EOF
+
+grep '@ALLOW_GENFLAGS:' $file | sed 's/-G2//g'
+grep '@ALLOW_MINFLAGS:' $file
+
+cat << EOF
+ */
+using System;
+// Disables lots of warnings that appear in the test suite
+#pragma warning disable 0168, 0169, 0219, 0162, 0414
+namespace Test {
+class $class
+{
+EOF
+
+# Write the data declarations
+sed -n '/^%%$/q;{s/^/\t/;p}' $file.pr
+
+# Write out the machine specification.
+sed -n '/^%%{$/,/^}%%/{s/^/\t/;p}' $file.pr
+
+# Write out the init and execute routines.
+cat << EOF
+
+ int cs;
+ %% write data;
+
+ void init()
+ {
+EOF
+
+sed -n '0,/^%%$/d; /^%%{$/q; {s/^/\t\t/;p}' $file.pr
+
+cat << EOF
+ %% write init;
+ }
+
+ void exec( char[] data, int len )
+ {
+ int p = 0;
+ int pe = len;
+ int eof = len;
+ string _s;
+ %% write exec;
+ }
+
+ void finish( )
+ {
+ if ( cs >= ${class}_first_final )
+ Console.WriteLine( "ACCEPT" );
+ else
+ Console.WriteLine( "FAIL" );
+ }
+
+EOF
+
+# Write out the test data.
+sed -n '0,/\/\* _____INPUT_____/d; /_____INPUT_____ \*\//q; p;' $file | awk '
+BEGIN {
+ print " static readonly string[] inp = {"
+}
+{
+ print " " $0 ","
+}
+END {
+ print " };"
+ print ""
+ print " static readonly int inplen = " NR ";"
+}'
+
+
+# Write out the main routine.
+cat << EOF
+
+ public static void Main (string[] args)
+ {
+ $class machine = new $class();
+ for ( int i = 0; i < inplen; i++ ) {
+ machine.init();
+ machine.exec( inp[i].ToCharArray(), inp[i].Length );
+ machine.finish();
+ }
+ }
+}
+}
+EOF
+
+# Write out the expected output.
+sed -n '/\/\* _____OUTPUT_____/,/_____OUTPUT_____ \*\//p;' $file
+
+# Don't need this language-specific file anymore.
+rm $file.pr
diff --git a/test/langtrans_csharp.txl b/test/langtrans_csharp.txl
new file mode 100644
index 0000000..a8c6003
--- /dev/null
+++ b/test/langtrans_csharp.txl
@@ -0,0 +1,358 @@
+include "testcase.txl"
+
+keys
+ 'bool 'new
+end keys
+
+
+define csharp_statements
+ [repeat csharp_lang_stmt]
+end define
+
+define csharp_lang_stmt
+ [al_ragel_stmt]
+ | [csharp_variable_decl]
+ | [csharp_expr_stmt]
+ | [csharp_if_stmt]
+ | [EX] '{ [IN] [NL] [csharp_statements] [EX] '} [IN] [NL]
+end define
+
+define csharp_variable_decl
+ [csharp_type_decl] [opt union] [id] '; [NL]
+end define
+
+define csharp_type_decl
+ [al_type_decl]
+ | 'bool
+ | 'String
+end define
+
+define csharp_expr_stmt
+ [csharp_expr] '; [NL]
+end define
+
+define csharp_expr
+ [csharp_term] [repeat csharp_expr_extend]
+end define
+
+define csharp_expr_extend
+ [al_expr_op] [csharp_term]
+end define
+
+define csharp_term
+ [al_term]
+ | [id] [repeat csharp_dot_id]
+ | [id] [repeat csharp_dot_id] '( [csharp_args] ')
+ | 'new [csharp_type_decl] [union]
+ | 'new [csharp_type_decl] '( [csharp_args] ')
+end define
+
+define csharp_dot_id
+ '. [id]
+end define
+
+define csharp_args
+ [list csharp_expr]
+end define
+
+define csharp_sign
+ '- | '+
+end define
+
+define csharp_if_stmt
+ 'if '( [csharp_expr] ') [NL] [IN]
+ [csharp_lang_stmt] [EX]
+ [opt csharp_else]
+end define
+
+define csharp_else
+ 'else [NL] [IN]
+ [csharp_lang_stmt] [EX]
+end define
+
+define csharp_lang
+ [csharp_statements]
+ '%% [NL]
+ [csharp_statements]
+ [ragel_def]
+end define
+
+define program
+ [lang_indep]
+ | [csharp_lang]
+end define
+
+redefine al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+ | '{ [NL] [IN] [csharp_statements] [EX] '} [NL]
+end define
+
+redefine cond_action_stmt
+ 'action [id] '{ [al_expr] '} [NL]
+ | 'action [id] '{ [csharp_expr] '} [NL]
+end redefine
+
+
+function clearUnion Type [csharp_type_decl] Id [id]
+ replace [opt union]
+ Union [union]
+ import ArrayInits [csharp_statements]
+ Stmts [repeat csharp_lang_stmt]
+ export ArrayInits
+ Id '= 'new Type Union '; Stmts
+ by
+ '[]
+end function
+
+rule ptrTypes
+ replace [al_type_decl]
+ 'ptr
+ by
+ 'int
+end rule
+
+function alStmtToCSharp1 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] OptUnion [opt union] ';
+ construct CSharpType [csharp_type_decl]
+ Type
+ construct Result [csharp_variable_decl]
+ CSharpType [ptrTypes] OptUnion [clearUnion CSharpType Id] Id ';
+ replace [repeat csharp_lang_stmt]
+ by
+ Result
+end function
+
+rule alTermToCSharp1
+ replace [al_term]
+ 'first_token_char
+ by
+ 'data '[ts]
+end rule
+
+rule alTermToCSharp2
+ replace [al_term]
+ '< _ [al_type_decl] '> '( AlExpr [al_expr] ')
+ by
+ '( AlExpr ')
+end rule
+
+function alTermToCSharp
+ replace [al_term]
+ AlTerm [al_term]
+ by
+ AlTerm
+ [alTermToCSharp1]
+ [alTermToCSharp2]
+end function
+
+function alExprExtendToCSharp AlExprExtend [repeat al_expr_extend]
+ deconstruct AlExprExtend
+ Op [al_expr_op] Term [al_term] Rest [repeat al_expr_extend]
+ construct CSharpRest [repeat csharp_expr_extend]
+ _ [alExprExtendToCSharp Rest]
+ replace [repeat csharp_expr_extend]
+ by
+ Op Term [alTermToCSharp] CSharpRest
+end function
+
+function alExprToCSharp AlExpr [al_expr]
+ deconstruct AlExpr
+ ALTerm [al_term] AlExprExtend [repeat al_expr_extend]
+ construct CSharpExprExtend [repeat csharp_expr_extend]
+ _ [alExprExtendToCSharp AlExprExtend]
+ construct Result [opt csharp_expr]
+ ALTerm [alTermToCSharp] CSharpExprExtend
+ replace [opt csharp_expr]
+ by
+ Result
+end function
+
+function alStmtToCSharp2 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ AlExpr [al_expr] ';
+ construct OptCSharpExpr [opt csharp_expr]
+ _ [alExprToCSharp AlExpr]
+ deconstruct OptCSharpExpr
+ CSharpExpr [csharp_expr]
+ replace [repeat csharp_lang_stmt]
+ by
+ CSharpExpr ';
+end function
+
+function alOptElseCSharp AlOptElse [opt al_else]
+ deconstruct AlOptElse
+ 'else
+ AlSubStmt [action_lang_stmt]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct CSharpSubStmts [repeat csharp_lang_stmt]
+ _ [alToCSharp AlSubStmts]
+ deconstruct CSharpSubStmts
+ CSharpSubStmt [csharp_lang_stmt]
+ replace [opt csharp_else]
+ by
+ 'else
+ CSharpSubStmt
+end function
+
+function alStmtToCSharp3 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'if '( AlExpr [al_expr] ')
+ AlSubStmt [action_lang_stmt]
+ AlOptElse [opt al_else]
+ construct OptCSharpExpr [opt csharp_expr]
+ _ [alExprToCSharp AlExpr]
+ deconstruct OptCSharpExpr
+ CSharpExpr [csharp_expr]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct CSharpSubStmts [repeat csharp_lang_stmt]
+ _ [alToCSharp AlSubStmts]
+ deconstruct CSharpSubStmts
+ CSharpSubStmt [csharp_lang_stmt]
+ construct OptCSharpElse [opt csharp_else]
+ _ [alOptElseCSharp AlOptElse]
+ replace [repeat csharp_lang_stmt]
+ by
+ 'if '( CSharpExpr ')
+ CSharpSubStmt
+ OptCSharpElse
+end function
+
+function alStmtToCSharp4a AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printi Id [id] ';
+ replace [repeat csharp_lang_stmt]
+ by
+ 'Console '. 'Write '( Id ');
+end function
+
+function alStmtToCSharp4b AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'prints String [stringlit] ';
+ replace [repeat csharp_lang_stmt]
+ by
+ 'Console '. 'Write '( String ');
+end function
+
+function alStmtToCSharp4c AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printb Id [id] ';
+ replace [repeat csharp_lang_stmt]
+ by
+ '_s '= 'new 'String '( Id ', '0 ', 'pos ') ';
+ 'Console '. 'Write '( '_s ');
+end function
+
+function alStmtToCSharp4d AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'print_token ';
+ replace [repeat csharp_lang_stmt]
+ by
+ '_s '= 'new 'String '( 'data ', 'ts ', 'te '- 'ts ') ';
+ 'Console '. 'Write '( '_s ');
+end function
+
+function alStmtToCSharp5 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ '{ AlSubStmts [repeat action_lang_stmt] '}
+ construct CSharpSubStmts [repeat csharp_lang_stmt]
+ _ [alToCSharp AlSubStmts]
+ replace [repeat csharp_lang_stmt]
+ by
+ '{ CSharpSubStmts '}
+end function
+
+function alStmtToCSharp6 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ RagelStmt [al_ragel_stmt]
+ replace [repeat csharp_lang_stmt]
+ by
+ RagelStmt
+end function
+
+
+function alToCSharp AlStmts [repeat action_lang_stmt]
+ deconstruct AlStmts
+ FirstStmt [action_lang_stmt] Rest [repeat action_lang_stmt]
+ construct CSharpFirst [repeat csharp_lang_stmt]
+ _
+ [alStmtToCSharp1 FirstStmt]
+ [alStmtToCSharp2 FirstStmt]
+ [alStmtToCSharp3 FirstStmt]
+ [alStmtToCSharp4a FirstStmt]
+ [alStmtToCSharp4b FirstStmt]
+ [alStmtToCSharp4c FirstStmt]
+ [alStmtToCSharp4d FirstStmt]
+ [alStmtToCSharp5 FirstStmt]
+ [alStmtToCSharp6 FirstStmt]
+ construct CSharpRest [repeat csharp_lang_stmt]
+ _ [alToCSharp Rest]
+ replace [repeat csharp_lang_stmt]
+ by
+ CSharpFirst [. CSharpRest]
+end function
+
+rule actionTransCSharp
+ replace [al_host_block]
+ '{ AlStmts [repeat action_lang_stmt] '}
+ construct CSharpStmts [repeat csharp_lang_stmt]
+ _ [alToCSharp AlStmts]
+ by
+ '{ CSharpStmts '}
+end rule
+
+rule condTransCSharp
+ replace [cond_action_stmt]
+ 'action Id [id] '{ AlExpr [al_expr] '}
+ construct OptCSharpExpr [opt csharp_expr]
+ _ [alExprToCSharp AlExpr]
+ deconstruct OptCSharpExpr
+ CSharpExpr [csharp_expr]
+ by
+ 'action Id '{ CSharpExpr '}
+end rule
+
+rule machineName
+ replace $ [machine_stmt]
+ 'machine _ [id] ';
+ import TXLargs [repeat stringlit]
+ Arg1 [stringlit] _ [repeat stringlit]
+ construct ClassName [id]
+ _ [unquote Arg1]
+ by
+ 'machine ClassName ';
+end rule
+
+function langTransCSharp
+ replace [program]
+ Definitions [repeat action_lang_stmt]
+ '%%
+ Initializations [repeat action_lang_stmt]
+ RagelDef [ragel_def]
+ construct CSharpDefinitions [repeat csharp_lang_stmt]
+ _ [alToCSharp Definitions]
+ construct CSharpInitializations [repeat csharp_lang_stmt]
+ _ [alToCSharp Initializations]
+ construct NewRagelDef [ragel_def]
+ RagelDef [actionTransCSharp] [condTransCSharp] [machineName]
+ import ArrayInits [csharp_statements]
+ ArrayInitStmts [repeat csharp_lang_stmt]
+ by
+ CSharpDefinitions
+ '%%
+ ArrayInitStmts [. CSharpInitializations]
+ NewRagelDef
+end function
+
+function main
+ replace [program]
+ P [program]
+ export ArrayInits [csharp_statements]
+ _
+ by
+ P [langTransCSharp]
+end function
diff --git a/test/langtrans_d.sh b/test/langtrans_d.sh
new file mode 100755
index 0000000..764afd7
--- /dev/null
+++ b/test/langtrans_d.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+#
+
+file=$1
+
+[ -f $file ] || exit 1
+
+# Get the amchine name.
+machine=`sed -n 's/^[\t ]*machine[\t ]*\([a-zA-Z_0-9]*\)[\t ]*;[\t ]*$/\1/p' $file`
+
+# Make a temporary version of the test case the D language translations.
+sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin langtrans_d.txl > $file.pr
+
+# Begin writing out the test case.
+cat << EOF
+/*
+ * @LANG: d
+ * @GENERATED: yes
+EOF
+
+grep '@ALLOW_GENFLAGS:' $file
+grep '@ALLOW_MINFLAGS:' $file
+
+cat << EOF
+ */
+import std.stdio;
+import std.string;
+
+class $machine
+{
+EOF
+
+# Write the data declarations
+sed -n '/^%%$/q;{s/^/\t/;p}' $file.pr
+
+# Write out the machine specification.
+sed -n '/^%%{$/,/^}%%/{s/^/\t/;p}' $file.pr
+
+# Write out the init and execute routines.
+cat << EOF
+ int cs;
+ %% write data;
+ void init()
+ {
+EOF
+
+sed -n '0,/^%%$/d; /^%%{$/q; {s/^/\t\t/;p}' $file.pr
+
+cat << EOF
+ %% write init;
+ }
+
+ void exec( char data[] )
+ {
+ char *p = data.ptr;
+ char *pe = data.ptr + data.length;
+ char *eof = pe;
+ char _s[];
+
+ %% write exec;
+ }
+
+ void finish( )
+ {
+ if ( cs >= ${machine}_first_final )
+ writefln( "ACCEPT" );
+ else
+ writefln( "FAIL" );
+ }
+
+EOF
+
+# Write out the test data.
+sed -n '0,/\/\* _____INPUT_____/d; /_____INPUT_____ \*\//q; p;' $file | awk '
+BEGIN {
+ print " char[][] inp = ["
+}
+{
+ print " " $0 ","
+}
+END {
+ print " ];"
+ print ""
+ print " int inplen = " NR ";"
+}'
+
+# Write out the main routine.
+cat << EOF
+}
+
+int main( )
+{
+ $machine m = new $machine();
+ int i;
+ for ( i = 0; i < m.inplen; i++ ) {
+ m.init();
+ m.exec( m.inp[i] );
+ m.finish();
+ }
+ return 0;
+}
+/* _____OUTPUT_____
+EOF
+
+# Write out the expected output.
+sed -n '0,/\/\* _____OUTPUT_____/d; /_____OUTPUT_____ \*\//q; p;' $file
+echo "*/"
+
+# Don't need this language-specific file anymore.
+rm $file.pr
diff --git a/test/langtrans_d.txl b/test/langtrans_d.txl
new file mode 100644
index 0000000..845a003
--- /dev/null
+++ b/test/langtrans_d.txl
@@ -0,0 +1,299 @@
+include "testcase.txl"
+
+define d_statements
+ [repeat d_lang_stmt]
+end define
+
+define d_lang_stmt
+ [al_ragel_stmt]
+ | [d_variable_decl]
+ | [d_expr_stmt]
+ | [d_if_stmt]
+ | [EX] '{ [IN] [NL] [d_statements] [EX] '} [IN] [NL]
+end define
+
+define d_variable_decl
+ [d_type_decl] [id] [opt union] '; [NL]
+end define
+
+define d_type_decl
+ [al_type_decl]
+ | 'char '*
+end define
+
+define d_expr_stmt
+ [d_expr] '; [NL]
+end define
+
+define d_expr
+ [d_term] [repeat d_expr_extend]
+end define
+
+define d_expr_extend
+ [al_expr_op] [d_term]
+end define
+
+define d_term
+ [al_term]
+ | [id] '( [d_args] ')
+end define
+
+define d_args
+ [list d_expr]
+end define
+
+define d_sign
+ '- | '+
+end define
+
+define d_if_stmt
+ 'if '( [d_expr] ') [NL] [IN]
+ [d_lang_stmt] [EX]
+ [opt d_else]
+end define
+
+define d_else
+ 'else [NL] [IN]
+ [d_lang_stmt] [EX]
+end define
+
+define d_lang
+ [d_statements]
+ '%% [NL]
+ [d_statements]
+ [ragel_def]
+end define
+
+define program
+ [lang_indep]
+ | [d_lang]
+end define
+
+redefine al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+ | '{ [NL] [IN] [d_statements] [EX] '} [NL]
+end define
+
+rule ptrTypes
+ replace [d_type_decl]
+ 'ptr
+ by
+ 'char '*
+end rule
+
+function alStmtToD1 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] OptUnion [opt union] ';
+ construct DType [d_type_decl]
+ Type
+ construct Result [d_variable_decl]
+ DType [ptrTypes] Id OptUnion ';
+ replace [repeat d_lang_stmt]
+ by
+ Result
+end function
+
+rule alTermToD1
+ replace [al_term]
+ 'first_token_char
+ by
+ 'ts '[0]
+end rule
+
+rule alTermToD2
+ replace [al_term]
+ '< _ [al_type_decl] '> '( AlExpr [al_expr] ')
+ by
+ '( AlExpr ')
+end rule
+
+function alTermToD
+ replace [al_term]
+ AlTerm [al_term]
+ by
+ AlTerm
+ [alTermToD1]
+ [alTermToD2]
+end function
+
+function alExprExtendToD AlExprExtend [repeat al_expr_extend]
+ deconstruct AlExprExtend
+ Op [al_expr_op] Term [al_term] Rest [repeat al_expr_extend]
+ construct DRest [repeat d_expr_extend]
+ _ [alExprExtendToD Rest]
+ replace [repeat d_expr_extend]
+ by
+ Op Term [alTermToD] DRest
+end function
+
+function alExprToD AlExpr [al_expr]
+ deconstruct AlExpr
+ ALTerm [al_term] AlExprExtend [repeat al_expr_extend]
+ construct DExprExtend [repeat d_expr_extend]
+ _ [alExprExtendToD AlExprExtend]
+ construct Result [opt d_expr]
+ ALTerm [alTermToD] DExprExtend
+ replace [opt d_expr]
+ by
+ Result
+end function
+
+function alStmtToD2 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ AlExpr [al_expr] ';
+ construct OptDExpr [opt d_expr]
+ _ [alExprToD AlExpr]
+ deconstruct OptDExpr
+ DExpr [d_expr]
+ replace [repeat d_lang_stmt]
+ by
+ DExpr ';
+end function
+
+function alOptElseD AlOptElse [opt al_else]
+ deconstruct AlOptElse
+ 'else
+ AlSubStmt [action_lang_stmt]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct DSubStmts [repeat d_lang_stmt]
+ _ [alToD AlSubStmts]
+ deconstruct DSubStmts
+ DSubStmt [d_lang_stmt]
+ replace [opt d_else]
+ by
+ 'else
+ DSubStmt
+end function
+
+function alStmtToD3 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'if '( AlExpr [al_expr] ')
+ AlSubStmt [action_lang_stmt]
+ AlOptElse [opt al_else]
+ construct OptDExpr [opt d_expr]
+ _ [alExprToD AlExpr]
+ deconstruct OptDExpr
+ DExpr [d_expr]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct DSubStmts [repeat d_lang_stmt]
+ _ [alToD AlSubStmts]
+ deconstruct DSubStmts
+ DSubStmt [d_lang_stmt]
+ construct OptDElse [opt d_else]
+ _ [alOptElseD AlOptElse]
+ replace [repeat d_lang_stmt]
+ by
+ 'if '( DExpr ')
+ DSubStmt
+ OptDElse
+end function
+
+function alStmtToD4a AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printi Id [id] ';
+ replace [repeat d_lang_stmt]
+ by
+ 'writef '( '"%d" ', Id ') ';
+end function
+
+function alStmtToD4b AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'prints String [stringlit] ';
+ replace [repeat d_lang_stmt]
+ by
+ 'writef '( '"%s" ', String ') ';
+end function
+
+function alStmtToD4c AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printb Id [id] ';
+ replace [repeat d_lang_stmt]
+ by
+ '_s '= Id '[0..pos] ';
+ 'writef '( '"%s" ', '_s ') ';
+end function
+
+function alStmtToD4d AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'print_token ';
+ replace [repeat d_lang_stmt]
+ by
+ '_s '= ts '[0..(te-ts)] ';
+ 'writef '( '"%s" ', '_s ') ';
+end function
+
+function alStmtToD5 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ '{ AlSubStmts [repeat action_lang_stmt] '}
+ construct DSubStmts [repeat d_lang_stmt]
+ _ [alToD AlSubStmts]
+ replace [repeat d_lang_stmt]
+ by
+ '{ DSubStmts '}
+end function
+
+function alStmtToD6 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ RagelStmt [al_ragel_stmt]
+ replace [repeat d_lang_stmt]
+ by
+ RagelStmt
+end function
+
+function alToD AlStmts [repeat action_lang_stmt]
+ deconstruct AlStmts
+ FirstStmt [action_lang_stmt] Rest [repeat action_lang_stmt]
+ construct DFirst [repeat d_lang_stmt]
+ _
+ [alStmtToD1 FirstStmt]
+ [alStmtToD2 FirstStmt]
+ [alStmtToD3 FirstStmt]
+ [alStmtToD4a FirstStmt]
+ [alStmtToD4b FirstStmt]
+ [alStmtToD4c FirstStmt]
+ [alStmtToD4d FirstStmt]
+ [alStmtToD5 FirstStmt]
+ [alStmtToD6 FirstStmt]
+ construct DRest [repeat d_lang_stmt]
+ _ [alToD Rest]
+ replace [repeat d_lang_stmt]
+ by
+ DFirst [. DRest]
+end function
+
+rule actionTransD
+ replace [al_host_block]
+ '{ AlStmts [repeat action_lang_stmt] '}
+ construct DStmts [repeat d_lang_stmt]
+ _ [alToD AlStmts]
+ by
+ '{ DStmts '}
+end rule
+
+function langTransD
+ replace [program]
+ Definitions [repeat action_lang_stmt]
+ '%%
+ Initializations [repeat action_lang_stmt]
+ RagelDef [ragel_def]
+ construct DDefinitions [repeat d_lang_stmt]
+ _ [alToD Definitions]
+ construct DInitializations [repeat d_lang_stmt]
+ _ [alToD Initializations]
+ by
+ DDefinitions
+ '%%
+ DInitializations
+ RagelDef [actionTransD]
+end function
+
+function main
+ replace [program]
+ P [program]
+ by
+ P [langTransD]
+end function
diff --git a/test/langtrans_java.sh b/test/langtrans_java.sh
new file mode 100755
index 0000000..69a6f90
--- /dev/null
+++ b/test/langtrans_java.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+#
+
+file=$1
+
+[ -f $file ] || exit 1
+root=${file%.rl}
+class=${root}_java
+
+# Make a temporary version of the test case using the Java language translations.
+sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin langtrans_java.txl - $class > $file.pr
+
+# Begin writing out the test case.
+cat << EOF
+/*
+ * @LANG: java
+ * @GENERATED: yes
+EOF
+
+grep '@ALLOW_GENFLAGS:' $file
+grep '@ALLOW_MINFLAGS:' $file
+
+cat << EOF
+ */
+
+class $class
+{
+EOF
+
+# Write the data declarations
+sed -n '/^%%$/q;{s/^/\t/;p}' $file.pr
+
+# Write out the machine specification.
+sed -n '/^%%{$/,/^}%%/{s/^/\t/;p}' $file.pr
+
+# Write out the init and execute routines.
+cat << EOF
+
+ int cs;
+ %% write data;
+
+ void init()
+ {
+EOF
+
+sed -n '0,/^%%$/d; /^%%{$/q; {s/^/\t\t/;p}' $file.pr
+
+cat << EOF
+ %% write init;
+ }
+
+ void exec( char data[], int len )
+ {
+ int p = 0;
+ int pe = len;
+ int eof = len;
+ String _s;
+ %% write exec;
+ }
+
+ void finish( )
+ {
+ if ( cs >= ${class}_first_final )
+ System.out.println( "ACCEPT" );
+ else
+ System.out.println( "FAIL" );
+ }
+
+EOF
+
+# Write out the test data.
+sed -n '0,/\/\* _____INPUT_____/d; /_____INPUT_____ \*\//q; p;' $file | awk '
+BEGIN {
+ print " static final String inp[] = {"
+}
+{
+ print " " $0 ","
+}
+END {
+ print " };"
+ print ""
+ print " static final int inplen = " NR ";"
+}'
+
+
+# Write out the main routine.
+cat << EOF
+
+ public static void main (String[] args)
+ {
+ $class machine = new $class();
+ for ( int i = 0; i < inplen; i++ ) {
+ machine.init();
+ machine.exec( inp[i].toCharArray(), inp[i].length() );
+ machine.finish();
+ }
+ }
+}
+
+EOF
+
+# Write out the expected output.
+sed -n '/\/\* _____OUTPUT_____/,/_____OUTPUT_____ \*\//p;' $file
+
+# Don't need this language-specific file anymore.
+rm $file.pr
diff --git a/test/langtrans_java.txl b/test/langtrans_java.txl
new file mode 100644
index 0000000..c5cde5d
--- /dev/null
+++ b/test/langtrans_java.txl
@@ -0,0 +1,365 @@
+include "testcase.txl"
+
+keys
+ 'boolean 'new
+end keys
+
+
+define java_statements
+ [repeat java_lang_stmt]
+end define
+
+define java_lang_stmt
+ [al_ragel_stmt]
+ | [java_variable_decl]
+ | [java_expr_stmt]
+ | [java_if_stmt]
+ | [EX] '{ [IN] [NL] [java_statements] [EX] '} [IN] [NL]
+end define
+
+define java_variable_decl
+ [java_type_decl] [id] [opt union] '; [NL]
+end define
+
+define java_type_decl
+ [al_type_decl]
+ | 'boolean
+ | 'String
+end define
+
+define java_expr_stmt
+ [java_expr] '; [NL]
+end define
+
+define java_expr
+ [java_term] [repeat java_expr_extend]
+end define
+
+define java_expr_extend
+ [al_expr_op] [java_term]
+end define
+
+define java_term
+ [al_term]
+ | [id] [repeat java_dot_id]
+ | [id] [repeat java_dot_id] '( [java_args] ')
+ | 'new [java_type_decl] [union]
+ | 'new [java_type_decl] '( [java_args] ')
+end define
+
+define java_dot_id
+ '. [id]
+end define
+
+define java_args
+ [list java_expr]
+end define
+
+define java_sign
+ '- | '+
+end define
+
+define java_if_stmt
+ 'if '( [java_expr] ') [NL] [IN]
+ [java_lang_stmt] [EX]
+ [opt java_else]
+end define
+
+define java_else
+ 'else [NL] [IN]
+ [java_lang_stmt] [EX]
+end define
+
+define java_lang
+ [java_statements]
+ '%% [NL]
+ [java_statements]
+ [ragel_def]
+end define
+
+define program
+ [lang_indep]
+ | [java_lang]
+end define
+
+redefine al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+ | '{ [NL] [IN] [java_statements] [EX] '} [NL]
+end define
+
+redefine cond_action_stmt
+ 'action [id] '{ [al_expr] '} [NL]
+ | 'action [id] '{ [java_expr] '} [NL]
+end redefine
+
+
+function clearUnion Type [java_type_decl] Id [id]
+ replace [opt union]
+ Union [union]
+ import ArrayInits [java_statements]
+ Stmts [repeat java_lang_stmt]
+ export ArrayInits
+ Id '= 'new Type Union '; Stmts
+ by
+ '[]
+end function
+
+rule boolTypes
+ replace [java_type_decl]
+ 'bool
+ by
+ 'boolean
+end rule
+
+rule ptrTypes
+ replace [al_type_decl]
+ 'ptr
+ by
+ 'int
+end rule
+
+function alStmtToJava1 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] OptUnion [opt union] ';
+ construct JavaType [java_type_decl]
+ Type
+ construct Result [java_variable_decl]
+ JavaType [boolTypes] [ptrTypes] Id OptUnion [clearUnion JavaType Id] ';
+ replace [repeat java_lang_stmt]
+ by
+ Result
+end function
+
+rule alTermToJava1
+ replace [al_term]
+ 'first_token_char
+ by
+ 'data '[ts]
+end rule
+
+rule alTermToJava2
+ replace [al_term]
+ '< _ [al_type_decl] '> '( AlExpr [al_expr] ')
+ by
+ '( AlExpr ')
+end rule
+
+function alTermToJava
+ replace [al_term]
+ AlTerm [al_term]
+ by
+ AlTerm
+ [alTermToJava1]
+ [alTermToJava2]
+end function
+
+function alExprExtendToJava AlExprExtend [repeat al_expr_extend]
+ deconstruct AlExprExtend
+ Op [al_expr_op] Term [al_term] Rest [repeat al_expr_extend]
+ construct JavaRest [repeat java_expr_extend]
+ _ [alExprExtendToJava Rest]
+ replace [repeat java_expr_extend]
+ by
+ Op Term [alTermToJava] JavaRest
+end function
+
+function alExprToJava AlExpr [al_expr]
+ deconstruct AlExpr
+ ALTerm [al_term] AlExprExtend [repeat al_expr_extend]
+ construct JavaExprExtend [repeat java_expr_extend]
+ _ [alExprExtendToJava AlExprExtend]
+ construct Result [opt java_expr]
+ ALTerm [alTermToJava] JavaExprExtend
+ replace [opt java_expr]
+ by
+ Result
+end function
+
+function alStmtToJava2 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ AlExpr [al_expr] ';
+ construct OptJavaExpr [opt java_expr]
+ _ [alExprToJava AlExpr]
+ deconstruct OptJavaExpr
+ JavaExpr [java_expr]
+ replace [repeat java_lang_stmt]
+ by
+ JavaExpr ';
+end function
+
+function alOptElseJava AlOptElse [opt al_else]
+ deconstruct AlOptElse
+ 'else
+ AlSubStmt [action_lang_stmt]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct JavaSubStmts [repeat java_lang_stmt]
+ _ [alToJava AlSubStmts]
+ deconstruct JavaSubStmts
+ JavaSubStmt [java_lang_stmt]
+ replace [opt java_else]
+ by
+ 'else
+ JavaSubStmt
+end function
+
+function alStmtToJava3 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'if '( AlExpr [al_expr] ')
+ AlSubStmt [action_lang_stmt]
+ AlOptElse [opt al_else]
+ construct OptJavaExpr [opt java_expr]
+ _ [alExprToJava AlExpr]
+ deconstruct OptJavaExpr
+ JavaExpr [java_expr]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct JavaSubStmts [repeat java_lang_stmt]
+ _ [alToJava AlSubStmts]
+ deconstruct JavaSubStmts
+ JavaSubStmt [java_lang_stmt]
+ construct OptJavaElse [opt java_else]
+ _ [alOptElseJava AlOptElse]
+ replace [repeat java_lang_stmt]
+ by
+ 'if '( JavaExpr ')
+ JavaSubStmt
+ OptJavaElse
+end function
+
+function alStmtToJava4a AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printi Id [id] ';
+ replace [repeat java_lang_stmt]
+ by
+ 'System '. 'out '. 'print '( Id ');
+end function
+
+function alStmtToJava4b AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'prints String [stringlit] ';
+ replace [repeat java_lang_stmt]
+ by
+ 'System '. 'out '. 'print '( String ');
+end function
+
+function alStmtToJava4c AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printb Id [id] ';
+ replace [repeat java_lang_stmt]
+ by
+ '_s '= 'new 'String '( Id ', '0 ', 'pos ') ';
+ 'System '. 'out '. 'print '( '_s ');
+end function
+
+function alStmtToJava4d AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'print_token ';
+ replace [repeat java_lang_stmt]
+ by
+ '_s '= 'new 'String '( 'data ', 'ts ', 'te '- 'ts ') ';
+ 'System '. 'out '. 'print '( '_s ');
+end function
+
+function alStmtToJava5 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ '{ AlSubStmts [repeat action_lang_stmt] '}
+ construct JavaSubStmts [repeat java_lang_stmt]
+ _ [alToJava AlSubStmts]
+ replace [repeat java_lang_stmt]
+ by
+ '{ JavaSubStmts '}
+end function
+
+function alStmtToJava6 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ RagelStmt [al_ragel_stmt]
+ replace [repeat java_lang_stmt]
+ by
+ RagelStmt
+end function
+
+
+function alToJava AlStmts [repeat action_lang_stmt]
+ deconstruct AlStmts
+ FirstStmt [action_lang_stmt] Rest [repeat action_lang_stmt]
+ construct JavaFirst [repeat java_lang_stmt]
+ _
+ [alStmtToJava1 FirstStmt]
+ [alStmtToJava2 FirstStmt]
+ [alStmtToJava3 FirstStmt]
+ [alStmtToJava4a FirstStmt]
+ [alStmtToJava4b FirstStmt]
+ [alStmtToJava4c FirstStmt]
+ [alStmtToJava4d FirstStmt]
+ [alStmtToJava5 FirstStmt]
+ [alStmtToJava6 FirstStmt]
+ construct JavaRest [repeat java_lang_stmt]
+ _ [alToJava Rest]
+ replace [repeat java_lang_stmt]
+ by
+ JavaFirst [. JavaRest]
+end function
+
+rule actionTransJava
+ replace [al_host_block]
+ '{ AlStmts [repeat action_lang_stmt] '}
+ construct JavaStmts [repeat java_lang_stmt]
+ _ [alToJava AlStmts]
+ by
+ '{ JavaStmts '}
+end rule
+
+rule condTransJava
+ replace [cond_action_stmt]
+ 'action Id [id] '{ AlExpr [al_expr] '}
+ construct OptJavaExpr [opt java_expr]
+ _ [alExprToJava AlExpr]
+ deconstruct OptJavaExpr
+ JavaExpr [java_expr]
+ by
+ 'action Id '{ JavaExpr '}
+end rule
+
+rule machineName
+ replace $ [machine_stmt]
+ 'machine _ [id] ';
+ import TXLargs [repeat stringlit]
+ Arg1 [stringlit] _ [repeat stringlit]
+ construct ClassName [id]
+ _ [unquote Arg1]
+ by
+ 'machine ClassName ';
+end rule
+
+function langTransJava
+ replace [program]
+ Definitions [repeat action_lang_stmt]
+ '%%
+ Initializations [repeat action_lang_stmt]
+ RagelDef [ragel_def]
+ construct JavaDefinitions [repeat java_lang_stmt]
+ _ [alToJava Definitions]
+ construct JavaInitializations [repeat java_lang_stmt]
+ _ [alToJava Initializations]
+ construct NewRagelDef [ragel_def]
+ RagelDef [actionTransJava] [condTransJava] [machineName]
+ import ArrayInits [java_statements]
+ ArrayInitStmts [repeat java_lang_stmt]
+ by
+ JavaDefinitions
+ '%%
+ ArrayInitStmts [. JavaInitializations]
+ NewRagelDef
+end function
+
+function main
+ replace [program]
+ P [program]
+ export ArrayInits [java_statements]
+ _
+ by
+ P [langTransJava]
+end function
diff --git a/test/langtrans_ruby.sh b/test/langtrans_ruby.sh
new file mode 100755
index 0000000..355d8d4
--- /dev/null
+++ b/test/langtrans_ruby.sh
@@ -0,0 +1,96 @@
+#!/bin/bash
+#
+
+file=$1
+
+[ -f $file ] || exit 1
+
+# Get the machine name.
+machine=`sed -n 's/^[\t ]*machine[\t ]*\([a-zA-Z_0-9]*\)[\t ]*;[\t ]*$/\1/p' \
+ $file | tr '[A-Z]' '[a-z]'`
+
+# Make a temporary version of the test case using the Ruby language translations.
+sed -n '/\/\*/,/\*\//d;p' $file | txl -q stdin langtrans_ruby.txl > $file.pr
+
+# Begin writing out the test case.
+cat << EOF
+#
+# @LANG: ruby
+# @GENERATED: yes
+EOF
+
+grep '@ALLOW_GENFLAGS:' $file | sed 's/^ *\*/#/' | sed 's/-G.//g'
+grep '@ALLOW_MINFLAGS:' $file | sed 's/^ *\*/#/'
+
+cat << EOF
+#
+
+EOF
+
+# Write out the machine specification.
+sed -n '/^%%{$/,/^}%%/{s/^/\t/;p}' $file.pr
+
+# Write out the init and execute routines.
+cat << EOF
+
+ %% write data;
+
+ def run_machine( data )
+ p = 0
+ pe = data.length
+ eof = data.length
+ cs = 0;
+EOF
+
+# Write the data declarations
+sed -n '/^%%$/q;{s/^/\t/;p}' $file.pr
+
+# Write the data initializations
+sed -n '0,/^%%$/d; /^%%{$/q; {s/^/\t\t/;p}' $file.pr
+
+cat << EOF
+
+ %% write init;
+ %% write exec;
+ if cs >= ${machine}_first_final
+ puts "ACCEPT"
+ else
+ puts "FAIL"
+ end
+ end
+
+EOF
+
+# Write out the test data.
+sed -n '0,/\/\* _____INPUT_____/d; /_____INPUT_____ \*\//q; p;' $file | awk '
+BEGIN {
+ print " inp = ["
+}
+{
+ print " " $0 ","
+}
+END {
+ print " ]"
+ print ""
+ print " inplen = " NR ";"
+}'
+
+
+# Write out the main routine.
+cat << EOF
+
+ inp.each { |str|
+ run_machine(str.unpack("c*"))
+ }
+
+EOF
+
+# Write out the expected output.
+echo "=begin _____OUTPUT_____"
+
+sed -n '/\/\* _____OUTPUT_____/,/_____OUTPUT_____ \*\//{/_____OUTPUT_____/d;p;};' $file
+
+echo "=end _____OUTPUT_____"
+
+# Don't need this language-specific file anymore.
+rm $file.pr
diff --git a/test/langtrans_ruby.txl b/test/langtrans_ruby.txl
new file mode 100644
index 0000000..42f203d
--- /dev/null
+++ b/test/langtrans_ruby.txl
@@ -0,0 +1,392 @@
+include "testcase.txl"
+
+keys
+ 'boolean 'new
+end keys
+
+
+define ruby_statements
+ [repeat ruby_lang_stmt]
+end define
+
+define ruby_lang_stmt
+ [al_ragel_stmt]
+ | [ruby_expr_stmt]
+ | [ruby_if_stmt]
+ | [EX] 'do [IN] [NL] [ruby_statements] [EX] 'end [IN] [NL]
+end define
+
+define ruby_type_decl
+ [al_type_decl]
+ | 'boolean
+end define
+
+define ruby_expr_stmt
+ [ruby_expr] '; [NL]
+end define
+
+define ruby_expr
+ [ruby_term] [repeat ruby_expr_extend]
+end define
+
+define ruby_expr_extend
+ [al_expr_op] [ruby_term]
+end define
+
+define ruby_term
+ [al_term]
+ | [stringlit] [union]
+ | [id] [repeat ruby_dot_id]
+ | [SPOFF] [id] [repeat ruby_dot_id] '( [SPON] [ruby_args] ')
+ | [union]
+end define
+
+define ruby_dot_id
+ '. [id]
+end define
+
+define ruby_args
+ [list ruby_expr]
+end define
+
+define ruby_sign
+ '- | '+
+end define
+
+define ruby_if_stmt
+ 'if [ruby_expr] [NL] [IN]
+ [ruby_statements] [EX]
+ [opt ruby_else]
+ 'end [NL]
+end define
+
+define ruby_else
+ 'else [NL] [IN]
+ [ruby_statements] [EX]
+end define
+
+define ruby_lang
+ [ruby_statements]
+ '%% [NL]
+ [ruby_statements]
+ [ragel_def]
+end define
+
+define program
+ [lang_indep]
+ | [ruby_lang]
+end define
+
+redefine al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+ | '{ [NL] [IN] [ruby_statements] [EX] '} [NL]
+end define
+
+redefine cond_action_stmt
+ 'action [id] '{ [al_expr] '} [NL]
+ | 'action [id] '{ [ruby_expr] '} [NL]
+end redefine
+
+function initDecl1 VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ 'bool Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ Id '= 'false ';
+end function
+
+function initDecl2 VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ 'char Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ Id '= ''c' ';
+end function
+
+function initDecl3 VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ 'int Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ Id '= '0 ';
+end function
+
+function initDecl4 VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ 'ptr Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ Id '= '-1 ';
+end function
+
+function initDecl5 VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] Union [union] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ Id '= '[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ';
+end function
+
+
+function alStmtToRuby1 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ VarDecl [al_variable_decl]
+ deconstruct VarDecl
+ Type [al_type_decl] Id [id] OptUnion [opt union] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ _ [initDecl1 VarDecl] [initDecl2 VarDecl]
+ [initDecl3 VarDecl] [initDecl4 VarDecl]
+ [initDecl5 VarDecl]
+end function
+
+rule alTermToRuby1
+ replace [al_term]
+ 'first_token_char
+ by
+ 'data '[ts]
+end rule
+
+rule alTermToRuby2
+ replace [al_term]
+ '< _ [al_type_decl] '> '( AlExpr [al_expr] ')
+ by
+ '( AlExpr ')
+end rule
+
+function alTermToRuby
+ replace [al_term]
+ AlTerm [al_term]
+ by
+ AlTerm
+ [alTermToRuby1]
+ [alTermToRuby2]
+end function
+
+function alExprExtendToRuby AlExprExtend [repeat al_expr_extend]
+ deconstruct AlExprExtend
+ Op [al_expr_op] Term [al_term] Rest [repeat al_expr_extend]
+ construct RubyRest [repeat ruby_expr_extend]
+ _ [alExprExtendToRuby Rest]
+ replace [repeat ruby_expr_extend]
+ by
+ Op Term [alTermToRuby] RubyRest
+end function
+
+% Note: this doesn't go into the ( al_expr ) form of al_term.
+function alExprToRuby AlExpr [al_expr]
+ deconstruct AlExpr
+ ALTerm [al_term] AlExprExtend [repeat al_expr_extend]
+ construct RubyExprExtend [repeat ruby_expr_extend]
+ _ [alExprExtendToRuby AlExprExtend]
+ construct Result [opt ruby_expr]
+ ALTerm [alTermToRuby] RubyExprExtend
+ replace [opt ruby_expr]
+ by
+ Result
+end function
+
+function alStmtToRuby2 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ AlExpr [al_expr] ';
+ construct OptRubyExpr [opt ruby_expr]
+ _ [alExprToRuby AlExpr]
+ deconstruct OptRubyExpr
+ RubyExpr [ruby_expr]
+ replace [repeat ruby_lang_stmt]
+ by
+ RubyExpr ';
+end function
+
+function liftBlock
+ replace [repeat ruby_lang_stmt]
+ 'do Block [repeat ruby_lang_stmt] 'end
+ by
+ Block
+end function
+
+function alOptElseRuby AlOptElse [opt al_else]
+ deconstruct AlOptElse
+ 'else
+ AlSubStmt [action_lang_stmt]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct RubySubStmts [repeat ruby_lang_stmt]
+ _ [alToRuby AlSubStmts]
+ deconstruct RubySubStmts
+ RubySubStmt [ruby_lang_stmt]
+ replace [opt ruby_else]
+ by
+ 'else
+ RubySubStmts [liftBlock]
+end function
+
+function alStmtToRuby3 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'if '( AlExpr [al_expr] ')
+ AlSubStmt [action_lang_stmt]
+ AlOptElse [opt al_else]
+ construct OptRubyExpr [opt ruby_expr]
+ _ [alExprToRuby AlExpr]
+ deconstruct OptRubyExpr
+ RubyExpr [ruby_expr]
+ construct AlSubStmts [repeat action_lang_stmt]
+ AlSubStmt
+ construct RubySubStmts [repeat ruby_lang_stmt]
+ _ [alToRuby AlSubStmts]
+ construct OptRubyElse [opt ruby_else]
+ _ [alOptElseRuby AlOptElse]
+ replace [repeat ruby_lang_stmt]
+ by
+ 'if RubyExpr
+ RubySubStmts [liftBlock]
+ OptRubyElse
+ 'end
+end function
+
+function alStmtToRuby4a AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printi Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ 'print '( Id ') ';
+end function
+
+function alStmtToRuby4b AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'prints String [stringlit] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ 'print '( String ') ';
+end function
+
+function alStmtToRuby4c AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'printb Id [id] ';
+ replace [repeat ruby_lang_stmt]
+ by
+ '_a = Id '[0..pos-1] ';
+ 'print '( '_a '. 'pack '( '"c*" ') ') ';
+end function
+
+function alStmtToRuby4d AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ 'print_token ';
+ replace [repeat ruby_lang_stmt]
+ by
+ '_m = 'data '[ts..te-1] ';
+ 'print '( '_m '. 'pack '( '"c*" ') ') ';
+end function
+
+function alStmtToRuby5 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ '{ AlSubStmts [repeat action_lang_stmt] '}
+ construct RubySubStmts [repeat ruby_lang_stmt]
+ _ [alToRuby AlSubStmts]
+ replace [repeat ruby_lang_stmt]
+ by
+ 'do RubySubStmts 'end
+end function
+
+function alStmtToRuby6 AlStmt [action_lang_stmt]
+ deconstruct AlStmt
+ RagelStmt [al_ragel_stmt]
+ replace [repeat ruby_lang_stmt]
+ by
+ RagelStmt
+end function
+
+rule fixCharLit
+ replace $ [al_term]
+ CharLit [charlit]
+ construct BaseId [id]
+ 'id
+ construct Id [id]
+ BaseId [unquote CharLit]
+ construct EmptyString [stringlit]
+ '""
+ construct Repl [stringlit]
+ EmptyString [quote Id]
+ by
+ Repl '[0]
+end rule
+
+
+function alToRuby AlStmts [repeat action_lang_stmt]
+ deconstruct AlStmts
+ FirstStmt [action_lang_stmt] Rest [repeat action_lang_stmt]
+ construct RubyFirst [repeat ruby_lang_stmt]
+ _
+ [alStmtToRuby1 FirstStmt]
+ [alStmtToRuby2 FirstStmt]
+ [alStmtToRuby3 FirstStmt]
+ [alStmtToRuby4a FirstStmt]
+ [alStmtToRuby4b FirstStmt]
+ [alStmtToRuby4c FirstStmt]
+ [alStmtToRuby4d FirstStmt]
+ [alStmtToRuby5 FirstStmt]
+ [alStmtToRuby6 FirstStmt]
+ [fixCharLit]
+ construct RubyRest [repeat ruby_lang_stmt]
+ _ [alToRuby Rest]
+ replace [repeat ruby_lang_stmt]
+ by
+ RubyFirst [. RubyRest]
+end function
+
+rule actionTransRuby
+ replace [al_host_block]
+ '{ AlStmts [repeat action_lang_stmt] '}
+ construct RubyStmts [repeat ruby_lang_stmt]
+ _ [alToRuby AlStmts]
+ by
+ '{ RubyStmts '}
+end rule
+
+rule condTransRuby
+ replace [cond_action_stmt]
+ 'action Id [id] '{ AlExpr [al_expr] '}
+ construct OptRubyExpr [opt ruby_expr]
+ _ [alExprToRuby AlExpr]
+ deconstruct OptRubyExpr
+ RubyExpr [ruby_expr]
+ by
+ 'action Id '{ RubyExpr '}
+end rule
+
+rule lowercaseMachine
+ replace $ [machine_stmt]
+ 'machine Id [id] ';
+ by
+ 'machine Id [tolower] ';
+end rule
+
+function langTransRuby
+ replace [program]
+ Definitions [repeat action_lang_stmt]
+ '%%
+ Initializations [repeat action_lang_stmt]
+ RagelDef [ragel_def]
+ construct RubyDefinitions [repeat ruby_lang_stmt]
+ _ [alToRuby Definitions]
+ construct RubyInitializations [repeat ruby_lang_stmt]
+ _ [alToRuby Initializations]
+ construct NewRagelDef [ragel_def]
+ RagelDef [actionTransRuby] [condTransRuby] [lowercaseMachine]
+ import ArrayInits [ruby_statements]
+ ArrayInitStmts [repeat ruby_lang_stmt]
+ by
+ RubyDefinitions
+ '%%
+ ArrayInitStmts [. RubyInitializations]
+ NewRagelDef
+end function
+
+function main
+ replace [program]
+ P [program]
+ export ArrayInits [ruby_statements]
+ _
+ by
+ P [langTransRuby]
+end function
diff --git a/test/lmgoto.rl b/test/lmgoto.rl
new file mode 100644
index 0000000..e8e82a8
--- /dev/null
+++ b/test/lmgoto.rl
@@ -0,0 +1,198 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using namespace std;
+
+#define TK_Dlit 192
+#define TK_Slit 193
+#define TK_Float 194
+#define TK_Id 195
+#define TK_NameSep 197
+#define TK_Arrow 211
+#define TK_PlusPlus 212
+#define TK_MinusMinus 213
+#define TK_ArrowStar 214
+#define TK_DotStar 215
+#define TK_ShiftLeft 216
+#define TK_ShiftRight 217
+#define TK_IntegerDecimal 218
+#define TK_IntegerOctal 219
+#define TK_IntegerHex 220
+#define TK_EqualsEquals 223
+#define TK_NotEquals 224
+#define TK_AndAnd 225
+#define TK_OrOr 226
+#define TK_MultAssign 227
+#define TK_DivAssign 228
+#define TK_PercentAssign 229
+#define TK_PlusAssign 230
+#define TK_MinusAssign 231
+#define TK_AmpAssign 232
+#define TK_CaretAssign 233
+#define TK_BarAssign 234
+#define TK_DotDotDot 240
+#define TK_Whitespace 241
+#define TK_Comment 242
+
+struct Scanner
+{
+ int cs, act;
+ const char *ts, *te;
+ bool isCxx;
+
+ void token( int tok );
+ void run( const char *buf );
+};
+
+
+%%{
+ machine Scanner;
+
+ # Process all comments, relies on isCxx being set.
+ comment := |*
+ '*/' {
+ if ( ! isCxx )
+ fgoto main;
+ else {
+ cout << "comm char: " << ts[0] << endl;
+ cout << "comm char: " << ts[1] << endl;
+ }
+ };
+
+ '\n' {
+ if ( isCxx )
+ fgoto main;
+ else
+ cout << "comm char: " << ts[0] << endl;
+ };
+
+ any {
+ cout << "comm char: " << ts[0] << endl;
+ };
+ *|;
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" ) { token( TK_Slit );};
+ ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' ) { token( TK_Dlit );};
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* ) { token( TK_Id ); };
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? ) { token( TK_Float );};
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} ) { token( TK_IntegerDecimal );};
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]{0,2} ) { token( TK_IntegerOctal );};
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) ) { token( TK_IntegerHex );};
+
+ # Only buffer the second item, first buffered by symbol. */
+ '::' {token( TK_NameSep );};
+ '==' {token( TK_EqualsEquals );};
+ '!=' {token( TK_NotEquals );};
+ '&&' {token( TK_AndAnd );};
+ '||' {token( TK_OrOr );};
+ '*=' {token( TK_MultAssign );};
+ '/=' {token( TK_DivAssign );};
+ '%=' {token( TK_PercentAssign );};
+ '+=' {token( TK_PlusAssign );};
+ '-=' {token( TK_MinusAssign );};
+ '&=' {token( TK_AmpAssign );};
+ '^=' {token( TK_CaretAssign );};
+ '|=' {token( TK_BarAssign );};
+ '++' {token( TK_PlusPlus );};
+ '--' {token( TK_MinusMinus );};
+ '->' {token( TK_Arrow );};
+ '->*' {token( TK_ArrowStar );};
+ '.*' {token( TK_DotStar );};
+
+ # Three char compounds, first item already buffered. */
+ '...' { token( TK_DotDotDot );};
+
+ # Single char symbols.
+ ( punct - [_"'] ) { token( ts[0] );};
+
+ # Comments and whitespace. Handle these outside of the machine so that se
+ # don't end up buffering the comments.
+ '/*' { isCxx = false; fgoto comment; };
+ '//' { isCxx = true; fgoto comment; };
+
+ ( any - 33..126 )+ { token( TK_Whitespace );};
+
+ *|;
+}%%
+
+%% write data nofinal;
+
+void Scanner::token( int tok )
+{
+ const char *data = ts;
+ int len = te - ts;
+ cout << "<" << tok << "> ";
+ if ( data != 0 ) {
+ for ( int i = 0; i < len; i++ )
+ cout << data[i];
+ }
+ cout << '\n';
+}
+
+void Scanner::run( const char *buf )
+{
+ int len = strlen( buf );
+ %% write init;
+ const char *p = buf;
+ const char *pe = buf + len;
+ const char *eof = pe;
+ %% write exec;
+
+ if ( cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cout << "PARSE ERROR" << endl;
+ }
+}
+
+int main()
+{
+ Scanner scanner;
+ scanner.run(
+ "//hello*/\n"
+ "/*hi there*/ hello 0x88"
+ );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+comm char: h
+comm char: e
+comm char: l
+comm char: l
+comm char: o
+comm char: *
+comm char: /
+comm char: h
+comm char: i
+comm char:
+comm char: t
+comm char: h
+comm char: e
+comm char: r
+comm char: e
+<241>
+<195> hello
+<241>
+<220> 0x88
+#endif
diff --git a/test/mailbox1.h b/test/mailbox1.h
new file mode 100644
index 0000000..e7cd37c
--- /dev/null
+++ b/test/mailbox1.h
@@ -0,0 +1,33 @@
+#ifndef _MAILBOX1_H
+#define _MAILBOX1_H
+
+#include <stdio.h>
+#include <string.h>
+#include "vector.h"
+
+struct MBox
+{
+ int cs;
+
+ Vector<char> headName;
+ Vector<char> headContent;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ void execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+#endif
diff --git a/test/mailbox1.rl b/test/mailbox1.rl
new file mode 100644
index 0000000..ea23173
--- /dev/null
+++ b/test/mailbox1.rl
@@ -0,0 +1,253 @@
+/*
+ * @LANG: c++
+ * @CFLAGS: -I../aapl
+ *
+ * Test works with split code gen.
+ */
+
+/*
+ * Parses unix mail boxes into headers and bodies.
+ */
+
+#include "mailbox1.h"
+
+%%{
+ machine MBox;
+
+ # Buffer the header names.
+ action bufHeadName { fsm->headName.append(fc); }
+
+ # Buffer the header content.
+ action bufHeadContent { fsm->headContent.append(fc); }
+
+ # Terminate a header. If it is an interesting header then prints it.
+ action finBufHeadContent {
+ /* Terminate the buffers. */
+ fsm->headName.append(0);
+ fsm->headContent.append(0);
+
+ /* Print the header. Interesting headers. */
+ printf("%s:%s\n", fsm->headName.data, fsm->headContent.data);
+
+ /* Clear for the next time we use them. */
+ fsm->headName.empty();
+ fsm->headContent.empty();
+ }
+
+ action msgstart{
+ printf("NEW MESSAGE\n");
+ }
+
+ # Prints a blank line after the end of the headers of each message.
+ action blankLine {
+ printf("\n");
+ }
+
+ # Helpers we will use in matching the date section of the from line.
+ day = /[A-Z][a-z][a-z]/;
+ month = /[A-Z][a-z][a-z]/;
+ year = /[0-9][0-9][0-9][0-9]/;
+ time = /[0-9][0-9]:[0-9][0-9]/ . ( /:[0-9][0-9]/ | '' );
+ letterZone = /[A-Z][A-Z][A-Z]/;
+ numZone = /[+\-][0-9][0-9][0-9][0-9]/;
+ zone = letterZone | numZone;
+ 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.
+ date = day . ' ' . month . ' ' . dayNum . ' ' . time . ' ' .
+ ( year | year . ' ' . zone | zone . ' ' . year );
+
+ # Note the priority assignment on the end of the from line. While we
+ # matching the body of a message we may enter into this machine. We will
+ # not leave the body of the previous message until this entire from line is
+ # matched.
+ fromLine = 'From ' . /[^\n]/* . ' ' . date . '\n' @(new_msg,1) @msgstart;
+
+ # The types of characters that can be used as a header name.
+ hchar = print - [ :];
+
+ header =
+ # The name of the header.
+ hchar+ $bufHeadName . ':'
+ # The content of the header. Look out for continuations.
+ . ( (extend - '\n') $bufHeadContent | '\n'. [ \t] @bufHeadContent )*
+ # Buffer must end with a newline that does not continue.
+ . '\n' %finBufHeadContent;
+
+ messageLine = ( extend - '\n' )* . '\n' @(new_msg, 0);
+
+ # When we get to the last newline we are still matching messageLine
+ # so on the last newline it will think we are still in the message.
+ # We need this because we can't assume that every newline means
+ # the end of the current message, whereas at the same time we requre
+ # that there be a newline before the fromLine of the next message.
+ message = ( fromLine . header* . '\n' @blankLine . messageLine* . '\n' );
+
+ # Its important that the priority in the fromLine gets bumped up
+ # so that we are able to move to new messages. Otherwise we
+ # will always stay in the message body of the first message.
+ main := message*;
+}%%
+
+%% write data;
+
+void MBox::init( )
+{
+ MBox *fsm = this;
+ %% write init;
+}
+
+void MBox::execute( const char *data, int len )
+{
+ MBox *fsm = this;
+ const char *p = data;
+ const char *pe = data + len;
+ %%{
+ access fsm->;
+ write exec;
+ }%%
+}
+
+int MBox::finish( )
+{
+ if ( cs == MBox_error )
+ return -1;
+ if ( cs >= MBox_first_final )
+ return 1;
+ return 0;
+}
+
+MBox mbox;
+
+void test( const char *buf )
+{
+ int len = strlen( buf );
+ mbox.init();
+ mbox.execute( buf, len );
+ if ( mbox.finish() > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test(
+ "From email address goes here Wed Nov 28 13:30:05 2001 -0500\n"
+ "Header1: this is the header contents\n"
+ " there is more on the second line\n"
+ " and more on the third line.\n"
+ "Header2: slkdj\n"
+ "\n"
+ "This is the message data\n"
+ "\n"
+ "From email Wed Nov 28 13:30:05 2001 -0500\n"
+ "Header: \n"
+ "\n"
+ "mail message\n"
+ "\n"
+ );
+
+ test(
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "\n"
+ "There are no headers. \n"
+ "\n"
+ "From email Wed Nov 28 13:30:05 EST 2000\n"
+ "\n"
+ "There are no headers.\n"
+ "\n"
+ );
+
+ test(
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "Header:alsdj\n"
+ "\n"
+ "Header:\n"
+ "salkfj\n"
+ "\n"
+ "There are no headers. \n"
+ "\n"
+ );
+
+ test(
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "Header:alsdj\n"
+ "\n"
+ "Header:\n"
+ "salkfj\n"
+ "\n"
+ "There are no headers. \n"
+ "\n"
+ ">From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "\n"
+ );
+
+ test(
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "Header:alsdj\n"
+ "\n"
+ "Header:\n"
+ "salkfj\n"
+ "\n"
+ "There are no headers. \n"
+ "\n"
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "\n"
+ );
+
+ test(
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "Header:alsdj\n"
+ "\n"
+ "Header:\n"
+ "salkfj\n"
+ "\n"
+ "There are no headers. \n"
+ "\n"
+ "From user@host.dom Wed Nov 28 13:30:05 2001\n"
+ "\n"
+ "\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+NEW MESSAGE
+Header1: this is the header contents there is more on the second line and more on the third line.
+Header2: slkdj
+
+NEW MESSAGE
+Header:
+
+ACCEPT
+NEW MESSAGE
+
+NEW MESSAGE
+
+ACCEPT
+NEW MESSAGE
+Header:alsdj
+
+ACCEPT
+NEW MESSAGE
+Header:alsdj
+
+ACCEPT
+NEW MESSAGE
+Header:alsdj
+
+NEW MESSAGE
+
+FAIL
+NEW MESSAGE
+Header:alsdj
+
+NEW MESSAGE
+
+ACCEPT
+#endif
diff --git a/test/mailbox2.rl b/test/mailbox2.rl
new file mode 100644
index 0000000..bbaf820
--- /dev/null
+++ b/test/mailbox2.rl
@@ -0,0 +1,173 @@
+/*
+ * @LANG: c++
+ * @CFLAGS: -I../aapl
+ */
+
+#include <iostream>
+#include <string.h>
+
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+%%{
+ machine mailbox;
+
+ action prn_char { cout << *p; }
+ action prn_space { cout << ' '; }
+ action prn_word { cout.write(ws, p-ws); cout << ' '; }
+ action prn_addr1 { cout << "| "; cout.write(ws+1, p-ws-2); }
+ action prn_addr2 { cout << "| "; cout.write(ws, p-ws); }
+ action prn_tab { cout << '\t'; }
+ action prn_nl { cout << '\n'; }
+ action prn_separator { cout << "------\n"; }
+ action prn_from { cout << "FROM\n"; }
+ action prn_to { cout << "TO\n"; }
+ action prn_subj { cout << "SUBJECT\n"; }
+
+ action start_word { ws = p; }
+ action start_headers { preserve = p; }
+ action end_headers {preserve = 0;}
+
+ day = upper lower{2};
+ month = upper lower{2};
+ year = digit{4};
+ time = digit{2} ':' digit{2}
+ ( ':' digit{2} )?;
+ letterZone = upper{3};
+ numZone = [+\-] digit{4};
+ zone = letterZone | numZone;
+ dayNum = ( digit | ' ' ) digit;
+
+ date = day ' ' month ' '
+ dayNum ' ' time ' '
+ (
+ year |
+ year ' ' zone |
+ zone ' ' year
+ );
+
+ fromLine = 'From ' [^\n]* ' '
+ date '\n' @start_headers;
+
+ headerChar = print - [ :];
+ headersToPrint = 'From' |
+ 'To' | 'Subject';
+ headersToConsume =
+ headerChar+ - headersToPrint;
+
+ consumeHeader =
+ headersToConsume ':'
+ (
+ [^\n] |
+ ( '\n' [ \t] )
+ )*
+ '\n';
+
+ addrWS = ( [ \t]+ | '\n' [ \t]+ );
+ addrComment = '(' [^)]* ')';
+ addrWord = [^"'@,<>() \t\n]+;
+ addrAddr1 = '<' [^>]* '>';
+ addrAddr2 = addrWord '@' addrWord;
+ addrString =
+ '"' [^"]* '"' |
+ "'" [^']* "'";
+
+ addrItem = (
+ addrAddr1 %prn_addr1 |
+ addrAddr2 %prn_addr2 |
+ addrWord %prn_word |
+ addrString %prn_word
+ ) >start_word;
+
+ address = (
+ addrWS |
+ addrComment |
+ addrItem
+ )** >prn_tab;
+
+ addrHeader = (
+ 'From' %prn_from |
+ 'To' %prn_to
+ ) ':'
+ address ( ',' @prn_nl address )*
+ '\n' %prn_nl;
+
+ subjectHeader =
+ 'Subject:' @prn_subj @prn_tab
+ ' '* <:
+ (
+ [^\n] @prn_char |
+ ( '\n' [ \t]+ ) %prn_space
+ )**
+ '\n' %prn_nl;
+
+ header = consumeHeader |
+ addrHeader | subjectHeader;
+
+ messageLine =
+ ( [^\n]* '\n' - fromLine );
+
+ main := (
+ fromLine %prn_separator
+ header*
+ '\n' @end_headers
+ messageLine*
+ )*;
+ }%%
+
+%% write data;
+
+#define BUFSIZE 8192
+
+void test( const char *buf )
+{
+ int cs, len = strlen( buf );
+ const char *preserve = 0, *ws = 0;
+
+ %% write init;
+ const char *p = buf;
+ const char *pe = p + len;
+ %% write exec;
+
+ if ( cs == mailbox_error )
+ cerr << "ERROR" << endl;
+
+ if ( cs < mailbox_first_final )
+ cerr << "DID NOT FINISH IN A FINAL STATE" << endl;
+}
+
+int main()
+{
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "From: \"Adrian D. Thurston\" <thurston@complang.org>\n"
+ "Subject: the squirrel has landed\n"
+ "\n"
+ "Message goes here. \n"
+ "From (trick from line).\n"
+ "From: not really a header\n"
+ "\n"
+ "From user2@host2.com Wed Nov 28 13:30:05 2001\n"
+ "To: Edgar Allen Poe <ep@net.com> (da man)\n"
+ "Subject: (no subject) \n"
+ "\n"
+ "Message goes here. \n"
+ "\n"
+ );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+------
+FROM
+ "Adrian D. Thurston" | thurston@complang.org
+SUBJECT
+ the squirrel has landed
+------
+TO
+ Edgar Allen Poe | ep@net.com
+SUBJECT
+ (no subject)
+#endif
diff --git a/test/mailbox3.rl b/test/mailbox3.rl
new file mode 100644
index 0000000..8039f80
--- /dev/null
+++ b/test/mailbox3.rl
@@ -0,0 +1,247 @@
+/*
+ * @LANG: c++
+ * @CFLAGS: -I../aapl
+ */
+
+#include <iostream>
+#include <string.h>
+
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+%%{
+ machine mailbox;
+
+ action prn_char { cout << *p; }
+ action prn_space { cout << ' '; }
+ action prn_word { cout.write(ws, p-ws); cout << ' '; }
+ action prn_addr1 { cout << "| "; cout.write(ws+1, p-ws-2); }
+ action prn_addr2 { cout << "| "; cout.write(ws, p-ws); }
+ action prn_tab { cout << '\t'; }
+ action prn_nl { cout << '\n'; }
+ action prn_separator { cout << "------\n"; }
+ action prn_from { cout << "FROM\n"; }
+ action prn_to { cout << "TO\n"; }
+ action prn_subj { cout << "SUBJECT\n"; }
+
+ action start_word { ws = p; }
+ action start_headers { preserve = p; }
+ action end_headers {preserve = 0;}
+
+ day = upper lower{2};
+ month = upper lower{2};
+ year = digit{4};
+ time = digit{2} ':' digit{2}
+ ( ':' digit{2} )?;
+ letterZone = upper{3};
+ numZone = [+\-] digit{4};
+ zone = letterZone | numZone;
+ dayNum = ( digit | ' ' ) digit;
+
+ date = day ' ' month ' '
+ dayNum ' ' time ' '
+ (
+ year |
+ year ' ' zone |
+ zone ' ' year
+ );
+
+ fromLine = 'From ' [^\n]* ' '
+ date '\n' @start_headers;
+
+ headerChar = print - [ :];
+ headersToPrint = 'From' |
+ 'To' | 'Subject';
+ headersToConsume =
+ headerChar+ - headersToPrint;
+
+ action init_hlen {hlen = 0;}
+ action hlen {hlen++ < 50}
+
+ consumeHeaderBody =
+ ':' @init_hlen
+ (
+ [^\n] |
+ ( '\n' [ \t] )
+ )* when hlen
+ '\n';
+
+ consumeHeader =
+ headersToConsume consumeHeaderBody;
+
+ addrWS = ( [ \t]+ | '\n' [ \t]+ );
+ addrComment = '(' [^)]* ')';
+ addrWord = [^"'@,<>() \t\n]+;
+ addrAddr1 = '<' [^>]* '>';
+ addrAddr2 = addrWord '@' addrWord;
+ addrString =
+ '"' [^"]* '"' |
+ "'" [^']* "'";
+
+ addrItem = (
+ addrAddr1 %prn_addr1 |
+ addrAddr2 %prn_addr2 |
+ addrWord %prn_word |
+ addrString %prn_word
+ ) >start_word;
+
+ address = (
+ addrWS |
+ addrComment |
+ addrItem
+ )** >prn_tab;
+
+ addrHeader = (
+ 'From' %prn_from |
+ 'To' %prn_to
+ ) ':' @init_hlen
+ ( address ( ',' @prn_nl address )* ) when hlen
+ '\n' %prn_nl;
+
+ subjectHeader =
+ 'Subject:' @prn_subj @prn_tab @init_hlen
+ (
+ ' '* <:
+ (
+ [^\n] @prn_char |
+ ( '\n' [ \t]+ ) %prn_space
+ )**
+ ) when hlen
+ '\n' %prn_nl;
+
+ header = consumeHeader |
+ addrHeader | subjectHeader;
+
+ messageLine =
+ ( [^\n]* when hlen '\n' @init_hlen ) - fromLine;
+
+ main := (
+ fromLine %prn_separator
+ header*
+ '\n' @end_headers @init_hlen
+ messageLine*
+ )*;
+ }%%
+
+%% write data;
+
+#define BUFSIZE 8192
+
+void test( const char *buf )
+{
+ int cs, len = strlen( buf );
+ const char *preserve = 0, *ws = 0;
+ int hlen = 0;
+
+ %% write init;
+ const char *p = buf;
+ const char *pe = p + len;
+ %% write exec;
+
+ if ( cs < mailbox_first_final ) {
+ cout << endl << endl;
+ cout << "DID NOT FINISH IN A FINAL STATE" << endl;
+ }
+}
+
+int main()
+{
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "From: \"Adrian D. Thurston\" <thurston@complang.org>\n"
+ "Subject: the squirrel has landed\n"
+ "\n"
+ "Message goes here. \n"
+ "From (trick from line).\n"
+ "From: not really a header\n"
+ "\n"
+ "From user2@host2.com Wed Nov 28 13:30:05 2001\n"
+ "To: \"(kill 1)\" Edgar Allen Poe <ep@net.com> (da man)\n"
+ "Subject: (no subject) this is a really long subject which should fail the length constraint \n"
+ "Other: 0123456789\n"
+ "\n"
+ "Message goes here. \n"
+ "\n"
+ );
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "To: \"(kill 2)\" some guy <sg@net.com>\n"
+ "From: \"Adrian D. Thurston this name is far too long\" <thurston@complang.org>\n"
+ "Subject: the squirrel has landed\n"
+ "\n"
+ "From user2@host2.com Wed Nov 28 13:30:05 2001\n"
+ "To: Edgar Allen Poe <ep@net.com> (da man)\n"
+ "Subject: (no subject) \n"
+ "\n"
+ );
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "To: \"(kill 3)\" some guy <sg@net.com>\n"
+ "From: \"Adrian D. Thurston This name is fore sure absolutely too long\" <t@cs.ca>\n"
+ "Subject: the squirrel has landed\n"
+ "\n"
+ );
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "From: \"Adrian D. Thurston \" <t@cs.ca>\n"
+ "Subject: (kill 4) the squirrel has landed\n"
+ "Other: This is another header field, not interpreted, that is too long\n"
+ "\n"
+ );
+ test(
+ "From user@host.com Wed Nov 28 13:30:05 2001\n"
+ "From: \"Adrian D. Thurston \" <t@cs.ca>\n"
+ "Subject: (kill 5)the squirrel has landed\n"
+ "\n"
+ "This message line is okay.\n"
+ "But this message line is far too long and will cause an error.\n"
+ );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+------
+FROM
+ "Adrian D. Thurston" | thurston@complang.org
+SUBJECT
+ the squirrel has landed
+------
+TO
+ "(kill 1)" Edgar Allen Poe | ep@net.com
+SUBJECT
+ (no subject) this is a really long subject whic
+
+DID NOT FINISH IN A FINAL STATE
+------
+TO
+ "(kill 2)" some guy | sg@net.com
+FROM
+ "Adrian D. Thurston this name is far too long"
+
+DID NOT FINISH IN A FINAL STATE
+------
+TO
+ "(kill 3)" some guy | sg@net.com
+FROM
+
+
+DID NOT FINISH IN A FINAL STATE
+------
+FROM
+ "Adrian D. Thurston " | t@cs.ca
+SUBJECT
+ (kill 4) the squirrel has landed
+
+
+DID NOT FINISH IN A FINAL STATE
+------
+FROM
+ "Adrian D. Thurston " | t@cs.ca
+SUBJECT
+ (kill 5)the squirrel has landed
+
+
+DID NOT FINISH IN A FINAL STATE
+#endif
diff --git a/test/minimize1.rl b/test/minimize1.rl
new file mode 100644
index 0000000..c550ebb
--- /dev/null
+++ b/test/minimize1.rl
@@ -0,0 +1,81 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct min
+{
+ int cs;
+};
+
+%%{
+ machine min;
+ variable cs fsm->cs;
+
+ action a_or_b { printf("a or b\n"); }
+
+ main := (
+ ( 'a' . [ab]* @a_or_b ) |
+ ( 'b' . [ab]* @a_or_b )
+ ) . '\n';
+}%%
+
+%% write data;
+
+void min_init( struct min *fsm )
+{
+ %% write init;
+}
+
+void min_execute( struct min *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int min_finish( struct min *fsm )
+{
+ if ( fsm->cs == min_error )
+ return -1;
+ if ( fsm->cs >= min_first_final )
+ return 1;
+ return 0;
+}
+
+struct min fsm;
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ min_init( &fsm );
+ min_execute( &fsm, buf, len );
+ if ( min_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test( "aaaaaa\n" );
+ test( "a\n" );
+ test( "abc\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+a or b
+a or b
+a or b
+a or b
+a or b
+ACCEPT
+ACCEPT
+a or b
+FAIL
+#endif
diff --git a/test/patact.rl b/test/patact.rl
new file mode 100644
index 0000000..864299d
--- /dev/null
+++ b/test/patact.rl
@@ -0,0 +1,100 @@
+/*
+ * @LANG: indep
+ */
+
+char comm;
+int top;
+int stack[32];
+ptr ts;
+ptr te;
+int act;
+int val;
+%%
+%%{
+ machine patact;
+
+ other := |*
+ [a-z]+ => { prints "word\n"; };
+ [0-9]+ => { prints "num\n"; };
+ [\n ] => { prints "space\n"; };
+ *|;
+
+ exec_test := |*
+ [a-z]+ => { prints "word (w/lbh)\n"; fexec te-1; fgoto other; };
+ [a-z]+ ' foil' => { prints "word (c/lbh)\n"; };
+ [\n ] => { prints "space\n"; };
+ '22' => { prints "num (w/switch)\n"; };
+ [0-9]+ => { prints "num (w/switch)\n"; fexec te-1; fgoto other;};
+ [0-9]+ ' foil' => {prints "num (c/switch)\n"; };
+ '!';# => { prints "immdiate\n"; fgoto exec_test; };
+ *|;
+
+ semi := |*
+ ';' => { prints "in semi\n"; fgoto main; };
+ *|;
+
+ main := |*
+ [a-z]+ => { prints "word (w/lbh)\n"; fhold; fgoto other; };
+ [a-z]+ ' foil' => { prints "word (c/lbh)\n"; };
+ [\n ] => { prints "space\n"; };
+ '22' => { prints "num (w/switch)\n"; };
+ [0-9]+ => { prints "num (w/switch)\n"; fhold; fgoto other;};
+ [0-9]+ ' foil' => {prints "num (c/switch)\n"; };
+ ';' => { prints "going to semi\n"; fhold; fgoto semi;};
+ '!' => { prints "immdiate\n"; fgoto exec_test; };
+ *|;
+}%%
+/* _____INPUT_____
+"abcd foix\n"
+"abcd\nanother\n"
+"123 foix\n"
+"!abcd foix\n"
+"!abcd\nanother\n"
+"!123 foix\n"
+";"
+_____INPUT_____ */
+/* _____OUTPUT_____
+word (w/lbh)
+word
+space
+word
+space
+ACCEPT
+word (w/lbh)
+word
+space
+word
+space
+ACCEPT
+num (w/switch)
+num
+space
+word
+space
+ACCEPT
+immdiate
+word (w/lbh)
+word
+space
+word
+space
+ACCEPT
+immdiate
+word (w/lbh)
+word
+space
+word
+space
+ACCEPT
+immdiate
+num (w/switch)
+num
+space
+word
+space
+ACCEPT
+going to semi
+in semi
+ACCEPT
+_____OUTPUT_____ */
+
diff --git a/test/range.rl b/test/range.rl
new file mode 100644
index 0000000..43e6214
--- /dev/null
+++ b/test/range.rl
@@ -0,0 +1,74 @@
+/*
+ * @LANG: c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct range
+{
+ int cs;
+};
+
+%%{
+ machine range;
+ variable cs fsm->cs;
+
+ main := ( 'a' .. 'c' | 'c' .. 'e' | 'm' .. 'n' | 'a' .. 'z' ) '\n';
+}%%
+
+%% write data;
+
+void range_init( struct range *fsm )
+{
+ %% write init;
+}
+
+void range_execute( struct range *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int range_finish( struct range *fsm )
+{
+ if ( fsm->cs == range_error )
+ return -1;
+ if ( fsm->cs >= range_first_final )
+ return 1;
+ return 0;
+}
+
+struct range fsm;
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ range_init( &fsm );
+ range_execute( &fsm, buf, len );
+ if ( range_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test( "a\n" );
+ test( "z\n" );
+ test( "g\n" );
+ test( "no\n" );
+ test( "1\n" );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+#endif
diff --git a/test/recdescent1.rl b/test/recdescent1.rl
new file mode 100644
index 0000000..1ffca28
--- /dev/null
+++ b/test/recdescent1.rl
@@ -0,0 +1,128 @@
+/*
+ * @LANG: c
+ * Test growable stack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+%%{
+ machine recdescent;
+
+ prepush {
+ if ( top == stack_size ) {
+ printf( "growing stack\n" );
+ stack_size = top * 2;
+ stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ }
+ }
+
+ postpop {
+ if ( stack_size > (top * 4) ) {
+ stack_size = top * 2;
+ stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ printf( "shrinking stack\n" );
+ }
+ }
+
+ action item_start { item = p; }
+
+ action item_finish
+ {
+ printf( "item: " );
+ fwrite( item, 1, p-item, stdout );
+ printf( "\n" );
+ }
+
+ action call_main
+ {
+ printf( "calling main\n" );
+ fcall main;
+ }
+
+ action return_main
+ {
+ if ( top == 0 ) {
+ printf( "STRAY CLOSE\n" );
+ fbreak;
+ }
+
+ printf( "returning from main\n" );
+ fhold;
+ fret;
+ }
+
+ id = [a-zA-Z_]+;
+ number = [0-9]+;
+ ws = [ \t\n]+;
+
+ main := (
+ ws |
+ ( number | id ) >item_start %item_finish |
+
+ '{' @call_main '}' |
+
+ '}' @return_main
+ )**;
+}%%
+
+%% write data;
+
+void test( char *buf )
+{
+ int cs;
+ int *stack;
+ int top, stack_size;
+ char *p, *pe, *eof, *item = 0;
+
+ int len = strlen( buf );
+
+ %% write init;
+
+ stack_size = 1;
+ stack = (int*)malloc( sizeof(int) * stack_size );
+
+ p = buf;
+ pe = buf + len;
+ eof = pe;
+
+ %% write exec;
+
+ if ( cs == recdescent_error ) {
+ /* Machine failed before finding a token. */
+ printf( "PARSE ERROR\n" );
+ }
+}
+
+int main()
+{
+ test( "88 foo { 99 {{{{}}}}{ } }");
+ test( "76 } sadf");
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+#endif
diff --git a/test/recdescent2.rl b/test/recdescent2.rl
new file mode 100644
index 0000000..59c4586
--- /dev/null
+++ b/test/recdescent2.rl
@@ -0,0 +1,116 @@
+/*
+ * @LANG: java
+ */
+
+class recdescent2
+{
+ %%{
+ machine recdescent;
+
+ prepush {
+ if ( top == stack_size ) {
+ System.out.print( "growing stack\n" );
+ stack_size = top * 2;
+ // Don't actually bother to resize here, but we do print messages.
+ //stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ }
+ }
+
+ postpop {
+ if ( stack_size > (top * 4) ) {
+ stack_size = top * 2;
+ // Don't actually bother to resize here, but we do print messages.
+ //stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ System.out.print( "shrinking stack\n" );
+ }
+ }
+
+ action item_start { item = p; }
+
+ action item_finish
+ {
+ String item_data = new String ( data, item, p-item );
+ System.out.print( "item: " );
+ System.out.print( item_data );
+ System.out.print( "\n" );
+ }
+
+ action call_main
+ {
+ System.out.print( "calling main\n" );
+ fcall main;
+ }
+
+ action return_main
+ {
+ if ( top == 0 ) {
+ System.out.print( "STRAY CLOSE\n" );
+ fbreak;
+ }
+
+ System.out.print( "returning from main\n" );
+ fhold;
+ fret;
+ }
+
+ id = [a-zA-Z_]+;
+ number = [0-9]+;
+ ws = [ \t\n]+;
+
+ main := (
+ ws |
+ ( number | id ) >item_start %item_finish |
+
+ '{' @call_main '}' |
+
+ '}' @return_main
+ )**;
+ }%%
+
+ %% write data;
+
+ static void test( char data[] )
+ {
+ int cs, p = 0, pe = data.length, eof = data.length, item = 0;
+ int stack[] = new int[1024];
+ int stack_size = 1;
+ int top;
+
+ %% write init;
+ %% write exec;
+
+ if ( cs == recdescent_error )
+ System.out.println( "SCANNER ERROR" );
+ }
+
+ public static void main( String args[] )
+ {
+ test( "88 foo { 99 {{{{}}}}{ } }".toCharArray() );
+ test( "76 } sadf".toCharArray() );
+ }
+}
+
+/* _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+*/
diff --git a/test/recdescent3.rl b/test/recdescent3.rl
new file mode 100644
index 0000000..1216b43
--- /dev/null
+++ b/test/recdescent3.rl
@@ -0,0 +1,117 @@
+#
+# @LANG: ruby
+#
+
+%%{
+ machine recdescent3;
+
+ prepush {
+ if top == stack_size
+ print( "growing stack\n" );
+ stack_size = top * 2;
+ # Don't actually bother to resize here, but we do print messages.
+ # stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ end
+ }
+
+ postpop {
+ if stack_size > (top * 4)
+ print( "shrinking stack\n" );
+ stack_size = top * 2;
+ # Don't actually bother to resize here, but we do print messages.
+ # stack = (int*)realloc( stack, sizeof(int)*stack_size );
+ end
+ }
+
+ action item_start { item = p; }
+
+ action item_finish
+ {
+ print( "item: " );
+ print( data[item..p-1] );
+ print( "\n" );
+ }
+
+ action call_main
+ {
+ print( "calling main\n" );
+ fcall main;
+ }
+
+ action return_main
+ {
+ if top == 0
+ print( "STRAY CLOSE\n" );
+ fbreak;
+ end
+
+ print( "returning from main\n" );
+ fhold;
+ fret;
+ }
+
+ id = [a-zA-Z_]+;
+ number = [0-9]+;
+ ws = [ \t\n]+;
+
+ main := (
+ ws |
+ ( number | id ) >item_start %item_finish |
+
+ '{' @call_main '}' |
+
+ '}' @return_main
+ )**;
+}%%
+
+%% write data;
+
+def run_machine( data )
+ item = 0;
+ p = 0;
+ pe = data.length;
+ eof = pe;
+ cs = 0;
+ stack = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
+ stack_size = 1;
+ top = 0;
+
+ %% write init;
+ %% write exec;
+
+ if cs == recdescent3_error
+ puts "SCANNER_ERROR"
+ end
+end
+
+inp = [
+ "88 foo { 99 {{{{}}}}{ } }",
+ "76 } sadf"
+]
+
+inp.each { |str| run_machine(str) }
+
+=begin _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+=end _____OUTPUT_____
diff --git a/test/repetition.rl b/test/repetition.rl
new file mode 100644
index 0000000..328cfa9
--- /dev/null
+++ b/test/repetition.rl
@@ -0,0 +1,293 @@
+/*
+ * @LANG: c++
+ */
+
+/* Test repeptition operators. */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+struct Rep
+{
+ int cs;
+
+ int init( );
+ int execute( const char *data, int len );
+ int finish( );
+};
+
+%%{
+ machine Rep;
+
+ action begin { cout << "begin" << endl; }
+ action in { cout << "in" << endl; }
+ action end { cout << "end" << endl; }
+
+ a = 'a' >begin @in %end;
+ b = 'b' >begin @in %end;
+ c = 'c' >begin @in %end;
+ d = 'd' >begin @in %end;
+
+ main :=
+ ( a {5} '\n' )* '-\n'
+ ( b {,5} '\n' )* '-\n'
+ ( c {5,} '\n' )* '-\n'
+ ( d {2,5} '\n' )*;
+}%%
+
+%% write data;
+
+int Rep::init( )
+{
+ %% write init;
+ return 1;
+}
+
+int Rep::execute( const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+
+ if ( cs == Rep_error )
+ return -1;
+ if ( cs >= Rep_first_final )
+ return 1;
+ return 0;
+}
+
+int Rep::finish( )
+{
+ if ( cs == Rep_error )
+ return -1;
+ if ( cs >= Rep_first_final )
+ return 1;
+ return 0;
+}
+
+void test( const char *buf )
+{
+ Rep rep;
+ int len = strlen( buf );
+ rep.init();
+ rep.execute( buf, len );
+ if ( rep.finish() > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+int main()
+{
+ test(
+ "aaaaa\n"
+ "-\n"
+ "\n"
+ "b\n"
+ "bb\n"
+ "bbb\n"
+ "bbbb\n"
+ "bbbbb\n"
+ "-\n"
+ "ccccc\n"
+ "ccccccc\n"
+ "cccccccccc\n"
+ "-\n"
+ "dd\n"
+ "ddd\n"
+ "dddd\n"
+ "ddddd\n"
+ );
+
+ test(
+ "a\n"
+ "-\n"
+ "b\n"
+ "-\n"
+ "c\n"
+ "-\n"
+ "d\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+begin
+in
+end
+ACCEPT
+begin
+in
+FAIL
+#endif
diff --git a/test/rlscan.rl b/test/rlscan.rl
new file mode 100644
index 0000000..448b979
--- /dev/null
+++ b/test/rlscan.rl
@@ -0,0 +1,289 @@
+/*
+ * Lexes Ragel input files.
+ *
+ * @LANG: c++
+ *
+ * Test works with split code gen.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+void escapeXML( const char *data )
+{
+ while ( *data != 0 ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ data += 1;
+ }
+}
+
+void escapeXML( char c )
+{
+ switch ( c ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << c; break;
+ }
+}
+
+void escapeXML( const char *data, int len )
+{
+ for ( const char *end = data + len; data != end; data++ ) {
+ switch ( *data ) {
+ case '<': cout << "&lt;"; break;
+ case '>': cout << "&gt;"; break;
+ case '&': cout << "&amp;"; break;
+ default: cout << *data; break;
+ }
+ }
+}
+
+inline void write( const char *data )
+{
+ cout << data;
+}
+
+inline void write( char c )
+{
+ cout << c;
+}
+
+inline void write( const char *data, int len )
+{
+ cout.write( data, len );
+}
+
+
+%%{
+ machine RagelScan;
+
+ word = [a-zA-Z_][a-zA-Z_0-9]*;
+ integer = [0-9]+;
+ hex = '0x' [0-9a-fA-F] [0-9a-fA-F]*;
+
+ default = ^0;
+ EOF = 0;
+
+ # Handles comments in outside code and inline blocks.
+ c_comment :=
+ ( default* :>> '*/' )
+ ${ escapeXML( fc ); }
+ @{ fret; };
+
+ action emit {
+ escapeXML( ts, te-ts );
+ }
+
+ #
+ # Inline action code
+ #
+
+ ilscan := |*
+
+ "'" ( [^'\\] | /\\./ )* "'" => emit;
+ '"' ( [^"\\] | /\\./ )* '"' => emit;
+ '/*' {
+ write( "/*" );
+ fcall c_comment;
+ };
+ '//' [^\n]* '\n' => emit;
+
+ '{' {
+ write( '{' );
+ inline_depth += 1;
+ };
+
+ '}' {
+ write( '}' );
+ /* If dropping down to the last } then return
+ * to ragel code. */
+ if ( --inline_depth == 0 ) {
+ write( "</inline>\n" );
+ fgoto rlscan;
+ }
+ };
+
+ default => { escapeXML( *ts ); };
+ *|;
+
+ #
+ # Ragel Tokens
+ #
+
+ rlscan := |*
+ '}%%' {
+ if ( !single_line ) {
+ write( "</section>\n" );
+ fgoto main;
+ }
+ };
+
+ '\n' {
+ if ( single_line ) {
+ write( "</section>\n" );
+ fgoto main;
+ }
+ };
+
+ # Word
+ word {
+ write( "<word>" );
+ write( ts, te-ts );
+ write( "</word>\n" );
+ };
+
+ # Decimal integer.
+ integer {
+ write( "<int>" );
+ write( ts, te-ts );
+ write( "</int>\n" );
+ };
+
+ # Hexidecimal integer.
+ hex {
+ write( "<hex>" );
+ write( ts, te-ts );
+ write( "</hex>\n" );
+ };
+
+ # Consume comments.
+ '#' [^\n]* '\n';
+
+ # Single literal string.
+ "'" ( [^'\\] | /\\./ )* "'" {
+ write( "<single_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</single_lit>\n" );
+ };
+
+ # Double literal string.
+ '"' ( [^"\\] | /\\./ )* '"' {
+ write( "<double_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</double_lit>\n" );
+ };
+
+ # Or literal.
+ '[' ( [^\]\\] | /\\./ )* ']' {
+ write( "<or_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</or_lit>\n" );
+ };
+
+ # Regex Literal.
+ '/' ( [^/\\] | /\\./ ) * '/' {
+ write( "<re_lit>" );
+ escapeXML( ts, te-ts );
+ write( "</re_lit>\n" );
+ };
+
+ # Open an inline block
+ '{' {
+ inline_depth = 1;
+ write( "<inline>{" );
+ fgoto ilscan;
+ };
+
+ punct {
+ write( "<symbol>" );
+ escapeXML( fc );
+ write( "</symbol>\n" );
+ };
+
+ default;
+ *|;
+
+ #
+ # Outside code.
+ #
+
+ main := |*
+
+ "'" ( [^'\\] | /\\./ )* "'" => emit;
+ '"' ( [^"\\] | /\\./ )* '"' => emit;
+
+ '/*' {
+ escapeXML( ts, te-ts );
+ fcall c_comment;
+ };
+
+ '//' [^\n]* '\n' => emit;
+
+ '%%{' {
+ write( "<section>\n" );
+ single_line = false;
+ fgoto rlscan;
+ };
+
+ '%%' {
+ write( "<section>\n" );
+ single_line = true;
+ fgoto rlscan;
+ };
+
+ default {
+ escapeXML( *ts );
+ };
+
+ # EOF.
+ EOF;
+ *|;
+}%%
+
+%% write data nofinal;
+
+void test( const char *data )
+{
+ std::ios::sync_with_stdio(false);
+
+ int cs, act;
+ const char *ts, *te;
+ int stack[1], top;
+
+ bool single_line = false;
+ int inline_depth = 0;
+
+ %% write init;
+
+ /* Read in a block. */
+ const char *p = data;
+ const char *pe = data + strlen( data );
+ const char *eof = pe;
+ %% write exec;
+
+ if ( cs == RagelScan_error ) {
+ /* Machine failed before finding a token. */
+ cerr << "PARSE ERROR" << endl;
+ exit(1);
+ }
+}
+
+#define BUFSIZE 2048
+
+int main()
+{
+ std::ios::sync_with_stdio(false);
+
+ test("hi %%{ /'}%%'/ { /*{*/ {} } + '\\'' }%%there\n");
+
+ return 0;
+}
+#ifdef _____OUTPUT_____
+hi <section>
+<re_lit>/'}%%'/</re_lit>
+<inline>{ /*{*/ {} }</inline>
+<symbol>+</symbol>
+<single_lit>'\''</single_lit>
+</section>
+there
+#endif
diff --git a/test/ruby1.rl b/test/ruby1.rl
new file mode 100644
index 0000000..e2f4bc9
--- /dev/null
+++ b/test/ruby1.rl
@@ -0,0 +1,56 @@
+#
+# @LANG: ruby
+#
+# Test the host language scanning for ruby.
+#
+
+# %%{
+a = 1
+b = /%%\{\}/;
+
+%%{
+ machine ruby1;
+
+ main := lower+ digit+ '\n' @{
+
+ # }
+ c = 1
+ d = /\}/
+ puts "NL"
+ };
+}%%
+
+# %%{
+e = 1
+f = /%%\{\}/;
+
+%% write data;
+
+# %%{
+g = 1
+h = /%%\{\}/;
+
+def run_machine( data )
+ p = 0;
+ pe = data.length
+ cs = 0
+
+ %% write init;
+ %% write exec;
+ if cs >= ruby1_first_final
+ puts "ACCEPT"
+ else
+ puts "FAIL"
+ end
+end
+
+inp = [
+ "abc1231\n",
+]
+
+inp.each { |str| run_machine(str) }
+
+=begin _____OUTPUT_____
+NL
+ACCEPT
+=end _____OUTPUT_____
diff --git a/test/runtests.in b/test/runtests.in
new file mode 100755
index 0000000..2d6cae7
--- /dev/null
+++ b/test/runtests.in
@@ -0,0 +1,335 @@
+#!/bin/bash
+
+#
+# Copyright 2006-2009 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
+
+while getopts "gcnmleT:F:G:P:CDJRAZ" opt; do
+ case $opt in
+ T|F|G|P)
+ genflags="$genflags -$opt$OPTARG"
+ options="$options -$opt$OPTARG"
+ ;;
+ n|m|l|e)
+ minflags="$minflags -$opt"
+ options="$options -$opt"
+ ;;
+ c)
+ compile_only="true"
+ options="$options -$opt"
+ ;;
+ g)
+ allow_generated="true"
+ ;;
+ C|D|J|R|A|Z)
+ langflags="$langflags -$opt"
+ ;;
+ esac
+done
+
+[ -z "$minflags" ] && minflags="-n -m -l -e"
+[ -z "$genflags" ] && genflags="-T0 -T1 -F0 -F1 -G0 -G1 -G2"
+[ -z "$langflags" ] && langflags="-C -D -J -R -A -Z"
+
+shift $((OPTIND - 1));
+
+[ -z "$*" ] && set -- *.rl
+
+config=../src/config.h
+ragel=../ragel/ragel
+
+cxx_compiler="@CXX@"
+c_compiler="@CC@"
+objc_compiler="@GOBJC@"
+d_compiler="@GDC@"
+java_compiler="@JAVAC@"
+txl_engine="@TXL@"
+ruby_engine="@RUBY@"
+csharp_compiler="@GMCS@"
+go_compiler="@GOBIN@"
+
+function test_error
+{
+ exit 1;
+}
+
+# split_objs=""
+# if test $split_iters != "$gen_opt"; then
+# n=0;
+# while test $n -lt $split_iters; do
+# part_root=${root}_`awk 'BEGIN {
+# width = 0;
+# high = '$split_iters' - 1;
+# while ( high > 0 ) {
+# width = width + 1;
+# high = int(high / 10);
+# }
+# suffFormat = "%" width "." width "d\n";
+# printf( suffFormat, '$n' );
+# exit 0;
+# }'`
+# part_src=${part_root}.c
+# part_bin=${part_root}.o
+# echo "$compiler -c $cflags -o $part_bin $part_src"
+# if ! $compiler -c $cflags -o $part_bin $part_src; then
+# test_error;
+# fi
+# split_objs="$split_objs $part_bin"
+# n=$((n+1))
+# done
+# fi
+
+function run_test()
+{
+ echo "$ragel $lang_opt $min_opt $gen_opt -o $code_src $test_case"
+ if ! $ragel $lang_opt $min_opt $gen_opt -o $code_src $test_case; then
+ test_error;
+ fi
+
+ out_args=""
+ [ $lang != java ] && out_args="-o ${binary}";
+ [ $lang == csharp ] && out_args="-out:${binary}";
+
+ # Ruby doesn't need to be compiled.
+ if [ $lang != ruby ]; then
+ echo "$compiler ${cflags} ${out_args} ${code_src}"
+ if ! $compiler ${cflags} ${out_args} ${code_src}; then
+ test_error;
+ fi
+ fi
+
+ if [ "$compile_only" != "true" ]; then
+ echo -n "running $root ... ";
+
+ exec_cmd=./$binary
+ [ $lang = java ] && exec_cmd="java ${root}"
+ [ $lang = ruby ] && exec_cmd="ruby ${code_src}"
+ [ $lang = csharp ] && [ "$csharp_compiler" = gmcs ] && exec_cmd="mono ${exec_cmd}"
+
+ $exec_cmd 2>&1 > $output;
+ if diff --strip-trailing-cr $expected_out $output > /dev/null; then
+ echo "passed";
+ else
+ echo "FAILED";
+ test_error;
+ fi;
+ fi
+}
+
+for test_case; do
+ root=${test_case%.rl};
+
+ if ! [ -f "$test_case" ]; then
+ echo "runtests: not a file: $test_case"; >&2
+ exit 1;
+ fi
+
+ # Check if we should ignore the test case
+ ignore=`sed '/@IGNORE:/s/^.*: *//p;d' $test_case`
+ if [ "$ignore" = yes ]; then
+ continue;
+ fi
+
+ # If the generated flag is given make sure that the test case is generated.
+ is_generated=`sed '/@GENERATED:/s/^.*: *//p;d' $test_case`
+ if [ "$is_generated" = yes ] && [ "$allow_generated" != true ]; then
+ continue;
+ fi
+
+ expected_out=$root.exp;
+ sed '1,/_____OUTPUT_____/d;$d' $test_case > $expected_out
+
+ lang=`sed '/@LANG:/s/^.*: *//p;d' $test_case`
+ if [ -z "$lang" ]; then
+ echo "$test_case: language unset"; >&2
+ exit 1;
+ fi
+
+ case $lang in
+ c++)
+ lang_opt=-C;
+ code_suffix=cpp;
+ compiler=$cxx_compiler;
+ cflags="-pedantic -ansi -Wall -O3"
+ ;;
+ d)
+ lang_opt=-D;
+ code_suffix=d;
+ compiler=$d_compiler;
+ cflags="-Wall -O3"
+ ;;
+ c)
+ lang_opt=-C;
+ code_suffix=c;
+ compiler=$c_compiler;
+ cflags="-pedantic -ansi -Wall -O3"
+ ;;
+ obj-c)
+ lang_opt=-C;
+ code_suffix=m;
+ compiler=$objc_compiler
+ cflags="-Wall -O3 -fno-strict-aliasing -lobjc"
+ ;;
+ java)
+ lang_opt=-J;
+ code_suffix=java;
+ compiler=$java_compiler
+ cflags=""
+ ;;
+ ruby)
+ lang_opt=-R;
+ code_suffix=rb;
+ compiler=$ruby_engine
+ cflags=""
+ ;;
+ csharp)
+ lang_opt="-A";
+ code_suffix=cs;
+ compiler=$csharp_compiler
+ cflags=""
+ ;;
+ go)
+ lang_opt="-Z"
+ code_suffix=go
+ compiler=$go_compiler
+ cflags=""
+ ;;
+ indep)
+ lang_opt="";
+
+ # If we have no txl engine then skip this test.
+ [ -z "$txl_engine" ] && continue
+ for lang in c d java ruby csharp go; do
+ case $lang in
+ c) lf="-C";;
+ d) lf="-D";;
+ java) lf="-J";;
+ ruby) lf="-R";;
+ csharp) lf="-A";;
+ go) lf="-Z";;
+ esac
+
+ echo "$langflags" | grep -e $lf >/dev/null || continue
+
+ targ=${root}_$lang.rl
+ echo "./langtrans_$lang.sh $test_case > $targ"
+ if ! ./langtrans_$lang.sh $test_case > $targ; then
+ test_error
+ fi
+ echo "./runtests -g $options $targ"
+ if ! ./runtests -g $options $targ; then
+ test_error
+ fi
+ done
+ continue;
+ ;;
+ *)
+ echo "$test_case: unknown language type $lang" >&2
+ exit 1;
+ ;;
+ esac
+
+ # Make sure that we are interested in the host language.
+ echo "$langflags" | grep -e $lang_opt >/dev/null || continue
+
+ code_src=$root.$code_suffix;
+ binary=$root.bin;
+ output=$root.out;
+
+ # If we have no compiler for the source program then skip it.
+ [ -z "$compiler" ] && continue
+
+ additional_cflags=`sed '/@CFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -n "$additional_cflags" ] && cflags="$cflags $additional_cflags"
+
+ allow_minflags=`sed '/@ALLOW_MINFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -z "$allow_minflags" ] && allow_minflags="-n -m -l -e"
+
+ case $lang in
+ c|c++|d)
+ # Using genflags, get the allowed gen flags from the test case. If the
+ # test case doesn't specify assume that all gen flags are allowed.
+ allow_genflags=`sed '/@ALLOW_GENFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -z "$allow_genflags" ] && allow_genflags="-T0 -T1 -F0 -F1 -G0 -G1 -G2"
+
+ for min_opt in $minflags; do
+ echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+ for gen_opt in $genflags; do
+ echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
+ run_test
+ done
+ done
+ ;;
+
+ java)
+ # Not interested in gen opt.
+ gen_opt=""
+ for min_opt in $minflags; do
+ echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+ run_test
+ done
+ ;;
+
+ ruby)
+ # Using genflags, get the allowed gen flags from the test case. If the
+ # test case doesn't specify assume that all gen flags are allowed.
+ allow_genflags=`sed '/@ALLOW_GENFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -z "$allow_genflags" ] && allow_genflags="-T0 -T1 -F0 -F1"
+
+ for min_opt in $minflags; do
+ echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+
+ for gen_opt in $genflags; do
+ echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
+ run_test
+ done
+ done
+ ;;
+
+ csharp)
+ # Using genflags, get the allowed gen flags from the test case. If the
+ # test case doesn't specify assume that all gen flags are allowed.
+ allow_genflags=`sed '/@ALLOW_GENFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -z "$allow_genflags" ] && allow_genflags="-T0 -T1 -F0 -F1 -G0 -G1"
+
+ for min_opt in $minflags; do
+ echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+ for gen_opt in $genflags; do
+ echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
+ run_test
+ done
+ done
+ ;;
+
+ go)
+ # Using genflags, get the allowed gen flags from the test case. If the
+ # test case doesn't specify assume that all gen flags are allowed.
+ allow_genflags=`sed '/@ALLOW_GENFLAGS:/s/^.*: *//p;d' $test_case`
+ [ -z "$allow_genflags" ] && allow_genflags="-T0 -T1 -F0 -F1 -G0 -G1 -G2"
+
+ for min_opt in $minflags; do
+ echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+ for gen_opt in $genflags; do
+ echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
+ run_test
+ done
+ done
+ ;;
+ esac
+done
diff --git a/test/scan1.rl b/test/scan1.rl
new file mode 100644
index 0000000..df0971a
--- /dev/null
+++ b/test/scan1.rl
@@ -0,0 +1,64 @@
+/*
+ * @LANG: indep
+ */
+ptr ts;
+ptr te;
+int act;
+int token;
+%%
+%%{
+ machine scanner;
+
+ # Warning: changing the patterns or the input string will affect the
+ # coverage of the scanner action types.
+ main := |*
+ 'a' => {
+ prints "on last ";
+ if ( p+1 == te )
+ prints "yes";
+ prints "\n";
+ };
+
+ 'b'+ => {
+ prints "on next ";
+ if ( p+1 == te )
+ prints "yes";
+ prints "\n";
+ };
+
+ 'c1' 'dxxx'? => {
+ prints "on lag ";
+ if ( p+1 == te )
+ prints "yes";
+ prints "\n";
+ };
+
+ 'd1' => {
+ prints "lm switch1 ";
+ if ( p+1 == te )
+ prints "yes";
+ prints "\n";
+ };
+ 'd2' => {
+ prints "lm switch2 ";
+ if ( p+1 == te )
+ prints "yes";
+ prints "\n";
+ };
+
+ [d0-9]+ '.';
+
+ '\n';
+ *|;
+}%%
+/* _____INPUT_____
+"abbc1d1d2\n"
+_____INPUT_____ */
+/* _____OUTPUT_____
+on last yes
+on next yes
+on lag yes
+lm switch1 yes
+lm switch2 yes
+ACCEPT
+_____OUTPUT_____ */
diff --git a/test/scan2.rl b/test/scan2.rl
new file mode 100644
index 0000000..a1ae959
--- /dev/null
+++ b/test/scan2.rl
@@ -0,0 +1,34 @@
+/*
+ * @LANG: indep
+ */
+ptr ts;
+ptr te;
+int act;
+int token;
+%%
+%%{
+ machine scanner;
+
+ # Warning: changing the patterns or the input string will affect the
+ # coverage of the scanner action types.
+ main := |*
+ 'a' => {
+ prints "pat1\n";
+ };
+
+ [ab]+ . 'c' => {
+ prints "pat2\n";
+ };
+
+ any => {
+ prints "any\n";
+ };
+ *|;
+}%%
+/* _____INPUT_____
+"a"
+_____INPUT_____ */
+/* _____OUTPUT_____
+pat1
+ACCEPT
+_____OUTPUT_____ */
diff --git a/test/scan3.rl b/test/scan3.rl
new file mode 100644
index 0000000..ca1a136
--- /dev/null
+++ b/test/scan3.rl
@@ -0,0 +1,32 @@
+/*
+ * @LANG: indep
+ */
+ptr ts;
+ptr te;
+int act;
+int token;
+%%
+%%{
+ machine scanner;
+
+ # Warning: changing the patterns or the input string will affect the
+ # coverage of the scanner action types.
+ main := |*
+ 'a' => {
+ prints "pat1\n";
+ };
+ 'b' => {
+ prints "pat2\n";
+ };
+ [ab] any* => {
+ prints "pat3\n";
+ };
+ *|;
+}%%
+/* _____INPUT_____
+"ab89"
+_____INPUT_____ */
+/* _____OUTPUT_____
+pat3
+ACCEPT
+_____OUTPUT_____ */
diff --git a/test/scan4.rl b/test/scan4.rl
new file mode 100644
index 0000000..12d4d4c
--- /dev/null
+++ b/test/scan4.rl
@@ -0,0 +1,33 @@
+/*
+ * @LANG: indep
+ */
+ptr ts;
+ptr te;
+int act;
+int token;
+%%
+%%{
+ machine scanner;
+
+ # Warning: changing the patterns or the input string will affect the
+ # coverage of the scanner action types.
+ main := |*
+ 'a' => {
+ prints "pat1\n";
+ };
+
+ [ab]+ . 'c' => {
+ prints "pat2\n";
+ };
+
+ any;
+ *|;
+}%%
+/* _____INPUT_____
+"ba a"
+_____INPUT_____ */
+/* _____OUTPUT_____
+pat1
+pat1
+ACCEPT
+_____OUTPUT_____ */
diff --git a/test/stateact1.rl b/test/stateact1.rl
new file mode 100644
index 0000000..ef50c75
--- /dev/null
+++ b/test/stateact1.rl
@@ -0,0 +1,48 @@
+/*
+ * @LANG: indep
+ *
+ * Test in and out state actions.
+ */
+%%
+%%{
+ machine state_act;
+
+ action a1 { prints "a1\n"; }
+ action a2 { prints "a2\n"; }
+ action b1 { prints "b1\n"; }
+ action b2 { prints "b2\n"; }
+ action c1 { prints "c1\n"; }
+ action c2 { prints "c2\n"; }
+ action next_again {fnext again;}
+
+ hi = 'hi';
+ line = again:
+ hi
+ >to b1
+ >from b2
+ '\n'
+ >to c1
+ >from c2
+ @next_again;
+
+ main := line*
+ >to a1
+ >from a2;
+}%%
+
+/* _____INPUT_____
+"hi\nhi\n"
+_____INPUT_____ */
+
+/* _____OUTPUT_____
+a2
+b2
+c1
+c2
+b1
+b2
+c1
+c2
+b1
+FAIL
+_____OUTPUT_____ */
diff --git a/test/statechart1.rl b/test/statechart1.rl
new file mode 100644
index 0000000..884f3f0
--- /dev/null
+++ b/test/statechart1.rl
@@ -0,0 +1,100 @@
+/*
+ * @LANG: c
+ */
+
+/*
+ * Test in and out state actions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+struct state_chart
+{
+ int cs;
+};
+
+%%{
+ machine state_chart;
+ variable cs fsm->cs;
+
+ action a { printf("a"); }
+ action b { printf("b"); }
+ action hexa { printf("a"); }
+ action hexb { printf("b"); }
+
+ hex_a = '0x' '0'* '61' @hexa;
+ hex_b = '0x' '0'* '62' @hexb;
+
+ a = 'a' @a | hex_a;
+ b = 'b' @b | hex_b;
+ ws = ' '+;
+
+ mach =
+ start: (
+ a -> st1 |
+ b -> st2 |
+ zlen -> final
+ ),
+ st1: (
+ a -> st1 |
+ ws -> start |
+ zlen -> final
+ ),
+ st2: (
+ b -> st2 |
+ ws -> start |
+ zlen -> final
+ );
+
+ main := ( mach '\n' )*;
+}%%
+
+%% write data;
+
+void state_chart_init( struct state_chart *fsm )
+{
+ %% write init;
+}
+
+void state_chart_execute( struct state_chart *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int state_chart_finish( struct state_chart *fsm )
+{
+ if ( fsm->cs == state_chart_error )
+ return -1;
+ if ( fsm->cs >= state_chart_first_final )
+ return 1;
+ return 0;
+}
+
+struct state_chart sc;
+
+void test( char *buf )
+{
+ int len = strlen( buf );
+ state_chart_init( &sc );
+ state_chart_execute( &sc, buf, len );
+ state_chart_finish( &sc );
+ printf("\n");
+}
+
+int main()
+{
+ test(
+ "aa0x0061aa b\n"
+ "bbb0x62b 0x61 0x000062\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+aaaaabbbbbbab
+#endif
diff --git a/test/strings1.rl b/test/strings1.rl
new file mode 100644
index 0000000..0d5eea8
--- /dev/null
+++ b/test/strings1.rl
@@ -0,0 +1,193 @@
+/*
+ * @LANG: c
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+struct strs
+{
+ int cs;
+};
+
+%%{
+ machine strs;
+ variable cs fsm->cs;
+
+ main :=
+ "__gmon_start__\n" |
+ "cerr\n" |
+ "__cp_push_exception\n" |
+ "_DYNAMIC\n" |
+ "__rtti_user\n" |
+ "__rtti_si\n" |
+ "_init\n" |
+ "__throw\n" |
+ "__deregister_frame_info\n" |
+ "terminate__Fv\n" |
+ "__builtin_vec_new\n" |
+ "_fini\n" |
+ "__builtin_vec_delete\n" |
+ "_GLOBAL_OFFSET_TABLE_\n" |
+ "__nw__FUiPv\n" |
+ "__builtin_delete\n" |
+ "__builtin_new\n" |
+ "cout\n" |
+ "__register_frame_info\n" |
+ "__eh_alloc\n" |
+ "strcpy\n" |
+ "stdout\n" |
+ "memmove\n" |
+ "memcpy\n" |
+ "malloc\n" |
+ "isatty\n" |
+ "strtoul\n" |
+ "fprintf\n" |
+ "stdin\n" |
+ "ferror\n" |
+ "strncpy\n" |
+ "unlink\n" |
+ "strcasecmp\n" |
+ "realloc\n" |
+ "_IO_getc\n" |
+ "fread\n" |
+ "memset\n" |
+ "__assert_fail\n" |
+ "strcmp\n" |
+ "stderr\n" |
+ "fwrite\n" |
+ "exit\n" |
+ "fopen\n" |
+ "atoi\n" |
+ "fileno\n" |
+ "_IO_stdin_used\n" |
+ "__libc_start_main\n" |
+ "strlen\n" |
+ "free\n" |
+ "_edata\n" |
+ "__bss_start\n" |
+ "_end\n" |
+ "QVhl\n" |
+ "BPPh\n" |
+ "PHRV\n" |
+ "PHRj\n" |
+ "PHRj\n" |
+ "jphy\n" |
+ "jqhy\n" |
+ "PHRj\n" |
+ "PHRj\n" |
+ "LWVS\n" |
+ "LWVS\n" |
+ "bad_alloc\n" |
+ "main\n" |
+ "false\n" |
+ "help\n" |
+ "bad_alloc\n" |
+ "bad_alloc\n" |
+ "bad_alloc\n" |
+ "ascii\n" |
+ "extend\n" |
+ "alnum\n" |
+ "alpha\n" |
+ "cntrl\n" |
+ "digit\n" |
+ "graph\n" |
+ "lower\n" |
+ "print\n" |
+ "punct\n" |
+ "space\n" |
+ "upper\n" |
+ "xdigit\n" |
+ "false\n" |
+ "bad_alloc\n" |
+ "bad_alloc\n" |
+ "bad_alloc\n" |
+ "TransStruct\n" |
+ "StateStruct\n" |
+ "Struct\n" |
+ "Init\n" |
+ "bad_alloc\n" |
+ "TransStruct\n" |
+ "StateStruct\n" |
+ "Struct\n" |
+ "Init\n" |
+ "Accept\n" |
+ "Finish\n" |
+ "bad_alloc\n" |
+ "Struct\n" |
+ "Init\n" |
+ "Finish\n" |
+ "Accept\n" |
+ "bad_alloc\n" |
+ "Struct\n" |
+ "Init\n" |
+ "bad_alloc\n" |
+ "Struct\n" |
+ "Init\n" |
+ "Finish\n" |
+ "Accept\n" |
+ "bad_alloc\n" |
+ "Struct\n" |
+ "Init\n" |
+ "Finish\n" |
+ "Accept";
+}%%
+
+%% write data;
+
+void strs_init( struct strs *fsm )
+{
+ %% write init;
+}
+
+void strs_execute( struct strs *fsm, const char *_data, int _len )
+{
+ const char *p = _data;
+ const char *pe = _data+_len;
+
+ %% write exec;
+}
+
+int strs_finish( struct strs *fsm )
+{
+ if ( fsm->cs == strs_error )
+ return -1;
+ if ( fsm->cs >= strs_first_final )
+ return 1;
+ return 0;
+}
+
+struct strs fsm;
+void test( char *buf )
+{
+ int len = strlen( buf );
+ strs_init( &fsm );
+ strs_execute( &fsm, buf, len );
+ if ( strs_finish( &fsm ) > 0 )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test( "stdin\n" );
+ test( "bad_alloc\n" );
+ test( "_GLOBAL_OFFSET_TABLE_\n" );
+ test( "not in\n" );
+ test(
+ "isatty\n"
+ "junk on end.\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+#endif
diff --git a/test/strings2.h b/test/strings2.h
new file mode 100644
index 0000000..1cf0ce9
--- /dev/null
+++ b/test/strings2.h
@@ -0,0 +1,9 @@
+#ifndef _STRINGS1_H
+#define _STRINGS1_H
+
+struct strs
+{
+ int cs;
+};
+
+#endif
diff --git a/test/strings2.rl b/test/strings2.rl
new file mode 100644
index 0000000..edad63b
--- /dev/null
+++ b/test/strings2.rl
@@ -0,0 +1,1349 @@
+/*
+ * @LANG: c
+ * @ALLOW_GENFLAGS: -T0 -T1 -F0 -F1
+ * @ALLOW_MINFLAGS: -n -m -l
+ *
+ * Test works with split code gen.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "strings2.h"
+
+%%{
+ machine strs;
+ variable cs fsm->cs;
+
+ main :=
+ "/lib/ld-linux.so.2\n" |
+ "libstdc++-libc6.2-2.so.3\n" |
+ "cerr\n" |
+ "__cp_push_exception\n" |
+ "_DYNAMIC\n" |
+ "endl__FR7ostream\n" |
+ "__ls__7ostreamc\n" |
+ "_._9exception\n" |
+ "__vt_9bad_alloc\n" |
+ "__rtti_user\n" |
+ "__ls__7ostreamPFR7ostream_R7ostream\n" |
+ "__rtti_si\n" |
+ "_init\n" |
+ "bad__C3ios\n" |
+ "__throw\n" |
+ "__ls__7ostreamPCc\n" |
+ "__deregister_frame_info\n" |
+ "terminate__Fv\n" |
+ "__ls__7ostreamb\n" |
+ "__ls__7ostreami\n" |
+ "__8ofstreamiPCcii\n" |
+ "__builtin_vec_new\n" |
+ "_fini\n" |
+ "__9exception\n" |
+ "__builtin_vec_delete\n" |
+ "_GLOBAL_OFFSET_TABLE_\n" |
+ "__vt_9exception\n" |
+ "__nw__FUiPv\n" |
+ "_._9bad_alloc\n" |
+ "__builtin_delete\n" |
+ "__builtin_new\n" |
+ "cout\n" |
+ "__register_frame_info\n" |
+ "__eh_alloc\n" |
+ "__gmon_start__\n" |
+ "libm.so.6\n" |
+ "libc.so.6\n" |
+ "strcpy\n" |
+ "stdout\n" |
+ "memmove\n" |
+ "memcpy\n" |
+ "malloc\n" |
+ "strtoul\n" |
+ "fprintf\n" |
+ "stdin\n" |
+ "ferror\n" |
+ "strncpy\n" |
+ "strcasecmp\n" |
+ "realloc\n" |
+ "_IO_getc\n" |
+ "fread\n" |
+ "memset\n" |
+ "clearerr\n" |
+ "__assert_fail\n" |
+ "strcmp\n" |
+ "stderr\n" |
+ "fwrite\n" |
+ "__errno_location\n" |
+ "exit\n" |
+ "fopen\n" |
+ "atoi\n" |
+ "_IO_stdin_used\n" |
+ "__libc_start_main\n" |
+ "strlen\n" |
+ "free\n" |
+ "_edata\n" |
+ "__bss_start\n" |
+ "_end\n" |
+ "GLIBC_2.1\n" |
+ "GLIBC_2.0\n" |
+ "PTRh\n" |
+ "QVhL\n" |
+ "<WVS\n" |
+ "LWVS\n" |
+ "PHRW\n" |
+ "<WVS\n" |
+ "\WVS\n" |
+ ",WVS\n" |
+ "@Phl\n" |
+ "<WVS\n" |
+ "jZjA\n" |
+ "jzja\n" |
+ "j9j0\n" |
+ "j9j0\n" |
+ "jZjA\n" |
+ "jzja\n" |
+ "jzja\n" |
+ "jZjA\n" |
+ "j~j!\n" |
+ "j~j \n" |
+ "j/j!\n" |
+ "j@j:\n" |
+ "j`j[\n" |
+ "j~j{\n" |
+ "j9j0\n" |
+ "jFjA\n" |
+ "jfja\n" |
+ ",WVS\n" |
+ ",WVS\n" |
+ ";C<|\n" |
+ "<WVS\n" |
+ "C ;C\n" |
+ "C$;C\n" |
+ "C$;C\n" |
+ "C ;C\n" |
+ ",WVS\n" |
+ ";E uF\n" |
+ "P ;U\n" |
+ "P ;U\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "E$fP\n" |
+ "u!h@\n" |
+ "PHRj\n" |
+ "PHRj\n" |
+ "P\ U\n" |
+ "j]hY\n" |
+ "johY\n" |
+ "PHRj\n" |
+ "PHRj\n" |
+ "E fPj\n" |
+ "E fP\n" |
+ "E fP\n" |
+ "E fP\n" |
+ "E fP\n" |
+ "E fP\n" |
+ "E fPj\n" |
+ "t$h`\n" |
+ "F ;C } \n" |
+ "F ;C ~ \n" |
+ "@X:BXt)\n" |
+ "\WVS\n" |
+ "\WVS\n" |
+ "PPRS\n" |
+ "F ;C } \n" |
+ "F ;C ~ \n" |
+ "@X:BXt)\n" |
+ ";H(}:\n" |
+ "@ fP\n" |
+ ";P |\n" |
+ "<WVS\n" |
+ ";P |\n" |
+ "bad_alloc\n" |
+ "usage: ragel [options] file\n" |
+ "general:\n" |
+ " -h, -H, -? Disply this usage.\n" |
+ " -o <file> Write output to <file>.\n" |
+ " -s Print stats on the compiled fsm.\n" |
+ " -f Dump the final fsm.\n" |
+ "fsm minimization:\n" |
+ " -n No minimization (default).\n" |
+ " -m Find the minimal fsm accepting the language.\n" |
+ "generated code language:\n" |
+ " -c Generate c code (default).\n" |
+ " -C Generate c++ code.\n" |
+ "generated code style:\n" |
+ " -T0 Generate a table driven fsm (default).\n" |
+ " -T1 Generate a faster table driven fsm.\n" |
+ " -S0 Generate a switch driven fsm.\n" |
+ " -G0 Generate a goto driven fsm.\n" |
+ " -G1 Generate a faster goto driven fsm.\n" |
+ " -G2 Generate a really fast goto driven fsm.\n" |
+ "char * FileNameFromStem(char *, char *)\n" |
+ "main.cpp\n" |
+ "len > 0\n" |
+ "main\n" |
+ "ragel: main graph not defined\n" |
+ "graph states: \n" |
+ "graph transitions: \n" |
+ "machine states: \n" |
+ "machine functions: \n" |
+ "function array: \n" |
+ "T:S:G:Cco:senmabjkfhH?-:\n" |
+ "ragel: zero length output file name given\n" |
+ "ragel: output file already given\n" |
+ "ragel: invalid param specified (try -h for a list of options)\n" |
+ "help\n" |
+ "ragel: zero length input file name given\n" |
+ "ragel: input file already given\n" |
+ "ragel: warning: -e given but minimization is not enabled\n" |
+ "ragel: no input file (try -h for a list of options)\n" |
+ " for reading\n" |
+ "ragel: could not open \n" |
+ " for writing\n" |
+ "ragel: error opening \n" |
+ " * Parts of this file are copied from Ragel source covered by the GNU\n" |
+ " * GPL. As a special exception, you may use the parts of this file copied\n" |
+ " * from Ragel source without restriction. The remainder is derived from\n" |
+ "bad_alloc\n" |
+ "%s:%i: unterminated literal\n" |
+ "%s:%i: unterminated comment\n" |
+ "%s:%i: bad character in literal\n" |
+ "fatal flex scanner internal error--no action found\n" |
+ "fatal flex scanner internal error--end of buffer missed\n" |
+ "fatal error - scanner input buffer overflow\n" |
+ "input in flex scanner failed\n" |
+ "out of dynamic memory in yy_create_buffer()\n" |
+ "out of dynamic memory in yy_scan_buffer()\n" |
+ "out of dynamic memory in yy_scan_bytes()\n" |
+ "bad buffer in yy_scan_bytes()\n" |
+ "bad_alloc\n" |
+ "%s:%i: warning: range gives null fsm\n" |
+ "%s:%i: warning: literal used in range is not of length 1, using 0x%x\n" |
+ "%s:%i: warning: overflow in byte constant\n" |
+ "parse error\n" |
+ "parser stack overflow\n" |
+ "%s:%i: %s\n" |
+ "bad_alloc\n" |
+ "extend\n" |
+ "ascii\n" |
+ "alpha\n" |
+ "digit\n" |
+ "alnum\n" |
+ "lower\n" |
+ "upper\n" |
+ "cntrl\n" |
+ "graph\n" |
+ "print\n" |
+ "punct\n" |
+ "space\n" |
+ "xdigit\n" |
+ "struct Fsm * FactorWithAugNode::Walk()\n" |
+ "parsetree.cpp\n" |
+ "false\n" |
+ "bad_alloc\n" |
+ "xx []()\n" |
+ " df \n" |
+ "StartState: \n" |
+ "Final States:\n" |
+ "void FsmGraph<State,int,Trans>::AttachStates(State *, State *, Trans *, FsmKeyType, int)\n" |
+ "rlfsm/fsmattach.cpp\n" |
+ "trans->toState == __null\n" |
+ "trans->fromState == __null\n" |
+ "void FsmGraph<State,int,Trans>::DetachStates(State *, State *, Trans *, FsmKeyType, int)\n" |
+ "trans->toState == to\n" |
+ "trans->fromState == from\n" |
+ "inTel != __null\n" |
+ "void Vector<BstMapEl<int,int>,ResizeExpn>::setAs(const Vector<BstMapEl<int,int>,ResizeExpn> &)\n" |
+ "aapl/vectcommon.h\n" |
+ "&v != this\n" |
+ "void FsmGraph<State,int,Trans>::ChangeRangeLowerKey(Trans *, int, int)\n" |
+ "inRangeEl != __null\n" |
+ "void FsmGraph<State,int,Trans>::IsolateStartState()\n" |
+ "rlfsm/fsmgraph.cpp\n" |
+ "md.stateDict.nodeCount == 0\n" |
+ "md.stfil.listLength == 0\n" |
+ "struct State * FsmGraph<State,int,Trans>::DetachState(State *)\n" |
+ "fromTel != __null\n" |
+ "struct Trans * FsmGraph<State,int,Trans>::AttachStates(State *, State *, FsmKeyType, int, int)\n" |
+ "outTel != __null\n" |
+ "outTel1 != __null\n" |
+ "from->defOutTrans == __null\n" |
+ "void FsmGraph<State,int,Trans>::VerifyOutFuncs()\n" |
+ "state->outTransFuncTable.tableLength == 0\n" |
+ "!state->isOutPriorSet\n" |
+ "state->outPriority == 0\n" |
+ "void FsmGraph<State,int,Trans>::VerifyIntegrity()\n" |
+ "rlfsm/fsmbase.cpp\n" |
+ "outIt.trans->fromState == state\n" |
+ "inIt.trans->toState == state\n" |
+ "static int FsmTrans<State,Trans,int,CmpOrd<int> >::ComparePartPtr(FsmTrans<State,Trans,int,CmpOrd<int> > *, FsmTrans<State,Trans,int,CmpOrd<int> > *)\n" |
+ "rlfsm/fsmstate.cpp\n" |
+ "false\n" |
+ "void FsmGraph<State,int,Trans>::InTransMove(State *, State *)\n" |
+ "dest != src\n" |
+ "static bool FsmTrans<State,Trans,int,CmpOrd<int> >::ShouldMarkPtr(MarkIndex<State> &, FsmTrans<State,Trans,int,CmpOrd<int> > *, FsmTrans<State,Trans,int,CmpOrd<int> > *)\n" |
+ "bad_alloc\n" |
+ "10FsmCodeGen\n" |
+ "bad_alloc\n" |
+ " case \n" |
+ "break;}\n" |
+ "unsigned char\n" |
+ "unsigned short\n" |
+ "unsigned int\n" |
+ "{0, \n" |
+ "/* Forward dec state for the transition structure. */\n" |
+ "struct \n" |
+ "StateStruct;\n" |
+ "/* A single transition. */\n" |
+ "struct \n" |
+ "TransStruct\n" |
+ " struct \n" |
+ "StateStruct *toState;\n" |
+ " int *funcs;\n" |
+ "typedef struct \n" |
+ "TransStruct \n" |
+ "Trans;\n" |
+ "/* A single state. */\n" |
+ "struct \n" |
+ "StateStruct\n" |
+ " int lowIndex;\n" |
+ " int highIndex;\n" |
+ " void *transIndex;\n" |
+ " unsigned int dflIndex;\n" |
+ " int *outFuncs;\n" |
+ " int isFinState;\n" |
+ "typedef struct \n" |
+ "StateStruct \n" |
+ "State;\n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ "State *curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "#define f \n" |
+ "#define s \n" |
+ "#define i \n" |
+ "#define t \n" |
+ "/* The array of functions. */\n" |
+ "#if \n" |
+ "static int \n" |
+ "_f[] = {\n" |
+ "#endif\n" |
+ "/* The array of indicies into the transition array. */\n" |
+ "#if \n" |
+ "static \n" |
+ "_i[] = {\n" |
+ "#endif\n" |
+ "/* The aray of states. */\n" |
+ "static \n" |
+ "State \n" |
+ "_s[] = {\n" |
+ "/* The array of transitions. */\n" |
+ "static \n" |
+ "Trans \n" |
+ "_t[] = {\n" |
+ "/* The start state. */\n" |
+ "static \n" |
+ "State *\n" |
+ "_startState = s+\n" |
+ "#undef f\n" |
+ "#undef s\n" |
+ "#undef i\n" |
+ "#undef t\n" |
+ "* Execute functions pointed to by funcs until the null function is found. \n" |
+ "inline static void \n" |
+ "ExecFuncs( \n" |
+ " *fsm, int *funcs, char *p )\n" |
+ " int len = *funcs++;\n" |
+ " while ( len-- > 0 ) {\n" |
+ " switch ( *funcs++ ) {\n" |
+ " * Init the fsm to a runnable state.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ " * Did the fsm accept? \n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ "State *cs = fsm->curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " int c = (unsigned char) *p;\n" |
+ "Trans *trans;\n" |
+ " if ( cs == 0 )\n" |
+ " goto finished;\n" |
+ " /* If the character is within the index bounds then get the\n" |
+ " * transition for it. If it is out of the transition bounds\n" |
+ " * we will use the default transition. */\n" |
+ " if ( cs->lowIndex <= c && c < cs->highIndex ) {\n" |
+ " /* Use the index to look into the transition array. */\n" |
+ " trans = \n" |
+ "_t + \n" |
+ " ((\n" |
+ "*)cs->transIndex)[c - cs->lowIndex];\n" |
+ " else {\n" |
+ " /* Use the default index as the char is out of range. */\n" |
+ " trans = \n" |
+ "_t + cs->dflIndex;\n" |
+ " /* If there are functions for this transition then execute them. */\n" |
+ " if ( trans->funcs != 0 )\n" |
+ "ExecFuncs( fsm, trans->funcs, p );\n" |
+ " /* Move to the new state. */\n" |
+ " cs = trans->toState;\n" |
+ "finished:\n" |
+ " fsm->curState = cs;\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ "State *cs = fsm->curState;\n" |
+ " if ( cs != 0 && cs->isFinState ) {\n" |
+ " /* If finishing in a final state then execute the\n" |
+ " * out functions for it. (if any). */\n" |
+ " if ( cs->outFuncs != 0 )\n" |
+ "ExecFuncs( fsm, cs->outFuncs, 0 );\n" |
+ " fsm->accept = 1;\n" |
+ " else {\n" |
+ " /* If we are not in a final state then this\n" |
+ " * is an error. Move to the error state. */\n" |
+ " fsm->curState = 0;\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Forward dec state for the transition structure. */\n" |
+ " struct State;\n" |
+ " /* A single transition. */\n" |
+ " struct Trans\n" |
+ " State *toState;\n" |
+ " int *funcs;\n" |
+ " /* A single state. */\n" |
+ " struct State\n" |
+ " int lowIndex;\n" |
+ " int highIndex;\n" |
+ " void *transIndex;\n" |
+ " unsigned int dflIndex;\n" |
+ " int *outFuncs;\n" |
+ " int isFinState;\n" |
+ " /* Constructor. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " State *curState;\n" |
+ " int accept;\n" |
+ " inline void ExecFuncs( int *funcs, char *p );\n" |
+ "/* The array of functions. */\n" |
+ "#if \n" |
+ "::State \n" |
+ "/* The array of trainsitions. */\n" |
+ "static \n" |
+ "::Trans \n" |
+ "/* The start state. */\n" |
+ "static \n" |
+ "::State *\n" |
+ " * Execute functions pointed to by funcs until the null function is found. \n" |
+ "inline void \n" |
+ "::ExecFuncs( int *funcs, char *p )\n" |
+ " int len = *funcs++;\n" |
+ " while ( len-- > 0 ) {\n" |
+ " switch ( *funcs++ ) {\n" |
+ " * Constructor\n" |
+ " Init();\n" |
+ "Init\n" |
+ "void \n" |
+ "::Init( )\n" |
+ " curState = \n" |
+ "_startState;\n" |
+ " accept = 0;\n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "::Execute( char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ " State *cs = curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " int c = (unsigned char)*p;\n" |
+ " Trans *trans;\n" |
+ " if ( cs == 0 )\n" |
+ " goto finished;\n" |
+ " /* If the character is within the index bounds then get the\n" |
+ " * transition for it. If it is out of the transition bounds\n" |
+ " * we will use the default transition. */\n" |
+ " if ( cs->lowIndex <= c && c < cs->highIndex ) {\n" |
+ " /* Use the index to look into the transition array. */\n" |
+ " trans = \n" |
+ "_t + cs->dflIndex;\n" |
+ " /* If there are functions for this transition then execute them. */\n" |
+ " if ( trans->funcs != 0 )\n" |
+ " ExecFuncs( trans->funcs, p );\n" |
+ " /* Move to the new state. */\n" |
+ " cs = trans->toState;\n" |
+ "finished:\n" |
+ " curState = cs;\n" |
+ "::Finish( )\n" |
+ " State *cs = curState;\n" |
+ " if ( cs != 0 && cs->isFinState ) {\n" |
+ " /* If finishing in a final state then execute the\n" |
+ " * out functions for it. (if any). */\n" |
+ " if ( cs->outFuncs != 0 )\n" |
+ " ExecFuncs( cs->outFuncs, 0 );\n" |
+ " accept = 1;\n" |
+ " else {\n" |
+ " /* If we are not in a final state then this\n" |
+ " * is an error. Move to the error state. */\n" |
+ " curState = 0;\n" |
+ "10TabCodeGen\n" |
+ "11CTabCodeGen\n" |
+ "12CCTabCodeGen\n" |
+ "10FsmCodeGen\n" |
+ "bad_alloc\n" |
+ " case \n" |
+ " break;\n" |
+ "/* Forward dec state for the transition structure. */\n" |
+ "struct \n" |
+ "StateStruct;\n" |
+ "/* A single transition. */\n" |
+ "struct \n" |
+ "TransStruct\n" |
+ " struct \n" |
+ "StateStruct *toState;\n" |
+ " int funcs;\n" |
+ "typedef struct \n" |
+ "TransStruct \n" |
+ "Trans;\n" |
+ "/* A single state. */\n" |
+ "struct \n" |
+ "StateStruct\n" |
+ " int lowIndex;\n" |
+ " int highIndex;\n" |
+ " void *transIndex;\n" |
+ " int dflIndex;\n" |
+ " int outFuncs;\n" |
+ " int isFinState;\n" |
+ "typedef struct \n" |
+ "StateStruct \n" |
+ "State;\n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ "State *curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "#define s \n" |
+ "#define i \n" |
+ "#define t \n" |
+ "/* The array of indicies into the transition array. */\n" |
+ "#if \n" |
+ "static \n" |
+ "_i[] = {\n" |
+ "#endif\n" |
+ "/* The aray of states. */\n" |
+ "static \n" |
+ "State \n" |
+ "_s[] = {\n" |
+ "/* The array of trainsitions. */\n" |
+ "static \n" |
+ "Trans \n" |
+ "_t[] = {\n" |
+ "/* The start state. */\n" |
+ "static \n" |
+ "State *\n" |
+ "_startState = s+\n" |
+ "#undef f\n" |
+ "#undef s\n" |
+ "#undef i\n" |
+ "#undef t\n" |
+ "/***************************************************************************\n" |
+ " * Execute functions pointed to by funcs until the null function is found. \n" |
+ "inline static void \n" |
+ "ExecFuncs( \n" |
+ " *fsm, int funcs, char *p )\n" |
+ " switch ( funcs ) {\n" |
+ "/****************************************\n" |
+ "Init\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ "/****************************************\n" |
+ "Accept\n" |
+ " * Did the fsm accept? \n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ "State *cs = fsm->curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " int c = (unsigned char)*p;\n" |
+ "Trans *trans;\n" |
+ " if ( cs == 0 )\n" |
+ " goto finished;\n" |
+ " /* If the character is within the index bounds then get the\n" |
+ " * transition for it. If it is out of the transition bounds\n" |
+ " * we will use the default transition. */\n" |
+ " if ( cs->lowIndex <= c && c < cs->highIndex ) {\n" |
+ " /* Use the index to look into the transition array. */\n" |
+ " trans = \n" |
+ "_t + \n" |
+ " ((\n" |
+ "*)cs->transIndex)[c - cs->lowIndex];\n" |
+ " else {\n" |
+ " /* Use the default index as the char is out of range. */\n" |
+ " trans = \n" |
+ "_t + cs->dflIndex;\n" |
+ " /* If there are functions for this transition then execute them. */\n" |
+ " if ( trans->funcs >= 0 )\n" |
+ "ExecFuncs( fsm, trans->funcs, p );\n" |
+ " /* Move to the new state. */\n" |
+ " cs = trans->toState;\n" |
+ "finished:\n" |
+ " fsm->curState = cs;\n" |
+ "/**********************************************************************\n" |
+ "Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ "State *cs = fsm->curState;\n" |
+ " if ( cs != 0 && cs->isFinState ) {\n" |
+ " /* If finishing in a final state then execute the\n" |
+ " * out functions for it. (if any). */\n" |
+ " if ( cs->outFuncs != 0 )\n" |
+ "ExecFuncs( fsm, cs->outFuncs, 0 );\n" |
+ " fsm->accept = 1;\n" |
+ " else {\n" |
+ " /* If we are not in a final state then this\n" |
+ " * is an error. Move to the error state. */\n" |
+ " fsm->curState = 0;\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Function and index type. */\n" |
+ " typedef int Func;\n" |
+ " /* Forward dec state for the transition structure. */\n" |
+ " struct State;\n" |
+ " /* A single transition. */\n" |
+ " struct Trans\n" |
+ " State *toState;\n" |
+ " int funcs;\n" |
+ " /* A single state. */\n" |
+ " struct State\n" |
+ " int lowIndex;\n" |
+ " int highIndex;\n" |
+ " void *transIndex;\n" |
+ " int dflIndex;\n" |
+ " int outFuncs;\n" |
+ " int isFinState;\n" |
+ " /* Constructor. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " State *curState;\n" |
+ " int accept;\n" |
+ " inline void ExecFuncs( int funcs, char *p );\n" |
+ "::State \n" |
+ "::Trans \n" |
+ "::State *\n" |
+ "/***************************************************************************\n" |
+ " * Execute functions pointed to by funcs until the null function is found. \n" |
+ "inline void \n" |
+ "::ExecFuncs( int funcs, char *p )\n" |
+ " switch ( funcs ) {\n" |
+ "/****************************************\n" |
+ " * Constructor\n" |
+ " Init();\n" |
+ "/****************************************\n" |
+ "::Init( )\n" |
+ " curState = \n" |
+ "_startState;\n" |
+ " accept = 0;\n" |
+ "/****************************************\n" |
+ " * Did the fsm accept? \n" |
+ "int \n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ "::Execute( char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ " State *cs = curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " int c = (unsigned char)*p;\n" |
+ " Trans *trans;\n" |
+ " if ( cs == 0 )\n" |
+ " goto finished;\n" |
+ " /* If the character is within the index bounds then get the\n" |
+ " * transition for it. If it is out of the transition bounds\n" |
+ " * we will use the default transition. */\n" |
+ " if ( cs->lowIndex <= c && c < cs->highIndex ) {\n" |
+ " /* Use the index to look into the transition array. */\n" |
+ " trans = \n" |
+ "_t + cs->dflIndex;\n" |
+ " /* If there are functions for this transition then execute them. */\n" |
+ " if ( trans->funcs != 0 )\n" |
+ " ExecFuncs( trans->funcs, p );\n" |
+ " /* Move to the new state. */\n" |
+ " cs = trans->toState;\n" |
+ "finished:\n" |
+ " curState = cs;\n" |
+ "/**********************************************************************\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ "::Finish( )\n" |
+ " State *cs = curState;\n" |
+ " if ( cs != 0 && cs->isFinState ) {\n" |
+ " /* If finishing in a final state then execute the\n" |
+ " * out functions for it. (if any). */\n" |
+ " if ( cs->outFuncs != 0 )\n" |
+ " ExecFuncs( cs->outFuncs, 0 );\n" |
+ " accept = 1;\n" |
+ " else {\n" |
+ " /* If we are not in a final state then this\n" |
+ " * is an error. Move to the error state. */\n" |
+ " curState = 0;\n" |
+ "11FTabCodeGen\n" |
+ "12CFTabCodeGen\n" |
+ "13CCFTabCodeGen\n" |
+ "bad_alloc\n" |
+ "cs = -1; \n" |
+ "cs = \n" |
+ "break;\n" |
+ " switch( cs ) {\n" |
+ " case \n" |
+ " switch ( c ) {\n" |
+ "case \n" |
+ "default: \n" |
+ " }\n" |
+ " break;\n" |
+ " switch( cs ) {\n" |
+ "accept = 1; \n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "/* The start state. */\n" |
+ "static int \n" |
+ "_startState = \n" |
+ "/****************************************\n" |
+ "Init\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ " int cs = fsm->curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " unsigned char c = (unsigned char)*p;\n" |
+ " fsm->curState = cs;\n" |
+ "/**********************************************************************\n" |
+ "Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " int cs = fsm->curState;\n" |
+ " int accept = 0;\n" |
+ " fsm->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ "/* Only non-static data: current state. */\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Init the fsm. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ " /* The start state. */\n" |
+ " static int startState;\n" |
+ "/* The start state. */\n" |
+ "int \n" |
+ "::startState = \n" |
+ " Init();\n" |
+ "/****************************************\n" |
+ "::Init\n" |
+ "void \n" |
+ "::Init( )\n" |
+ " curState = startState;\n" |
+ " accept = 0;\n" |
+ "::Execute( char *data, int dlen )\n" |
+ " char *p = data;\n" |
+ " int len = dlen;\n" |
+ " int cs = curState;\n" |
+ " for ( ; len > 0; p++, len-- ) {\n" |
+ " unsigned char c = (unsigned char)*p;\n" |
+ " curState = cs;\n" |
+ "/**********************************************************************\n" |
+ "::Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ "::Finish( )\n" |
+ " int cs = curState;\n" |
+ " int accept = 0;\n" |
+ " this->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "::Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "10SelCodeGen\n" |
+ "11CSelCodeGen\n" |
+ "12CCSelCodeGen\n" |
+ "10FsmCodeGen\n" |
+ "bad_alloc\n" |
+ "goto tr\n" |
+ "goto st\n" |
+ "goto err;\n" |
+ " case \n" |
+ "break;}\n" |
+ ": goto st\n" |
+ " case \n" |
+ " default: return;\n" |
+ " goto st\n" |
+ " if ( --len == 0 )\n" |
+ " goto out\n" |
+ " switch( (alph) *++p ) {\n" |
+ "case \n" |
+ " default: \n" |
+ " return;\n" |
+ "curState = \n" |
+ " switch( cs ) {\n" |
+ "accept = 1; \n" |
+ "break;\n" |
+ "err:\n" |
+ "curState = -1;\n" |
+ ", p );\n" |
+ "ExecFuncs( fsm, f+\n" |
+ "fsm->\n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "/* The start state. */\n" |
+ "static int \n" |
+ "_startState = \n" |
+ "#define f \n" |
+ "#define alph unsigned char\n" |
+ "/* The array of functions. */\n" |
+ "#if \n" |
+ "static int \n" |
+ "_f[] = {\n" |
+ "#endif\n" |
+ "/****************************************\n" |
+ "Init\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ "/***************************************************************************\n" |
+ " * Function exection. We do not inline this as in tab\n" |
+ " * code gen because if we did, we might as well just expand \n" |
+ " * the function as in the faster goto code generator.\n" |
+ "static void \n" |
+ "ExecFuncs( \n" |
+ " *fsm, int *funcs, char *p )\n" |
+ " int len = *funcs++;\n" |
+ " while ( len-- > 0 ) {\n" |
+ " switch ( *funcs++ ) {\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data - 1;\n" |
+ " register int len = dlen + 1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( \n" |
+ "curState ) {\n" |
+ "/**********************************************************************\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " int cs = fsm->curState;\n" |
+ " int accept = 0;\n" |
+ " fsm->accept = accept;\n" |
+ "/*******************************************************\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ "#undef f\n" |
+ "#undef alph\n" |
+ " ExecFuncs( f+\n" |
+ "/* Only non-static data: current state. */\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Init the fsm. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ " /* The start state. */\n" |
+ " static int startState;\n" |
+ " /* Function exection. We do not inline this as in tab code gen\n" |
+ " * because if we did, we might as well just expand the function \n" |
+ " * as in the faster goto code generator. */\n" |
+ " void ExecFuncs( int *funcs, char * );\n" |
+ "/* The start state. */\n" |
+ "int \n" |
+ "::startState = \n" |
+ "/* some defines to lessen the code size. */\n" |
+ "#define f \n" |
+ "#endif\n" |
+ "/****************************************\n" |
+ " * Make sure the fsm is initted.\n" |
+ " Init();\n" |
+ "/****************************************\n" |
+ " * Initialize the fsm.\n" |
+ "void \n" |
+ "::Init( )\n" |
+ " curState = startState;\n" |
+ " accept = 0;\n" |
+ "/***************************************************************************\n" |
+ " * Execute functions pointed to by funcs until the null function is found. \n" |
+ "void \n" |
+ "::ExecFuncs( int *funcs, char *p )\n" |
+ " int len = *funcs++;\n" |
+ " while ( len-- > 0 ) {\n" |
+ " switch ( *funcs++ ) {\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ "::Execute( char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data - 1;\n" |
+ " register int len = dlen + 1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( curState ) {\n" |
+ "/**********************************************************************\n" |
+ "::Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ "::Finish( )\n" |
+ " int cs = curState;\n" |
+ " int accept = 0;\n" |
+ " this->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "::Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "#undef f\n" |
+ "#undef alph\n" |
+ "11GotoCodeGen\n" |
+ "12CGotoCodeGen\n" |
+ "13CCGotoCodeGen\n" |
+ "10FsmCodeGen\n" |
+ "bad_alloc\n" |
+ " case \n" |
+ " break;\n" |
+ ", p );\n" |
+ "ExecFuncs( fsm, \n" |
+ "fsm->\n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "/* The start state. */\n" |
+ "static int \n" |
+ "_startState = \n" |
+ "/****************************************\n" |
+ "Init\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ "/***************************************************************************\n" |
+ " * Function exection. We do not inline this as in tab\n" |
+ " * code gen because if we did, we might as well just expand \n" |
+ " * the function as in the faster goto code generator.\n" |
+ "static void \n" |
+ "ExecFuncs( \n" |
+ " *fsm, int func, char *p )\n" |
+ " switch ( func ) {\n" |
+ "#define alph unsigned char\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data-1;\n" |
+ " register int len = dlen+1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( \n" |
+ "curState ) {\n" |
+ "/**********************************************************************\n" |
+ "Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " int cs = fsm->curState;\n" |
+ " int accept = 0;\n" |
+ " fsm->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ "#undef alph\n" |
+ " ExecFuncs( \n" |
+ "/* Only non-static data: current state. */\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Init the fsm. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ " /* The start state. */\n" |
+ " static int startState;\n" |
+ " /* Function exection. We do not inline this as in tab code gen\n" |
+ " * because if we did, we might as well just expand the function \n" |
+ " * as in the faster goto code generator. */\n" |
+ " void ExecFuncs( int func, char *p );\n" |
+ "/* The start state. */\n" |
+ "int \n" |
+ "::startState = \n" |
+ " Init();\n" |
+ "/****************************************\n" |
+ "::Init\n" |
+ "void \n" |
+ "::Init( )\n" |
+ " curState = startState;\n" |
+ " accept = 0;\n" |
+ "/***************************************************************************\n" |
+ " * Execute functions pointed to by funcs until the null function is found. \n" |
+ "void \n" |
+ "::ExecFuncs( int func, char *p )\n" |
+ " switch ( func ) {\n" |
+ "::Execute( char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data-1;\n" |
+ " register int len = dlen+1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( curState ) {\n" |
+ "::Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ "::Finish( )\n" |
+ " int cs = curState;\n" |
+ " int accept = 0;\n" |
+ " this->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "::Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "#undef alph\n" |
+ "12FGotoCodeGen\n" |
+ "13CFGotoCodeGen\n" |
+ "14CCFGotoCodeGen\n" |
+ "11GotoCodeGen\n" |
+ "10FsmCodeGen\n" |
+ "bad_alloc\n" |
+ "fsm->\n" |
+ "/* Only non-static data: current state. */\n" |
+ "struct \n" |
+ "Struct\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ "typedef struct \n" |
+ "Struct \n" |
+ "/* Init the fsm. */\n" |
+ "void \n" |
+ "Init( \n" |
+ " *fsm );\n" |
+ "/* Execute some chunk of data. */\n" |
+ "void \n" |
+ "Execute( \n" |
+ " *fsm, char *data, int dlen );\n" |
+ "/* Indicate to the fsm tha there is no more data. */\n" |
+ "void \n" |
+ "Finish( \n" |
+ " *fsm );\n" |
+ "/* Did the machine accept? */\n" |
+ "int \n" |
+ "Accept( \n" |
+ " *fsm );\n" |
+ "/* The start state. */\n" |
+ "static int \n" |
+ "_startState = \n" |
+ "/****************************************\n" |
+ "Init\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " fsm->curState = \n" |
+ "_startState;\n" |
+ " fsm->accept = 0;\n" |
+ "#define alph unsigned char\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ " *fsm, char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data-1;\n" |
+ " register int len = dlen+1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( \n" |
+ "curState ) {\n" |
+ "/**********************************************************************\n" |
+ "Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ " *fsm )\n" |
+ " int cs = fsm->curState;\n" |
+ " int accept = 0;\n" |
+ " fsm->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ " *fsm )\n" |
+ " return fsm->accept;\n" |
+ "#undef alph\n" |
+ "/* Only non-static data: current state. */\n" |
+ "class \n" |
+ "public:\n" |
+ " /* Init the fsm. */\n" |
+ " void Init( );\n" |
+ " /* Execute some chunk of data. */\n" |
+ " void Execute( char *data, int dlen );\n" |
+ " /* Indicate to the fsm tha there is no more data. */\n" |
+ " void Finish( );\n" |
+ " /* Did the machine accept? */\n" |
+ " int Accept( );\n" |
+ " int curState;\n" |
+ " int accept;\n" |
+ " /* The start state. */\n" |
+ " static int startState;\n" |
+ "/* The start state. */\n" |
+ "int \n" |
+ "::startState = \n" |
+ " Init();\n" |
+ "/****************************************\n" |
+ "::Init\n" |
+ "void \n" |
+ "::Init( )\n" |
+ " curState = startState;\n" |
+ " accept = 0;\n" |
+ "#define alph unsigned char\n" |
+ "/**********************************************************************\n" |
+ " * Execute the fsm on some chunk of data. \n" |
+ "void \n" |
+ "::Execute( char *data, int dlen )\n" |
+ " /* Prime these to one back to simulate entering the \n" |
+ " * machine on a transition. */ \n" |
+ " register char *p = data-1;\n" |
+ " register int len = dlen+1;\n" |
+ " /* Switch statment to enter the machine. */\n" |
+ " switch ( curState ) {\n" |
+ "::Finish\n" |
+ " * Indicate to the fsm that the input is done. Does cleanup tasks.\n" |
+ "void \n" |
+ "::Finish( )\n" |
+ " int cs = curState;\n" |
+ " int accept = 0;\n" |
+ " this->accept = accept;\n" |
+ "/*******************************************************\n" |
+ "::Accept\n" |
+ " * Did the machine accept?\n" |
+ "int \n" |
+ "::Accept( )\n" |
+ " return accept;\n" |
+ "#undef alph\n" |
+ "13IpGotoCodeGen\n" |
+ "14CIpGotoCodeGen\n" |
+ "15CCIpGotoCodeGen\n" |
+ "11GotoCodeGen\n" |
+ "10FsmCodeGen\n";
+}%%
+
+%% write data;
+struct strs the_fsm;
+
+void test( char *buf )
+{
+ struct strs *fsm = &the_fsm;
+ char *p = buf;
+ char *pe = buf + strlen( buf );
+
+ %% write init;
+ %% write exec;
+
+ if ( fsm->cs >= strs_first_final )
+ printf("ACCEPT\n");
+ else
+ printf("FAIL\n");
+}
+
+
+int main()
+{
+ test( "stdin\n" );
+ test( "bad_alloc\n" );
+ test( "_GLOBAL_OFFSET_TABLE_\n" );
+ test( "not in\n" );
+ test(
+ "isatty\n"
+ "junk on end.\n"
+ );
+
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+ACCEPT
+ACCEPT
+ACCEPT
+FAIL
+FAIL
+#endif
diff --git a/test/testcase.txl b/test/testcase.txl
new file mode 100644
index 0000000..65d7912
--- /dev/null
+++ b/test/testcase.txl
@@ -0,0 +1,192 @@
+comments
+ '#
+end comments
+
+tokens
+ union "\[[(\\\c)#\]]*\]"
+end tokens
+
+compounds
+ '%% '%%{ '}%% '== ':= '-> '<> '>= '<= '=>
+ '|* '*|
+ '>! '<! '$! '%! '@! '<>!
+ '>/ '</ '$/ '%/ '@/ '<>/
+end compounds
+
+keys
+ 'int 'bool 'true 'false 'char 'ptr
+ 'if 'else 'printi 'prints 'printb 'print_token
+ 'fc 'fpc 'fbreak 'fgoto 'fcall 'fret 'fhold 'fexec
+ 'machine 'alphtype 'action
+ 'first_token_char
+end keys
+
+define lang_indep
+ [al_statements]
+ '%% [NL]
+ [al_statements]
+ [ragel_def]
+end define
+
+define ragel_def
+ '%%{ [NL] [IN]
+ [ragel_program]
+ [EX] '}%% [NL]
+end define
+
+define ragel_program
+ [repeat statement]
+end define
+
+define statement
+ [machine_stmt]
+ | [alphtype_stmt]
+ | [action_stmt]
+ | [cond_action_stmt]
+ | [machine_def]
+ | [machine_inst]
+end define
+
+define machine_stmt
+ 'machine [id] '; [NL]
+end define
+
+define alphtype_stmt
+ 'alphtype [repeat id] '; [NL]
+end define
+
+define action_stmt
+ 'action [id] [al_host_block]
+end define
+
+define cond_action_stmt
+ 'action [id] '{ [al_expr] '} [NL]
+end define
+
+define al_statements
+ [repeat action_lang_stmt]
+end define
+
+define action_lang_stmt
+ [al_ragel_stmt]
+ | [al_variable_decl]
+ | [al_expr_stmt]
+ | [al_if_stmt]
+ | [al_print_stmt]
+ | '{ [al_statements] '}
+end define
+
+define al_print_stmt
+ [print_cmd] [al_expr] '; [NL]
+ | 'print_token '; [NL]
+end define
+
+define print_cmd
+ 'printi | 'prints | 'printb
+end define
+
+define al_variable_decl
+ [al_type_decl] [id] [opt union] '; [NL]
+end define
+
+define al_array_decl
+ '[ [number] ']
+end define
+
+define al_type_decl
+ 'int | 'bool | 'char | 'ptr
+end define
+
+define al_expr_stmt
+ [al_expr] '; [NL]
+end define
+
+define al_expr
+ [al_term] [repeat al_expr_extend]
+end define
+
+define al_expr_extend
+ [al_expr_op] [al_term]
+end define
+
+define al_expr_op
+ '= | '+ | '- | '* | '/ | '== | '<= | '>= | '< | '>
+end define
+
+define al_term
+ [al_term_base] [opt union]
+end define
+
+define al_term_base
+ [id]
+ | [SPOFF] [id] '( [SPON] [al_expr] ')
+ | [opt al_sign] [number]
+ | [stringlit]
+ | [charlit]
+ | 'fc
+ | 'true
+ | 'false
+ | '( [al_expr] ')
+ | '< [SPOFF] [al_type_decl] '> '( [SPON] [al_expr] ')
+ | 'first_token_char
+end define
+
+define al_sign
+ '- | '+
+end define
+
+define al_if_stmt
+ 'if '( [al_expr] ') [NL] [IN]
+ [action_lang_stmt] [EX]
+ [opt al_else]
+end define
+
+define al_else
+ 'else [NL] [IN]
+ [action_lang_stmt] [EX]
+end define
+
+define al_ragel_stmt
+ 'fbreak '; [NL]
+ | 'fhold '; [NL]
+ | 'fexec [repeat al_expr] '; [NL]
+ | 'fnext [id] '; [NL]
+ | 'fgoto [id] '; [NL]
+ | 'fcall [id] '; [NL]
+ | 'fnext '* [repeat al_expr] '; [NL]
+ | 'fgoto '* [repeat al_expr] '; [NL]
+ | 'fcall '* [repeat al_expr] '; [NL]
+ | 'fret '; [NL]
+end define
+
+define machine_def
+ [id] '= [machine_expr] '; [NL]
+end define
+
+define machine_inst
+ [id] ':= [machine_expr] '; [NL]
+end define
+
+define machine_expr
+ [repeat machine_expr_item]
+end define
+
+define scanner_item
+ [repeat machine_expr_item] '; [NL]
+end define
+
+define machine_expr_item
+ [action_embed] [al_host_block]
+ | '|* [repeat scanner_item] '*|
+ | [not ';] [not '*|] [token]
+end define
+
+define al_host_block
+ '{ [NL] [IN] [al_statements] [EX] '} [NL]
+end define
+
+define action_embed
+ '> | '$ | '@ | '% |
+ '$! | '=>
+end define
+
diff --git a/test/tokstart1.rl b/test/tokstart1.rl
new file mode 100644
index 0000000..e8c1552
--- /dev/null
+++ b/test/tokstart1.rl
@@ -0,0 +1,238 @@
+/*
+ * @LANG: c++
+ */
+
+#include <iostream>
+#include <string.h>
+using namespace std;
+
+extern char buf[];
+
+struct Scanner
+{
+ int cs, act;
+ char *ts, *te;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ int execute( char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine Scanner;
+
+ action to_act {
+ cout << "to: fc = ";
+ if ( fc == '\'' )
+ cout << (int)fc;
+ else
+ cout << fc;
+ cout << " ts = " << ( ts == 0 ? -1 : ts-buf ) << endl;
+ }
+ action from_act {
+ cout << "from: fc = ";
+ if ( fc == '\'' )
+ cout << (int)fc;
+ else
+ cout << fc;
+ cout << " ts = " << ( ts == 0 ? -1 : ts-buf ) << endl;
+ }
+
+ c_comm := ( any* $0 '*/' @1 @{ fgoto main; } ) $~to_act $*from_act;
+ cxx_comm := ( any* $0 '\n' @1 @{ fgoto main; } ) $~to_act $*from_act;
+
+ main := |*
+
+ # Single and double literals.
+ ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" ) $~ to_act $* from_act;
+ ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' ) $~ to_act $* from_act;
+
+ # Identifiers
+ ( [a-zA-Z_] [a-zA-Z0-9_]* ) $~ to_act $* from_act;
+
+ # Floating literals.
+ fract_const = digit* '.' digit+ | digit+ '.';
+ exponent = [eE] [+\-]? digit+;
+ float_suffix = [flFL];
+
+ ( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? ) $~ to_act $* from_act;
+
+ # Integer decimal. Leading part buffered by float.
+ ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} ) $~ to_act $* from_act;
+
+ # Integer octal. Leading part buffered by float.
+ ( '0' [0-9]+ [ulUL]{0,2} ) $~ to_act $* from_act;
+
+ # Integer hex. Leading 0 buffered by float.
+ ( '0x' [0-9a-fA-F]+ [ulUL]{0,2} ) $~ to_act $* from_act;
+
+ # Three char compounds, first item already buffered. */
+ ( '...' ) $~ to_act $* from_act;
+
+ # Single char symbols.
+ ( punct - [_"'] ) $~ to_act $* from_act;
+
+ # Comments and whitespace.
+ ( '/*' ) $~ to_act $* from_act { fgoto c_comm; };
+ ( '//' ) $~ to_act $* from_act { fgoto cxx_comm; };
+
+ ( any - 33..126 )+ $~ to_act $* from_act;
+
+ *|;
+}%%
+
+%% write data;
+
+void Scanner::init( )
+{
+ %% write init;
+}
+
+int Scanner::execute( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+
+ %% write exec;
+
+ return 0;
+}
+
+int Scanner::finish( )
+{
+ if ( cs == Scanner_error )
+ return -1;
+ if ( cs >= Scanner_first_final )
+ return 1;
+ return 0;
+}
+
+void test( )
+{
+ int len = strlen( buf );
+ Scanner scanner;
+
+ scanner.init();
+ scanner.execute( buf, len );
+ if ( scanner.cs == Scanner_error ) {
+ /* Machine failed before finding a token. */
+ cout << "PARSE ERROR" << endl;
+ }
+ scanner.finish();
+}
+
+char buf[4096];
+
+int main()
+{
+ strcpy( buf,
+ "a b 0.98 /*\n"
+ "9 */'\\''//hi\n"
+ "there\n"
+ );
+ test();
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+from: fc = a ts = 0
+to: fc = a ts = 0
+from: fc = ts = 0
+to: fc = a ts = -1
+from: fc = ts = 1
+to: fc = ts = 1
+from: fc = b ts = 1
+to: fc = ts = -1
+from: fc = b ts = 2
+to: fc = b ts = 2
+from: fc = ts = 2
+to: fc = b ts = -1
+from: fc = ts = 3
+to: fc = ts = 3
+from: fc = 0 ts = 3
+to: fc = ts = -1
+from: fc = 0 ts = 4
+to: fc = 0 ts = 4
+from: fc = . ts = 4
+to: fc = . ts = 4
+from: fc = 9 ts = 4
+to: fc = 9 ts = 4
+from: fc = 8 ts = 4
+to: fc = 8 ts = 4
+from: fc = ts = 4
+to: fc = 8 ts = -1
+from: fc = ts = 8
+to: fc = ts = 8
+from: fc = / ts = 8
+to: fc = ts = -1
+from: fc = / ts = 9
+to: fc = / ts = 9
+from: fc = * ts = 9
+to: fc = * ts = -1
+from: fc =
+ ts = -1
+to: fc =
+ ts = -1
+from: fc = 9 ts = -1
+to: fc = 9 ts = -1
+from: fc = ts = -1
+to: fc = ts = -1
+from: fc = * ts = -1
+to: fc = * ts = -1
+from: fc = / ts = -1
+to: fc = / ts = -1
+from: fc = 39 ts = 16
+to: fc = 39 ts = 16
+from: fc = \ ts = 16
+to: fc = \ ts = 16
+from: fc = 39 ts = 16
+to: fc = 39 ts = 16
+from: fc = 39 ts = 16
+to: fc = 39 ts = -1
+from: fc = / ts = 20
+to: fc = / ts = 20
+from: fc = / ts = 20
+to: fc = / ts = -1
+from: fc = h ts = -1
+to: fc = h ts = -1
+from: fc = i ts = -1
+to: fc = i ts = -1
+from: fc =
+ ts = -1
+to: fc =
+ ts = -1
+from: fc = t ts = 25
+to: fc = t ts = 25
+from: fc = h ts = 25
+to: fc = h ts = 25
+from: fc = e ts = 25
+to: fc = e ts = 25
+from: fc = r ts = 25
+to: fc = r ts = 25
+from: fc = e ts = 25
+to: fc = e ts = 25
+from: fc =
+ ts = 25
+to: fc = e ts = -1
+from: fc =
+ ts = 30
+to: fc =
+ ts = 30
+to: fc =
+ ts = -1
+#endif
diff --git a/test/union.rl b/test/union.rl
new file mode 100644
index 0000000..a3cc98f
--- /dev/null
+++ b/test/union.rl
@@ -0,0 +1,193 @@
+/*
+ * @LANG: c++
+ * Show off concurrent abilities.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+struct Concurrent
+{
+ int cur_char;
+ int start_word;
+ int start_comment;
+ int start_literal;
+
+ int cs;
+
+ // Initialize the machine. Invokes any init statement blocks. Returns 0
+ // if the machine begins in a non-accepting state and 1 if the machine
+ // begins in an accepting state.
+ void init( );
+
+ // Execute the machine on a block of data. Returns -1 if after processing
+ // the data, the machine is in the error state and can never accept, 0 if
+ // the machine is in a non-accepting state and 1 if the machine is in an
+ // accepting state.
+ void execute( const char *data, int len );
+
+ // Indicate that there is no more data. Returns -1 if the machine finishes
+ // in the error state and does not accept, 0 if the machine finishes
+ // in any other non-accepting state and 1 if the machine finishes in an
+ // accepting state.
+ int finish( );
+};
+
+%%{
+ machine Concurrent;
+
+ action next_char {
+ cur_char += 1;
+ }
+
+ action start_word {
+ start_word = cur_char;
+ }
+ action end_word {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+
+ action start_comment {
+ start_comment = cur_char;
+ }
+ action end_comment {
+ cout << "comment: " << start_comment <<
+ " " << cur_char-1 << endl;
+ }
+
+ action start_literal {
+ start_literal = cur_char;
+ }
+ action end_literal {
+ cout << "literal: " << start_literal <<
+ " " << cur_char-1 << endl;
+ }
+
+ # Count characters.
+ chars = ( any @next_char )*;
+
+ # Words are non-whitespace.
+ word = ( any-space )+ >start_word %end_word;
+ words = ( ( word | space ) $1 %0 )*;
+
+ # Finds C style comments.
+ comment = ( '/*' any* $0 '*/'@1 ) >start_comment %end_comment;
+ comments = ( ( comment | any ) $1 %0 )*;
+
+ # Finds single quoted strings.
+ literalChar = ( any - ['\\] ) | ( '\\' . any );
+ literal = ('\'' literalChar* '\'' ) >start_literal %end_literal;
+ literals = ( ( literal | (any-'\'') ) $1 %0 )*;
+
+ main := chars | words | comments | literals;
+}%%
+
+%% write data;
+
+void Concurrent::init( )
+{
+ cur_char = 0;
+ start_word = 0;
+ start_comment = 0;
+ start_literal = 0;
+ %% write init;
+}
+
+void Concurrent::execute( const char *data, int len )
+{
+ const char *p = data;
+ const char *pe = data + len;
+ const char *eof = pe;
+
+ %% write exec;
+}
+
+int Concurrent::finish( )
+{
+ if ( cs == Concurrent_error )
+ return -1;
+ if ( cs >= Concurrent_first_final )
+ return 1;
+ return 0;
+}
+
+void test( const char *buf )
+{
+ Concurrent concurrent;
+ concurrent.init();
+ concurrent.execute( buf, strlen(buf) );
+ if ( concurrent.finish() > 0 )
+ cout << "ACCEPT" << endl;
+ else
+ cout << "FAIL" << endl;
+}
+
+int main()
+{
+ test(
+ "/* in a comment,\n"
+ " * ' and now in a literal string\n"
+ " */ \n"
+ " \n"
+ "the comment has now ended but the literal string lives on\n"
+ "\n"
+ "' comment closed\n" );
+ test( "/* * ' \\' */ \\' '\n" );
+ test( "/**/'\\''/*/*/\n" );
+ return 0;
+}
+
+#ifdef _____OUTPUT_____
+word: 1 2
+word: 4 5
+word: 7 7
+word: 9 16
+word: 19 19
+word: 21 21
+word: 23 25
+word: 27 29
+word: 31 32
+word: 34 34
+word: 36 42
+word: 44 49
+word: 52 53
+comment: 1 53
+word: 58 60
+word: 62 68
+word: 70 72
+word: 74 76
+word: 78 82
+word: 84 86
+word: 88 90
+word: 92 98
+word: 100 105
+word: 107 111
+word: 113 114
+word: 117 117
+literal: 21 117
+word: 119 125
+word: 127 132
+ACCEPT
+word: 1 2
+word: 4 4
+word: 6 6
+word: 8 9
+word: 11 12
+comment: 1 12
+word: 14 15
+word: 17 17
+literal: 6 17
+ACCEPT
+comment: 1 4
+literal: 5 8
+word: 1 13
+comment: 9 13
+ACCEPT
+#endif
diff --git a/test/xml.rl b/test/xml.rl
new file mode 100644
index 0000000..3a76400
--- /dev/null
+++ b/test/xml.rl
@@ -0,0 +1,107 @@
+/*
+ * XML parser based on the XML 1.0 BNF from:
+ * http://www.jelks.nu/XML/xmlebnf.html
+ *
+ * @LANG: c++
+ * @ALLOW_MINFLAGS: -l -e
+ * @ALLOW_GENFLAGS: -T0 -T1
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace std;
+
+#define BUFSIZE 2048
+
+struct XML
+{
+ int cur_char;
+ int start_word;
+ int start_comment;
+ int start_literal;
+
+ int cs, top, stack[1024];
+
+ int init( );
+ int execute( const unsigned short *data, int len );
+ int finish( );
+};
+
+%%{
+ machine XML;
+ alphtype unsigned short;
+
+ action next_char {
+ cur_char += 1;
+ }
+
+ action start_word {
+ start_word = cur_char;
+ }
+ action end_word {
+ cout << "word: " << start_word <<
+ " " << cur_char-1 << endl;
+ }
+
+ Extender = 0x00B7 | 0x02D0 | 0x02D1 | 0x0387 | 0x0640 | 0x0E46 | 0x0EC6 | 0x3005 | (0x3031..0x3035) | (0x309D..0x309E) | (0x30FC..0x30FE);
+
+ Digit = (0x0030..0x0039) | (0x0660..0x0669) | (0x06F0..0x06F9) | (0x0966..0x096F) | (0x09E6..0x09EF) | (0x0A66..0x0A6F) | (0x0AE6..0x0AEF) | (0x0B66..0x0B6F) | (0x0BE7..0x0BEF) | (0x0C66..0x0C6F) | (0x0CE6..0x0CEF) | (0x0D66..0x0D6F) | (0x0E50..0x0E59) | (0x0ED0..0x0ED9) | (0x0F20..0x0F29);
+
+ CombiningChar = (0x0300..0x0345) | (0x0360..0x0361) | (0x0483..0x0486) | (0x0591..0x05A1) | (0x05A3..0x05B9) | (0x05BB..0x05BD) | 0x05BF | (0x05C1..0x05C2) | 0x05C4 | (0x064B..0x0652) | 0x0670 | (0x06D6..0x06DC) | (0x06DD..0x06DF) | (0x06E0..0x06E4) | (0x06E7..0x06E8) | (0x06EA..0x06ED) | (0x0901..0x0903) | 0x093C | (0x093E..0x094C) | 0x094D | (0x0951..0x0954) | (0x0962..0x0963) | (0x0981..0x0983) | 0x09BC | 0x09BE | 0x09BF | (0x09C0..0x09C4) | (0x09C7..0x09C8) | (0x09CB..0x09CD) | 0x09D7 | (0x09E2..0x09E3) | 0x0A02 | 0x0A3C | 0x0A3E | 0x0A3F | (0x0A40..0x0A42) | (0x0A47..0x0A48) | (0x0A4B..0x0A4D) | (0x0A70..0x0A71) | (0x0A81..0x0A83) | 0x0ABC | (0x0ABE..0x0AC5) | (0x0AC7..0x0AC9) | (0x0ACB..0x0ACD) | (0x0B01..0x0B03) | 0x0B3C | (0x0B3E..0x0B43) | (0x0B47..0x0B48) | (0x0B4B..0x0B4D) | (0x0B56..0x0B57) | (0x0B82..0x0B83) | (0x0BBE..0x0BC2) | (0x0BC6..0x0BC8) | (0x0BCA..0x0BCD) | 0x0BD7 | (0x0C01..0x0C03) | (0x0C3E..0x0C44) | (0x0C46..0x0C48) | (0x0C4A..0x0C4D) | (0x0C55..0x0C56) | (0x0C82..0x0C83) | (0x0CBE..0x0CC4) | (0x0CC6..0x0CC8) | (0x0CCA..0x0CCD) | (0x0CD5..0x0CD6) | (0x0D02..0x0D03) | (0x0D3E..0x0D43) | (0x0D46..0x0D48) | (0x0D4A..0x0D4D) | 0x0D57 | 0x0E31 | (0x0E34..0x0E3A) | (0x0E47..0x0E4E) | 0x0EB1 | (0x0EB4..0x0EB9) | (0x0EBB..0x0EBC) | (0x0EC8..0x0ECD) | (0x0F18..0x0F19) | 0x0F35 | 0x0F37 | 0x0F39 | 0x0F3E | 0x0F3F | (0x0F71..0x0F84) | (0x0F86..0x0F8B) | (0x0F90..0x0F95) | 0x0F97 | (0x0F99..0x0FAD) | (0x0FB1..0x0FB7) | 0x0FB9 | (0x20D0..0x20DC) | 0x20E1 | (0x302A..0x302F) | 0x3099 | 0x309A;
+
+ Ideographic = (0x4E00..0x9FA5) | 0x3007 | (0x3021..0x3029);
+
+ BaseChar = (0x0041..0x005A) | (0x0061..0x007A) | (0x00C0..0x00D6) | (0x00D8..0x00F6) | (0x00F8..0x00FF) | (0x0100..0x0131) | (0x0134..0x013E) | (0x0141..0x0148) | (0x014A..0x017E) | (0x0180..0x01C3) | (0x01CD..0x01F0) | (0x01F4..0x01F5) | (0x01FA..0x0217) | (0x0250..0x02A8) | (0x02BB..0x02C1) | 0x0386 | (0x0388..0x038A) | 0x038C | (0x038E..0x03A1) | (0x03A3..0x03CE) | (0x03D0..0x03D6) | 0x03DA | 0x03DC | 0x03DE | 0x03E0 | (0x03E2..0x03F3) | (0x0401..0x040C) | (0x040E..0x044F) | (0x0451..0x045C) | (0x045E..0x0481) | (0x0490..0x04C4) | (0x04C7..0x04C8) | (0x04CB..0x04CC) | (0x04D0..0x04EB) | (0x04EE..0x04F5) | (0x04F8..0x04F9) | (0x0531..0x0556) | 0x0559 | (0x0561..0x0586) | (0x05D0..0x05EA) | (0x05F0..0x05F2) | (0x0621..0x063A) | (0x0641..0x064A) | (0x0671..0x06B7) | (0x06BA..0x06BE) | (0x06C0..0x06CE) | (0x06D0..0x06D3) | 0x06D5 | (0x06E5..0x06E6) | (0x0905..0x0939) | 0x093D | (0x0958..0x0961) | (0x0985..0x098C) | (0x098F..0x0990) | (0x0993..0x09A8) | (0x09AA..0x09B0) | 0x09B2 | (0x09B6..0x09B9) | (0x09DC..0x09DD) | (0x09DF..0x09E1) | (0x09F0..0x09F1) | (0x0A05..0x0A0A) | (0x0A0F..0x0A10) | (0x0A13..0x0A28) | (0x0A2A..0x0A30) | (0x0A32..0x0A33) | (0x0A35..0x0A36) | (0x0A38..0x0A39) | (0x0A59..0x0A5C) | 0x0A5E | (0x0A72..0x0A74) | (0x0A85..0x0A8B) | 0x0A8D | (0x0A8F..0x0A91) | (0x0A93..0x0AA8) | (0x0AAA..0x0AB0) | (0x0AB2..0x0AB3) | (0x0AB5..0x0AB9) | 0x0ABD | 0x0AE0 | (0x0B05..0x0B0C) | (0x0B0F..0x0B10) | (0x0B13..0x0B28) | (0x0B2A..0x0B30) | (0x0B32..0x0B33) | (0x0B36..0x0B39) | 0x0B3D | (0x0B5C..0x0B5D) | (0x0B5F..0x0B61) | (0x0B85..0x0B8A) | (0x0B8E..0x0B90) | (0x0B92..0x0B95) | (0x0B99..0x0B9A) | 0x0B9C | (0x0B9E..0x0B9F) | (0x0BA3..0x0BA4) | (0x0BA8..0x0BAA) | (0x0BAE..0x0BB5) | (0x0BB7..0x0BB9) | (0x0C05..0x0C0C) | (0x0C0E..0x0C10) | (0x0C12..0x0C28) | (0x0C2A..0x0C33) | (0x0C35..0x0C39) | (0x0C60..0x0C61) | (0x0C85..0x0C8C) | (0x0C8E..0x0C90) | (0x0C92..0x0CA8) | (0x0CAA..0x0CB3) | (0x0CB5..0x0CB9) | 0x0CDE | (0x0CE0..0x0CE1) | (0x0D05..0x0D0C) | (0x0D0E..0x0D10) | (0x0D12..0x0D28) | (0x0D2A..0x0D39) | (0x0D60..0x0D61) | (0x0E01..0x0E2E) | 0x0E30 | (0x0E32..0x0E33) | (0x0E40..0x0E45) | (0x0E81..0x0E82) | 0x0E84 | (0x0E87..0x0E88) | 0x0E8A | 0x0E8D | (0x0E94..0x0E97) | (0x0E99..0x0E9F) | (0x0EA1..0x0EA3) | 0x0EA5 | 0x0EA7 | (0x0EAA..0x0EAB) | (0x0EAD..0x0EAE) | 0x0EB0 | (0x0EB2..0x0EB3) | 0x0EBD | (0x0EC0..0x0EC4) | (0x0F40..0x0F47) | (0x0F49..0x0F69) | (0x10A0..0x10C5) | (0x10D0..0x10F6) | 0x1100 | (0x1102..0x1103) | (0x1105..0x1107) | 0x1109 | (0x110B..0x110C) | (0x110E..0x1112) | 0x113C | 0x113E | 0x1140 | 0x114C | 0x114E | 0x1150 | (0x1154..0x1155) | 0x1159 | (0x115F..0x1161) | 0x1163 | 0x1165 | 0x1167 | 0x1169 | (0x116D..0x116E) | (0x1172..0x1173) | 0x1175 | 0x119E | 0x11A8 | 0x11AB | (0x11AE..0x11AF) | (0x11B7..0x11B8) | 0x11BA | (0x11BC..0x11C2) | 0x11EB | 0x11F0 | 0x11F9 | (0x1E00..0x1E9B) | (0x1EA0..0x1EF9) | (0x1F00..0x1F15) | (0x1F18..0x1F1D) | (0x1F20..0x1F45) | (0x1F48..0x1F4D) | (0x1F50..0x1F57) | 0x1F59 | 0x1F5B | 0x1F5D | (0x1F5F..0x1F7D) | (0x1F80..0x1FB4) | (0x1FB6..0x1FBC) | 0x1FBE | (0x1FC2..0x1FC4) | (0x1FC6..0x1FCC) | (0x1FD0..0x1FD3) | (0x1FD6..0x1FDB) | (0x1FE0..0x1FEC) | (0x1FF2..0x1FF4) | (0x1FF6..0x1FFC) | 0x2126 | (0x212A..0x212B) | 0x212E | (0x2180..0x2182) | (0x3041..0x3094) | (0x30A1..0x30FA) | (0x3105..0x312C) | (0xAC00..0xD7A3);
+
+ # Full Unicode 3.1 requires: Char = 0x9 | 0xA | 0xD | (0x20..0xD7FF) | (0xE000..0xFFFD) | (0x10000..0x10FFFF);
+
+ Char = 0x9 | 0xA | 0xD | (0x20..0xD7FF) | (0xE000..0xFFFD);
+
+ Letter = BaseChar | Ideographic;
+
+ NameChar = Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender;
+
+ include CommonXml "xmlcommon.rl";
+
+}%%
+
+ %% write data;
+
+ int XML::init( )
+ {
+ %% write init;
+ cur_char = 0;
+ return 1;
+ }
+
+ int XML::execute( const unsigned short *data, int len )
+ {
+ const unsigned short *p = data;
+ const unsigned short *pe = data + len;
+
+ %% write exec;
+
+ if ( cs == XML_error )
+ return -1;
+ if ( cs >= XML_first_final )
+ return 1;
+ return 0;
+ }
+
+ int XML::finish( )
+ {
+ if ( cs == XML_error )
+ return -1;
+ if ( cs >= XML_first_final )
+ return 1;
+ return 0;
+ }
+
+ int main()
+ {
+ return 0;
+ }
+/* _____OUTPUT_____
+_____OUTPUT_____ */
diff --git a/test/xmlcommon.rl b/test/xmlcommon.rl
new file mode 100644
index 0000000..e7a855e
--- /dev/null
+++ b/test/xmlcommon.rl
@@ -0,0 +1,205 @@
+/*
+ * This file is included by xml.rl
+ *
+ * @IGNORE: yes
+ */
+
+%%{
+
+ #
+ # Common XML grammar rules based on the XML 1.0 BNF from:
+ # http://www.jelks.nu/XML/xmlebnf.html
+ #
+
+ machine CommonXml;
+
+ S = (0x20 | 0x9 | 0xD | 0xA)+;
+
+ # WAS PubidChar = 0x20 | 0xD | 0xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%];
+ PubidChar = 0x20 | 0xD | 0xA | [a-zA-Z0-9] | [\-'()+,./:=?;!*#@$_%];
+
+ PubidLiteral = '"' PubidChar* '"' | "'" (PubidChar - "'")* "'";
+
+ Name = (Letter | '_' | ':') (NameChar)*;
+
+ Comment = '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->';
+
+ # Used strong subtraction operator, and replaced * with +. Ragel complained since using
+ # * results in a machine that accepts 0 length strings, and later it's only used in an
+ # optional construct anyway.
+ #
+ CharData_Old = [^<&]* - ([^<&]* ']]>' [^<&]*);
+ CharData = [^<&]+ -- ']]>';
+
+ SystemLiteral = ('"' [^"]* '"') | ("'" [^']* "'");
+
+ Eq = S? '=' S?;
+
+ VersionNum = ([a-zA-Z0-9_.:] | '-')+;
+
+ # WAS S 'version' Eq (' VersionNum ' | " VersionNum ") - fixed quotes
+ VersionInfo = S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"');
+
+ ExternalID = 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral;
+
+ PublicID = 'PUBLIC' S PubidLiteral;
+
+ NotationDecl = '<!NOTATION' S Name S (ExternalID | PublicID) S? '>';
+
+ EncName = [A-Za-z] ([A-Za-z0-9._] | '-')*;
+
+ EncodingDecl = S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" );
+
+ # UNUSED TextDecl = '<?xml' VersionInfo? EncodingDecl S? '?>';
+
+ NDataDecl = S 'NDATA' S Name;
+
+ PEReference = '%' Name ';';
+
+ EntityRef = '&' Name ';';
+
+ CharRef = '&#' [0-9]+ ';' | '&0x' [0-9a-fA-F]+ ';';
+
+ Reference = EntityRef | CharRef;
+
+ EntityValue = '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'";
+
+ PEDef = EntityValue | ExternalID;
+
+ EntityDef = EntityValue | (ExternalID NDataDecl?);
+
+ PEDecl = '<!ENTITY' S '%' S Name S PEDef S? '>';
+
+ GEDecl = '<!ENTITY' S Name S EntityDef S? '>';
+
+ EntityDecl = GEDecl | PEDecl;
+
+ Mixed = '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')';
+
+ # WAS cp = (Name | choice | seq) ('?' | '*' | '+')?;
+
+ # WAS seq = '(' S? cp ( S? ',' S? cp )* S? ')';
+
+ # WAS choice = '(' S? cp ( S? '|' S? cp )* S? ')';
+
+ # WAS children = (choice | seq) ('?' | '*' | '+')?;
+
+ # TODO put validation for this in and make it clearer
+ alt = '?' | '*' | '+';
+ children = '(' S?
+ ( ( Name alt? ) |
+ '(' |
+ ( ')' alt? ) |
+ [,|] |
+ S )
+ ')' alt?;
+
+ contentspec = 'EMPTY' | 'ANY' | Mixed | children;
+
+ elementdecl = '<!ELEMENT' S Name S contentspec S? '>';
+
+ AttValue = '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'";
+
+ Attribute = Name Eq AttValue;
+
+ Nmtoken = (NameChar)+;
+
+ # UNUSED Nmtokens = Nmtoken (S Nmtoken)*;
+
+ Enumeration = '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')';
+
+ NotationType = 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')';
+
+ EnumeratedType = NotationType | Enumeration;
+
+ TokenizedType = 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS';
+
+ StringType = 'CDATA';
+
+ AttType = StringType | TokenizedType | EnumeratedType;
+
+ DefaultDecl = '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue);
+
+ AttDef = S Name S AttType S DefaultDecl;
+
+ AttlistDecl = '<!ATTLIST' S Name AttDef* S? '>';
+
+ EmptyElemTag = '<' Name (S Attribute)* S? '/>';
+
+ ETag = '</' Name S? '>';
+
+ PITarget_Old = Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'));
+ PITarget = Name -- "xml"i;
+
+ PI = '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>';
+
+ markupdecl = elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment;
+
+ doctypedecl = '<!DOCTYPE' S Name (S ExternalID)? S? ('[' (markupdecl | PEReference | S)* ']' S?)? '>';
+
+ # TODO extSubsetDecl = ( markupdecl | conditionalSect | PEReference | S )*;
+ # UNUSED extSubsetDecl = ( markupdecl | PEReference | S )*;
+
+ # UNUSED extSubset = TextDecl? extSubsetDecl;
+
+ # UNUSED Ignore = Char* - (Char* ('<![' | ']]>') Char*);
+
+ # TODO: ignoreSectContents = Ignore ('<![' ignoreSectContents ']]>' Ignore)*;
+ # UNUSED ignoreSectContents = Ignore ('<![' ']]>' Ignore)*;
+
+ # UNUSED ignoreSect = '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>';
+
+ # UNUSED includeSect = '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>';
+
+ # UNUSED conditionalSect = includeSect | ignoreSect;
+
+ STag = '<' Name (S Attribute)* S? '>';
+
+ CDStart = '<![CDATA[';
+
+ CDEnd = ']]>';
+
+ # WAS CData = (Char* - (Char* ']]>' Char*));
+ CData = (Char* -- CDEnd);
+
+ CDSect = CDStart CData CDEnd;
+
+ # UNUSED Subcode = ([a-z] | [A-Z])+;
+
+ # UNUSED UserCode = ('x' | 'X') '-' ([a-z] | [A-Z])+;
+
+ # UNUSED IanaCode = ('i' | 'I') '-' ([a-z] | [A-Z])+;
+
+ # UNUSED ISO639Code = ([a-z] | [A-Z]) ([a-z] | [A-Z]);
+
+ # UNUSED Langcode = ISO639Code | IanaCode | UserCode;
+
+ # UNUSED LanguageID = Langcode ('-' Subcode)*;
+
+ SDDecl = S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'));
+
+ # UNUSED extPE = TextDecl? extSubsetDecl;
+
+ Misc = Comment | PI | S;
+
+ XMLDecl = '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>';
+
+ prolog = XMLDecl? Misc* (doctypedecl Misc*)?;
+
+ # UNUSED Names = Name (S Name)*;
+
+ # Added fcall - TODO check logic is correct
+ # UNUSED extParsedEnt = TextDecl? @{fcall content;};
+
+ # TODO tag stack validation
+
+ # WAS element = EmptyElemTag | STag content ETag
+ # WAS content = (element | CharData | Reference | CDSect | PI | Comment)*;
+ content = (EmptyElemTag | STag | ETag | CharData | Reference | CDSect | PI | Comment)*;
+
+ # WAS document = prolog element Misc*;
+ document = prolog ( EmptyElemTag | ( STag content ETag ) ) Misc*;
+
+ main := document;
+
+}%%