# pX/Common/p6compiler.pl - fglock # # experimental implementation of a p6 compiler # use strict; use warnings; no warnings 'redefine'; require 'p6rule.pl'; require 'emit.pl'; require 'interface.pm'; my @OLD_ARGV = @ARGV; RESTART: @ARGV = @OLD_ARGV; undef $interface::got_options; interface->import; # TODO: see TASKS file { package grammar1; no warnings 'once'; use vars qw( @statements @terms @ops ); *immediate_statement_exec = sub { my $match = immediate_statement_rule( @_ ); # print "immediate_statement_exec: BEGIN AST: \n", Dumper( $match->{capture} ); return $match unless $match->{bool}; # print "immediate_statement_exec: BEGIN AST: \n", Dumper( $match->{capture} ); my $program = Perl6Grammar::emit( $match->{capture} ); #print "immediate_statement_exec: matching ###$_[0]###\n"; #print "immediate_statement_exec: eval'ing code:\n###$program###\n"; no strict 'refs'; my $code = eval($program); print "Error in statement:\n", $program if $@; die "error in immediate_statement_exec: " . $@ if $@; # print "immediate_statement_exec: CODE[ $code ]\n"; return { %$match, capture => [ { perl5 => $program } ], } }; # load/precompile Prelude(s) my $recompile; for my $prelude_file ( 'p6prelude', 'p6primitives', ) { # loading the prelude is always required, even if it is out of date! warn "* loading Prelude: $prelude_file-cached.pl\n"; require "$prelude_file-cached.pl"; if ( -f "$prelude_file-cached.pl" ) { $recompile = -M "$prelude_file-cached.pl" > -M "$prelude_file.pl"; } else { $recompile = 1; } if ( $recompile ) { local $/ = undef; warn "* precompiling Prelude: $prelude_file.pl\n"; open( FILE, "<", "$prelude_file.pl" ) or die "can't open prelude file: $prelude_file.pl - $!"; my $prelude = ; # print "Prelude:$prelude\n"; my $perl5; { no warnings 'redefine'; $perl5 = Perl6Grammar::compile( $prelude ); } # print "MATCH\n", Dumper($match), "END MATCH\n"; warn "* caching Prelude: $prelude_file-cached.pl\n"; open( FILE, ">", "$prelude_file-cached.pl" ) or die "can't open prelude file: $prelude_file-cached.pl - $!"; print FILE "# Generated file - do not edit!\n" . $perl5; close FILE; warn "*** restarting the compilation to use the new prelude...\n"; goto RESTART; } else { ## print "* loading Prelude: $prelude_file-cached.pl\n"; ## require "$prelude_file-cached.pl"; } } { my $filename = shift || die "no filename"; if ($filename eq '-') { warn "* compiling source from STDIN\n"; *FILE = *STDIN } else { warn "* compiling: $filename\n"; open( FILE, "<", $filename ) or die "can't open file: $filename - $!"; } local $/ = undef; my $source = ; my $perl5 = Perl6Grammar::compile( $source,{ print_ast => $interface::print_ast, print_program => $interface::print_program, print_match => $interface::print_match }); } exit; } # ------ emitter my $namespace = 'grammar1::'; { package Perl6Grammar; use p6dump; sub header { return <value} ); # # flags: # print_program=>1 - prints the generated program # sub compile { #print "compile: matching: \n$_[0]\n"; my $match = grammar1::grammar->( $_[0] ); #print "compile: matched.\n"; my $flags = $_[1]; die "compile: syntax error in program '$_[0]' at '" . $match->{tail} . "'\n" if $match->{tail}; die "compile: syntax error in program '$_[0]'\n" unless $match->{bool}; if ($flags->{print_match}) { print dump_tree($match,'match'); } if ($flags->{print_ast}) { print dump_tree($match->{capture},'ast'); } my $program = emit( $match->{capture} ); if ($flags->{print_program}) { my $sum = sprintf('%08X', unpack('%32N*', $_[0])); print "# Generated file - do not edit!\n"; print << "..."; ##################((( 32-bit Checksum Validator )))################## BEGIN { use 5.006; local (*F, \$/); (\$F = __FILE__) =~ s!c\$!!; open(F) or die "Cannot open \$F: \$!"; binmode(F, ':crlf'); unpack('%32N*',) == 0x$sum or die "Checksum failed for outdated .pmc file: \${F}c"} ##################################################################### ... print $program; } return $program; } sub get_data { match::get( { capture => $_[0] }, $_[1] ) } sub get_str { match::str( get_data( @_ ) ) } # XXX not used - intended to bind variables in a macro, when it returns an AST # instead of string sub bind_variable { my $n = $_[0]; my ( $var_name, $value ) = @_; #print ref($n),"\n"; if ( ref( $n ) eq 'ARRAY' ) { bind_variable( $_, @_[1,2] ) for @$n; } elsif ( ref( $n ) eq 'HASH' ) { #print Dumper($n); my ( $k ) = keys %$n; my $v = $n->{$k}; #print "*** $k, $v \n"; #return unless defined $k; return bind_variable( $v, @_[1,2] ) if ref( $v ); if ( $k eq 'variable' && $v eq $_[1] ) { #print "subst $k $v @_[1,2] ",$_[0]->{$k}, "\n"; $_[0]->{$k} = $_[2]; } } } } # /package 1;