* build-aux/bin/fuse-switch: New.
* build-aux/bin/bison++.in: Upgrade: use fuse-switch (does not
make any difference in the case of tc), support more options,
support verbosity levels.
* src/parse/Makefile.am: Fix the bison++ regeneration.
(BISONXXFLAGS, AM_BISONFLAGS): New.
(FROM_PARSETIGER_YY): Rename as...
(SOURCES_PARSETIGER_YY): this, for clarity.
Signed-off-by: Roland Levillain <roland(a)lrde.epita.fr>
---
ChangeLog | 13 ++
build-aux/bin/bison++.in | 313 ++++++++++++++++++++++++++++++++++-----------
build-aux/bin/fuse-switch | 168 ++++++++++++++++++++++++
src/parse/Makefile.am | 32 +++--
4 files changed, 442 insertions(+), 84 deletions(-)
create mode 100755 build-aux/bin/fuse-switch
diff --git a/ChangeLog b/ChangeLog
index 540c335..7eaa468 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-02-20 Akim Demaille <demaille(a)gostai.com>
+
+ maint: upgrade bison++.
+
+ * build-aux/bin/fuse-switch: New.
+ * build-aux/bin/bison++.in: Upgrade: use fuse-switch (does not
+ make any difference in the case of tc), support more options,
+ support verbosity levels.
+ * src/parse/Makefile.am: Fix the bison++ regeneration.
+ (BISONXXFLAGS, AM_BISONFLAGS): New.
+ (FROM_PARSETIGER_YY): Rename as...
+ (SOURCES_PARSETIGER_YY): this, for clarity.
+
2012-02-17 Akim Demaille <demaille(a)gostai.com>
move-if-change: in colors (no 3d available).
diff --git a/build-aux/bin/bison++.in b/build-aux/bin/bison++.in
index bb11bca..1659e38 100755
--- a/build-aux/bin/bison++.in
+++ b/build-aux/bin/bison++.in
@@ -1,34 +1,117 @@
#! /bin/sh
-
+set -x
# Exit status.
status=0
# Any tool failure is a failure of the script.
set -e
-: ${BISON=@BISON@}
+: ${BISON='@BISON@'}
+
+stderr ()
+{
+ local i
+ for i
+ do
+ echo "$i"
+ done | sed >&2 -e "s/^/$me: /"
+}
+
+verbose ()
+{
+ if "$verbose"; then
+ stderr "$@"
+ fi
+}
+
+fatal ()
+{
+ stderr "$@"
+ exit 1
+}
+
+usage ()
+{
+ cat <<EOF
+usage: bison++ OPTIONS... -- INPUT OUTPUT BISON-OPTIONS
-# bison++ INPUT OUTPUT OPTIONS
-# ----------------------------
+Options:
+ -h, --help display this message and exit successfully
+ --location-dir=DIR where to install position.hh and location.hh.
+ E.g., "\$(top_srcdir)/include/foo"
+ --location-prefix=DIR where #include must look for these headers.
+ E.g., "foo"
+ --verbose display diffs
+EOF
+ exit 0
+}
me=$(basename $0)
-move_if_change='@abs_srcdir@/move-if-change'
+fuse_switch='@abs_srcdir@/fuse-switch'
+move_if_change='@abs_srcdir@/move-if-change --color'
+verbose=false
+
+## ---------------------- ##
+## Command line parsing. ##
+## ---------------------- ##
+
+get_options ()
+{
+ while test $# != 0
+ do
+ # Handle --option=value by splitting apart and putting back on argv.
+ case $1 in
+ (--*=*)
+ opt=$(echo "$1" | sed -e 's/=.*//')
+ val=$(echo "$1" | sed -e 's/[^=]*=//')
+ shift
+ set dummy "$opt" "$val" ${1+"$@"}; shift
+ ;;
+ esac
+
+ case $1 in
+ (-h | --help ) usage;;
+ (--location-dir) shift; location_dir=$1;;
+ (--location-prefix) shift; location_prefix=$1/;;
+ (--verbose) verbose=:
+ move_if_change="$move_if_change --verbose";;
+ (--) shift; break;;
+ (*) fatal "invalid argument: $1";;
+ esac
+ shift
+ done
+
+ input=$1
+ shift
+ output=$1
+ shift
+ bisonflags="$@"
+}
+
+
+## ------ ##
+## Main. ##
+## ------ ##
+
+get_options "$@"
-input=$1
input_base=$(basename "$input")
-shift
-output=$1
+input_dir=$(dirname "$input")
+
output_base=$(basename "$output")
output_base_noext=$(echo "$output_base" | sed -e 's/\.[^.]*//')
output_dir=$(dirname "$output")
-shift
-options="$@"
+: ${location_dir=$output_dir}
+
+# The namespace we are in.
+# FIXME: We need $srcdir to be able to compute it.
+namespace=parse
+
if $BISON --xml --version >/dev/null 2>&1; then
- options="$options --xml"
+ bisonflags="$bisonflags --xml"
fi
-
# Alexandre Duret-Lutz also notes that in VPATH-builds $(srcdir) can
# be an absolute path depending on how ./configure is called ...
# In that case
@@ -48,7 +131,7 @@ mkdir $tmp
cp $input $tmp
cd $tmp
set +e
-$BISON $options $input_base -o $output_base
+$BISON $bisonflags $input_base -o $output_base
status=$?
set -e
@@ -58,71 +141,157 @@ set -e
# Fixes in place.
fix_bison_output ()
{
- # Fix doxygen tags.
- perl -pi -e "s|\Q\\file $base\E\b|\\\\file parse/$base|g;" "$1"
+ local file="$1"
+ local base
+ base=$(basename "$file")
+ local base_noext
+ base_noext=$(echo "$file" | sed -e 's/\..*//')
+ perl -pi -e "
+# Fix doxygen tags.
+s|\Q\\file $base\E\b|\\\\file $namespace/$base|g;
+
+# Fix sync lines for composite paths.
+s|(^#line.*)$base_noext|\$1$input_dir/$base_noext|g
+ if '$input_dir' ne '$output_dir';
+
+# In case position.hh and location.hh were moved.
+s{include \"(position.hh|location.hh)\"}
+ {include <$location_prefix\$1>}g
+ if '$location_prefix' ne '';
+
+# Kill trailing blanks.
+s/[ \t]+\$//;
+" "$1"
+
+ # Fuse the switches of the parser.
+ case $file in
+ (*.cc) $fuse_switch $file
+ # diff -uw $file.bak $file || true
+ ;;
+ esac
+}
+
+# compile_xml_file XML XSL OUT-EXT
+# --------------------------------
+# By transforming XML = FILE.xml with XSL.xsl, create FILE.OUT-EXT if needed.
+# "Needed" means FILE.OUT-EXT does not exist, or XML was updated.
+compile_xml_file ()
+{
+ local xml="$1"
+ local xsl="$2.xsl"
+ local out
+ out=$(basename "$xml" ".xml").$3
+
+ # "cmp NON-EXISTENT FILE" does what we want: fail.
+ if ! cmp -s "$xml" "$(out "$xml")" \
+ || test ! -f "$(out "$out")"; then
+ local compile="xsltproc $($BISON --print-datadir)/xslt/$xsl"
+ if ! $compile "$xml" >"$(tmp "$out")"; then
+ stderr "cannot convert $xml report to $out"
+ # Produce a stub for the HTML for sake of the Makefile.
+ cat >"$(tmp "$out")" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+ <head>
+ <title>Cannot run xsltproc</title>
+ </head>
+ <body>
+ <p>Cannot run xsltproc</p>
+ </body>
+</html>
+EOF
+ fi
+ install "$out"
+ fi
+}
+
+# out FILE
+# --------
+# Return path name of FILE once installed in its destination directory.
+out ()
+{
+ local f
+ f=$(basename "$1")
+ case $f in
+ (position.hh|location.hh) echo "$location_dir/$f";;
+ (*) echo "$output_dir/$f";;
+ esac
+}
+
+# out FILE
+# --------
+# Return path name of FILE in the tmp directory.
+tmp ()
+{
+ echo "$tmp/$(basename "$1")"
+}
+# install FILE
+# ------------
+# Install FILE in its destination directory.
+install ()
+{
+ local dest
+ dest=$(out "$1")
+ local dir
+ dir=$(dirname "$dest")
+ mkdir -p "$dir" ||
+ fatal "cannot create $dir"
+ $move_if_change "$(tmp "$1")" "$dest"
}
# Go back to where we were and use relative paths instead of using
# absolute file names. The messages look nicer.
cd ..
-case $status in
- 0)
- for file in $tmp/*
- do
- base=$(basename $file)
- base_noext=$(echo "$base" | sed -e 's/\.[^.]*//')
- out=$output_dir/$base
- case $base in
- $input_base)
- # Leave it here.
- ;;
-
- *.xml)
- # Computing the HTML is slow. Do it when the XML changed.
- fix_bison_output "$file"
- if ! test -r "$out" || ! cmp -s "$file" "$out";
then
- xml2html="xsltproc $($BISON --print-datadir)/xslt/xml2xhtml.xsl"
- if $xml2html "$file" >$tmp/$base_noext.html; then
- $move_if_change "$tmp/$base_noext.html" \
- "$output_dir/$base_noext.html"
- else
- echo >&2 "$0: cannot convert XML report to HTML"
- rm $tmp/$base_noext.html
- fi
- fi
- $move_if_change "$file" "$out"
- ;;
-
- *.hh)
- fix_bison_output "$file"
- # To save cycles, if the file differs only on sync lines,
- # update it (to be right), but keep the original timestamps.
- if test -r "$out" &&
- diff -I '^#line' -I '/\* Line .* of .* \*/' -q
"$file" "$out"; then
- touch -r "$out" "$file"
- cp "$out" "$out.bak"
- echo >&2 "$0: kept the stamps of $file"
- fi
- $move_if_change "$file" "$out"
- ;;
-
- *)
- fix_bison_output "$file"
- $move_if_change "$file" "$out"
- ;;
- esac
- done
- ;;
-
- *) # We really want to keep the *.output files.
- for file in $(ls $tmp/*.output $tmp/*.xml $tmp/*.html 2>/dev/null)
- do
- $move_if_change "$file" "$output_dir/$(basename $file)"
- done
- ;;
-esac
+for file in $tmp/*
+do
+ base=$(basename $file)
+ base_noext=$(echo "$base" | sed -e 's/\.[^.]*//')
+ case $status:$base in
+ (*:$input_base)
+ # Leave it here.
+ ;;
+
+ # Success or not, install it.
+ (*:*.xml)
+ # Computing the HTML is slow. Do it when the XML changed.
+ fix_bison_output "$file"
+ compile_xml_file "$file" "xml2xhtml" "html"
+ # Compiling the dot output is quite long, it would be better
+ # to do that from the Makefile, so that -j applies.
+ # compile_xml_file "$file" "xml2dot" "dot"
+ install "$file"
+ ;;
+
+ (0:*.hh)
+ fix_bison_output "$file"
+ # To save cycles, if the file differs only on sync lines,
+ # update it (to be right), but keep the original timestamps.
+ if test -r "$(out "$file")" &&
+ diff -I '^#line' -I '/\* Line .* of .* \*/' -q \
+ "$file" "$(out "$file")"
+ then
+ touch -r "$(out "$file")" "$file"
+ cp "$(out "$file")" "$(out "$file").bak"
+ verbose "kept the stamps of $file"
+ fi
+ install "$file"
+ ;;
+
+ (*:*.output)
+ install "$file"
+ ;;
+
+ (0:*)
+ fix_bison_output "$file"
+ install "$file"
+ ;;
+ esac
+done
# Get rid of the tmp dir.
-rm -rf $tmp
+# rm -rf $tmp
exit $status
diff --git a/build-aux/bin/fuse-switch b/build-aux/bin/fuse-switch
new file mode 100755
index 0000000..0d48d41
--- /dev/null
+++ b/build-aux/bin/fuse-switch
@@ -0,0 +1,168 @@
+#! /usr/bin/perl -w
+
+# This script *tries* to fuse consecutive "switches" that have the
+# same body.
+#
+# Usage: $0 FILES
+#
+# Leaves a copy of the input files as FILE.bak.
+
+
+use strict;
+
+my $case_re = '^\s*(case\b.*|default)\s*:';
+
+# Return the block of code with all the ignored parts removed.
+sub code ($)
+{
+ local ($_) = @_;
+# print STDERR "CODE IN: $_";
+ s,//.*,,gm;
+ s,/\*.*?.*\*/,,gm;
+ s/#line .*//gm;
+# print STDERR "CODE OUT: $_";
+ return $_;
+}
+
+# Compare two case blocks against equality, ignoring the case label.
+sub case_eq($$)
+{
+ my ($b1, $b2) = @_;
+ return case_body(code($b1)) eq case_body(code($b2));
+}
+
+# Return the line which contains the "case" this block of code.
+sub case_label($)
+{
+ my ($case) = @_;
+ my $res = '';
+ for my $line (split "\n", $case)
+ {
+ # We put no space at the end of '//-' not to introduce trailing
+ # spaces.
+ $res .= ($line !~ /$case_re/ && '//-') . $line . "\n"
+ }
+ return $res;
+}
+
+# Return the case-block without its case line.
+sub case_body($)
+{
+ local ($_) = @_;
+# print STDERR "BODY IN: $_";
+ s/^.*$case_re.*\n//mg;
+# print STDERR "BODY OUT: $_";
+ return $_;
+}
+
+
+sub fuse($$)
+{
+ my ($input, $output) = @_;
+ use IO::File;
+
+ my $in = new IO::File($input) or die;
+ my $out = new IO::File(">$output") or die;
+
+ # Something before the next $case.
+ my $pre_case = '';
+ # The body of the case: from case/default to the next break;
+ # There must be no break inside.
+ my $case = '';
+ my $previous_case = '';
+
+ # Whether we are in the switch {}.
+ my $in_switch = 0;
+
+ while ($_ = $in->getline)
+ {
+# print STDERR "\$_ = $_";
+ if (!$in_switch)
+ {
+ if (/^\s*switch\b/)
+ {
+ $in_switch = 1;
+ }
+ }
+ else
+ {
+ # in switch.
+ #
+ # The "default: break" one a single line is output by
+ # bison's lalr1.cc..
+ if (m/$case_re/ .. m/^\s*(?:default:\s*)?break/)
+ {
+ # Register the current case.
+ $case .= $_;
+ if (/break/)
+ {
+ if (case_eq($previous_case, $case))
+ {
+# print STDERR "== {{$previous_case}} {{$case}}\n";
+ $_ = case_label ($previous_case);
+ }
+ else
+ {
+ # The previous case is needed.
+# print STDERR "!= {{$previous_case}} {{$case}}\n";
+ $_ = $previous_case;
+ }
+ $previous_case = $case;
+ $case = "";
+ $_ .= $pre_case;
+ $pre_case = '';
+ }
+ else
+ {
+ # Print nothing.
+ $_ = "";
+ }
+ }
+ elsif (m/}/)
+ {
+ # The closing brace of the switch.
+ $_ = $previous_case . $pre_case . $_;
+ $pre_case = '';
+ $previous_case = '';
+ $in_switch = 0;
+ }
+ else
+ {
+ # Something in a switch, but not in a case. Keep it,
+ # and output it before the forth coming output. Don't
+ # put it in $case though, as it would be commented out,
+ # which might be wrong (e.g., pragmas, or cpp
+ # directives).
+ $pre_case .= $_;
+ $_ = '';
+ }
+ }
+ print $out $_;
+ }
+ die "could not insert $pre_case"
+ if $pre_case;
+}
+
+use File::Copy;
+for my $file (@ARGV)
+{
+ copy ($file, "$file.bak") or die;
+ fuse("$file.bak", "$file");
+}
+
+### Setup "GNU" style for perl-mode and cperl-mode.
+## Local Variables:
+## perl-indent-level: 2
+## perl-continued-statement-offset: 2
+## perl-continued-brace-offset: 0
+## perl-brace-offset: 0
+## perl-brace-imaginary-offset: 0
+## perl-label-offset: -2
+## cperl-indent-level: 2
+## cperl-brace-offset: 0
+## cperl-continued-brace-offset: 0
+## cperl-label-offset: -2
+## cperl-extra-newline-before-brace: t
+## cperl-merge-trailing-else: nil
+## cperl-continued-statement-offset: 2
+## End:
diff --git a/src/parse/Makefile.am b/src/parse/Makefile.am
index 7b50a34..f19a240 100644
--- a/src/parse/Makefile.am
+++ b/src/parse/Makefile.am
@@ -1,15 +1,15 @@
# From LRDE's TC's src/parse/Makefile.am:
-# "[asm-parse.cc] is not part of [FROM_ASM_PARSE_YY] to prevent
+# "[asm-parse.cc] is not part of [SOURCES_ASM_PARSE_YY] to prevent
# [asm-parse.cc] from occuring twice in libparse_a_SOURCES to avoid
# double inclusion of [asm-parse.o]."
-FROM_ASM_PARSE_YY = \
+SOURCES_ASM_PARSE_YY = \
$(srcdir)/stack.hh $(srcdir)/position.hh $(srcdir)/location.hh \
$(srcdir)/asm-parse.hh
BUILT_SOURCES = \
asm-scan.ll asm-scan.ll.stamp \
asm-parse.yy asm-parse.yy.stamp \
- $(FROM_ASM_PARSE_YY)
+ $(SOURCES_ASM_PARSE_YY)
# This code comes from "Handling Tools that Produce Many Outputs",
# from the Automake documentation.
@@ -34,25 +34,33 @@ $(srcdir)/asm-parse.yy: asm-parse.yy.stamp
BISONXX = $(top_builddir)/build-aux/bin/bison++
BISONXX_IN = $(top_srcdir)/build-aux/bin/bison++.in
$(BISONXX): $(BISONXX_IN)
- cd $(top_builddir)/build-aux && $(MAKE) $(AM_MAKEFLAGS) bin/bison++
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) build-aux/bin/bison++
+
+BISONXXFLAGS = \
+ --verbose
+AM_BISONFLAGS = \
+ --report=all
EXTRA_DIST += $(srcdir)/bison++.stamp $(srcdir)/asm-parse.yy
$(srcdir)/bison++.stamp: $(srcdir)/asm-parse.yy $(BISONXX_IN)
- $(MAKE) $(AM_MAKEFLAGS) $(BISONXX)
- @rm -rf bison++.stamp.tmp
- @touch bison++.stamp.tmp
- $(BISONXX) $(srcdir)/asm-parse.yy $(srcdir)/asm-parse.cc -d -ra
- @mv -f bison++.stamp.tmp $@
+ mkdir -p $(@D)
+ rm -f $@ $@.tmp
+ echo '$@ rebuilt because of: $?' >$@.tmp
+ $(MAKE) $(BISONXX)
+ $(BISONXX) $(BISONXXFLAGS) -- \
+ $< $(srcdir)/asm-parse.cc \
+ $(AM_BISONFLAGS) $(BISONFLAGS)
+ mv -f $@.tmp $@
# Run bison if a file that can be created by it is missing:
-$(srcdir)/asm-parse.cc $(FROM_ASM_PARSE_YY): $(srcdir)/bison++.stamp
+$(srcdir)/asm-parse.cc $(SOURCES_ASM_PARSE_YY): $(srcdir)/bison++.stamp
@if test ! -f $@; then \
rm -f $(srcdir)/bison++.stamp; \
$(MAKE) $(AM_MAKEFLAGS) $(srcdir)/bison++.stamp; \
fi
-MAINTAINERCLEANFILES = asm-scan.ll asm-scan.yy $(FROM_ASM_PARSE_YY)
+MAINTAINERCLEANFILES = asm-scan.ll asm-scan.yy $(SOURCES_ASM_PARSE_YY)
noinst_LTLIBRARIES = libparse.la
@@ -60,6 +68,6 @@ libparse_la_CPPFLAGS = -I $(top_srcdir)/src -I $(top_builddir)/src
libparse_la_SOURCES = \
fwd.hh \
asm-parse.cc asm-parse.yy.stamp \
- $(FROM_ASM_PARSE_YY) \
+ $(SOURCES_ASM_PARSE_YY) \
asm-scan.ll asm-scan.hh asm-scan.ll.stamp \
libparse.hh libparse.cc
--
1.7.2.5