#! /usr/bin/perl # # C - a pseudo-interpreter of the C programming language # http://labs.cybozu.co.jp/blog/kazuhoatwork/ # # Copyright (C) 2006 Cybozu Labs, Inc. # # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # use strict; use warnings; use Getopt::Std; use POSIX qw(tmpnam); my $VERSION = 0.01; sub usage { print <<"EOF"; C - a pseudo interpreter of the C programming language (version $VERSION) http://labs.cybozu.co.jp/blog/kazuhoatwork/ Usage: $0 [options] [source_file] [argv] Example: C -cO2 -e 'printf("hello world\\n")' Options: -c pass an option to gcc -i add an include file -e expression executes the expression -h, --help displays this help message EOF ; exit 0; } my $src_text; my $out_file = tmpnam(); my $src_file = "$out_file.c"; my $includes = "#include \n#include \n"; my @gcc_opts; sub cleanup { unlink($src_file); unlink($out_file); } # parse args while ($#ARGV <=> -1 && $ARGV[0] =~ /^-/) { my $arg = shift(@ARGV); if ($arg =~ /^-c/) { push(@gcc_opts, "-$'"); } elsif ($arg eq '-e') { $src_text = $#ARGV <=> -1 ? shift(@ARGV).';' : undef; } elsif ($arg =~ /^-i/) { $includes .= "#include \"$'\"\n"; } elsif ($arg eq '-h' || $arg eq '--help') { usage(); } else { print STDERR "unknown option: $arg\n"; exit(255); } } if (! defined($src_text)) { my $file; my $fd; if ($#ARGV <=> -1) { $file = shift(@ARGV); open($fd, $file) || die "cannot open file: $file\n"; } else { $fd = \*STDIN; } while (my $l = <$fd>) { $src_text .= $l unless $l =~ /^#!/; } close($fd) if defined($file); } # build source $src_text =<<"EOF"; $includes int main(int argc, char** argv) { #line 1 $src_text return 0; } EOF ; # save source file my $fd; open($fd, "> $src_file") || die "cannot create source file: $src_file\n"; print $fd $src_text; close($fd); # compile system('gcc', @gcc_opts, '-o', $out_file, $src_file); cleanup() if ($? <=> 0); die "failed to execute gcc\n" if $? == 1; exit($? >> 8) if $? <=> 0; # execute system($out_file, @ARGV); cleanup(); die "failed to execute the generated binary\n" if $? == 1; exit($? >> 8) if $? <=> 0;