summaryrefslogtreecommitdiff
path: root/lib/sbin/cpp.pl
diff options
context:
space:
mode:
authorgoodale <goodale@17b73243-c579-4c4c-a9d2-2d5706c11dac>2001-11-20 00:36:21 +0000
committergoodale <goodale@17b73243-c579-4c4c-a9d2-2d5706c11dac>2001-11-20 00:36:21 +0000
commit8140e77075a3a4c4c3b9ba453928d2a336012573 (patch)
tree9f3ef41bf3d2ec3c314733fc3606bc30e05b610a /lib/sbin/cpp.pl
parentcb1ab63b14165b33cf65e62abea3d3fb02ee9eb5 (diff)
Updated version of the perl cpp replacement. I can now build Cactus using this.
If you feel brave and want to use this, edit configs/<config>/config-data/make.config.defn and change the CPP = <whatever> line to CPP = $(PERL) $(CCTK_HOME)/lib/sbin/cpp.pl I have tested this on the Fortran files from WaveToyF* and it works ok. Caveats: It will merrily go into a loop with recursive macro definitions. Some of its error messages may not be too friendly at the moment. Tom git-svn-id: http://svn.cactuscode.org/flesh/trunk@2466 17b73243-c579-4c4c-a9d2-2d5706c11dac
Diffstat (limited to 'lib/sbin/cpp.pl')
-rwxr-xr-xlib/sbin/cpp.pl1064
1 files changed, 755 insertions, 309 deletions
diff --git a/lib/sbin/cpp.pl b/lib/sbin/cpp.pl
index 4bdb976a..17d7ede7 100755
--- a/lib/sbin/cpp.pl
+++ b/lib/sbin/cpp.pl
@@ -1,4 +1,3 @@
-#! /usr/bin/perl
#/*@@
# @file cpp.pl
# @date Wed Sep 15 14:21:53 1999
@@ -9,26 +8,110 @@
# @version $Header$
#@@*/
+###############################################################################
+###############################################################################
+# Setup some global variables.
+
+# Symbol table
%defines = ();
+
+#Initial symbols
+
+&Define("__FILE__", "\"replace-me\"", "<main>",__LINE__);
+&Define("__LINE__", "\"replace-me\"", "<main>",__LINE__);
+
+# Current working directory for opening files.
+$current_wd = ".";
+
+# Include path
+@include_path = ();
+
+# Filename and linenumber stacks for error traces.
@filelist = ();
@linelist = ();
-@dirlist = ();
-$current_wdir = ".";
-$cxx = 0;
+# Complete list of included files for generating dependencies
+%complete_file_list = ();
+
+# Are we in the middle of a comment ?
+$incomment = 0;
+
+###############################################################################
+###############################################################################
+
+# Parse the command line
($source_file, $output_file, $do_deps, @include_path) = &ParseCommandLine(@ARGV);
-if($do_deps)
+###############################################################################
+###############################################################################
+
+#If no source file given, choose stdin
+if(! $source_file)
{
- print "$source_file.o $source_file.d :";
+ $source_file = "-"
}
-&ProcessFile($source_file, $output_file, $do_deps, @include_path);
+# Setup output stream
+if($output_file && $output_file ne "-")
+{
+ open(OUTSTREAM,">$output_file") || die "Unable to open output file";
+}
+else
+{
+ *OUTSTREAM = STDOUT;
+}
+
+###############################################################################
+###############################################################################
-print "\n";
+# Parse the input.
+&ProcessFile($source_file, "-", -1, 1-$do_deps);
+
+###############################################################################
+###############################################################################
+
+# Do Dependency generation if requested
+if($do_deps)
+{
+ my $file;
+
+ my $depend_target;
+
+ $source_file =~ m,^.+/([^/]+)$,;
+
+ if($1)
+ {
+ $depend_target = "$1.o";
+ }
+ else
+ {
+ $depend_target = "$source_file.o";
+ }
+
+ foreach $file (sort keys %complete_file_list)
+ {
+ # Ignore any empry entries
+ next if($file =~ m/^\s*$/);
+ # The source file depends upon this file
+ print OUTSTREAM "$depend_target : $file\n";
+ }
+
+ foreach $file (sort keys %complete_file_list)
+ {
+ # Ignore any empry entries
+ next if($file =~ m/^\s*$/);
+ # Generate empty rule for file so can delete header files without problems
+ print OUTSTREAM "$file :\n";
+ }
+}
exit;
+###############################################################################
+###############################################################################
+###############################################################################
+###############################################################################
+
#/*@@
# @routine ParseCommandLine
# @date Wed Sep 15 14:22:28 1999
@@ -46,7 +129,7 @@ exit;
sub ParseCommandLine
{
my(@args) = @_;
- my($source_file, $output_file, $do_deps, @include_path) = (0,0,0,("."));
+ my($source_file, $output_file, $do_deps, @include_path) = (0,0,0,());
while($arg = shift(@args))
{
@@ -56,43 +139,41 @@ sub ParseCommandLine
}
elsif($arg =~ m:^-D([^=]+)(=)?(.*):)
{
- &define($1, $3);
+ &Define($1, $3,"command-line",0);
}
elsif($arg =~ m:^-M(.*):)
{
$do_deps = 1;
}
- elsif($arg =~ m:^-C\+\+:)
+ elsif($arg =~ m:^-.+:)
{
- $cxx = 1;
+ die("Unknown preprocessor option '$arg'");
}
- elsif($arg =~ m:^-:)
+ elsif($source_file && $output_file)
{
- die("Unknown preprocessor option '$arg'");
+ die("Source and output files already set");
}
elsif($source_file)
{
- die("Source file already set");
+ $output_file = $arg;
}
else
{
- $arg =~ m:(.*/)?(.*):;
-
- $source_file = $2;
- $current_wdir = $1 if($1);
+ $source_file = $arg;
}
}
return ($source_file, $output_file, $do_deps, @include_path);
}
+###############################################################################
#/*@@
-# @routine define
-# @date Wed Sep 15 14:22:58 1999
+# @routine ProcessFile
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Defines a macro
+# Open a file and parse its contents.
# @enddesc
# @calls
# @calledby
@@ -101,24 +182,69 @@ sub ParseCommandLine
# @endhistory
#
#@@*/
-sub define
+sub ProcessFile
{
- local($what, $value);
+ my ($newfilename, $oldfilename, $oldlinenumber, $printline) = @_;
+ local *FILEDESC;
+ my $fullpath;
+ my $new_current_wd;
+
+ ($new_current_wd,$fullpath) = &FindFile($newfilename,$current_wd,\@include_path);
+
+ # Override this variable on the stack
+ local $current_wd = $new_current_wd;
+
+ if($newfilename ne "-" && !$fullpath)
+ {
+ die "Unable to find $newfilename included at $oldfilename:$oldlinenumber";
+ }
+
+ if($newfilename ne "-")
+ {
+ if($debug)
+ {
+ print "Opening $newfilename\n";
+ }
+
+ open(FILEDESC, "< $fullpath") || die "Unable to open file $fullpath";
+ push(@filelist, $oldfilename);
+ push(@linelist, $oldlinenumber);
+ }
+ else
+ {
+ $newfilename = "<STDIN>";
+ $current_wd = ".";
+ *FILEDESC = STDIN;
+ }
- if($defines{$what})
+ # If we are not printing lines, must being doing deps, so save file name
+ if($newfilename ne "-" && ! $printline )
{
- print STDERR "Redefining $defines{$what}\n";
+ $complete_file_list{"$fullpath"} = 1;
}
- $defines{$what} = $value;
+ &ParseFile(FILEDESC,$newfilename,0,1,$printline);
+
+ if($newfilename ne "-")
+ {
+ if($debug)
+ {
+ print "Closing $newfilename\n";
+ }
+ close(FILEDESC);
+ pop(@filelist);
+ pop(@linelist);
+ }
}
+###############################################################################
+
#/*@@
-# @routine ProcessFile
-# @date Wed Sep 15 14:23:16 1999
+# @routine FindFile
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Opens a file and calls the routine to process it.
+# Finds a file and works out its full name and the directory its in.
# @enddesc
# @calls
# @calledby
@@ -127,63 +253,55 @@ sub define
# @endhistory
#
#@@*/
-sub ProcessFile
+sub FindFile
{
- my($source_file, $output_file, $do_deps, @include_path) = @_;
- my($line, $found, $path);
- local(*F);
+ my($newfilename,$old_current_wd,$ra_include_path) = @_;
- $found = "";
+ my $fullpath;
+ my $new_current_wd;
- for $path ($current_wdir, @include_path)
+ if($newfilename =~ m,^/,)
{
- if (-r "$path/$source_file")
- {
- $found = $path;
- last;
- }
+ #absolute path
+ $fullpath = $newfilename;
}
- if($found eq "")
+ elsif($old_current_wd && -r "$old_current_wd/$newfilename")
{
- &Warning("Error: Cannot find $source_file in " . join(":", @include_path));
- exit 2;
+ $fullpath = "$old_current_wd/$newfilename";
}
-
- $path = $found;
-
- $path =~ s:/*$::;
-
- push(@dirlist, $current_wdir);
-
- "$path/$source_file" =~ m:(.*/)?(.*):;
-
- $current_wdir = $1;
-
- open(F, "$path/$source_file") || &Warning("Error: Unable to open $path/$source_file") || exit 2;
-
- push(@filelist, "$path/$source_file");
-
-
- if($do_deps)
+ else
{
- printf("\\\n %-40s","$path/$source_file");
+ for(my $dir=0; $dir < @$ra_include_path; $dir++)
+ {
+ if(-r "$ra_include_path->[$dir]/$newfilename")
+ {
+ $fullpath = "$ra_include_path->[$dir]/$newfilename";
+ last;
+ }
+ }
}
+ # Tidy up the path a bit
+ $fullpath =~ s,/./,/,g;
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- close(F);
-
- pop(@filelist);
- $current_wdir = pop(@dirlist);
+ if($fullpath)
+ {
+ $fullpath =~ m,^(.+)/[^/]+$,;
+ $new_current_wd = $1;
+ }
+ $fullpath =~ s,^./,,;
+ return ($new_current_wd, $fullpath);
}
+
+###############################################################################
#/*@@
# @routine ParseFile
-# @date Wed Sep 15 14:24:11 1999
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# The meat of the program - this actually tries to make sense of the input file
+# Parse part or all of a file.
# @enddesc
# @calls
# @calledby
@@ -194,129 +312,210 @@ sub ProcessFile
#@@*/
sub ParseFile
{
- local(*F, $output_file, $do_deps, @include_path) = @_;
-
- while($line = <F>)
+ local *INFILE = $_[0];
+ my $filename = $_[1];
+ my $linenumber = $_[2];
+ my $active = $_[3];
+ my $printline = $_[4];
+
+ my $firstline = $linenumber;
+
+ my $retcode = 0;
+
+ my $line;
+ my $currentline;
+
+ if($debug)
{
- chomp($line);
+ print "Entered ParseFile: $filename:$linenumber, active=$active\n";
+ }
- # Strip off C++ comments
- $line =~ s://.*:: if($cxx);
+ while(1)
+ {
+ ($line, $linenumber) = &ReadLine(*INFILE,$linenumber);
- # Strip off C comments
- if($line =~ m:/\*:)
- {
- $line = &StripComments(*F, $line);
- }
+ $currentline = $line;
- if($line =~ m:^\#:)
+ # Exit loop if file is finished
+ last if(! defined($line));
+
+ # If it isn't a preprocessor command, just process it
+ if($line !~ m/^\#/)
{
- if($line =~ m:\#include\s+<:)
- {
- # Ignore standard includes
- }
- elsif($line =~ m:^\#include\s+\"([^\"]+)\":)
- {
- push(@linelist, $.);
- &ProcessFile($1, $output_file, $do_deps, @include_path);
- pop(@linelist);
- }
- elsif($line =~ m:^\#define:)
+ if($active)
{
- &CreateDefine(*F, $line);
+ my $retval;
+ ($expanded,$retval) = &ParseAndExpand($line, "STDIN", $linenumber);
+ print OUTSTREAM "$expanded\n" if $printline;
+ $retcode += $retval;
}
- elsif($line =~ m:^\#ifdef\s+(.+):)
+ next;
+ }
+
+ if($line =~ m/^#define\s+([^\s]+)(\s+(.*))?/)
+ {
+ # Define a macro
+ &Define($1,$3,$filename, $linenumber) if($active);
+ next;
+ }
+ elsif($line =~ m/^#undef\s+([^\s]+)/)
+ {
+ # Undefine a macro
+ &UnDefine($1,$filename,$linenumber) if($active);
+ next;
+ }
+ elsif($line =~ m/^#if(.+)/)
+ {
+ #Deal with a #if clause - do it recursively
+ my $newactive;
+
+ # Parse the if statement and see if the first clause is active
+ if($active)
{
- if(! &defined($1))
- {
- if(&FindMatchingEndifOrElse(*F, $line))
- {
- # Found an else, so go down a level
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
- }
- else
- {
- # Go down a level to process this block.
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
+ $newactive = &ProcessIf($1, $filename, $linumber,$printline);
}
- elsif($line =~ m:^\#ifndef\s+(.+):)
+ else
{
- if(&defined($1))
- {
- if(&FindMatchingEndifOrElse(*F, $line))
- {
- # Found an else, so go down a level
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
- }
- else
- {
- # Go down a level to process this block.
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
+ #If not active before, still inactive
+ $newactive = 0;
}
- elsif($line =~ m:^\#if\s+(.+):)
+ my $beenactive = $newactive;
+ my $foundelse = 0;
+
+ # Now process first clause and any #elif or #else clauses
+ while(1)
{
- if(! &IfLine($1))
- {
- if(&FindMatchingEndifOrElse(*F, $line))
- {
- # Found an else, so go down a level
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
- }
- else
- {
- # Go down a level to process this block.
- &ParseFile(*F, $output_file, $do_deps, @include_path);
- }
+ # Parse the clause
+ ($currentline, $linenumber) = &ParseFile(*INFILE,$filename,$linenumber,$newactive && $active,$printline);
+ if(! $currentline)
+ {
+ # Got EOF !
+ die "Unexpected EOF when parsing $filename";
+ }
+ elsif($currentline && $currentline =~ /\#endif\s*/)
+ {
+ # Finished
+ last;
+ }
+ elsif($currentline =~ m/^#elif\s+(.+)/ && ! $foundelse)
+ {
+ # Got #elif, is this next clause active ?
+ if(! $beenactive)
+ {
+ if($active)
+ {
+ $newactive = &ProcessIf($1, $filename, $linumber);
+ }
+ else
+ {
+ $newactive = 0;
+ }
+ $beenactive = $newactive;
+ }
+ else
+ {
+ $newactive = 0;
+ }
+ }
+ elsif($currentline =~ m/^#else\s*$/ && ! $foundelse)
+ {
+ # Got #else, have any of the clauses been active ?
+ if($active)
+ {
+ $newactive = 1 - $beenactive
+ }
+ else
+ {
+ $newactive = 0;
+ }
+
+ $foundelse = 1;
+ }
+ else
+ {
+ if($currentline =~ m/^#else/ || $currentline =~ m/^#elsif/)
+ {
+ print STDERR "Extraneous #else of #elsif found at $filename:$linenumber\n";
+ $newactive = 0;
+ }
+ else
+ {
+ die "Unexpected line '$currentline' at $filename:$linenumber";
+ }
+ }
}
- elsif($line =~ m:^\#else:)
+ }
+ elsif($line =~ m/^\#elif/ || $line =~ m/^\#else/ || $line =~ m/^\#endif/)
+ {
+ if($firstline > 0)
{
- if(&FindMatchingEndifOrElse(*F, $line))
- {
- &Warning("Error: Syntax error - only one else allowed.");
- exit 2;
- }
- # Return to previous level at an endif
- return;
+ # If we are processing just part of the file, ok
+ last;
}
- elsif($line =~ m:^\#endif:)
+ else
{
- # Return to previous level at an endif
- return;
+ # Otherwise there's an extra one here
+ die "Unexpected #elif/#else/#endif at $filename:$linenumber";
}
- elsif($line =~ m:^\#undef:)
+ }
+ elsif($line =~ m/^#include\s+(.+)?/)
+ {
+ # Now to include files.
+ if(! defined($1))
{
- &UnDefine($line);
+ print STDERR "Missing argument to #include directive at $filename:$linenumber\n";
}
else
{
- &Warning("Warning: Unknown preprocessor directive $line");
+ if($active)
+ {
+ my $argument = $1;
+ if($argument =~ m/<[^>]*>\s*/)
+ {
+ # Ignore system includes
+ print OUTSTREAM "$line\n" if $printline;
+ }
+ else
+ {
+ # Allow people to use macros to define name of include file
+ ($argument,undef) = &ParseAndExpand($argument,$filename,$linenumber);
+
+ if($argument !~ m/\s*\"(.+)\"\s*$/)
+ {
+ print STDERR "Invalid filename $argument in #include directive at $filename:$linenumber\n";
+ }
+ else
+ {
+ # Process the new file. Don't need to pass $active since wouldn't be here if inactive.
+ &ProcessFile($1,$filename,$linenumber,$printline);
+ }
+ }
+ }
}
}
else
{
- if(! $do_deps)
- {
- $line = &ExpandLine($line);
-
- print "$line\n";
- }
+ print STDERR "Unrecognised # directive at $filename:$linenumber\n"
}
}
- return;
+ if($debug)
+ {
+ print "Leaving ParseFile : currentline = '$currentline', linenumber = $linenumber\n";
+ }
+
+ return ($currentline,$linenumber);
}
+###############################################################################
+
#/*@@
-# @routine CreateDefine
-# @date Wed Sep 15 14:24:51 1999
+# @routine ReadLine
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Takes a line with #define on it and creates the appropriate macro
+# Read a line from the current file descriptor.
+# Deals with comments and continuation lines
# @enddesc
# @calls
# @calledby
@@ -325,43 +524,65 @@ sub ParseFile
# @endhistory
#
#@@*/
-sub CreateDefine
+sub ReadLine
{
- local(*F, $line) = @_;
- my($var, $val);
+ local *INFILE = $_[0];
+ my $linenumber = $_[1];
+ my $line;
- $line =~ m:\#define\s+([^\s]+)\s*(.*):;
-
- $var = $1;
- $val = $2;
+ ($line,$linenumber) = &GetNextLine(*INFILE,$linenumber);
+
+ # Deal with C-style comments
- if($val =~ m:\\$:)
+ # Deal with completely enclosed comments
+ $line =~ s,/\*.*\*/, ,g;
+
+ # Are we already processing a comment ?
+ if($incomment)
{
- while($val =~ m:\\$:)
+ if($line =~ m,\*/,)
+ {
+ # Get rid of line up to end of comment
+ $line =~ s,^.*\*/, ,;
+ # Line finished the comment
+ $incomment = 0;
+ }
+ else
{
- $val =~ s:\\$::;
- $line = <F>;
- chomp($line);
+ # Line doesn't finish the comment
+ $line = " ";
+ }
+ }
- $val .= $line;
+ if(! $incomment)
+ {
+ if($line =~ m,/\*,)
+ {
+ # Get rid of line after beginning of comment
+ $line =~ s,/\*.*$, ,;
+ # Line starts the comment
+ $incomment = 1;
}
}
- if($val eq "")
+ # Get rid of C++ comments too
+ if(! $incomment)
{
- $val = "__cctk__internal_val__%%%%";
+ $line =~ s,//.*$, ,;
}
- $defines{$var} = $val;
-
+
+ return ($line, $linenumber);
}
+###############################################################################
#/*@@
-# @routine UnDefine
-# @date Wed Sep 15 14:25:27 1999
+# @routine Get next line
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Undefines a macro given a line with #undef on it.
+# Read a line from the current file descriptor.
+# Dealing with continuation lines.
# @enddesc
# @calls
# @calledby
@@ -370,26 +591,34 @@ sub CreateDefine
# @endhistory
#
#@@*/
-sub UnDefine
+sub GetNextLine
{
- my($line) = @_;
- my($var);
+ local *INFILE = $_[0];
+ my $linenumber = $_[1];
- $line =~ m:\#undef\s+([^\s]+):;
-
- $var = $1;
+ my $line = <INFILE>;
+ $linenumber++;
- delete $defines{$var};
-
-}
+ # Deal with continuation lines
+ while($line =~ m/\\\n$/)
+ {
+ chop($line);
+ chop($line);
+ $line .= <INFILE>;
+ $linenumber++;
+ }
+ chop($line);
+ return ($line, $linenumber);
+}
+###############################################################################
#/*@@
-# @routine defined
-# @date Wed Sep 15 14:25:55 1999
+# @routine ProcessIf
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Checks to see if a macros is defined.
+# Parse an #if statement and return true or false.
# @enddesc
# @calls
# @calledby
@@ -398,23 +627,37 @@ sub UnDefine
# @endhistory
#
#@@*/
-sub defined
+sub ProcessIf
{
- my($var) = @_;
+ my($line,$filename,$linenumber) = @_;
- return 1 if defined $defines{$var};
-
- return 0;
+ my $retval = 0;
+
+ if($line =~ m/^def\s+(.+)/)
+ {
+ $retval = defined($defines{$1});
+ }
+ elsif($line =~ m/^ndef\s+(.+)/)
+ {
+ $retval = ! defined($defines{$1});
+ }
+ else
+ {
+ print STDERR "#if can currently to #ifdef and #ifndef, sorry !\n";
+ $retval = 0;
+ }
+
+ return $retval;
}
+###############################################################################
#/*@@
-# @routine FindMatchingEndifOrElse
-# @date Wed Sep 15 14:26:23 1999
+# @routine Define
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Skips through a file until there is an else or an endif without a matching if.
-# Return 1 if it is an else, 0 if it is an endif.
+# Define a macro.
# @enddesc
# @calls
# @calledby
@@ -423,45 +666,72 @@ sub defined
# @endhistory
#
#@@*/
-sub FindMatchingEndifOrElse
+sub Define
{
- local(*F, $line) = @_;
- my($if_count,$retval) = (0,0);
+ my ($arg1,$arg2,$filename,$linenumber) = @_;
+
+ $arg1 =~ m:^([a-zA-Z_][a-zA-Z0-9_]*)(\(([a-zA-Z0-9_,]+)\))?$:;
+
+ my $defname = $1;
+ my $defargs = $3;
+
+ my @args = split(/,/, $defargs);
- while(<F>)
+ if($debug)
{
- if(m:^\#ifdef:)
- {
- $if_count++;
- next;
- }
- elsif(m:\#endif:)
- {
- last if($ifcount == 0);
-
- $if_count--;
- }
- elsif(m:\#else:)
- {
- if($ifcount == 0)
- {
- $retval = 1;
- last;
- }
-
- $if_count--;
- }
+ print "Defining '$defname'\n";
}
- return $retval;
+ if($defines{$defname})
+ {
+ print STDERR "Redefining $defname at $filename:$linenumber\n";
+ }
+
+ # Translate argument names just once at original definition.
+ my @transargs = ();
+ for(my $arg = 0; $arg < @args; $arg++)
+ {
+ $transargs[$arg] = "__^CCTK_INTERNAL${arg}__";
+ }
+
+ my $newbody = &ArgumentSubstitute($arg2, scalar(@args), @args, @transargs);
+
+ $defines{$defname}{"ARGS"} = \@transargs;
+
+ $defines{$defname}{"BODY"} = $newbody;
+}
+
+###############################################################################
+
+#/*@@
+# @routine Undefine
+# @date Mon Nov 19 23:51:03 2001
+# @author Tom Goodale
+# @desc
+# Undefine a macro.
+# @enddesc
+# @calls
+# @calledby
+# @history
+#
+# @endhistory
+#
+#@@*/
+sub UnDefine
+{
+ my ($def,$filename,$linenumber) = @_;
+
+ delete $defines{$def};
}
+###############################################################################
+
#/*@@
-# @routine ExpandLine
-# @date Wed Sep 15 14:27:18 1999
+# @routine ExpandMacro
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Expands all macros in a line.
+# Expand a macro recursively.
# @enddesc
# @calls
# @calledby
@@ -470,52 +740,92 @@ sub FindMatchingEndifOrElse
# @endhistory
#
#@@*/
-sub ExpandLine
+sub ExpandMacro
{
- my($line) = @_;
- my(@tokens);
- my($stringify);
+ my ($macro, $args, $filename, $linenumber) = @_;
+
+ my $retcode = 0;
+ my @arguments = &SplitArgs($args);
- @tokens = split(/(\W+)/, $line);
+ my $outstring = $defines{$macro}{"BODY"};
- $line = "";
+ if($macro eq "__FILE__")
+ {
+ $outstring = "\"$filename\"";
+ }
+ elsif($macro eq "__LINE__")
+ {
+ $outstring = "$linenumber";
+ }
- $stringify = 0;
- for $token (@tokens)
+ if(@arguments != @{$defines{$macro}{"ARGS"}})
{
- if($token =~ m:\w:&& $stringify == 0 && defined $defines{$token})
- {
- $line .= &ExpandLine($defined{$token});
- }
- elsif($stringify == 1)
+ my $expected = @{$defines{$macro}{"ARGS"}};
+ my $got = @arguments;
+ print STDERR "Error expanding macro '$macro' at $filename:$linenumber\n";
+ print STDERR " Expected $expected arguments\n";
+ print STDERR " Got $got arguments\n";
+ $outstring = $macro;
+ $retcode--;
+ }
+ else
+ {
+ my @prescanned_args;
+
+ # Argument prescan
+ for(my $arg = 0; $arg < @arguments; $arg++)
{
- $line .= "\"$token\"";
- $stringify = 0;
+ my $retval;
+ ($prescanned_args[$arg],$retval) = &ParseAndExpand($arguments[$arg], $filename, $linenumber);
+ $retcode += $retval;
}
- else
- {
- # Concatanation character
- $token =~ s:\s*\#\#\s*::;
- # Check for stringification.
- if($token =~ m:\#$:)
+ # Argument substitution
+ for(my $arg = 0; $arg < @arguments; $arg++)
+ {
+ if($debug)
{
- $stringify = 1;
- $token =~ s:\#$::;
+ print "Outstring is '$outstring'\n";
+ print "Arg $arg: '$defines{$macro}{\"ARGS\"}[$arg]', '$arguments[$arg]', '$prescanned_args[$arg]'\n";
}
- $line .= $token;
+
+ my $tobesubsted = quotemeta($defines{$macro}{"ARGS"}[$arg]);
+
+ # Concatenation takes non-prescanned argument
+ $outstring =~ s/##\s*$tobesubsted\b/##$arguments[$arg]/g;
+
+ # Stringification takes non-prescanned argument and stringifies it
+ $outstring =~ s/#\s*$tobesubsted\b/\"$arguments[$arg]\"/g;
+
+ $outstring =~ s/\b$tobesubsted\b/$prescanned_args[$arg]/g;
}
+
+ # Now recurse
+
+ ($outstring,$retval) = &ParseAndExpand($outstring, $filename, $linenumber);
+ $retcode += $retval;
+
+ # Final Concatenation
+ $outstring =~ s/\s*##\s*//g;
+
+ # Now get rid of repeated ""
+
+ $outstring =~ s/\\\"/__CCTK_STRINGPROTECT__/g;
+ $outstring =~ s/\"\"//g;
+ $outstring =~ s/__CCTK_STRINGPROTECT__/\\\"/g;
}
- return $line;
+ return ($outstring,$retcode);
}
+###############################################################################
+
#/*@@
-# @routine StripComments
-# @date Wed Sep 15 14:27:49 1999
+# @routine SplitArgs
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Strips out C comments
+# Split the arguments given to a macro into an array.
# @enddesc
# @calls
# @calledby
@@ -524,38 +834,58 @@ sub ExpandLine
# @endhistory
#
#@@*/
-sub StripComments
+sub SplitArgs
{
- local(*F, $line) = @_;
- my($var, $val);
+ my ($args) = @_;
+ my @outargs;
+
+ # Split the input into individual chars
+ my @splitargs = split(//, $args);
+
+ my $nestlevel = 0;
+ my @thistoken = ();
- if($line !~ m:\*/:)
+ for(my $pos = 0; $pos < @splitargs; $pos++)
{
- while($line !~ m:\*/:)
+ # Now split at , at the top level
+ if($splitargs[$pos] eq "(")
{
- $line .= <F>;
- chomp($line);
+ $nestlevel++;
+ }
+ elsif($splitargs[$pos] eq ")")
+ {
+ $nestlevel++;
+ }
+ elsif($splitargs[$pos] eq "," && $nestlevel == 0)
+ {
+ push(@outargs, join("",@thistoken));
+ @thistoken = ();
+ next;
+ }
+ else
+ {
+ push(@thistoken, $splitargs[$pos]);
}
}
- # Strip off comments
- if($line =~ m:\*/:)
+ # Push any remaining token
+ if(@thistoken > 0)
{
- $line =~ s:/\*.*\*/::g;
- return $line;
+ push(@outargs, join("",@thistoken));
}
- return $line;
+ return @outargs;
}
+###############################################################################
#/*@@
-# @routine Warning
-# @date Wed Sep 15 14:28:11 1999
+# @routine ParseAndExpand
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Prints a warning to stderr.
+# Parse a string and expand any macros in it.
# @enddesc
# @calls
# @calledby
@@ -564,28 +894,95 @@ sub StripComments
# @endhistory
#
#@@*/
-
-sub Warning
+sub ParseAndExpand
{
- my($message) = @_;
- my($number);
-
- print STDERR "$message at " . $filelist[$#filelist] . " line $.\n";
+ my ($line,$filename, $linenumber) = @_;
+
+ # Split the line into individual characters.
+ my @splitline = split(//, $line);
+
+ my @outline = ();
+ my $retcode = 0;
- for($number = $#filelist -1; $number >= 0; $number--)
+ for(my $pos = 0 ; $pos < @splitline; $pos++)
{
- print STDERR " opened from $filelist[$number] line $linelist[$number]\n";
+ if($splitline[$pos] !~ m/[A-Za-z_]/)
+ {
+ push(@outline, $splitline[$pos]);
+ next;
+ }
+
+ # Ok, should be at the beginning of a token
+
+ my $token = $splitline[$pos];
+
+ while($pos+1 < @splitline && $splitline[$pos+1] =~ m:[A-Za-z0-9_]:)
+ {
+ $pos++;
+ $token .= $splitline[$pos];
+ }
+
+ # Is this token a macro ?
+ if($defines{$token})
+ {
+ my $arg = "";
+ if($pos+1 < @splitline)
+ {
+ # Find any arguments
+ if($splitline[$pos+1] eq "(")
+ {
+ $pos++;
+ my $depth = 1;
+ $pos++;
+ while($pos < @splitline && $depth > 0)
+ {
+ if($splitline[$pos] eq "(")
+ {
+ $depth++;
+ }
+ elsif($splitline[$pos] eq ")")
+ {
+ $depth--;
+ }
+ if($depth > 0)
+ {
+ $arg .= $splitline[$pos];
+ $pos++;
+ }
+ }
+ }
+ }
+ if($debug)
+ {
+ print "Token is '$token', arguments are '$arg'\n";
+ }
+ # Expand the macro
+ my($expanded,$retval) = &ExpandMacro($token,$arg,$filename,$linenumber);
+ $retcode += $retval;
+ if($debug)
+ {
+ print "Expanded version is '$expanded'\n";
+ }
+ #Put the final expanded version into output.
+ push(@outline, $expanded);
+ }
+ else
+ {
+ push(@outline, $token);
+ }
}
- return 0;
+ return (join("",@outline),$retcode);
}
+###############################################################################
+
#/*@@
-# @routine IfLine
-# @date Wed Sep 15 14:57:22 1999
+# @routine ArgumentSubstitute
+# @date Mon Nov 19 23:51:03 2001
# @author Tom Goodale
# @desc
-# Parses a #if line
+# Substitute all non-string-enclosed arguments with replacement values.
# @enddesc
# @calls
# @calledby
@@ -594,45 +991,94 @@ sub Warning
# @endhistory
#
#@@*/
-sub IfLine
+sub ArgumentSubstitute
{
- my($statements) = @_;
- my(@tokens);
- my($toknum);
- my($state);
+ my ($body, $nargs, @args) = @_;
- @tokens = split(/(\W+)/, $statements);
+ my @splitbody = split(//,$body);
+ my @outbody = ();
- $state = 0;
- $toknum = 0;
- $lastop = "||";
+ my $instring = 0;
- while($toknum <= $#tokens)
+ for(my $pos = 0 ; $pos < @splitbody; $pos++)
{
- if($tokens[$toknum] =~ m:^defined$:)
+
+ # Just pass through all non-tokens and all tokens in a string.
+ if($splitbody[$pos] !~ m/[A-Za-z_]/ || $instring == 1)
{
- $currstate = &defined($tokens[$toknum+2]);
-
- eval "$state = $state $lastop $currstate";
- $toknum +=4
+ if($splitbody[$pos] eq '"')
+ {
+ if($pos == 0 || ($pos > 0 && $splitbody[$pos-1] ne '\\'))
+ {
+ $instring = 1 - $instring;
+ }
+ }
+ push(@outbody, $splitbody[$pos]);
+ next;
}
- elsif($tokens[$toknum] =~ m:\|\||\&\&:)
+
+ # Ok, should be at the beginning of a token
+
+ my $token = $splitbody[$pos];
+
+ while($pos+1 < @splitbody && $splitbody[$pos+1] =~ m:[A-Za-z0-9_]:)
{
- $lastop = $token[$toknum];
- $token++;
+ $pos++;
+ $token .= $splitbody[$pos];
}
- else
+
+ if($debug)
{
- $currstate = &defined($tokens[$toknum]);
+ print "Token is '$token'\n";
+ }
- eval "$state = $state $lastop $currstate";
- $toknum ++;
+ for(my $arg = 0; $arg < $nargs; $arg++)
+ {
+ if($token =~ m/^$args[$arg]$/)
+ {
+ $token = $args[$arg+$nargs];
+ last;
+ }
}
-
+
+ push(@outbody, $token);
}
- return $state;
+ return join("", @outbody);
}
+###############################################################################
+
+#/*@@
+# @routine Print Defines
+# @date Mon Nov 19 23:51:03 2001
+# @author Tom Goodale
+# @desc
+# Print all the macros in the symbol table.
+# @enddesc
+# @calls
+# @calledby
+# @history
+#
+# @endhistory
+#
+#@@*/
+sub PrintDefines
+{
+ my $def;
+
+ foreach $def (sort keys %defines)
+ {
+ print "Macro '$def'\n";
+ print @{$defines{$def}{"ARGS"}} . " arguments\n";
+ if (@{$defines{$def}{"ARGS"}})
+ {
+ for (my $arg = 0 ; $arg < @{$defines{$def}{"ARGS"}}; $arg++)
+ {
+ print "$arg: $defines{$def}{\"ARGS\"}[$arg]\n";
+ }
+ }
+ print "Body '$defines{$def}{\"BODY\"}'\n";
-
+ }
+}