diff options
author | goodale <goodale@17b73243-c579-4c4c-a9d2-2d5706c11dac> | 2001-11-20 00:36:21 +0000 |
---|---|---|
committer | goodale <goodale@17b73243-c579-4c4c-a9d2-2d5706c11dac> | 2001-11-20 00:36:21 +0000 |
commit | 8140e77075a3a4c4c3b9ba453928d2a336012573 (patch) | |
tree | 9f3ef41bf3d2ec3c314733fc3606bc30e05b610a /lib/sbin/cpp.pl | |
parent | cb1ab63b14165b33cf65e62abea3d3fb02ee9eb5 (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-x | lib/sbin/cpp.pl | 1064 |
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"; - + } +} |