#!/usr/bin/perl # This script translates a simple definition-based grammar # to either C, sh, Javascript, or in (in = identity grammar, i.e. # same grammar as input). # # Input grammar: # (1) comments having ';' or '#' as the first char in the line # (2) a blank line # (3) !include "file" # (4) !define foo bar # (5) !define foo "bar" # # Environmental variables can be used to override a setting. # The special value "null" causes the variable to be undefined. # If an environmental value is bracketed, i.e [abc], the brackets # will be converted to double quotes prior to output. sub comment { my ($cmt) = @_; print "//$cmt\n" if ($mode =~ /^(c|js|h)$/); print "#$cmt\n" if ($mode =~ /^(sh|nsi|in)$/); } sub define { my ($name, $value) = @_; if ($mode eq "sh") { $value="true" if !$value; print "[ -z \"\$$name\" ] && export $name=$value\n"; print "[ \"\$$name\" = \"$nulltag\" ] && unset $name\n"; } else { if ($ENV{$name}) { $value = $ENV{$name}; $value = "\"$1\"" if ($value =~ /\[(.*)\]$/); } if ($value ne $nulltag) { print "#define $name $value\n" if ($mode =~ /^(c|h)$/); print "!define $name $value\n" if ($mode =~ /^(nsi|in)$/); print "var $name=$value;\n" if ($mode eq "js"); } else { print "//#undef $name\n" if ($mode =~ /^(c|h)$/); print "#!undef $name\n" if ($mode eq "nsi"); print ";!undef $name\n" if ($mode eq "in"); print "//undef $name\n" if ($mode eq "js"); } } } sub include_file { local $_; $include_file_level++; die "!include file nesting too deep" if ($include_file_level > $max_inc_depth); my ($parm) = @_; my $fn = "$incdir/$parm"; local *IN; open(IN, "< $fn") or die "cannot open $fn"; while () { chomp; if (/^\s*$/) { print "\n"; } elsif (/^[#;](.*)$/) { comment ($1); } elsif (/^!define\s+(\w+)(?:\s+(.*?))?\s*$/) { define ($1, $2); } elsif (/^!include\s+"(.+)"$/) { include_file ($1); } else { die "can't parse this line: $_\n"; } } $include_file_level--; } die "usage: trans [-I] [files ...]" if (@ARGV < 1); ($mode) = shift(@ARGV); die "mode must be one of c, h, sh, js, nsi, or in" if !($mode =~ /^(c|h|sh|js|nsi|in)$/); $nulltag = "null"; $max_inc_depth = 10; $include_file_level = 0; $incdir = "."; comment(" This file was automatically generated by trans.pl"); while ($arg=shift(@ARGV)) { if ($arg =~ /^-/) { if ($arg =~ /^-I(.*)$/) { $incdir = $1; } else { die "unrecognized option: $arg"; } } else { print "\n"; include_file ($arg); } }