#!/usr/bin/env perl # # Yet another preprocessor # # $Id: yapp,v 1.5 1997/10/24 07:51:05 mhw Exp $ # %vars = ('' => '$'); @incPath = ("."); sub Error { print STDERR $_[0], "\n"; exit(1); } sub VarSubst { my ($varName, $undefOkay) = @_; if (defined($vars{$varName})) { return $vars{$varName}; } elsif (!$undefOkay) { &Error("Undefined variable '$varName' in $fileName line $."); } } sub NullFilter { 0; } sub IfFilter { local $_ = $_[0]; if (/^##else(\s+.*)?/) { return 1; } elsif (/^##endif(\s+.*)?/) { return 2; } else { return 0; } } sub DoFile { local $fileName = $_[0]; my $path; local *FILE; if ($fileName =~ m|^/|) { $path = $fileName; } else { for $dir (@incPath) { if (-e "$dir/$fileName") { $path = "$dir/$fileName"; last; } } } if ($path eq "") { &Error("Can't find '$fileName', from $fileName line $."); } open(FILE, "<$path") || &Error("Can't open $path: $!"); &DoOpenFile(*FILE, *NullFilter, 0); close(FILE) || die; 0; } sub DoPrepass { local ($_, $skipFlag) = @_; return "" if /^###/; s/\s*###.*//; # Strip comments s/\$\{(\w+)}/&VarSubst($1, $skipFlag)/eg; # Do variable substitutions $_; } sub DoOpenFile { local *FILE = $_[0]; local *filter = $_[1]; my $skipFlag = $_[2]; my $result; local $_; while () { $_ = &DoPrepass($_, $skipFlag); if ($result = &filter($_)) { return $result; } elsif (/^##(\w*)(\s+(.*))?/) { my ($cmd, $params) = ($1, $3); if ($cmd =~ /^if/) { my $condition; my $ifStartLine = $.; if ($cmd eq "if") { if ($params =~ /^(\d+)\s*$/) { $condition = int($1); } elsif ($params =~ /^(\d+)\s*([=!]=|[<>]=?)\s*(\d+)\s*$/) { my ($left, $op, $right) = ($1, $2, $3); $condition = eval($left . $op . $right); } elsif ($params =~ /^(\S+)\s*(eq|ne)\s*(\S+)\s*$/) { my ($left, $op, $right) = ($1, $2, $3); $left =~ s/([\\'])/\\$1/g; $right =~ s/([\\'])/\\$1/g; $condition = eval("'$left' $op '$right'"); } else { &Error("Invalid ##if params: '$params' " . "in $fileName line $."); } } elsif ($cmd =~ /^ifn?def$/) { if ($params =~ /^(\w+)\s*$/) { $condition = defined($vars{$1}); $condition = !$condition if ($cmd eq "ifndef"); } else { &Error("Invalid ##$cmd param: '$params' " . "in $fileName line $."); } } # Do main body of if $result = &DoOpenFile(*FILE, *IfFilter, $skipFlag || !$condition); if ($result == 1) # an '##else' was found { # Handle else $result = &DoOpenFile(*FILE, *IfFilter, $skipFlag || $condition); } if ($result == 1) # a second '##else' was found { &Error("Two ##else's in a row in $fileName line $."); } elsif ($result == 0) # EOF was encountered { &Error("Unterminated ##if " . "in $fileName line $ifStartLine"); } } elsif ($cmd eq "include") { if ($skipFlag) { } elsif ($params =~ /^"(.*)"\s*$/) { my $incFile = $1; &DoFile($incFile); } else { &Error("Invalid ##include params: '$params'"); } } elsif ($cmd eq "set") { if ($params =~ /^(\w+)=<<(")(.*)"\s*$/ or $params =~ /^(\w+)=<<(')(.*)'\s*$/) { my $varName = $1; my $quoteChar = $2; my $endTag = $3 . "\n"; my $value; while () { if ($_ eq $endTag) { chop $value; last; } else { if ($quoteChar eq '"') { $_ = &DoPrepass($_, $skipFlag); } $value .= $_; } } if (!$skipFlag) { $vars{$varName} = $value; } } elsif ($params =~ /^(\w+)="(.*)"\s*$/ or $params =~ /^(\w+)=(\S*)\s*$/) { if (!$skipFlag) { $vars{$1} = $2; } } else { &Error("Invalid ##set command: '$params'"); } } else { &Error("Unrecognized command: '$_'"); } } elsif (!$skipFlag) { print; } } return 0; } $optEnable = 1; foreach (@ARGV) { if ($optEnable and /^-/) { if (/^--$/) { $optEnable = 0; } elsif (/^-D(\w+)=(.*)$/) { $vars{$1} = $2; } elsif (/^-I(.*)$/) { unshift @incPath, $1; } else { &Error("Unrecognized option: '$_'"); } } else { &DoFile($_); } } # # vi: ai ts=4 # vim: si #