| # |
| # Copyright 1999, 2000, 2001 Patrik Stridvall |
| # |
| # This library is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU Lesser General Public |
| # License as published by the Free Software Foundation; either |
| # version 2.1 of the License, or (at your option) any later version. |
| # |
| # This library is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with this library; if not, write to the Free Software |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| # |
| |
| package preprocessor; |
| |
| use strict; |
| |
| sub new { |
| my $proto = shift; |
| my $class = ref($proto) || $proto; |
| my $self = {}; |
| bless ($self, $class); |
| |
| my $state = \%{$self->{STATE}}; |
| my $stack = \@{$self->{STACK}}; |
| my $include_found = \${$self->{INCLUDE_FOUND}}; |
| my $conditional_found = \${$self->{CONDITIONAL_FOUND}}; |
| |
| $$include_found = shift; |
| $$conditional_found = shift; |
| |
| return $self; |
| } |
| |
| sub include { |
| my $self = shift; |
| my $include_found = \${$self->{INCLUDE_FOUND}}; |
| |
| my $argument = shift; |
| |
| &$$include_found($argument); |
| } |
| |
| sub define { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $conditional_found = \${$self->{CONDITIONAL_FOUND}}; |
| |
| my $name = shift; |
| |
| $$state{$name} = "def"; |
| |
| &$$conditional_found($name); |
| } |
| |
| sub undefine { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $conditional_found = \${$self->{CONDITIONAL_FOUND}}; |
| |
| my $name = shift; |
| |
| $$state{$name} = "undef"; |
| |
| &$$conditional_found($name); |
| } |
| |
| sub begin_if { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $stack = \@{$self->{STACK}}; |
| |
| my $directive = shift; |
| local $_ = shift; |
| |
| while(!/^$/) { |
| if(/^0\s*\&\&/) { |
| $_ = "0"; |
| } elsif(/^1\s*\|\|/) { |
| $_ = "1"; |
| } |
| |
| if(/^(!)?defined\s*\(\s*(.+?)\s*\)\s*((\&\&|\|\|)\s*)?/){ |
| $_ = $'; |
| if(defined($1) && $1 eq "!") { |
| $self->undefine($2); |
| push @$stack, $2; |
| } else { |
| $self->define($2); |
| push @$stack, $2; |
| } |
| } elsif(/^(\w+)\s*(<|<=|==|!=|>=|>)\s*(\w+)\s*((\&\&|\|\|)\s*)?/) { |
| $_ = $'; |
| } elsif(/^(!)?(\w+)\s*$/) { |
| $_ = $'; |
| } elsif(/^\(|\)/) { |
| $_ = $'; |
| } else { |
| print "*** Can't parse '#$directive $_' ***\n"; |
| $_ = ""; |
| } |
| } |
| } |
| |
| sub else_if { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $stack = \@{$self->{STACK}}; |
| |
| my $argument = shift; |
| |
| $self->end_if; |
| |
| if(defined($argument)) { |
| $self->begin_if("elif", $argument); |
| } |
| } |
| |
| sub end_if { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $stack = \@{$self->{STACK}}; |
| |
| my $macro = pop @$stack; |
| delete $$state{$macro} if defined($macro); |
| } |
| |
| sub directive { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| my $stack = \@{$self->{STACK}}; |
| |
| my $directive = shift; |
| my $argument = shift; |
| |
| local $_ = $directive; |
| if(/^if$/) { |
| $self->begin_if("if",$argument); |
| } elsif(/^ifdef$/) { |
| $self->begin_if("if", "defined($argument)"); |
| } elsif(/^ifndef$/) { |
| $self->begin_if("if", "!defined($argument)"); |
| push @$stack, $argument; |
| } elsif(/^elif$/) { |
| $self->else_if($argument); |
| } elsif(/^else$/) { |
| $self->else_if; |
| } elsif(/^endif$/) { |
| $self->end_if; |
| } elsif(/^include/) { |
| $self->include($argument); |
| } |
| } |
| |
| sub is_def { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| |
| my $name = shift; |
| |
| my $status = $$state{$name}; |
| |
| return defined($status) && $status eq "def"; |
| } |
| |
| sub is_undef { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| |
| my $name = shift; |
| |
| my $status = $$state{$name}; |
| |
| return defined($status) && $status eq "undef"; |
| } |
| |
| sub is_unknown { |
| my $self = shift; |
| my $state = \%{$self->{STATE}}; |
| |
| my $name = shift; |
| |
| my $status = $$state{$name}; |
| |
| return !defined($status); |
| } |
| |
| 1; |