delta-2006.08.03/0000755000175000017500000000000010464463515011367 5ustar dswdswdelta-2006.08.03/topformflat.lex0000755000175000017500000000647410311650445014443 0ustar dswdsw/* topformflat.l; see License.txt for copyright and terms of use * * Scott McPeak * * flatten all toplevel forms to single lines. * very heuristic... */ %{ #include // atoi // emit yytext as-is void emit(); // debugging diagnostic, emitted when enabled void diag(char const *str); // add a newline if nesting <= threshold void possibleNewline(); // keep track of brace nesting (0 means not inside any pair) int nesting = 0; // nesting threshold; when nesting is greater than threshold, // newlines are suppressed int threshold = 0; %} /* don't try to call yywrap() */ %option noyywrap /* dsw: don't define yyunput() */ %option nounput /* start condition for strings */ %x STRING %x CHARLIT %% ";" { emit(); possibleNewline(); } "/\n" { if (nesting <= threshold) { /* end of C comment */ emit(); } else { printf("%c", yytext[0]); } } "{" { nesting++; emit(); possibleNewline(); // so the header is separated from the components } "}"(";"?) { nesting--; emit(); possibleNewline(); } /* a hash, then some non-newlines. then, possibly, an escaped * newline followed by more non-newlines (repeat as needed). * finally, a newline */ "#".*("\\\n".*)*"\n" { printf("\n"); /* make sure starts on own line */ emit(); /* preprocessor */ } "\n" { printf(" "); } /* not any above case, eat it*/ "//".*"\n" { emit(); } /* C++ comment */ "\"" { diag(""); emit(); BEGIN(STRING); } /* start quote */ { "\\"(.|\n) { emit(); } /* escaped character */ "\"" { emit(); diag(""); BEGIN(INITIAL); } /* close quote */ (.|\n) { emit(); } /* ordinary char */ } "\'" { diag(""); emit(); BEGIN(CHARLIT); } /* start tick */ { "\\"(.|\n) { emit(); } /* escaped character */ "\'" { emit(); diag(""); BEGIN(INITIAL); } /* close tick */ (.|\n) { emit(); } /* ordinary char */ } . { emit(); } %% void emit() { printf("%.*s", yyleng, yytext); } void diag(char const *str) { //printf("%s", str); } void possibleNewline() { if (nesting <= threshold) { printf("\n"); } } char *version = "2003.7.14"; int main(int argc, char *argv[]) { if (isatty(0)) { printf("topformflat version %s\n", version); printf("usage: %s [threshold] output.c\n", argv[0]); printf(" The threshold (default: 0) specifies at what nesting level\n" " of braces will line breaks be allowed (or inserted). By\n" " starting with 0, you get all top-level forms, one per line\n" " (roughly). Increasing the threshold leads to finer-grained\n" " structure on each line. The intent is to use the delta\n" " minimizer on each level of granularity.\n"); return 0; } if (argc >= 2) { threshold = atoi(argv[1]); // user-specified threshold } yyin = stdin; yylex(); return 0; } delta-2006.08.03/License.txt0000755000175000017500000000305010311650445013502 0ustar dswdswLicense.txt Copyright (c) 2002-2005, Regents of the University of California All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the University of California, Berkeley nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. delta-2006.08.03/multidelta0000755000175000017500000001036510464463725013471 0ustar dswdsw#!/usr/bin/perl -w # multidelta; see License.txt for copyright and terms of use # **************** # driver for delta, which works with multiple input files # Scott McPeak smcpeak@cs.berkeley.edu # the goal here is to be able to minimize in-place: given # a fragment of a build process which exhibits some failure, # minimize the relevant files without disturbing the build # process fragment itself use strict 'subs'; use FindBin; $delta = "$FindBin::Bin/delta"; $topformflat = "$FindBin::Bin/topformflat"; $log = "multidelta.log"; $level = 0; $undo = 0; $cpp = 0; # bool: use the cpp preprocessor? if (@ARGV == 0) { print(<<"EOF"); Multidelta version 2003.7.14 usage: $0 [options] test-script file [file [...]] The collection of input files is minimized as much as possible, such that the test-script continues to return true. When the script is run with a source file as an argument, it should do any single-file integrity checks on that file. Then, it should proceed to check the entire build, on the assumption that all other files have already passed their integrity checks. When the script is run with no arguments, it should check integrity of all files and then check the build. So that the script does not need to have the list of input files hard-coded in, the environment variable "multidelta_all_files" is always set to a space-separated list of the filenames no matter how the script is run. Options: -level=n When topformflattening, flatten to level n [$level]. -u Undo the last invocation, by copying the *.bak files onto the original copies. -cpp Before flattening run through the cpp preprocessor. EOF exit(0); } die "$topformflat doesn't exit or isn't executable. Did you run 'make'?\n" unless (-x $topformflat); while ($ARGV[0] =~ m"^-") { if ($ARGV[0] =~ m"^-level=") { ($level) = ($ARGV[0] =~ m"=(\d+)"); } elsif ($ARGV[0] eq "-u") { $undo = 1; } elsif ($ARGV[0] eq "-cpp") { $cpp = 1; } else { die ("unknown option: $ARGV[0]\n"); } shift(@ARGV); } $script = $ARGV[0]; shift(@ARGV); @files = @ARGV; for my $f(@files) { die "Input file contains a space '$f'\n" if $f=~/ /; # multidelta_all_files won't work if filenames contain spaces. } # So the script knows all the files even if it is called in a mode # where not all of them are passed in. $ENV{"multidelta_all_files"} = join(" ", @files); if ($undo) { # copy the .bak files back for $fn (@files) { diagnostic("reverting to backup copy of $fn"); run("cp -f ${fn}.bak $fn"); } exit(0); } diagnostic("verify the script passes now"); if (simpleRun($script) != 0) { die "Initial test fails\n"; } # for every input file, make a backup copy, and produce # another version with all comments and preprocessor # directives stripped, and toplevel forms flattened for $fn (@files) { diagnostic("making a backup copy of $fn"); run("cp -f $fn ${fn}.bak"); if ($cpp) { diagnostic("preprocessing and flattening $fn"); # -P: don't emit #line directives run("cpp -P ${fn}.bak | $topformflat $level >$fn"); } else { diagnostic("flattening $fn"); run("$topformflat $level <${fn}.bak >$fn"); } } diagnostic("verify still passes script"); if (simpleRun($script) != 0) { $actions = "topformflat"; if ($cpp) { $actions = "cpp and " . $actions; } die "Test fails after $actions\n"; } # one by one, apply delta for $fn (@files) { diagnostic("applying delta to $fn"); run("$delta -in_place -test=$script $fn"); if (-f "DELTA-STOP") { diagnostic("Stopping because DELTA-STOP exists"); exit 1; } } print("multidelta is finished\n"); exit(0); # -------------------- subroutines -------------------- sub diagnostic { print(@_, "\n"); open (LOG, ">>$log"); print LOG (@_, "\n"); close (LOG); } sub simpleRun { my $ret = system(@_); # from perldoc -f system my $signal = $ret & 127; my $exitValue = $ret >> 8; if ($signal) { die "$0 exiting due to signal $signal\n"; } return $exitValue; } sub run { diagnostic(@_); my $exitValue = simpleRun(@_); if ($exitValue) { die "stopping because delta exited with exit value $exitValue: " . join(' ', @_) . "\n"; } } delta-2006.08.03/www/0000755000175000017500000000000010464463514012212 5ustar dswdswdelta-2006.08.03/www/using_delta.html0000755000175000017500000002573310456315042015404 0ustar dswdsw Minimizing Interesting Files with Delta

Minimizing Interesting Files with Delta

Daniel S. Wilkerson

Delta assists you in minimizing "interesting" files, subject to a test of their interestingness. A common such situation is when attempting to isolate a small failure-inducing substring of a large input that causes your program to demonstrate a bug. Our implementation is based on the algorithm found here: http://www.st.cs.uni-sb.de/dd/

Three tools are provided: delta, multidelta, and topformflat. Delta is the script which does the minimizing. Topformflat is a utility flattens languages with balanced delimiters, such as most common programming languages, so that all nesting below a specified depth is one one line. Multidelta is a wrapper that runs delta for you but on multiple files using delta and topformflat underneath to change nesting granularity before it is fed into delta. Its UI is arguably probably more what you actually want, since for example it allows you to run on multiple input files.

Delta

Delta is an implementation of the delta debugging algorithm: http://www.st.cs.uni-sb.de/dd/. In short, you supply delta with

  1. a test shell script which decides if its input file is "interesting" and
  2. an initial interesting input file.

Delta uses heuristics to find a sub-file of your input file that is still "interesting" according to your test.

Usually "interesting" means a file causing a particular error as input to a program. For debugging or bug-reporting purposes you would like to find the smallest such file. An appropriate test here would run the program on the file and grep for the error message, returning success (0) if found, and failure (non-zero) otherwise.

Note that we use C programs as example input because delta was developed for debugging language tools like compilers, so often the input was some C program and it was interesting if it crashed _our_ program, a compiler.

An example

Here is a rather contrived example minimizing a C input file. In this case "interesting" means that the file compiles and when run returns false. This example is in delta/test/delta0.

The input file (below "in.c"):

#include 
int main(int argc, char **argv) {
    int a = 0;
    printf("Hello, World!\n");
    a++;
    a--;
    a+=2;
    a++;
    a--;
    a++;
    return a >= 3;} // Brace here prevents main from lacking a return.

The script test that decides interestingness. It is probably best if your test produces no output, so putting a &>/dev/null at the end of your grep, as I have here, is recommended.

Note that delta passes the name of the file to your script, so you can use it, as I have here; however when testing multiple files, perhaps it is best to use the Multidelta style and just hard-code in the filenames. Multidelta minimizes in-place, which makes passing in the name unnecessary.

The test script (below "testit"):

#!/bin/sh
# -*-sh-*-
if gcc $1 &> cmp_out; then
    if ! ./a.out &> run_out; then
        exit 0;                 # Success.
    fi
fi
exit 1;                         # Failure.

Put both of these files into a new directory and make your test executable, and run as follows:

delta -test=testit -quiet -cp_minimal=min.c < in.c

When delta returns, you will notice a file "min.c" in the directory which is smaller than "in.c" and yet still passes the interestingness test.

You will also notice a tmp* directory (tmp0 if it is the first run) that contains all the files that were found to be interesting during the search. Delta runs quickly on this small example, but for longer runs you might want to tail -f tmp0/log in another window to watch the interesting events of the progression of the search. If you remove the -quiet flag, you will get a very detailed transcript to standard out of the search process, probably more than you want to know, but fun to watch.

There are other features and modes to delta. Below is the usage message which you can get by typing: delta -help . (Usage messages reproduced here omit the initial header line and distribution version number.)

    usage: bin/delta [options] start-file

    -test=       Specify the test script
    -suffix=         Candidate filename suffix [.c]
    -dump_input              Dump input after reading
    -cp_minimal=   Copy the minimal successful test to the
                             current directory
    -granularity=line        Use lines as the granularity (default)
    -granularity=top_form    Use C top-level forms as the granularity
                             (currently only works with CIL output)
    -log=              Log file for main events
    -quiet                   Say nothing
    -verbose                 Get more verbose output
    -in_place                Overwrite start-file with inputs

    -help                    Get help

    The test program accepts a single argument, the name of the candidate
    file to test.  It is run within a directory containing only that file,
    and it can make temporary files/directories in that directory.  It
    should return zero for a candidate that exhibits the desired property,
    and nonzero for one that does not.

    Example test program (delta will retain a line containing "foo"):
      #!/bin/sh
      grep 'foo' <"$1" >/dev/null

Granularity

Delta has a notion of the granularity of the file: the smallest atomic elements of which the file is seen as a sequence. The default is the line granularity: in this mode, delta will attempt to delete entire lines, but will never try deleting a smaller element than that. You can filter a program through topformflat to produce a file where the line-granularity only goes to a specified nesting depth (if your file is in a nested language). Multidelta does this for you.

In general, use semantic granularity appropriate to the input language. Delta has a much easier time searching the space if the atomic chunks in the granularity match up with semantically-atomic chunks in your input language. That is, if you are minimizing C files, start with the C top-level form granularity. Only after that minimize with a finer level of granularity. This allows delta to try removing entire function definitions, rather than removing single lines which is much less likely to produce a meaningful, and therefore interesting, C file. If you have some other kind of file, you should probably write the equivalent of topformflat for it. If your hack is general and reusable, please send it to us.

1-minimality

An "interesting" sequence is 1-minimal iff it does not remain interesting if any one element is removed. Delta is guaranteed to find a 1-minimal file from your input file, where it is considered a sequence of elements at the granularity you specified.

Note that the space of interesting files is usually quite complex, and delta is doing only a rather simple local walk through it. Therefore it is easy for delta to get stuck someplace that is locally 1-minimal, but globally non-minimum. One often therefore gets better results if delta is run again on its output, with gradually finer granularity, if that is an option.

Topformflat

Topformflat is a filter written by Scott McPeak that will print its input with the line granularity matching a specified nesting depth. It is useful for making the granularity of an input file start of very coarse for the first runs of delta and then gradually increasing it. Multidelta will run topformflat for you with a given nesting depth if you ask for it on the command line. Here is the usage message which you can get by typing: topformflat .

usage: bin/topformflat [threshold] output.c
  The threshold (default: 0) specifies at what nesting level
  of braces will line breaks be allowed (or inserted).  By
  starting with 0, you get all top-level forms, one per line
  (roughly).  Increasing the threshold leads to finer-grained
  structure on each line.  The intent is to use the delta
  minimizer on each level of granularity.

Multidelta

Multidelta was written as a wrapper for delta by Scott McPeak. It allows you to easily minimize collections of files by minimizing each one individually for you using delta underneath. It also automatically pre-process the input with the C pre-processor (cpp) and then filters it through topformflat for you before running delta. (Thus, it is rather oriented towards C programs as input.) Below is the usage message which you can get by typing: multidelta .

usage: bin/multidelta [options] test-script file [file [...]]

The collection of input files is minimized as much as possible, such that the test-script continues to return true.

When the script is run with a source file as an argument, it should do any single-file integrity checks on that file. Then, it should proceed to check the entire build, on the assumption that all other files have already passed their integrity checks.

When the script is run with no arguments, it should check integrity of all files and then check the build.

So that the script does not need to have the list of input files hard-coded in, the environment variable "multidelta_all_files" is always set to a space-separated list of the filenames no matter how the script is run.

Options:
  -level=n       When topformflattening, flatten to level n [$level].
  -u             Undo the last invocation, by copying the *.bak files
                   onto the original copies.
  -cpp           Before flattening run through the cpp preprocessor.

Stopping

A new feature of delta and multidelta is that it is possible to stop it!

Delta now both distinguishes between a signal and a non-zero result code from the tests script, halting altogether in the case of a signal. Multidelta has always stopped if delta returns anything other than zero and still does. The consequence of this is that you can just type control-C at the terminal and everything should stop immediately. However, not sure what state the partially minimized file will be left in; for a safe way to stop, see the next paragraph. Thanks to Scott McPeak for pointing out how easy this was to do.

Delta has always stopped if a file DELTA-STOP appears in the current directory, however for some unexplained reason, I only checked for this when it increased the granularity of the search. Now it checks at every run of the external script. If DELTA-STOP comes into existence, delta and multidelta should stop before obliterating the current version of the file to be tested.

Notes

At some point probably delta should be made into a Perl module that could be used by any Perl program and any remaining desirable features of its UI that have not yet been subsumed by multidelta should be; But it works for now.

Yes, I wrote a script to re-run delta lots of times, but it seems that people prefer to do that manually. delta-2006.08.03/www/index.html0000644000175000017500000002445710456316300014212 0ustar dswdsw Delta

Maintainer: Daniel S. Wilkerson
Developer: Scott McPeak
Documenter: Simon Goldsmith

Summary

Delta assists you in minimizing "interesting" files subject to a test of their interestingness. A common such situation is when attempting to isolate a small failure-inducing substring of a large input that causes your program to exhibit a bug.

Our implementation is based on the Delta Debugging algorithm. Andreas wrote a book "Why Programs Fail" about debugging programs.

This work was supported by professors Alex Aiken and George Necula and was done at UC Berkeley.

I presented Delta at CodeCon 2006. The slides are here.

Releases

Feel free to just get the current Subversion repository version as a guest user.

  • delta-2006.07.15.tar.gz   md5: 57afa6d4e7d15f380803e878c24678ed This is the current recommended release.
  • delta-2005.09.13.tar.gz   md5: 588d65056ea48ae2a2ecee32598c5837 This version had a bug that it was too hard to stop delta once it started.
  • The first release of Delta was on 14 July 2003. It is now retired.

Introduction

The best way to understand how to use delta is with an example of its usage. Below is one example helpfully written up for me by Simon Goldsmith; read it first. For those wanting more, I also wrote a more detailed and harder to read document describing each tool: Using Delta.

Note that what follows is an example of using delta to minimize an input file to a program that reads programs, much as a compiler does. Note two features of file minimization that are present in the example.

Do a controlled experiment.

Below we don't just minimize a file that causes Oink to produce an error message, we minimize a file that causes gcc to accept AND oink to reject in a specific way. That is, the test delta does is a controlled experiment, where gcc is the control. Ignoring this aspect of the problem seems to be a frequent mistake of first time users.

Exploit nested structure.

One may minimize files of simpler syntax than C++ but really all files are interesting in the first place because they are in some language or another. Some simple configuration files are literally just a list of lines but most languages have some nested structure. Multidelta filters the input through the topformflat utility (included) to suppress any newlines past a particular nesting depth; this "explains" the nesting structure to the otherwise line-oriented delta utility (a brilliantly simple idea of Scott McPeak's). If your input file language has no nesting structure, you can hack on multidelta to remove the filtration through topformflat or just use the raw delta program. If your language has a different nesting structure than C/C++, you can write your own multidelta and substitute it. A simple flex program should suffice; it need not be terribly accurate for delta to do well.

Example use of delta

Simon Goldsmith 8 April / 12 Sept, 2005.

Note that this example is edited for simplicity from the raw output; we sincerely hope we did not introduce any bugs.

Setup

(1) Make a new directory and copy the file to be minimized there.

% mkdir deltaexample
% cd deltaexample/
% cp ../nsCSSDataBlock-23801-1112390043.cpp.g.ii ./foo.ii
% chmod +w foo.ii

(2) (optional) Put a read-only backup copy of the file in, say, orig/ .

% mkdir orig
% cp foo.ii orig/
% chmod -R a-w orig

Define interestingness

(3) Write a script (do not call it 'test' as that is a system utility program) to test the interestingness of the file, as we do below.

Note that for this example, "interesting" means the file passes gcc but fails oink with a particular error message. That is, if 1) gcc accepts, and 2) oink rejects with the desired error message, then we return zero (meaning "interesting"). If anything else happens then we return a nonzero exit code (meaning "not interesting")

Some reminders about shell: a zero exit code means "true"; so for the purposes of &&, a zero exit code means "keep going" and grep returns 0 if it matches, nonzero if not. We redirect output to /dev/null because the output of delta is noisy. Be careful of quoting hell: notice that we've used '.' to match characters like single quote.

% cat > test1.sh
#!/bin/bash

FILE=foo.ii
OINK=/home/simon/oink_all/oink/oink
GCC=/usr/bin/gcc

$GCC -c $FILE -o /dev/null &> /dev/null && $OINK $FILE | \
  grep 'error: cannot convert argument type .class .* const &. ' \
  'to receiver parameter type' \
  &> /dev/null
^D

(4) Make the script executable and run it on the file -- make sure it returns 0. Optionally turn off the redirection to /dev/null temporarily to check the error message that is being found by the grep.

% chmod +x test1.sh
% ./test1.sh foo.ii ; echo $?
0

Minimize automatically

(5) Run multidelta with the script on the file several times at, say, levels 0 0 1 1 2 2 10.

% multidelta -level=0 ./test1.sh foo.ii
(check email)
% multidelta -level=0 ./test1.sh foo.ii
(read slashdot)
% multidelta -level=1 ./test1.sh foo.ii
% multidelta -level=1 ./test1.sh foo.ii
% multidelta -level=2 ./test1.sh foo.ii
% multidelta -level=2 ./test1.sh foo.ii
% multidelta -level=10 ./test1.sh foo.ii
% multidelta -level=10 ./test1.sh foo.ii

(6) The input file will be modified in place and you should be left with something smaller.

[simon@otter][deltaexample]$ ls -l
total 116
-rw-r--r--  1 simon simon  8451 Sep 12 17:10 foo.ii
-rw-r--r--  1 simon simon  8948 Sep 12 17:10 foo.ii.bak
-rw-r--r--  1 simon simon  8451 Sep 12 17:10 foo.ii.ok
-rw-r--r--  1 simon simon 57739 Sep 12 17:10 log
-rw-r--r--  1 simon simon  2752 Sep 12 17:10 multidelta.log
dr-xr-xr-x  2 simon simon  4096 Sep 12 17:16 orig/
-rwxr-xr-x  1 simon simon   385 Sep 12 16:36 test1.sh*
-rw-r--r--  1 simon simon    11 Sep 12 16:02 test1.sh~

[simon@otter][deltaexample]$ ls -l orig/
total 552
-r--r--r--  1 simon simon 558970 Sep 12 16:00 foo.ii

Minimize further by hand

(7) Hack on foo.ii by hand, re-running test1.sh each time to check it is still "interesting". Sometimes it helps to hack on foo.ii a little to get delta unstuck and then rerun delta again. You might want to run indent as well whenever you stop to look at foo.ii as topformflat makes a mess.

Final file:

class A {};
int main() {
  const A *val;
  val->~A ();
}

Note that the original file was about 560 KB!

Endorsements

This section is just for fun because I've never had a tool so widely used before.

Subject: Thanks for Delta
   Date: Thu, 21 Jul 2005 21:13:20 -0700
   From: Flash Sheridan
     To: Daniel S. Wilkerson

This is just a quick thank-you note for Delta.  Andrew Pinski pointed
me towards it after filing a GCC bug with a very long source file; it
immediately reduced a different bug file from 16K lines to ten (GCC
bug 22604).  Oddly enough, it initially found a different bug (22603),
since I'd only specified "internal compiler error", not "segmentation
fault".  I might not have been able to file either of these bugs
without Delta, since the code was proprietary, but the two
Delta-reduced files were small enough to make public.


Subject: Re: Thanks for Delta Date: Tue, 13 Sep 2005 10:56:10 -0700 From: Flash Sheridan To: Daniel S. Wilkerson Delta has become even more valuable since my initial thank-you note. I'm not sure it's helped with all of the GCC bugs I've been filing (I've been tracking them at http://pobox.com/~flash/FlashsOpenSourceBugReports.html), but I couldn't have filed most of them without Delta. Typically I find a bug when GCC is compiling a large, confidential file, which I couldn't post to Bugzilla. Delta has always been able to find a radically smaller file, which I have been able to attach to my bug report.
Date: Sun, 23 Oct 2005 22:01:42 +0200 (CEST) From: Richard Guenther To: Daniel S. Wilkerson > > > Thanks for your interest in Delta. I would be interested to > > > hear more about what you are doing with it. If it is something > > > I can put in the endoresements section ("Delta saved my > > > daugher's life!") that would be great. > > > > Well, delta is saving a lot of gcc developers life ;) I would > > guess 1 of 3 bugs sumitted to the gcc bugzilla get their testcase > > reduced using delta. > > Holy moly! Can I quote that publicly such as on my web page? Yes - a little bit more accurate would be to say we're using delta to reduce all testcases from the gcc bugzilla in case they get entered unreduced.

Delta (both the algorithm and this tool) has been used in the Cal Berkeley (CS169) and Stanford (CS295) in software engineering classes.

Subject: Re: delta debugging on instructional machines?
   Date: Mon, 24 Oct 2005 22:55:08 -0700
   From: Gilad Arnold 
     To: Daniel S. Wilkerson

We've just assigned a delta-related homework to the students today,
. . .  We do hope that we can actually convince the students to use
delta in the course of their project development, but time will
tell. And thanks again!


Subject: Re: use of delta in your class Date: Mon, 24 Oct 2005 13:57:22 -0700 From: Alex Aiken To: Daniel S. Wilkerson Yes, I gave them a homework assignment for CS295 using delta. Feedback was positive but unquantified.

 

delta-2006.08.03/test1_multidelta/0000755000175000017500000000000010464463514014652 5ustar dswdswdelta-2006.08.03/test1_multidelta/file1.end.txt0000755000175000017500000000000610311650445017147 0ustar dswdsw foo; delta-2006.08.03/test1_multidelta/file2.end.txt0000755000175000017500000000000610311650445017150 0ustar dswdsw bar; delta-2006.08.03/test1_multidelta/trivtest0000755000175000017500000000067610456315042016466 0ustar dswdsw#!/bin/sh # see delta/License.txt for copyright and terms of use # The test script for this test of multidelta. # Demonstrate the difference between the multidelta_all_files # environment variable and the arugment list. echo echo "multidelta_all_files:$multidelta_all_files:" echo "argument list:$@:" exec >/dev/null 2>&1 set -e # file 1 should have "foo" grep "foo" file1.txt || exit # file 2 should have "bar" grep "bar" file2.txt || exit delta-2006.08.03/test1_multidelta/file1.start.txt0000755000175000017500000000005010311650445017535 0ustar dswdsw// file1.txt zebra; foo; giraffe; cow; delta-2006.08.03/test1_multidelta/file2.start.txt0000755000175000017500000000007710311650445017547 0ustar dswdsw// file2.txt zebddwqra; ; giraffe; bar; something {}; delta-2006.08.03/test1_multidelta/testit0000755000175000017500000000103510456315042016104 0ustar dswdsw#!/bin/bash # see delta/License.txt for copyright and terms of use # test multidelta set -e set -x # reset state cp file1.start.txt file1.txt cp file2.start.txt file2.txt # run multidelta ../multidelta -cpp -level=3 ./trivtest file1.txt file2.txt # compare to expected output diff file1.end.txt file1.txt diff file2.end.txt file2.txt # check that -u works ../multidelta -cpp -u ./trivtest file1.txt file2.txt # compare to original input diff file1.start.txt file1.txt diff file2.start.txt file2.txt # dsw: Tell the user. echo "PASS" delta-2006.08.03/test1_multidelta/Makefile0000755000175000017500000000024210456315042016304 0ustar dswdsw# see delta/License.txt for copyright and terms of use # test and clean multidelta check: ./testit clean: rm -f *.ok *.bak file[12].txt log *.log DELTA-STOP delta-2006.08.03/test0_delta/0000755000175000017500000000000010464463515013577 5ustar dswdswdelta-2006.08.03/test0_delta/hello.test0000755000175000017500000000027510311650445015601 0ustar dswdsw#!/bin/bash # -*-sh-*- if gcc -o a.out $1 &> cmp_out; then if ! ./a.out &> run_out; then exit 0; # Success. fi fi exit 1; # Failure. delta-2006.08.03/test0_delta/hello.c0000755000175000017500000000046010311650445015040 0ustar dswdsw// We are trying to find the minimum version of this program that // compiles but returns false. #include int main(int argc, char **argv) { int a = 0; printf("Hello, World!\n"); a++; a--; a+=2; a++; a--; a++; return a >= 3;} // Prevents main becoming empty. delta-2006.08.03/test0_delta/Makefile0000755000175000017500000000123010456315042015226 0ustar dswdsw# see delta/License.txt for copyright and terms of use DELTA_BASE := .. DELTA := $(DELTA_BASE)/delta DELTA_FLAGS += -test=$(TEST) DELTA_FLAGS += -quiet #DELTA_FLAGS += -verbose DELTA_FLAGS += -cp_minimal=$(MINIMAL) MINIMAL := minimal_test.c TEST := hello.test .SUFFIXES: .PHONY: check check: clean $(DELTA) $(DELTA_FLAGS) < hello.c @if diff -u $(MINIMAL) minimal_test.c.correct; then \ echo "PASS"; \ else \ echo "**************** FAIL ****************"; \ false; \ fi .PHONY: clean clean:; rm -f core a.out minimal_test.c hello DELTA-STOP *.o rm -rf tmp* # Build hello to see it run and check its return value. hello: hello.c gcc $^ -o $@ delta-2006.08.03/test0_delta/minimal_test.c.correct0000755000175000017500000000017110311650445020061 0ustar dswdswint main(int argc, char **argv) { int a = 0; a+=2; a++; return a >= 3;} // Prevents main becoming empty. delta-2006.08.03/Test.mk0000755000175000017500000000037510464463725012652 0ustar dswdsw# see License.txt for copyright and terms of use DIRS := test0_delta test1_multidelta test2_multidelta .SUFFIXES: .PHONY: check clean check: for D in $(DIRS); do $(MAKE) -C $$D $@ || exit 1; done clean: for D in $(DIRS); do $(MAKE) -C $$D $@; done delta-2006.08.03/Build.mk0000755000175000017500000000065510311650445012757 0ustar dswdsw# see License.txt for copyright and terms of use CC := gcc CFLAGS := -Wall # CFLAGS += -g FLEX := flex .SUFFIXES: .PHONY: all clean distbuild distclean # **** for distribution client use all: topformflat topformflat: %: %.c $(CC) $(CFLAGS) -o $@ $< clean: rm -f topformflat # **** for building the distribution distbuild: topformflat.c distclean: clean rm -f topformflat.c topformflat.c: %.c: %.lex $(FLEX) -o$@ $< delta-2006.08.03/test2_multidelta/0000755000175000017500000000000010464463515014654 5ustar dswdswdelta-2006.08.03/test2_multidelta/file1.end.txt0000755000175000017500000000000610464463725017164 0ustar dswdsw foo; delta-2006.08.03/test2_multidelta/trivtest0000755000175000017500000000067610464463725016502 0ustar dswdsw#!/bin/sh # see delta/License.txt for copyright and terms of use # The test script for this test of multidelta. # Demonstrate the difference between the multidelta_all_files # environment variable and the arugment list. echo echo "multidelta_all_files:$multidelta_all_files:" echo "argument list:$@:" exec >/dev/null 2>&1 set -e # file 1 should have "foo" grep "foo" file1.txt || exit # file 2 should have "bar" grep "bar" file2.txt || exit delta-2006.08.03/test2_multidelta/file2.end.txt0000755000175000017500000000000610464463725017165 0ustar dswdsw bar; delta-2006.08.03/test2_multidelta/file1.start.txt0000755000175000017500000000003210464463725017552 0ustar dswdswzebra; foo; giraffe; cow; delta-2006.08.03/test2_multidelta/file2.start.txt0000755000175000017500000000006110464463725017555 0ustar dswdswzebddwqra; ; giraffe; bar; something {}; delta-2006.08.03/test2_multidelta/testit0000755000175000017500000000102310464463725016115 0ustar dswdsw#!/bin/bash # see delta/License.txt for copyright and terms of use # test multidelta set -e set -x # reset state cp file1.start.txt file1.txt cp file2.start.txt file2.txt # run multidelta ../multidelta -level=3 ./trivtest file1.txt file2.txt # compare to expected output diff file1.end.txt file1.txt diff file2.end.txt file2.txt # check that -u works ../multidelta -u ./trivtest file1.txt file2.txt # compare to original input diff file1.start.txt file1.txt diff file2.start.txt file2.txt # dsw: Tell the user. echo "PASS" delta-2006.08.03/test2_multidelta/Makefile0000755000175000017500000000024210464463725016320 0ustar dswdsw# see delta/License.txt for copyright and terms of use # test and clean multidelta check: ./testit clean: rm -f *.ok *.bak file[12].txt log *.log DELTA-STOP delta-2006.08.03/delta0000755000175000017500000004060310456315042012401 0ustar dswdsw#!/usr/bin/perl -w # delta; see License.txt for copyright and terms of use use strict; # **************** # Implementation of the delta debugging algorithm: # http://www.st.cs.uni-sb.de/dd/ # Daniel S. Wilkerson dsw@cs.berkeley.edu # Notes: # The test script should not depend on the current directory to work. # Note that 1-minimality does not imply idempotency, so we could # re-run once it is stuck, perhaps with some randomization. # Global State **************** my @chunks = (); # Once input, is read only. my @markers = (); # Delimits a dynamic subsequence of @chunks being considered. my %test_cache = (); # Cached test results. # Mark boundaries that uniquely determine the marked contents. This # is used as a shorter key to hash on than the contents themselves. # Since Perl hashes retain their keys if you don't do this you get a # horrible memory leak in the test_cache. my $mark_signature; # End of the last marker rendered to the tmp file. Used to figure out # if the next one abuts it or not. my $last_mark_stop; my @current_markers; # Markers to be rendered to $tmpinput if answer not in cache. my $tmpinput; # Temporary file to render marked subsequence to. my $last_successful_tmpinput; # Last one to past the test. my $tmp_index = 0; # Cache the last index used to make a tmp file. my $tmpdir_index = 0; # Cache the last index used to make a tmp directory. my $tmpdir; # Temporary directory for external programs. my $logfile = "log"; # File in $tmpdir where log of successful runs is written. chomp (my $this_dir = `pwd`); # The current directory. my $starttime = time; # The time we started. my $granularity = "line"; # What is the size of an input chunk? my $dump_input = 0; # Dump out the input after reading it in. my $cp_minimal; # Copy the minimal successful test to the current dir. my $verbose = 0; # Be more verbose. my $quiet = 0; # Prints go to /dev/null. my $suffix = ".c"; # For now, our input files are .c files. my $test; # The script to run as the test. # when true, all operations on input file are in-place: # - don't make a new directory # - overwrite the original input file with our constructed inputs my $in_place = 0; my $start_file; # name of input/output file for in_place my $help_message = <<"END" Delta version 2003.7.14 delta implements the delta-debugging algorithm: http://www.st.cs.uni-sb.de/dd/ Implemented by Daniel Wilkerson. usage: $0 [options] start-file -test= Specify the test script. -suffix= Candidate filename suffix [$suffix] -dump_input Dump input after reading -cp_minimal= Copy the minimal successful test to the current directory -granularity=line Use lines as the granularity (default) -granularity=top_form Use C top-level forms as the granularity (currently only works with CIL output) -log= Log file for main events -quiet Say nothing -verbose Get more verbose output -in_place Overwrite start-file with inputs -help Get help The test program accepts a single argument, the name of the candidate file to test. It is run within a directory containing only that file, and it can make temporary files/directories in that directory. It should return zero for a candidate that exhibits the desired property, and nonzero for one that does not. Example test program (delta will retain a line containing "foo"): #!/bin/sh grep 'foo' <"\$1" >/dev/null END ; # Functions **************** sub output(@) { print @_ unless $quiet; } # Return true if the current_markers pass the interesting test. sub test { if (-f "DELTA-STOP") { output "Stopping because DELTA-STOP file exists\n"; exit 1; } my $cached_result = $test_cache{$mark_signature}; if (defined $cached_result) { output "\tcached\n"; return $cached_result; } render_tmpinput(); my $ret; my $input; if (!$in_place) { output " $tmpinput"; my $arena = "$tmpdir/arena"; die if system "rm -rf $arena/*"; # sm: added -r so I can make directories in the arena $input = "$tmpdir/$tmpinput"; my $arena_input = "input$suffix"; link $input, "$arena/$arena_input"; # $test gets fully qualified in parse_command_line() $ret = system "cd $arena; $test $arena_input"; } else { # for in_place, the test program is free to ignore the argument # (since it will be known ahead of time) but I'll pass it anyway $ret = system "$test $start_file"; $input = $start_file; } # from perldoc -f system my $signal = $ret & 127; my $exitValue = $ret >> 8; if ($signal) { die "$0 exiting due to signal $signal\n"; } my $result = ! $exitValue; # Keep around info only for successful runs. if ($result) { my $size = (split " ", `wc -l $input`)[0]; output "\tSUCCESS, lines: $size ****************\n"; log_msg_time("$tmpinput, lines: $size"); if (!$in_place) { $last_successful_tmpinput = $tmpinput; } else { # make a single copy of the latest successful file $last_successful_tmpinput = "${start_file}.ok"; die "cp failed" if system("cp ${start_file} $last_successful_tmpinput"); } } else { output "\n"; unlink $input unless $in_place; } return $test_cache{$mark_signature} = $result; } # given @current_markers, create a new file by writing the proper # subset of @chunks to a file; yield its name in $tmpinput sub render_tmpinput { if ($in_place) { # I can't just say $tmpinput = $start_file and be done with it, # because in many places $tmpdir/ is prefixed (and I don't want # to say $tmpdir="." because I want $start_file to possibly be # an absolute path. open TMPINPUT, ">$start_file" or die $!; $tmpinput = $start_file; } else { $tmpinput = unused_tempfile(); open TMPINPUT, ">${tmpdir}/$tmpinput" or die $!; } foreach my $marker (@current_markers) { for (my $i=$marker->{start}; $i<$marker->{stop}; ++$i) { print TMPINPUT $chunks[$i]; } } close TMPINPUT or die $!; # NOTE: Leave $tmpinput defined. } sub start_marking { @current_markers = (); $mark_signature = ""; undef $last_mark_stop; } sub mark { my ($marker) = @_; push @current_markers, $marker; if (defined $last_mark_stop) { if ($last_mark_stop < $marker->{start}) { $mark_signature .= $last_mark_stop . "]"; $mark_signature .= "[" . $marker->{start} . ","; } elsif ($last_mark_stop == $marker->{start}) { # This marker abuts the previous one. } else {die} } else { $mark_signature .= "[" . $marker->{start} . ","; } $last_mark_stop = $marker->{stop}; } sub stop_marking { $mark_signature .= $last_mark_stop . "]" if defined $last_mark_stop; output $mark_signature; } sub unused_tempfile { die unless defined $tmpdir; my $filename; do { $filename = sprintf("%03d", $tmp_index) . $suffix; $tmp_index++; } while -e "${tmpdir}/$filename"; return $filename; } sub unused_tempdir { my $dirname; for (; $dirname = "tmp${tmpdir_index}", -e $dirname; ++$tmpdir_index) {} return $dirname; } sub select_tmpdir { $tmpdir = unused_tempdir() unless defined $tmpdir; die if -e $tmpdir; mkdir $tmpdir, 0777 or die $!; mkdir "${tmpdir}/arena", 0777 or die $!; } sub parse_command_line { my $str; my @non_flags = (); while(defined ($str = shift @ARGV)) { if ($str=~/^-([^=]+)(=(.+))?/) { my ($flag, $argument) = ($1, $3); if ($flag eq "help") { output $help_message; exit 0; } elsif ($flag eq "dump_input") { $dump_input++; } elsif ($flag eq "verbose") { $verbose++; } elsif ($flag eq "quiet") { $quiet++; } elsif ($flag eq "granularity") { if ($argument eq "line" || $argument eq "top_form") { $granularity = $argument; } } elsif ($flag eq "cp_minimal") { $cp_minimal = $argument; } elsif ($flag eq "test") { $test = $argument; } elsif ($flag eq "suffix") { $suffix = $argument; } elsif ($flag eq "log") { $logfile = $argument; } elsif ($flag eq "in_place") { $in_place = 1; } else {die "Illegal flag: $flag \n"} } else {push @non_flags, $str;} } # Cleaning up. die "You specified both verbose and quiet." if $verbose && $quiet; push @ARGV, @non_flags; # fully qualify $test if it's not already die "You must specify a test script.\n" unless defined $test; if ($test !~ m"^/") { $test = "$this_dir/$test"; } # sm: I like a usage string when I give no arguments but it doesn't # make sense to read interactively (stdin is a tty) if ((@ARGV == 0) && (-t STDIN)) { output $help_message; exit(0); } if ($in_place) { if (@ARGV != 1) { die "Must give exactly one explicit input file for -in_place." } $start_file = $ARGV[0]; } } sub render_settings { my $out = "delta settings:\n"; if (!$in_place) { $out .= "\ttemporary directory: $tmpdir\n"; } $out .= "\tgranularity: $granularity\n"; my $input_str; if (scalar @ARGV > 0) { $input_str = join " ", @ARGV; } else { $input_str = ""; } $out .= "\tinput: $input_str\n"; return $out; } sub read_input_chunks { if ($granularity eq "line") { while (<>) {push @chunks, $_;} # Read one line at a time. } elsif ($granularity eq "top_form") { # Read chunks of C top-level forms. I assume that any line # starting with '//# ' followed by a line that does not start # with a whitespace is a good boundary for a top-level form. # I'm sure you could do this in one line with the proper # setting to the regex that is the line seperator. my $chunk = ""; my $a = <>; while (<>) { if ($a=~m|^//\# | and $_=~m|^\S|) { push @chunks, $chunk; $chunk = $a; } else { $chunk .= $a; } $a = $_; } $chunk .= $a; push @chunks, $chunk; } else {die "Illegal granularity setting: $granularity\n"} } sub dump_input { output "Dumping input ****************\n"; if ($granularity eq "line") { foreach my $chunk (@chunks) {output $chunk;} } elsif ($granularity eq "top_form") { foreach my $chunk (@chunks) {output "\t-----\n", $chunk} } else {die "Illegal granularity setting: $granularity\n"} output "****************\n"; } sub check_initial_input { die "The input must consist of at least one chunk." unless @chunks; start_marking(); mark($markers[0]); stop_marking(); die "\n\t**************** FAIL: The initial input does not pass the test.\n\n" unless test(); } sub dump_markers { my $i = 0; foreach my $marker (@markers) { output "\t$i [", $marker->{start}, ", ", $marker->{stop}, "]\n"; ++$i; } } sub increase_granularity { output "\nIncrease granularity\n"; output "Before "; dump_markers(); my @newmarkers = (); my $split_one = 0; foreach my $marker (@markers) { my $half = int (($marker->{start} + $marker->{stop}) / 2); if ($half == $marker->{start} or $half == $marker->{stop}) { push @newmarkers, $marker; } else { ++$split_one; push @newmarkers, {start=>$marker->{start}, stop=>$half}; push @newmarkers, {start=>$half, stop=>$marker->{stop}}; } } @markers = @newmarkers; output "After "; dump_markers(); output "\n"; return $split_one; } sub dhms_from_seconds { my ($total_seconds) = @_; my $sec = $total_seconds % 60; my $total_minutes = ($total_seconds - $sec) / 60; die unless $total_minutes == (int $total_minutes); my $min = $total_minutes % 60; my $total_hours = ($total_minutes - $min) / 60; die unless $total_hours == (int $total_hours); my $hours = $total_hours % 24; my $days = ($total_hours - $hours) / 24; die unless $days == (int $days); return ($days, $hours, $min, $sec); } sub timestamp { my $now = time; # Get a timestamp in seconds. my $elapsed = $now - $starttime; # Make relative to start time. my ($d,$h,$m,$s) = dhms_from_seconds($elapsed); # Convert to more familiar format. my $elapsed_dhms = sprintf("%02d:%02d:%02d", $h, $m, $s); # Format. if ($d > 0) { my $day_str = "$d day"; $day_str .= "s" if $d > 1; $day_str .= ", "; $elapsed_dhms = $day_str . $elapsed_dhms; } my $timestr = scalar localtime($now); # Format as abolute. return sprintf("%d sec/%s\t%s", $elapsed, $elapsed_dhms, $timestr); } sub log_msg { my ($message) = @_; open LOG, ">>${logfile}" or die $!; print LOG $message, "\n"; close LOG or die $!; } sub log_msg_time { my ($message) = @_; log_msg(sprintf("%-39s %s", $message, timestamp())); } sub done { output "Could not increase granularity; we are done.\n"; output "A log of successful runs is in ${logfile}\n"; if (defined $cp_minimal) { output "Copying minimal run to $cp_minimal\n"; die "cp failed" if system "cp ${tmpdir}/${last_successful_tmpinput} $cp_minimal"; } if ($in_place) { die "cp failed" if system("cp $last_successful_tmpinput $start_file"); } log_msg_time("delta done"); exit 0; } # Main **************** parse_command_line(); select_tmpdir() unless $in_place; if (!$in_place) { $logfile = "${tmpdir}/$logfile" if $logfile!~m|^/|; # Make absolute. } my $settings = render_settings(); log_msg($settings); if ($verbose) { output "\nDelta debugging algorithm, implemented by Daniel S. Wilkerson.\n"; output $settings, "\n"; } log_msg_time("delta start"); read_input_chunks(); dump_input() if $dump_input; $markers[0] = {start=>0, stop=>(scalar @chunks)}; # Initialize one marker. check_initial_input(); # This is a vital step! Don't omit it! big_loop: { # NOTE: this paragraph is part of the strict delta algorithm, but # it is not actually necessary, so by default I implement # something that is a little different from the published # algorithm. Un-comment this paragraph to have the algorithm # strictly as published. # Test the single markers. # foreach my $test_marker (@markers) { # start_marking(); # mark($test_marker); # stop_marking(); # if (test()) { # @markers = ($test_marker); # Get rid of all markers but this one. # if (increase_granularity()) {redo big_loop;} # else {done()} # } # } # Test the complements to single markers. complement_loop: { my %excluded = (); # Try them in reverse. In both the above "positive" loop and # this "negative" loop, the things you are throwing away start # at the end of the data, thus the two strategies are # consistent. foreach my $excluded_marker (reverse @markers) { start_marking(); foreach my $marker (@markers) { next if $marker eq $excluded_marker; next if $excluded{$marker}; mark($marker); } stop_marking(); if (test()) { die "Can't happen" if $excluded{$excluded_marker}; $excluded{$excluded_marker}++; } } # If any were excluded, record this fact into @markers. my @excluded_keys = keys %excluded; if (@excluded_keys) { @markers = grep {!$excluded{$_}} @markers; redo complement_loop; # Retry at the same granularity. } } # None of them worked, increase the granularity. if (increase_granularity()) {redo big_loop;} else {done()} } delta-2006.08.03/Makefile0000755000175000017500000000104010464463725013030 0ustar dswdsw# see License.txt for copyright and terms of use REPOSITORY := http://delta.tigris.org/svn/delta/trunk VERSION := 2006.08.03 DIR := delta-$(VERSION) .SUFFIXES: .PHONY: all check clean dist distclean all: $(MAKE) -f Build.mk all check: $(MAKE) -f Test.mk check clean: $(MAKE) -f Build.mk clean $(MAKE) -f Test.mk clean dist: svn export $(REPOSITORY) $(DIR) $(MAKE) -C $(DIR) -f Build.mk distbuild tar cvzf $(DIR).tar.gz $(DIR) chmod 444 $(DIR).tar.gz distclean: clean rm -rf $(DIR) rm -f *.tar.gz $(MAKE) -f Build.mk distclean delta-2006.08.03/Readme0000755000175000017500000000336310311650445012506 0ustar dswdswsee License.txt for copyright and terms of use The Readme for the Delta Interesting File Minimizer version 2003.7.14 **** Authors and maintainers Daniel S. Wilkerson Scott McPeak **** Introduction Delta assists you in minimizing "interesting" files subject to a test of their interestingness. A common such situation is when attempting to isolate a small failure-inducing substring of a large input that causes your program to exhibit a bug. Our implementation is based on the algorithm found here: http://www.st.cs.uni-sb.de/dd/ . Please see doc/using_delta.txt for documentation. **** Installation % tar xvzf delta.tar.gz % cd delta % make % make check #optional The resulting executables end up in delta/bin. Thus, put delta/bin on your path, copy them to a directory on your path, or simply use them in place. **** Requirements Perl5 GNU make gcc (including cpp) To rebuild the distribution from scratch you also need flex. We have not set up configuration to look for other C compilers yet. You can get much of the functionality even if you only have Perl5. Other make-s may work. Please see the documentation. **** Acknowledgments The program delta was written by Daniel S. Wilkerson with suggestions from Scott McPeak; Daniel also wrote the documentation using_delta.txt. The programs multidelta and topformflat were written by Scott McPeak. The authors would like to thank the following people for their bug submissions, debugging assistance, and suggestions on features and documentation. Westley Weimer Rob Johnson Simon Goldsmith **** License, Copyright, and Lack of Warranty See License.txt for copyright and terms of use. delta-2006.08.03/topformflat.c0000644000175000017500000013260210464463515014074 0ustar dswdsw#line 2 "topformflat.c" #line 4 "topformflat.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 31 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yywrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 17 #define YY_END_OF_BUFFER 18 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[37] = { 0, 0, 0, 0, 0, 0, 0, 18, 16, 6, 8, 16, 12, 16, 1, 3, 4, 11, 10, 11, 15, 14, 15, 0, 5, 0, 2, 0, 4, 9, 13, 5, 0, 7, 0, 0, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[11] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[44] = { 0, 0, 0, 8, 14, 18, 22, 32, 64, 64, 64, 29, 64, 36, 64, 64, 22, 64, 64, 0, 64, 64, 0, 41, 64, 26, 64, 23, 64, 64, 64, 48, 22, 64, 55, 19, 64, 19, 18, 17, 14, 13, 12, 11 } ; static yyconst flex_int16_t yy_def[44] = { 0, 36, 1, 37, 37, 38, 38, 36, 36, 36, 36, 39, 36, 36, 36, 36, 36, 36, 36, 40, 36, 36, 41, 39, 36, 23, 36, 42, 36, 36, 36, 43, 42, 36, 43, 34, 0, 36, 36, 36, 36, 36, 36, 36 } ; static yyconst flex_int16_t yy_nxt[75] = { 0, 8, 9, 10, 11, 12, 13, 14, 8, 15, 16, 18, 34, 32, 30, 29, 19, 18, 23, 20, 17, 31, 19, 21, 33, 33, 22, 21, 31, 28, 22, 24, 36, 36, 36, 36, 36, 25, 26, 36, 36, 36, 27, 24, 36, 36, 36, 36, 36, 25, 24, 36, 36, 36, 36, 36, 35, 24, 36, 36, 36, 36, 36, 35, 7, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36 } ; static yyconst flex_int16_t yy_chk[75] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 43, 42, 41, 40, 3, 4, 39, 38, 37, 35, 4, 5, 32, 27, 5, 6, 25, 16, 6, 11, 7, 0, 0, 0, 0, 11, 13, 0, 0, 0, 13, 23, 0, 0, 0, 0, 0, 23, 31, 0, 0, 0, 0, 0, 31, 34, 0, 0, 0, 0, 0, 34, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "topformflat.lex" /* topformflat.l; see License.txt for copyright and terms of use * * Scott McPeak * * flatten all toplevel forms to single lines. * very heuristic... */ #line 9 "topformflat.lex" #include // atoi // emit yytext as-is void emit(); // debugging diagnostic, emitted when enabled void diag(char const *str); // add a newline if nesting <= threshold void possibleNewline(); // keep track of brace nesting (0 means not inside any pair) int nesting = 0; // nesting threshold; when nesting is greater than threshold, // newlines are suppressed int threshold = 0; /* don't try to call yywrap() */ /* dsw: don't define yyunput() */ /* start condition for strings */ #line 500 "topformflat.c" #define INITIAL 0 #define STRING 1 #define CHARLIT 2 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 39 "topformflat.lex" #line 654 "topformflat.c" if ( (yy_init) ) { (yy_init) = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 37 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 64 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 41 "topformflat.lex" { emit(); possibleNewline(); } YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP #line 43 "topformflat.lex" { if (nesting <= threshold) { /* end of C comment */ emit(); } else { printf("%c", yytext[0]); } } YY_BREAK case 3: YY_RULE_SETUP #line 51 "topformflat.lex" { nesting++; emit(); possibleNewline(); // so the header is separated from the components } YY_BREAK case 4: YY_RULE_SETUP #line 56 "topformflat.lex" { nesting--; emit(); possibleNewline(); } YY_BREAK /* a hash, then some non-newlines. then, possibly, an escaped * newline followed by more non-newlines (repeat as needed). * finally, a newline */ case 5: /* rule 5 can match eol */ YY_RULE_SETUP #line 64 "topformflat.lex" { printf("\n"); /* make sure starts on own line */ emit(); /* preprocessor */ } YY_BREAK case 6: /* rule 6 can match eol */ YY_RULE_SETUP #line 69 "topformflat.lex" { printf(" "); } /* not any above case, eat it*/ YY_BREAK case 7: /* rule 7 can match eol */ YY_RULE_SETUP #line 71 "topformflat.lex" { emit(); } /* C++ comment */ YY_BREAK case 8: YY_RULE_SETUP #line 73 "topformflat.lex" { diag(""); emit(); BEGIN(STRING); } /* start quote */ YY_BREAK case 9: /* rule 9 can match eol */ YY_RULE_SETUP #line 76 "topformflat.lex" { emit(); } /* escaped character */ YY_BREAK case 10: YY_RULE_SETUP #line 77 "topformflat.lex" { emit(); diag(""); BEGIN(INITIAL); } /* close quote */ YY_BREAK case 11: /* rule 11 can match eol */ YY_RULE_SETUP #line 78 "topformflat.lex" { emit(); } /* ordinary char */ YY_BREAK case 12: YY_RULE_SETUP #line 81 "topformflat.lex" { diag(""); emit(); BEGIN(CHARLIT); } /* start tick */ YY_BREAK case 13: /* rule 13 can match eol */ YY_RULE_SETUP #line 84 "topformflat.lex" { emit(); } /* escaped character */ YY_BREAK case 14: YY_RULE_SETUP #line 85 "topformflat.lex" { emit(); diag(""); BEGIN(INITIAL); } /* close tick */ YY_BREAK case 15: /* rule 15 can match eol */ YY_RULE_SETUP #line 86 "topformflat.lex" { emit(); } /* ordinary char */ YY_BREAK case 16: YY_RULE_SETUP #line 89 "topformflat.lex" { emit(); } YY_BREAK case 17: YY_RULE_SETUP #line 91 "topformflat.lex" ECHO; YY_BREAK #line 852 "topformflat.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(STRING): case YY_STATE_EOF(CHARLIT): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 37 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 37 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 36); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param str a NUL-terminated string to scan * @param yy_str a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str ) { return yy_scan_bytes(yy_str,strlen(yy_str) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #undef YY_NEW_FILE #undef YY_FLUSH_BUFFER #undef yy_set_bol #undef yy_new_buffer #undef yy_set_interactive #undef yytext_ptr #undef YY_DO_BEFORE_ACTION #ifdef YY_DECL_IS_OURS #undef YY_DECL_IS_OURS #undef YY_DECL #endif #line 91 "topformflat.lex" void emit() { printf("%.*s", yyleng, yytext); } void diag(char const *str) { //printf("%s", str); } void possibleNewline() { if (nesting <= threshold) { printf("\n"); } } char *version = "2003.7.14"; int main(int argc, char *argv[]) { if (isatty(0)) { printf("topformflat version %s\n", version); printf("usage: %s [threshold] output.c\n", argv[0]); printf(" The threshold (default: 0) specifies at what nesting level\n" " of braces will line breaks be allowed (or inserted). By\n" " starting with 0, you get all top-level forms, one per line\n" " (roughly). Increasing the threshold leads to finer-grained\n" " structure on each line. The intent is to use the delta\n" " minimizer on each level of granularity.\n"); return 0; } if (argc >= 2) { threshold = atoi(argv[1]); // user-specified threshold } yyin = stdin; yylex(); return 0; }