|  | # | 
|  | # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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*\&\&/s) { | 
|  | $_ = "0"; | 
|  | } elsif(/^1\s*\|\|/s) { | 
|  | $_ = "1"; | 
|  | } | 
|  |  | 
|  | if (/^(!\s*)?defined\s*\(\s*(\w+)\s*\)\s*(?:(\&\&|\|\|)\s*)?/s || | 
|  | /^(!\s*)?defined\s*(\w+)\s*(?:(\&\&|\|\|)\s*)?/s) | 
|  | { | 
|  | $_ = $'; | 
|  |  | 
|  | my $sign = $1; | 
|  | my $var = $2; | 
|  |  | 
|  | if (defined($sign) && $sign eq "!") { | 
|  | $self->undefine($var); | 
|  | push @$stack, $var; | 
|  | } else { | 
|  | $self->define($var); | 
|  | push @$stack, $var; | 
|  | } | 
|  | } elsif (/^(!\s*)?(\w+)\s*(?:(<|<=|==|!=|>=|>|\+|\-|\*\/)\s*(\w+)\s*)?(?:(\&\&|\|\|)\s*)?/s) { | 
|  | $_ = $'; | 
|  |  | 
|  | my $sign = $1; | 
|  | my $var = $2; | 
|  |  | 
|  | if (defined($sign) && $sign eq "!") { | 
|  | $self->undefine($var); | 
|  | push @$stack, $var; | 
|  | } else { | 
|  | $self->define($var); | 
|  | push @$stack, $var; | 
|  | } | 
|  | } elsif(/^(!\s*)?\(/s) { | 
|  | $_ = ""; | 
|  | } 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; |