diff --git a/MAINTAINER b/MAINTAINER new file mode 100644 index 0000000..946e2ad --- /dev/null +++ b/MAINTAINER @@ -0,0 +1,7 @@ +# $Id: MAINTAINER 25984 2008-02-22 12:18:20Z kjs $ + +N: Kevin Tew +E: kevintew@tewk.com + +N: Klaas-Jan Stol (kjs) +E: parrotcode@gmail.com diff --git a/c99.pir b/c99.pir new file mode 100644 index 0000000..df2139f --- /dev/null +++ b/c99.pir @@ -0,0 +1,80 @@ +# $Id: c99.pir 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=head1 TITLE + +c99.pir - A C99 compiler. + +=head2 Description + +This is the base file for the C99 compiler. + +This file includes the parsing and grammar rules from +the src/ directory, loads the relevant PGE libraries, +and registers the compiler under the name 'C99'. + +=head2 Functions + +=over 4 + +=item onload() + +Creates the C compiler using a C +object. + +=cut + +.namespace [ 'C99';'Compiler' ] + +.loadlib 'c99_group' + +.sub 'onload' :anon :load :init + load_bytecode 'PCT.pbc' + + $P0 = get_hll_global ['PCT'], 'HLLCompiler' + $P1 = $P0.'new'() + $P1.'language'('C99') + $P1.'parsegrammar'('C99::Grammar') + $P1.'parseactions'('C99::Grammar::Actions') +.end + +=item main(args :slurpy) :main + +Start compilation by passing any command line C +to the C compiler. + +=cut + +.sub 'main' :main + .param pmc args + + $P0 = compreg 'C99' + $P1 = $P0.'command_line'(args) +.end + + +.include 'src/gen_builtins.pir' +.include 'src/gen_grammar.pir' +.include 'src/gen_actions.pir' + + +.namespace [ 'C99';'Grammar' ] + +.sub 'debug' + .param pmc match + .param pmc arg + .param pmc attrs :slurpy + printerr arg + printerr "\n" +.end + +=back + +=cut + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: + diff --git a/config/makefiles/cpp.in b/config/makefiles/cpp.in new file mode 100644 index 0000000..f2caa5f --- /dev/null +++ b/config/makefiles/cpp.in @@ -0,0 +1,102 @@ +# Copyright (C) 2008-2009, Parrot Foundation. +## $Id: cpp.in 36833 2009-02-17 20:09:26Z allison $ + +## arguments we want to run parrot with +PARROT_ARGS = + +## configuration settings +BUILD_DIR = @build_dir@ +LOAD_EXT = @load_ext@ +O = @o@ + +## Setup some commands +PERL = @perl@ +RM_F = @rm_f@ +CP = @cp@ +CAT = @cat@ +PARROT = ../../../../parrot@exe@ +BUILD_DYNPMC = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.pl +RECONFIGURE = $(PERL) $(BUILD_DIR)/tools/dev/reconfigure.pl + +## places to look for things +PARROT_DYNEXT = $(BUILD_DIR)/runtime/parrot/dynext +PGE_LIBRARY = $(BUILD_DIR)/runtime/parrot/library/PGE +PERL6GRAMMAR = $(PGE_LIBRARY)/Perl6Grammar.pbc +NQP = $(BUILD_DIR)/compilers/nqp/nqp.pbc +PCT = $(BUILD_DIR)/runtime/parrot/library/PCT.pbc + +PMC_DIR = src/pmc + +all: cpp.pbc + +SOURCES = cpp.pir \ + src/gen_grammar.pir \ + src/gen_actions.pir \ + src/gen_builtins.pir + +BUILTINS_PIR = \ + src/builtins/say.pir + +# the default target +cpp.pbc: $(PARROT) $(SOURCES) + $(PARROT) $(PARROT_ARGS) -o cpp.pbc cpp.pir + $(CP) cpp.pbc ../../cpp.pbc + +src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg + $(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \ + --output=src/gen_grammar.pir \ + src/parser/grammar.pg + +src/gen_actions.pir: $(NQP) $(PCT) src/parser/actions.pm + $(PARROT) $(PARROT_ARGS) $(NQP) --output=src/gen_actions.pir \ + --target=pir src/parser/actions.pm + +src/gen_builtins.pir: $(BUILTINS_PIR) + $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir + +# regenerate the Makefile +Makefile: ../../config/makefiles/cpp.in + cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=c99 + +# This is a listing of all targets, that are meant to be called by users +help: + @echo "" + @echo "Following targets are available for the user:" + @echo "" + @echo " all: c.pbc" + @echo " This is the default." + @echo "Testing:" + @echo " test: Run the test suite." + @echo " testclean: Clean up test results." + @echo "" + @echo "Cleaning:" + @echo " clean: Basic cleaning up." + @echo " realclean: Removes also files generated by 'Configure.pl'" + @echo " distclean: Removes also anything built, in theory" + @echo "" + @echo "Misc:" + @echo " help: Print this help message." + @echo "" + +test: all + $(PERL) t/harness + +# this target has nothing to do +testclean: + +CLEANUPS = \ + cpp.pbc \ + "src/gen_*.pir" + +clean: + $(RM_F) $(CLEANUPS) + +realclean: clean + $(RM_F) Makefile + +distclean: realclean + +# Local variables: +# mode: makefile +# End: +# vim: ft=make: diff --git a/config/makefiles/root.in b/config/makefiles/root.in new file mode 100644 index 0000000..d45ec92 --- /dev/null +++ b/config/makefiles/root.in @@ -0,0 +1,113 @@ +# Copyright (C) 2006-2009, Parrot Foundation. +## $Id: root.in 36833 2009-02-17 20:09:26Z allison $ + +## arguments we want to run parrot with +PARROT_ARGS = + +## configuration settings +BUILD_DIR = @build_dir@ +LOAD_EXT = @load_ext@ +O = @o@ + +## Setup some commands +PERL = @perl@ +RM_RF = @rm_rf@ +CP = @cp@ +CAT = @cat@ +MAKE = @make_c@ +PARROT = ../../parrot@exe@ +BUILD_DYNPMC = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.pl +RECONFIGURE = $(PERL) $(BUILD_DIR)/tools/dev/reconfigure.pl +#IF(darwin): +#IF(darwin):# MACOSX_DEPLOYMENT_TARGET must be defined for OS X compilation/linking +#IF(darwin):export MACOSX_DEPLOYMENT_TARGET := @osx_version@ + +## places to look for things +PARROT_DYNEXT = $(BUILD_DIR)/runtime/parrot/dynext +PGE_LIBRARY = $(BUILD_DIR)/runtime/parrot/library/PGE +PERL6GRAMMAR = $(PGE_LIBRARY)/Perl6Grammar.pbc +NQP = $(BUILD_DIR)/compilers/nqp/nqp.pbc +PCT = $(BUILD_DIR)/runtime/parrot/library/PCT.pbc + +PMC_DIR = src/pmc + +all: c99.pbc cpp + +C_GROUP = $(PMC_DIR)/c_group$(LOAD_EXT) + +SOURCES = c99.pir \ + src/gen_grammar.pir \ + src/gen_actions.pir \ + src/gen_builtins.pir + +BUILTINS_PIR = \ + src/builtins/say.pir + +c99.pbc: $(PARROT) $(SOURCES) + $(PARROT) $(PARROT_ARGS) -o c99.pbc c99.pir + +src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg + $(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \ + --output=src/gen_grammar.pir \ + src/parser/grammar.pg + +src/gen_actions.pir: $(NQP) $(PCT) src/parser/actions.pm + $(PARROT) $(PARROT_ARGS) $(NQP) --output=src/gen_actions.pir \ + --target=pir src/parser/actions.pm + +src/gen_builtins.pir: $(BUILTINS_PIR) + $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir + +cpp: + $(MAKE) src/cpp + +# regenerate the Makefile +Makefile: config/makefiles/root.in + cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=c99 + +# This is a listing of all targets, that are meant to be called by users +help: + @echo "" + @echo "Following targets are available for the user:" + @echo "" + @echo " all: c.pbc" + @echo " This is the default." + @echo "Testing:" + @echo " test: Run the test suite." + @echo " testclean: Clean up test results." + @echo "" + @echo "Cleaning:" + @echo " clean: Basic cleaning up." + @echo " realclean: Removes also files generated by 'Configure.pl'" + @echo " distclean: Removes also anything built, in theory" + @echo "" + @echo "Misc:" + @echo " help: Print this help message." + @echo "" + +test: all + $(PERL) t/harness + $(MAKE) src/cpp test + +# this target has nothing to do +testclean: + +CLEANUPS = \ + c99.pbc \ + "src/gen_*.pir" + +clean: + $(RM_RF) $(CLEANUPS) + $(MAKE) src/cpp clean + +realclean: clean + $(RM_RF) Makefile + $(MAKE) src/cpp realclean + +distclean: realclean + $(MAKE) src/cpp distclean + +# Local variables: +# mode: makefile +# End: +# vim: ft=make: diff --git a/lib/Parrot/Test/C99.pm b/lib/Parrot/Test/C99.pm new file mode 100644 index 0000000..3f73f2e --- /dev/null +++ b/lib/Parrot/Test/C99.pm @@ -0,0 +1,90 @@ +# $Id: C99.pm 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2006, Parrot Foundation. + + +package Parrot::Test::C99; + +use strict; +use warnings; + +use File::Basename; + +=head1 Parrot::Test::C99 + +Provide language specific testing routines here... + +This is currently alarmingly similar to the generated subs in Parrot::Test. +Perhaps someone can do a better job of delegation here. + +=cut + +sub new { + return bless {}; +} + +sub output_is() { + my ( $self, $code, $output, $desc ) = @_; + + #print "@_\n"; + + my $count = $self->{builder}->current_test + 1; + $desc = 'C99 Test' unless $desc; + + my $lang_f = File::Spec->rel2abs( Parrot::Test::per_test( '.c', $count ) ); + my $out_f = File::Spec->rel2abs( Parrot::Test::per_test( '.out', $count ) ); + my $c99_out_f = File::Spec->rel2abs( Parrot::Test::per_test( '.c99.out', $count ) ); + my $c99_out_debug_f = File::Spec->rel2abs( Parrot::Test::per_test( '.c99.debug.out', $count ) ); + my $parrotdir = dirname $self->{parrot}; + + Parrot::Test::write_code_to_file( $code, $lang_f ); + + my $args = $ENV{TEST_PROG_ARGS} || ''; + +#my $gcc_cmd = "gcc $lang_f"; +#my $gcc_exit_code = Parrot::Test::run_command($gcc_cmd, CD => $self->{relpath}, STDOUT => $out_f, STDERR => $out_f ); +#my $gcc_output = Parrot::Test::slurp_file($out_f); + + my $c99_cmd = "$self->{parrot} $args languages/c99/c99.pbc $lang_f"; + my $c99_exit_code = Parrot::Test::run_command( + $c99_cmd, + CD => $self->{relpath}, + STDOUT => $c99_out_f, + STDERR => $c99_out_f + ); + my $c99_output = Parrot::Test::slurp_file($c99_out_f); + + my $pass = $self->{builder}->is_eq( $c99_output, "1" ); + +#my $pass = $self->{builder}->is_eq( $c99_output, $gcc_output, $desc ); +#$self->{builder}->diag("'$gcc_cmd' failed with exit code $gcc_exit_code") if $gcc_exit_code and not $pass; + $self->{builder}->diag("'$c99_cmd' failed with exit code $c99_exit_code") + if $c99_exit_code and not $pass; + + if ( not $pass ) { + my $c99_debug_cmd = "$self->{parrot} $args languages/c99/c99.pbc -d $lang_f"; + my $c99_debug_exit_code = Parrot::Test::run_command( + $c99_debug_cmd, + CD => $self->{relpath}, + STDOUT => $c99_out_debug_f, + STDERR => $c99_out_debug_f + ); + my $c99_debug_output = Parrot::Test::slurp_file($c99_out_debug_f); + } + + unless ( $ENV{POSTMORTEM} ) { + + #unlink $lang_f; + unlink $out_f; + unlink $c99_out_f; + } + return $pass; +} + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/src/CPP_AST2Constants.tg b/src/CPP_AST2Constants.tg new file mode 100644 index 0000000..fa6db61 --- /dev/null +++ b/src/CPP_AST2Constants.tg @@ -0,0 +1,190 @@ +=head1 NAME + +C99::CPPConstants Grammar -- A grammar for transforming an CPP AST to a Parrot constants file + +=head1 SYNOPSYS + +=head1 DESCRIPTION + +=cut + +#code = new 'CodeString' +#code.'emit'(" %0 = find_name '%1'", value, name) + +grammar C99::CPP::Constants::ConstantsGrammar is TGE::Grammar; + +transform root (C99::CPP::PAST::Node) :language('PIR') { + .local pmc code + code = new 'CodeString' + code .= "# DO NOT EDIT THIS FILE.\n" + code .= "#\n" + code .= "# This file is generated automatically from\n" + code .= "# ?? by c99 --constants \n" + code .= "#\n" + code .= "# Any changes made here will be lost.\n" + code .= "#\n" + $P0 = tree.get('pir', node) + $S0 = $P0 + code .= $S0 + .return (code) +} + +transform pir (C99::CPP::PAST::Node) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir (C99::CPP::PAST::IF_SECTION) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir(C99::CPP::PAST::IFNDEF) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir(C99::CPP::PAST::IFDEF) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir(C99::CPP::PAST::IF) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir(C99::CPP::PAST::ELIF) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + +transform pir(C99::CPP::PAST::ELSE) :language('PIR') { + .local pmc code + .local pmc iter + code = new 'CodeString' + iter = node.'child_iter'() + iter_loop: + unless iter, iter_end + $P0 = shift iter + $P1 = tree.get('pir', $P0) + code .= $P1 + goto iter_loop + iter_end: + .return (code) +} + + +transform pir(C99::CPP::PAST::DEFINE) :language('PIR') { + .local pmc code + code = new 'CodeString' + $S0 = node.'name'() + $S1 = node.'line'() + code.'emit'(" .macro_const %0 %1", $S0, $S1) + .return (code) +} +transform pir(C99::CPP::PAST::DEFINE_FUNCTION) :language('PIR') { + .local pmc code + code = new 'CodeString' + $S0 = node.'name'() + $S1 = node.'line'() + code.'emit'(" .macro_const %0 = %1", $S0, $S1) + .return (code) +} +transform pir(C99::CPP::PAST::INCLUDE) :language('PIR') { + .local pmc code + .return ("") +} +transform pir(C99::CPP::PAST::ERROR) :language('PIR') { + .local pmc code + .return ("") +} +transform pir(C99::CPP::PAST::LINE) :language('PIR') { + .local pmc code + .return ("") +} +transform pir(C99::CPP::PAST::PRAGMA) :language('PIR') { + .local pmc code + .return ("") +} +transform pir(C99::CPP::PAST::SOURCE_LINE) :language('PIR') { + .local pmc code + .return ("") +} +transform pir(C99::CPP::PAST::WSNWS) :language('PIR') { + .local pmc code + .return ("") +} + +=head1 LICENSE + +Copyright (C) 2006, Parrot Foundation. + +This is free software; you may redistribute it and/or modify +it under the same terms as Parrot. + +=head1 AUTHOR + +Kevin Tew + +=cut diff --git a/src/CPP_ASTGrammar.tg b/src/CPP_ASTGrammar.tg new file mode 100644 index 0000000..310b4b3 --- /dev/null +++ b/src/CPP_ASTGrammar.tg @@ -0,0 +1,336 @@ +grammar C99::CPP::ASTGrammar is TGE::Grammar; + +transform result (ROOT) :language('PIR') { + debug_init + + .local pmc child + $I0 = defined node['group'] + unless $I0 goto err_no_tree + $P0 = node['group'] + child = tree.get('result', $P0, 'C99::CPP::ASTGrammar::group') + .return (child) + + err_no_tree: + print "The top-level node doesn't contain an 'group' match.\n" + end +} + +transform result (C99::CPP::ASTGrammar::group) :language('PIR') { + .local pmc child + .local pmc result + result = new 'C99::CPP::PAST::Node' + result.'init'() + + $I0 = defined node['group_line'] + unless $I0 goto err_no_tree + $P0 = node['group_line'] + + .local pmc iter + iter = new Iterator, $P0 + iter_loop: + unless iter, iter_end + $P1 = shift iter + child = tree.get('result', $P1, 'C99::CPP::ASTGrammar::group_line') + result.add_child(child) + goto iter_loop + iter_end: + .return (result) + + err_no_tree: + $S0 = "The group node doesn't contain an 'group_line' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::group_line) :language('PIR') { + .local pmc child + + $I0 = defined node['if_section'] + unless $I0 goto control_line + $P1 = node['if_section'] + child = tree.get('result', $P1, 'C99::CPP::ASTGrammar::if_section') + .return (child) + + control_line: + $I0 = defined node['control_line'] + unless $I0 goto source_line + $P1 = node['control_line'] + child = tree.get('result', $P1, 'C99::CPP::ASTGrammar::control_line') + .return (child) + + source_line: + $I0 = defined node['source_line'] + unless $I0 goto wsnws + $S0 = node + child = new 'C99::CPP::PAST::SOURCE_LINE' + child .'init'('line'=>$S0) + .return (child) + + wsnws: + $I0 = defined node['wsnws'] + unless $I0 goto err_no_tree + $S0 = node + child = new 'C99::CPP::PAST::WSNWS' + child .'init'('line'=>$S0) + .return (child) + + err_no_tree: + $S0 = "The group_line node doesn't contain an 'if_section' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::if_section) :language('PIR') { + .local pmc child + .local pmc result + result = new 'C99::CPP::PAST::IF_SECTION' + result.'init'('node'=>node) + + $I0 = defined node['if_group'] + unless $I0 goto err_no_tree + $P0 = node['if_group'] + child = tree.get('result', $P0, 'C99::CPP::ASTGrammar::if_group') + result.add_child(child) + + .local pmc iter + $I0 = defined node['elif_group'] + unless $I0 goto else_group + $P0 = node['elif_group'] + iter = new Iterator, $P0 + iter_loop: + unless iter, iter_end + $P1 = shift iter + child = tree.get('result', $P1, 'C99::CPP::ASTGrammar::elif_group') + result.add_child(child) + goto iter_loop + + else_group: + $I0 = defined node['else_group'] + unless $I0 goto return + $P0 = node['else_group'] + child = tree.get('result', $P0, 'C99::CPP::ASTGrammar::else_group') + result.add_child(child) + iter_end: + + return: + .return (result) + + err_no_tree: + $S0 = "The if_section node doesn't contain an 'if*_group' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::if_group) :language('PIR') { + .local pmc result + + $I0 = defined node['ifndef'] + unless $I0 goto ifdef_lbl + result = new 'C99::CPP::PAST::IFNDEF' + result.'init'('node'=>node) + goto parts + + ifdef_lbl: + $I0 = defined node['ifdef'] + unless $I0 goto if_lbl + $P0 = node['ifdef'] + result = new 'C99::CPP::PAST::IFDEF' + result.'init'('node'=>node) + goto parts + + if_lbl: + $I0 = defined node['if'] + unless $I0 goto err_no_tree + $P0 = node['if'] + result = new 'C99::CPP::PAST::IF' + result.'init'('node'=>node) + goto parts + + parts: + $I0 = defined node['identifier'] + unless $I0 goto constant_expression + $P0 = node['identifier'] + $S0 = $P0 + result.'line'($S0) + constant_expression: + $I0 = defined node['constant_expression'] + unless $I0 goto group + $P0 = node['constant_expression'] + $S0 = $P0 + result.'line'($S0) + group: + $I0 = defined node['group'] + unless $I0 goto err_no_tree + $P0 = node['group' ; 0] + $P1= tree.get('result', $P0, 'C99::CPP::ASTGrammar::group') + $P2 = $P1.'children'() + result.'append_children'($P2) + .return (result) + + + err_no_tree: + $S0 = "The if_group node doesn't contain an 'if*' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::elif_group) :language('PIR') { + .local pmc result + + $I0 = defined node['elif'] + unless $I0 goto err_no_tree + result = new 'C99::CPP::PAST::ELIF' + result.'init'('node'=>node) + + $I0 = defined node['constant_expression'] + unless $I0 goto err_no_tree + $P0 = node['constant_expression'] + $S0 = $P0 + result.'line'($S0) + group: + $I0 = defined node['group'] + unless $I0 goto err_no_tree + $P0 = node['group' ; 0] + $P1= tree.get('result', $P0, 'C99::CPP::ASTGrammar::group') + $P2 = $P1.'children'() + result.'append_children'($P2) + .return (result) + + + err_no_tree: + $S0 = "The elif_group node doesn't contain an 'if*' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::elif_group) :language('PIR') { + .local pmc result + + $I0 = defined node['elif'] + unless $I0 goto err_no_tree + result = new 'C99::CPP::PAST::ELIF' + result.'init'('node'=>node) + + $I0 = defined node['group'] + unless $I0 goto err_no_tree + $P0 = node['group' ; 0] + $P1= tree.get('result', $P0, 'C99::CPP::ASTGrammar::group') + $P2 = $P1.'children'() + result.'append_children'($P2) + .return (result) + + + err_no_tree: + $S0 = "The elif_group node doesn't contain an 'if*' match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +transform result (C99::CPP::ASTGrammar::control_line) :language('PIR') { + .local pmc child + .local pmc result + + $I0 = defined node['include'] + unless $I0 goto define_function_lbl + result = new 'C99::CPP::PAST::INCLUDE' + result.'init'('node'=>node) + bsr pp_tokens + .return (result) + + define_function_lbl: + $I0 = defined node['define_function'] + unless $I0 goto define_lbl + result = new 'C99::CPP::PAST::DEFINE_FUNCTION' + result.'init'('node'=>node) + $P0 = node['define_function'] + $S0 = $P0 + result.'name'($S0) + bsr pp_tokens + .return (result) + + define_lbl: + $I0 = defined node['define'] + unless $I0 goto undefine_lbl + result = new 'C99::CPP::PAST::DEFINE' + result.'init'('node'=>node) + $I0 = defined node['define_name'] + unless $I0 goto no_id + $P0 = node['define_name'] + $S0 = $P0 + result.'name'($S0) + no_id: + bsr pp_tokens + .return (result) + + undefine_lbl: + $I0 = defined node['undefine'] + unless $I0 goto line_lbl + result = new 'C99::CPP::PAST::UNDEFINE' + bsr pp_tokens + .return (result) + + line_lbl: + $I0 = defined node['line'] + unless $I0 goto error_lbl + result = new 'C99::CPP::PAST::LINE' + result.'init'('node'=>node) + bsr pp_tokens + .return (result) + + error_lbl: + $I0 = defined node['error'] + unless $I0 goto pragma_lbl + result = new 'C99::CPP::PAST::ERROR' + result.'init'('node'=>node) + bsr pp_tokens + .return (result) + + pragma_lbl: + $I0 = defined node['pragma'] + unless $I0 goto err_no_tree + result = new 'C99::CPP::PAST::PRAGMA' + result.'init'('node'=>node) + bsr pp_tokens + .return (result) + + pp_tokens: + $I0 = defined node['value'] + unless $I0 goto notoks1 + $P0 = node['value'] + $S0 = $P0 + result.'line'($S0) + notoks1: + ret + + err_no_tree: + print "The control_line node doesn't contain an appropriate match.\n" + print $S0 + .kdump(node) + print $S0 + end +} + +=head1 LICENSE + +Copyright (C) 2006, Parrot Foundation. + +This is free software; you may redistribute it and/or modify +it under the same terms as Parrot. + +=head1 AUTHOR + +Kevin Tew + +=cut diff --git a/src/CPP_PASTNodes.pir b/src/CPP_PASTNodes.pir new file mode 100644 index 0000000..16efee5 --- /dev/null +++ b/src/CPP_PASTNodes.pir @@ -0,0 +1,300 @@ +## $Id: CPP_PASTNodes.pir 31862 2008-10-10 18:23:45Z tene $ + +=head1 NAME + +C99::CPP::PAST - Abstract syntax tree nodes for C99 + +=head1 DESCRIPTION + +This file implements the various abstract syntax tree nodes +needed for C99. The currently defined ast nodes: + + C99::CPP::PAST::Node - base class for all ast nodes + +=head1 METHODS + +=over 4 + +=cut + +.include 'languages/c99/src/preamble' + +.HLL 'C99', 'c99_group' +.namespace [ 'C99';'CPP';'PAST' ] + +.sub '__onload' :load + .local pmc base, p6meta + p6meta = get_hll_global 'P6metaclass' + base = p6meta.'new_class'('C99::CPP::PAST::Node','attr'=>'children source pos name line') + + $P0 = p6meta.'new_class'('C99::CPP::PAST::IF_SECTION','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::IFNDEF','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::IFDEF','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::IF','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::ELIF','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::ELSE','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::DEFINE','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::DEFINE_FUNCTION','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::INCLUDE','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::ERROR','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::LINE','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::PRAGMA','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::SOURCE_LINE','parent'=>'C99::CPP::PAST::Node') + $P0 = p6meta.'new_class'('C99::CPP::PAST::WSNWS','parent'=>'C99::CPP::PAST::Node') + + + $P0 = new 'Integer' + $P0 = 10 + set_hll_global ['C99';'CPP';'PAST'], 'serial_number', $P0 + .return () +.end + + +.namespace [ 'C99';'CPP';'PAST';'Node' ] + +.sub 'attr' :method + .param string attrname + .param pmc value + .param int setvalue + if setvalue goto set + value = getattribute self, attrname + unless null value goto end + value = new .Undef + set: + setattribute self, attrname, value + end: + .return (value) +.end + + +.sub 'init' :method + .param pmc children :slurpy + .param pmc adverbs :slurpy :named + + unless null children goto set_children + children = new .ResizablePMCArray + set_children: + setattribute self, 'children', children + + if null adverbs goto end + .local pmc iter + iter = new .Iterator, adverbs + iter_loop: + unless iter goto iter_end + $S0 = shift iter + if $S0 == 'XXX' goto iter_loop + $P0 = iter[$S0] + $P1 = find_method self, $S0 + self.$P1($P0) + goto iter_loop + iter_end: + end: + .return () +.end + + +.sub 'new' :method + .param string class + .param pmc children :slurpy + .param pmc adverbs :slurpy :named + + $P0 = new class + $P0.'init'(children :flat, 'node'=>self, 'XXX'=>1, adverbs :flat :named) + .return ($P0) +.end + + +.sub 'add_child' :method + .param pmc child + .local pmc array + array = getattribute self, 'children' + push array, child + .return () + .end + +.sub 'append_children' :method + .param pmc children + .local pmc array + array = getattribute self, 'children' + array.'append'(children) + .return () +.end + + +.sub 'add_child_new' :method + .param string class + .param pmc children :slurpy + .param pmc adverbs :slurpy :named + $P0 = self.'new'(class, children :flat, 'XXX'=>0, adverbs :flat :named) + self.'add_child'($P0) + .return ($P0) +.end + +.gen_accessor('source') +.gen_accessor('pos') +.gen_accessor('name') +.gen_accessor('line') +.gen_get_accessor('children') + +.sub 'children' :method +# .param pmc value :optional +# .param int has_value :opt_flag + null $P0 + .return self.'attr'('children', $P0, 0) +.end + +.sub 'node' :method + .param pmc node + $I0 = isa node, ['C99';'CPP';'PAST';'Node'] + if $I0 goto clone_past + clone_pge: + $S0 = node + self.'source'($S0) + $I0 = node.'from'() + self.'pos'($I0) + .return () + clone_past: + $S0 = node.'source'() + self.'source'($S0) + $I0 = node.'pos'() + self.'pos'($I0) + .return () +.end + + +.sub 'child_iter' :method + $P0 = getattribute self, 'children' + $P1 = new .Iterator, $P0 + $P1 = 0 + .return ($P1) +.end + + +=item C + +Each call to C returns a unique number, or if a C +parameter is given it returns a unique string beginning with +C. (This may eventually be generalized to allow +uniqueness anywhere in the string.) The function starts +counting at 10 (so that the values 0..9 can be considered "safe"). + +=cut + +.sub 'unique' :method + .param string fmt :optional + .param int has_fmt :opt_flag + + if has_fmt goto unique_1 + fmt = '' + unique_1: + $P0 = get_hll_global ['C99';'CPP';'PAST'], 'serial_number' + $S0 = $P0 + $S0 = concat fmt, $S0 + inc $P0 + .return ($S0) +.end + + +.sub '__elements' :method + $P0 = getattribute self, 'children' + $I0 = elements $P0 + .return ($I0) +.end + + +.sub '__get_pmc_keyed_int' :method + .param int key + $P0 = getattribute self, 'children' + $P0 = $P0[key] + .return ($P0) +.end + + +.sub '__set_pmc_keyed_int' :method + .param int key + .param pmc val + $P0 = getattribute self, 'children' + $P0[key] = val + .return () +.end + +.sub '__get_string' :method + $P0 = getattribute self, 'name' + $S0 = $P0 + .return ($S0) +.end + + +.sub '__dumplist' :method + .return ('pos name children') +.end + + +.sub '__dump' :method + .param pmc dumper + .param string label + .local string indent, subindent + + (subindent, indent) = dumper.'newIndent'() + print '=> { ' +.local pmc attrlist, iter + $S0 = self.'__dumplist'() + attrlist = split ' ', $S0 + iter = new .Iterator, attrlist + iter_loop: + unless iter goto iter_end + .local string attrname + .local pmc val + attrname = shift iter + val = getattribute self, attrname + print "\n" + print subindent + print attrname + print ' => ' + dumper.'dump'(label, val) + goto iter_loop + iter_end: + print "\n" + print indent + print '}' + dumper.'deleteIndent'() + .return () +.end + + +.namespace [ 'C99';'CPP';'PAST';'Node' ] +.gen_dumplist('children') +.namespace [ 'C99';'CPP';'PAST';'IF_SECTION' ] +.gen_dumplist('children') +.namespace [ 'C99';'CPP';'PAST';'IFNDEF' ] +.gen_dumplist('line children') +.namespace [ 'C99';'CPP';'PAST';'IFDEF' ] +.gen_dumplist('line children') +.namespace [ 'C99';'CPP';'PAST';'IF' ] +.gen_dumplist('line children') +.namespace [ 'C99';'CPP';'PAST';'ELIF' ] +.gen_dumplist('line children') +.namespace [ 'C99';'CPP';'PAST';'ELSE' ] +.gen_dumplist('children') +.namespace [ 'C99';'CPP';'PAST';'DEFINE' ] +.gen_dumplist('name line') +.namespace [ 'C99';'CPP';'PAST';'DEFINE_FUNCTION' ] +.gen_dumplist('name line') +.namespace [ 'C99';'CPP';'PAST';'INCLUDE' ] +.gen_dumplist('line') +.namespace [ 'C99';'CPP';'PAST';'ERROR' ] +.gen_dumplist('line') +.namespace [ 'C99';'CPP';'PAST';'LINE' ] +.gen_dumplist('line') +.namespace [ 'C99';'CPP';'PAST';'PRAGMA' ] +.gen_dumplist('line') +.namespace [ 'C99';'CPP';'PAST';'SOURCE_LINE' ] +.gen_dumplist('line') +.namespace [ 'C99';'CPP';'PAST';'WSNWS' ] +.gen_dumplist('line') + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: diff --git a/src/CPP_PGE2AST.pir b/src/CPP_PGE2AST.pir new file mode 100644 index 0000000..bf861fc --- /dev/null +++ b/src/CPP_PGE2AST.pir @@ -0,0 +1,92 @@ +.namespace [ 'C99';'CPP';'ASTGrammar' ] + +.include 'languages/c99/src/preamble' +.include 'languages/c99/src/CPP_ASTGrammar.pir' +.include "iterator.pasm" + +.sub '__onload' :load + $P0 = get_class ['C99';'CPP';'ASTGrammar'] + if null $P0 goto error + addattribute $P0, 'scope_stack' + .return () +error: + print "C99::CPP::ASTGrammar class not found\n" + end +.end + +.sub 'attr' :method + .param string attrname + .param pmc value + .param int setvalue + if setvalue goto set + value = getattribute self, attrname + unless null value goto end + value = new .Undef + set: + setattribute self, attrname, value + end: + .return (value) +.end + +.sub 'scope_stack' :method + .param pmc attr :optional + .param int has_attr :opt_flag + .local pmc value + value = self.'attr'('scope_stack', attr, has_attr) + $I0 = defined value + if $I0 goto end + value = new .ResizablePMCArray + value = self.'attr'('scope_stack', value, 1) + end: + .return (value) +.end + +.sub 'push_scope_stack' :method + .param pmc value + .local pmc stack + stack = self.'scope_stack'() + push stack, value + .return (value) +.end + +.sub 'pop_scope_stack' :method + .local pmc value + .local pmc stack + stack = self.'scope_stack'() + value = pop stack + .return (value) +.end + +.sub 'top_scope_stack' :method + .local pmc value + .local pmc stack + stack = self.'scope_stack'() + $I0 = elements stack + unless $I0 goto end + $I0 -= 1 + value = stack[$I0] + .return (value) + end: + print "Error: top_scope_stack is empty" + end +.end + +.sub 'add_to_current_block' :method + .param string key + .param pmc value + .local pmc scope + scope = self.'top_scope_stack'() + $I0 = isa scope, ['Cardinal';'PAST';'Block'] + unless $I0 goto end + scope.'vardecl'(key, value) + .return () + end: + print "Error: top_scope_stack is empty" + end +.end + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: diff --git a/src/builtins/say.pir b/src/builtins/say.pir new file mode 100644 index 0000000..846a426 --- /dev/null +++ b/src/builtins/say.pir @@ -0,0 +1,82 @@ +# $Id: say.pir 27878 2008-05-28 14:44:03Z Whiteknight $ + +=head1 + +say.pir -- simple implementation of a say function + +=cut + +.namespace [] + +.sub 'say' + .param pmc args :slurpy + .local pmc iter + iter = new 'Iterator', args + iter_loop: + unless iter goto iter_end + $P0 = shift iter + print $P0 + goto iter_loop + iter_end: + print "\n" + .return () +.end + +.sub 'printf' + .param pmc format + .param pmc args :slurpy + .local pmc iter + iter = new 'Iterator', args + iter_loop: + unless iter goto iter_end + goto iter_loop + iter_end: +.end + +.sub 'puts' + .param pmc str + print str + print "\n" +.end + +.sub 'infix:<' + .param pmc a + .param pmc b + islt $I0, a, b + .return ($I0) +.end + +.sub 'postfix:++' + .param pmc arg + $P0 = clone arg + inc $P0 + .return (arg) +.end + +.sub 'postfix:--' + .param pmc arg + $P0 = clone arg + dec $P0 + .return (arg) +.end + +.sub 'prefix:++' + .param pmc arg + inc arg + .return (arg) +.end + +.sub 'prefix:--' + .param pmc arg + dec arg + .return (arg) +.end + + + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: + diff --git a/src/c99.pg b/src/c99.pg new file mode 100644 index 0000000..50abd7f --- /dev/null +++ b/src/c99.pg @@ -0,0 +1,581 @@ +#taken from n869.pdf +#google for n869.pdf + +## A.1 Lexical grammar +grammar C99::Grammar; + +## A.1.1 Lexical elements +token ws { + [ + | <'//'> \N* \n + | <'/*'> .*? <'*/'> + | \s+ + ]* +} + +rule c99_token { + | + | + | + | + | +} + +token pound { <'\#'> } + +regex preprocessing_token { + | + | + | + | + | + | + | + | <-[# \r\n\t]>\S* ## <-[#]-\S>\S* ##non-whitespace +} + +## A.1.2 Keywords +token keyword { + | auto | enum | restrict | unsigned + | break | extern | return | void + | case | float | short | volatile + | char | for | signed | while + | const | goto | sizeof | _Bool + | continue | if | static | _Complex + | default | inline | struct | _Imaginary + | do | int | switch + | double | long | typedef + | else | register | union + +} + +## A.1.3 Identifiers +#token identifier { [ | \d ]* } +token identifier { [ | ]* } + +token identifier_nondigit { | <[_]> | } + +## A.1.4 Universal character names +token universal_character_name { + | <'\u'> **{4} + | <'\U'> **{8} +} + +## A.1.5 Constants +token constant { + | + | + | + | +} + +token integer_constant { + [ + | + | + ] ? +} + +token decimal_constant { <[1..9]> } +#token decimal_constant { <[1..9]> \d* } +token octal_constant { 0 <[0..7]>+ } +token hexadecimal_constant { 0 <[xX]> + } + +token integer_suffix { + | <[uU]> [ll?|LL?]? + | [ll?|LL?] <[uU]>? +} + +token floating_constant { + | + | +} + +token decimal_floating_constant { + [ ? + | + ] ? +} + +token hexadecimal_prefix +{ + 0 <[xX]> +} + +token hexadecimal_floating_constant { + + [ + | + ] ? +} + +token fractional_constant { + | ? \. + | \. +} + +token exponent_part { + <[eE]> <[\+\-]>? +} + +#token digit_sequence { \d+ } +token digit_sequence { + } + +token hexadecimal_fractional_constant { + | ? \. + | \. +} + +token binary_exponent_part { + <[pP]> <[\+\-]>? +} + +token hexadecimal_digit_sequence { + } + +token floating_suffix { <[fFlL]> } + +token enumeration_constant { } + +token character_constant { <[L]>? \' + \' } + +token { <-['\\\n]> | } + +token escape_sequence { + \\ + [ <['"?\\abfnrtv]> + | **{1..3} + | x + + | + ] +} + +## A.1.6 String literals +token string_literal { <[L]>? " * " } + +token s_char { <-["\\\n]> | } + +## A.1.7 Punctuators +token punctuator { + | \[ | \] | <[(){}.]> | <'->'> + | <'++'> | <'--'> | <[&*+\-~!/%]> + | <'<<'> | <'>>'> | <[<>]> + | <'<='> | <'>='> | <'=='> | <'!='> + | <[^|]> | <'&&'> | <'||'> + | <[?:;]> | <'...'> + | [ <[*/%+\-&^|]> | <'<<'> | <'>>'> ] <'='> + | <[,#]> | <'##'> + | <'<:'> | <':>'> | <'<%'> | <'%>'> | <'%:'> | <'%:%:'> +} + +## A.1.8 Header names +token header_name { + | \< $=+ \> + | " $:=+ " +} + +token h_char { <-[\n>]> } +token q_char { <-[\n"]> } + +## A.1.9 Preprocessing numbers +token pp_number { \.? \d [ \d | | <[eEpP]> <[\+\-]> | \. ]* } + +## A.2 Phrase structure grammar +## XXX: see below + +## A.2.2 Declarations +rule declaration { + ? ; } + +rule declaration_specifier { + | + | + | + | +} + +rule init_declarator_list { init_declarator [ , ]* } + +rule init_declarator { [ = ]? } + +token storage_class_specifier { typedef | extern | static | auto | register } + +rule type_specifier { + | void | char | short | int + | long | float | double | signed + | unsigned | _Bool | _Complex | _Imaginary + | + | + | +} + +rule struct_or_union_specifier { + [ $:=<'struct'> | $:=<'union'> ] [ | ? \{ + \} ] +} + +rule struct_declaration { [|]+ + ; } + +rule struct_declarator { | ? : } + +rule enum_specifier { enum [ ? \{ [ , ]+ [,]? \}| ] } + +rule enumerator { [ = ]? } + +token type_qualifier { const | restrict | volatile } + +token function_specifier { inline } + +rule declarator { ? } + +rule direct_declarator { + [ | \( \) ] + [ + | \[ ? \] + | \[ \* \] + | \( \) + | \( ? \) + ]* +} + +rule pointer { [\* * ]+ } + +rule parameter_type_list { [ , ]* [ , <'...'>]? } + +rule parameter_declaration { + [ | ]? } + +rule identifier_list { [ , ]* } + +rule type_name { ? } + +rule abstract_declatator { + ? + | +} + +rule direct_abstract_declarator { + [ + | \( \) + | \[ ? \] + | \( \) + ] + * +} + +rule direct_abstract_declarator_1 { + | \[ ? \] + | \[ * \] + | \( \) +} + +rule typedef_name { } + +rule initializer { | \{ [,]? \} } + +rule initializer_list { ? [, ? ]* } + +rule designation { + = } + +rule designator { + | \[ \] + | \. +} + +## A.2.3 Statements +rule statement { + | + | + | + | + | + | +} + +rule labeled_statement { + [ \: + | case \: + | default \: + ] +} + +rule compound_statement { \{ [ | ]* \} } + +rule expression_statement { ? ; } + +rule selection_statement { + | if \( \) [else ]? + | switch \( \) +} + +rule iteration_statement { + | while \( \) + | do while \( \) ; + | for \( [ ? ; ? ; ? | ? ; ? ] \) +} + +rule jump_statement { + | goto ; + | continue ; + | break ; + | return ? ; +} + + +## A.2.4 External definitions +rule translation_unit { [ | ]+ } + +rule function_definition { + * } + + +## A.3 preprocessing directives +token wsnws { + ? \n ? +} + +regex prereprocessing_file { } + +regex group { + } + +regex group_line { + | + | + | ? $:= +} + +regex source_line { + +} + + +rule if_section { * ? } + +token ws_minus_n +{ + [ + | <'//'> \N* \n + | <'/*'> .*? <'*/'> + | \t + | <' '> + ## | <\s-<[\n]> + ]* +} + +regex if_group { + [ + | \# ? $:=<'ifndef'> + | \# ? $:=<'ifdef'> + | \# ? $:=<'if'> + ] ? +} + +regex elif_group { \# $:=<'elif'> ? } +regex else_group { \# $:=<'else'> ? } +regex endif_line { \# $:=<'endif'> } +regex control_line { + | \# ? $:=<'include'> $:= + | \# ? $:=<'define'> + [ + | $:= + | $:=( [ [, \.\.\.]? | [ \.\.\.] ]? \)) + ] ? $:=? + | \# ?? $:=<'undefine'> + | \# ?? $:=<'line'> $:= + | \# ?? $:=<'error'> $:=? + | \# ?? $:=<'pragma'> $:=? + | \# + +} + +token identifier_p { \( } +regex pp_tokens { [ ]* } + + +## A.2.1 Expressions +rule primary_expression { + | + | + | + | \( \) +} + +rule postfix_expression { + [ + | \( \) \{ [\,]? \} ] + + [ <'++'> + | <'--'> + | \[ \] + | \( [ [ \, ]* ]? \) + | \. + | <'->'> + | \( \) \{ [\,]? \} + ]* +} + +rule unary_expression { + [<'++'>|<'--'>|<'sizeof'>]? + + [ + | $:=<[&*+\-~!]> + | <'sizeof'> \( \) + ] +} + +rule cast_expression { [ \( \) ]* } + +#proto 'term:' is precedence('22=') +# is parsed(primary_expression) +# is pastrule('past_term') { ... } + +## postfix expressions +#proto 'postfix:++' is precedence('20=') { ... } +#proto 'postcircumfix:[]' is equiv('postfix:++') { ... } +#rule postfix_expression { \[ \] } +#proto 'postcircumfix:()' is equiv('postfix:++') { ... } +#rule postfix_expression { \( [ [\, ]* ]? \) } +#proto 'infix:.' is equiv('postfix:++') { ... } +#rule postfix_expression { . } +#proto 'infix:->' is equiv('postfix:++') { ... } +#rule postfix_expression { \-\> } +#proto 'postfix:--' is equiv('postfix:++') { ... } +#rule postfix_expression { \( \) \{ [,]? \} } + +## unary-expression +#proto 'prefix:++' is precedenc('18=') { ... } +#proto 'prefix:--' is equiv('prefix:++') { ... } +#proto 'prefix:&' is equiv('prefix:++') { ... } +#proto 'prefix:*' is equiv('prefix:++') { ... } +#proto 'prefix:+' is equiv('prefix:++') { ... } +#proto 'prefix:-' is equiv('prefix:++') { ... } +#proto 'prefix:~' is equiv('prefix:++') { ... } +#proto 'prefix:!' is equiv('prefix:++') { ... } +#proto 'prefix:sizeof' is equiv('prefix:++') { ... } +#proto 'prefix:sizeof' is equiv('prefix:++') { ... } +#rule unary_expression { sizeof } +#rule unary_expression { sizeof [\( \) ] } + +## cast-expression +## XXX: PGE doesn't have a precircumfix:() function (yet?) +#proto 'precircumfix:()' is precedence('17=') {...} +#rule cast_expression { [\( \) ]* } + +proto 'term:' is precedence('22=') + is parsed(cast_expression) + is pastrule('cast_expression') { ... } + +## multiplicative +proto 'infix:*' is precedence('16=') + is post('mul') + { ... } + +proto 'infix:/' is equiv('infix:*') + is post('div') + { ... } + +proto 'infix:%' is equiv('infix:*') + is post('mod') + { ... } + +## additive +proto 'infix:+' is precedence('16=') + is post('add') + { ... } + +proto 'infix:-' is equiv('infix:+') + is post('sub') + { ... } + + +## shift-expression +proto 'infix:<<' is precedence('15=') { ... } +proto 'infix:>>' is precedence('15=') { ... } + + +## relational-expression +## chaining binary +proto 'infix:<' is equiv('14=') is assoc('chain') + is pasttype('chain') + { ... } + +proto 'infix:<=' is equiv('infix:<') + is pasttype('chain') + { ... } + +proto 'infix:>' is equiv('infix:<') + is pasttype('chain') + { ... } + +proto 'infix:>=' is equiv('infix:<') + is pasttype('chain') + { ... } + +# equality-expression +proto 'infix:==' is precedence('13=') is assoc('chain') + is pasttype('chain') + { ... } + +proto 'infix:!=' is equiv('infix:==') + is pasttype('chain') + { ... } + + +proto 'infix:&' is precedence('12=') { ... } +proto 'infix:^' is precedence('11=') { ... } +proto 'infix:|' is precedence('10=') { ... } + +proto 'infix:&&' is precedence('09=') + is pasttype('cond') + { ... } + +proto 'infix:||' is precedence('08=') + is pasttype('cond') + { ... } + +## ternary +#proto 'ternary:? :' is precedence('07=') is assoc('right') +# is pasttype('cond') +# is parsed('conditional_expression') +# { ... } + +rule operator_precedence_parser { {{ + .local pmc optable + .local pmc match_result + #optable = get_hll_namespace ['Cardinal'; 'Grammar'] + optable = get_root_global [ 'parrot'; 'C99'], '$optable' + match_result = optable."parse"(match) + .return (match_result) +}} } + +rule conditional_expression { [ \? : ]* } + +rule assignment_expression { [ ]* } + +token assignment_operator { + | <'*='> + | <'/='> + | <'%='> + | <'+='> + | <'-='> + | <'<<='> + | <'>>='> + | <'&='> + | <'^='> + | <'|='> +} + +rule expression { [, ] } +rule constant_expression { } + +## assignment +#proto 'infix:=' is precedence('06=') is assoc('right') +# is parsed('assignment_expression') +# is pasttype('assign') +# { ... } + +#proto 'infix:*=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:/=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:%=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:+=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:-=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:<<=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:>>=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:&=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:^=' is equiv('infix:=') is parsed('assignment_expression') { ... } +#proto 'infix:|=' is equiv('infix:=') is parsed('assignment_expression') { ... } diff --git a/src/c99_PGE.pir b/src/c99_PGE.pir new file mode 100644 index 0000000..8563dd1 --- /dev/null +++ b/src/c99_PGE.pir @@ -0,0 +1,60 @@ +=head1 NAME + +C99::Grammar -- A grammar for parsing C99 + +=head1 SYNOPSYS + +=head1 DESCRIPTION + +This is a grammar to parse c99 programs. It inherits the behavior +of the PGE::Grammar class. It parses a string of source code according to +its hierarchy of rules and returns a PGE::Match object (a parse tree). + +=cut + +#.HLL 'C99', 'c99y_group' +#.namespace [ 'C99'; 'Grammar' ] +.namespace [ 'C99';'Grammar' ] + +.sub _load :load + load_bytecode 'PGE.pbc' + load_bytecode 'PGE/Text.pbc' +.end + +# Pull in the compiled grammar +.include "languages/c99/src/c99_grammar_gen.pir" +.sub '__onload' :load + $P0 = get_hll_global ['C99';'Grammar'], '$optable' + $P1 = get_hll_global ['C99';'Grammar'], 'ws' + setattribute $P0, '&!ws', $P1 + $P0 = new .Hash +.end + +# Operator precedence parsing rule +.sub "operator_precedence_parser" + .param pmc match_object + .local pmc optable + #optable = get_hll_namespace ['C99'; 'Grammar'] + optable = get_root_global [ 'parrot'; 'C99';'Grammar'], '$optable' + $P0 = optable."parse"(match_object) + .return ($P0) +.end + +=head1 LICENSE + +Copyright (C) 2005-2008, Parrot Foundation. + +This is free software; you may redistribute it and/or modify +it under the same terms as Parrot. + +=head1 AUTHOR + +Kevin Tew + +=cut + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: diff --git a/src/cpp/Makefile b/src/cpp/Makefile new file mode 100644 index 0000000..d7c174e --- /dev/null +++ b/src/cpp/Makefile @@ -0,0 +1,106 @@ +# ex: set ro: +# DO NOT EDIT THIS FILE +# Generated by Parrot::Configure::Compiler from languages/c99/config/makefiles/cpp.in + +# Copyright (C) 2008-2009, Parrot Foundation. +## $Id: cpp.in 36833 2009-02-17 20:09:26Z allison $ + +## arguments we want to run parrot with +PARROT_ARGS = + +## configuration settings +BUILD_DIR = /home/allison/projects/svn/parrot +LOAD_EXT = .so +O = .o + +## Setup some commands +PERL = /usr/bin/perl +RM_F = $(PERL) -MExtUtils::Command -e rm_f +CP = $(PERL) -MExtUtils::Command -e cp +CAT = $(PERL) -MExtUtils::Command -e cat +PARROT = ../../../../parrot +BUILD_DYNPMC = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.pl +RECONFIGURE = $(PERL) $(BUILD_DIR)/tools/dev/reconfigure.pl + +## places to look for things +PARROT_DYNEXT = $(BUILD_DIR)/runtime/parrot/dynext +PGE_LIBRARY = $(BUILD_DIR)/runtime/parrot/library/PGE +PERL6GRAMMAR = $(PGE_LIBRARY)/Perl6Grammar.pbc +NQP = $(BUILD_DIR)/compilers/nqp/nqp.pbc +PCT = $(BUILD_DIR)/runtime/parrot/library/PCT.pbc + +PMC_DIR = src/pmc + +all: cpp.pbc + +SOURCES = cpp.pir \ + src/gen_grammar.pir \ + src/gen_actions.pir \ + src/gen_builtins.pir + +BUILTINS_PIR = \ + src/builtins/say.pir + +# the default target +cpp.pbc: $(PARROT) $(SOURCES) + $(PARROT) $(PARROT_ARGS) -o cpp.pbc cpp.pir + $(CP) cpp.pbc ../../cpp.pbc + +src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg + $(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \ + --output=src/gen_grammar.pir \ + src/parser/grammar.pg + +src/gen_actions.pir: $(NQP) $(PCT) src/parser/actions.pm + $(PARROT) $(PARROT_ARGS) $(NQP) --output=src/gen_actions.pir \ + --target=pir src/parser/actions.pm + +src/gen_builtins.pir: $(BUILTINS_PIR) + $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir + +# regenerate the Makefile +Makefile: ../../config/makefiles/cpp.in + cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=c99 + +# This is a listing of all targets, that are meant to be called by users +help: + @echo "" + @echo "Following targets are available for the user:" + @echo "" + @echo " all: c.pbc" + @echo " This is the default." + @echo "Testing:" + @echo " test: Run the test suite." + @echo " testclean: Clean up test results." + @echo "" + @echo "Cleaning:" + @echo " clean: Basic cleaning up." + @echo " realclean: Removes also files generated by 'Configure.pl'" + @echo " distclean: Removes also anything built, in theory" + @echo "" + @echo "Misc:" + @echo " help: Print this help message." + @echo "" + +test: all + $(PERL) t/harness + +# this target has nothing to do +testclean: + +CLEANUPS = \ + cpp.pbc \ + "src/gen_*.pir" + +clean: + $(RM_F) $(CLEANUPS) + +realclean: clean + $(RM_F) Makefile + +distclean: realclean + +# Local variables: +# mode: makefile +# End: +# vim: ft=make: diff --git a/src/cpp/cpp.pir b/src/cpp/cpp.pir new file mode 100644 index 0000000..36968ca --- /dev/null +++ b/src/cpp/cpp.pir @@ -0,0 +1,80 @@ +# $Id: cpp.pir 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=head1 TITLE + +cpp.pir - A C pre processor. + +=head2 Description + +This is the base file for the C99 C pre processor. + +This file includes the parsing and grammar rules from +the src/ directory, loads the relevant PGE libraries, +and registers the compiler under the name 'C99::CPP'. + +=head2 Functions + +=over 4 + +=item onload() + +Creates the C compiler using a C +object. + +=cut + +.namespace [ 'C99';'CPP';'Compiler' ] + +.loadlib 'c99_group' + +.sub 'onload' :anon :load :init + load_bytecode 'PCT.pbc' + + $P0 = get_hll_global ['PCT'], 'HLLCompiler' + $P1 = $P0.'new'() + $P1.'language'('C99::CPP') + $P1.'parsegrammar'('C99::CPP::Grammar') + $P1.'parseactions'('C99::CPP::Grammar::Actions') +.end + +=item main(args :slurpy) :main + +Start compilation by passing any command line C +to the C compiler. + +=cut + +.sub 'main' :main + .param pmc args + + $P0 = compreg 'C99::CPP' + $P1 = $P0.'command_line'(args) +.end + + +.include 'src/gen_builtins.pir' +.include 'src/gen_grammar.pir' +.include 'src/gen_actions.pir' + + +.namespace [ 'C99';'CPP';'Grammar' ] + +.sub 'debug' + .param pmc match + .param pmc arg + .param pmc attrs :slurpy + printerr arg + printerr "\n" +.end + +=back + +=cut + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: + diff --git a/src/cpp/src/builtins/say.pir b/src/cpp/src/builtins/say.pir new file mode 100644 index 0000000..846a426 --- /dev/null +++ b/src/cpp/src/builtins/say.pir @@ -0,0 +1,82 @@ +# $Id: say.pir 27878 2008-05-28 14:44:03Z Whiteknight $ + +=head1 + +say.pir -- simple implementation of a say function + +=cut + +.namespace [] + +.sub 'say' + .param pmc args :slurpy + .local pmc iter + iter = new 'Iterator', args + iter_loop: + unless iter goto iter_end + $P0 = shift iter + print $P0 + goto iter_loop + iter_end: + print "\n" + .return () +.end + +.sub 'printf' + .param pmc format + .param pmc args :slurpy + .local pmc iter + iter = new 'Iterator', args + iter_loop: + unless iter goto iter_end + goto iter_loop + iter_end: +.end + +.sub 'puts' + .param pmc str + print str + print "\n" +.end + +.sub 'infix:<' + .param pmc a + .param pmc b + islt $I0, a, b + .return ($I0) +.end + +.sub 'postfix:++' + .param pmc arg + $P0 = clone arg + inc $P0 + .return (arg) +.end + +.sub 'postfix:--' + .param pmc arg + $P0 = clone arg + dec $P0 + .return (arg) +.end + +.sub 'prefix:++' + .param pmc arg + inc arg + .return (arg) +.end + +.sub 'prefix:--' + .param pmc arg + dec arg + .return (arg) +.end + + + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: + diff --git a/src/cpp/src/parser/actions.pm b/src/cpp/src/parser/actions.pm new file mode 100644 index 0000000..2d7f794 --- /dev/null +++ b/src/cpp/src/parser/actions.pm @@ -0,0 +1,31 @@ +# $Id: actions.pm 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=begin comments + +C99::Grammar::Actions - ast transformations for C99 + +This file contains the methods that are used by the parse grammar +to build the PAST representation of an C program. +Each method below corresponds to a rule in F, +and is invoked at the point where C<{*}> appears in the rule, +with the current match object as the first argument. If the +line containing C<{*}> also has a C<#= key> comment, then the +value of the comment is passed as the second argument to the method. + +=end comments + +class C99::CPP::Grammar::Actions; + +method TOP($/) { +} + + + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: + diff --git a/src/cpp/src/parser/grammar.pg b/src/cpp/src/parser/grammar.pg new file mode 100644 index 0000000..870eaa7 --- /dev/null +++ b/src/cpp/src/parser/grammar.pg @@ -0,0 +1,431 @@ +# $Id: grammar.pg 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=begin overview + +This is the grammar for C99 written as a sequence of Perl 6 rules. + + +taken from n869.pdf +google for n869.pdf + +=end overview + +grammar C99::CPP::Grammar is PCT::Grammar; + +token ws { + | \h* + | +} + +token TOP { + ^ + + [ $ || <.panic: Syntax error> ] + {*} +} + +## A.1.5 Constants +## +token constant { + | {*} #= floating_constant + | {*} #= integer_constant + | {*} #= enumeration_constant + | {*} #= character_constant +} + +token integer_constant { + [ + | + | + ] + ? + {*} +} + +token decimal_constant { + <[1..9]> * +} + +token octal_constant { + 0 <[0..7]>* +} + +token hexadecimal_constant { + 0 <[xX]> + +} + +token integer_suffix { + | <[uU]> [ll?|LL?]? + | [ll?|LL?] <[uU]>? +} + +token floating_constant { + [ + | + | + ] + {*} +} + +token decimal_floating_constant { + [ + | ? + | + ] + ? +} + +token hexadecimal_prefix { + 0 <[xX]> +} + +token hexadecimal_floating_constant { + + [ + | + | + ] + ? +} + +token fractional_constant { + | ? \. + | \. +} + +token exponent_part { + <[eE]> ['+'|'-']? +} + +token digit_sequence { + } + +token hexadecimal_fractional_constant { + | ? \. + | \. +} + +token binary_exponent_part { + <[pP]> ['+'|'-']? +} + +token hexadecimal_digit_sequence { + } + +token floating_suffix { <[fFlL]> } + +token enumeration_constant { } + +token character_constant { [L]? \' + \' } + +token { <-['\\\n]> | } + +token escape_sequence { + \\ + [ <['"?\\abfnrtv]> + | **{1..3} + | x + + | + ] +} + +## A.1.6 String literals +token c_string_literal { + [L]? + {*} +} + +##\" * \" + +token s_char { <-["\\\n]> | } + + +## A.2 Phrase structure grammar +## + +## A.2.1 Expressions +## + +rule expression { + + {*} +} + +rule constant_expression { + + {*} +} + +rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' } + +rule conditional_expression { + ['?' ':' ]? + {*} +} + +rule logical_expression is optable { ... } + +proto 'infix:||' is precedence('1') { ... } + +proto 'infix:&&' is tighter('infix:||') { ... } + +proto 'infix:|' is tighter('infix:&&') { ... } + +proto 'infix:^' is tighter('infix:|') { ... } + +proto 'infix:&' is tighter('infix:^') { ... } + +proto 'infix:==' is tighter('infix:&') { ... } +proto 'infix:!=' is equal('infix:==') { ... } + +proto 'infix:<' is tighter('infix:==') { ... } +proto 'infix:>' is equal('infix:<') { ... } +proto 'infix:>=' is equal('infix:<') { ... } +proto 'infix:<=' is equal('infix:<') { ... } + +proto 'infix:<<' is tighter('infix:==') { ... } +proto 'infix:>>' is equal('infix:<<') { ... } + +proto 'infix:+' is tighter('infix:<<') is pirop('n_add') { ... } +proto 'infix:-' is equal('infix:+') is pirop('n_sub') { ... } + +proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... } +proto 'infix:/' is equal('infix:*') is pirop('n_div') { ... } +proto 'infix:%' is equal('infix:*') is pirop('n_mod') { ... } + +proto 'term:' is tighter('infix:*') + is parsed(&cast_expression) { ... } + + +rule postfix_expression_prefix { + | {*} #= primary_expression + | '(' ')' '{' [',']? '}' {*} #= type_name +} + +rule postfix_expression { + + * + {*} +} + +rule postfix_expression_suffix { + | {*} #= index + | {*} #= arguments + | {*} #= direct_field + | {*} #= indirect_field + | {*} #= inc_or_dec +} + +rule inc_or_dec { + $=['++'|'--'] + {*} +} + +rule index { + '[' ']' + {*} +} + +rule direct_field { + '.' + {*} +} + +rule indirect_field { + '->' + {*} +} + +rule arguments { + '(' ? ')' + {*} +} + +rule argument_expression_list { + [',' ]* + {*} +} + +rule unary_expression { + | {*} #= postfix_expression + | {*} #= prefix_expression + | + | 'sizeof' + | 'sizeof' '(' ')' +} + +rule prefix_expression { + $=['++'|'--'] + {*} +} + +rule unary_operator { + '&' | '*' | '+' | '-' | '~' | '!' +} + +rule cast_expression { + ['(' ')']* + {*} +} + +rule primary_expression { + | {*} #= identifier + | {*} #= constant + | {*} #= c_string_literal + | '(' ')' {*} #= expression +} + +token pound { '#' } +token begincomment { '/*' } + +token multilinecomment { '/*' .*? '*/' } + + +regex preprocessing_token { +# | + | + | + | + | + | '"' '"' + | + | + | <-[# \t\r\n]>\S* ## <-[#]-\S>\S* ##non-whitespace +} + +## A.1.2 Keywords +## +token keyword { + [ auto | enum | restrict | unsigned + | break | extern | return | void + | case | float | short | volatile + | char | for | signed | while + | const | goto | sizeof | _Bool + | continue | if | static | _Complex + | default | inline | struct | _Imaginary + | do | int | switch + | double | long | typedef + | else | register | union ]>> +} + +token reserved_word { + +} + +token identifier { + + [ | ]* + {*} +} + +token identifier_nondigit { + | <[_]> | +} + +token character_constant { [L]? \' + \' } + +token { <-['\\\n]> | } + +## A.1.4 Universal character names +## +token universal_character_name { + | '\u' **{4} + | '\U' **{8} +} + + +## A.1.7 Punctuators +## + +token punctuator { + | \[ | \] | <[(){}.]> | '->' + | '++' | '--' | <[&*+\-~!/%]> + | '<<' | '>>' | '<' | '>' + | '<=' | '>=' | '==' | '!=' + | <[^|]> | '&&' | '||' + | <[?:;]> | '...' + | <[*/%+\-&^|]> | '<<' | '>>' | '=' + | <[,#]> | '##' + | '<:' | ':>' | '<%' | '%>' | '%:' | '%:%:' +} + +## A.3 Preprocessing directives +## + +rule pre_processing_file { + ? +} + +rule group { + + +} + +rule group_part { + | ? + | + | +} + +rule if_section { + * ? +} + +rule if_group { + | '#' 'if' ? + | '#' 'ifdef' ? + | '#' 'ifndef' ? +} + +rule elif_group { + '#' 'elif' ? +} + +rule else_group { + '#' 'else' ? +} + +rule endif_line { + '#' 'endif' +} + +rule control_line { + | '#' 'include' + | '#' 'define' + | '#' 'define' ? ')' + | '#' 'define' '...' ')' + | '#' 'define' ',' '...' ')' + | '#' 'undef' + | '#' 'line' + | '#' 'error' ? + | '#' 'pragma' ? + | '#' +} + +rule pp_tokens { [ ]+ } + +token pp_number { + ['.']? * +} + +token pp_number_suffix { + | '.' + | + | + | <[eEpP]> ['+'|'-'] +} + +rule replacement_list { + ? +} + +token lparen { '(' } + +token newline { \n } + +## A.1.8 Header names +token header_name { + | \< + \> + | \" + \" +} + +token h_char { <-[\n>]> } +token q_char { <-[\n"]> } diff --git a/src/cpp/t/comment_01.t b/src/cpp/t/comment_01.t new file mode 100644 index 0000000..ce091e2 --- /dev/null +++ b/src/cpp/t/comment_01.t @@ -0,0 +1 @@ +/*hello */ diff --git a/src/cpp/t/cpp_0.t b/src/cpp/t/cpp_0.t new file mode 100644 index 0000000..217cd45 --- /dev/null +++ b/src/cpp/t/cpp_0.t @@ -0,0 +1 @@ +#define L1 1 diff --git a/src/cpp/t/harness b/src/cpp/t/harness new file mode 100755 index 0000000..ec340fd --- /dev/null +++ b/src/cpp/t/harness @@ -0,0 +1,7 @@ +#!/usr/bin/perl + +# $Id: harness 26906 2008-04-10 19:45:40Z bernhard $ + +use FindBin; +use lib qw( . lib ../lib ../../lib ../../lib ../../../../lib ); +use Parrot::Test::Harness language => 'c99', exec => [ '../../../../parrot', './', 'cpp.pbc' ] ; diff --git a/src/cpp/t/spi.t b/src/cpp/t/spi.t new file mode 100644 index 0000000..883dc66 --- /dev/null +++ b/src/cpp/t/spi.t @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------- + * + * spi.h + * Server Programming Interface public declarations + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ +#ifndef SPI_H +#define SPI_H + +/* + * This file may be used by client modules that haven't already + * included postgres.h + */ +#include "postgres.h" + +/* + * Most of these are not needed by this file, but may be used by + * user-written code that uses SPI + */ +#include "access/heapam.h" +#include "access/xact.h" +#include "catalog/pg_language.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "executor/execdefs.h" +#include "executor/executor.h" +#include "nodes/execnodes.h" +#include "nodes/params.h" +#include "nodes/parsenodes.h" +#include "nodes/plannodes.h" +#include "nodes/primnodes.h" +#include "nodes/relation.h" +#include "tcop/dest.h" +#include "tcop/pquery.h" +#include "tcop/tcopprot.h" +#include "tcop/utility.h" +#include "utils/builtins.h" +#include "utils/datum.h" +#include "utils/portal.h" +#include "utils/syscache.h" + + +typedef struct SPITupleTable +{ + MemoryContext tuptabcxt; /* memory context of result table */ + uint32 alloced; /* # of alloced vals */ + uint32 free; /* # of free vals */ + TupleDesc tupdesc; /* tuple descriptor */ + HeapTuple *vals; /* tuples */ +} SPITupleTable; + +/* Plans are opaque structs for standard users of SPI */ +typedef struct _SPI_plan *SPIPlanPtr; + +#define SPI_ERROR_CONNECT (-1) +#define SPI_ERROR_COPY (-2) +#define SPI_ERROR_OPUNKNOWN (-3) +#define SPI_ERROR_UNCONNECTED (-4) +#define SPI_ERROR_CURSOR (-5) /* not used anymore */ +#define SPI_ERROR_ARGUMENT (-6) +#define SPI_ERROR_PARAM (-7) +#define SPI_ERROR_TRANSACTION (-8) +#define SPI_ERROR_NOATTRIBUTE (-9) +#define SPI_ERROR_NOOUTFUNC (-10) +#define SPI_ERROR_TYPUNKNOWN (-11) + +#define SPI_OK_CONNECT 1 +#define SPI_OK_FINISH 2 +#define SPI_OK_FETCH 3 +#define SPI_OK_UTILITY 4 +#define SPI_OK_SELECT 5 +#define SPI_OK_SELINTO 6 +#define SPI_OK_INSERT 7 +#define SPI_OK_DELETE 8 +#define SPI_OK_UPDATE 9 +#define SPI_OK_CURSOR 10 +#define SPI_OK_INSERT_RETURNING 11 +#define SPI_OK_DELETE_RETURNING 12 +#define SPI_OK_UPDATE_RETURNING 13 + +extern PGDLLIMPORT uint32 SPI_processed; +extern PGDLLIMPORT Oid SPI_lastoid; +extern PGDLLIMPORT SPITupleTable *SPI_tuptable; +extern PGDLLIMPORT int SPI_result; + +extern int SPI_connect(void); +extern int SPI_finish(void); +extern void SPI_push(void); +extern void SPI_pop(void); +extern void SPI_restore_connection(void); +extern int SPI_execute(const char *src, bool read_only, long tcount); +extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, + bool read_only, long tcount); +extern int SPI_exec(const char *src, long tcount); +extern int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, + long tcount); +extern int SPI_execute_snapshot(SPIPlanPtr plan, + Datum *Values, const char *Nulls, + Snapshot snapshot, + Snapshot crosscheck_snapshot, + bool read_only, bool fire_triggers, long tcount); +extern int SPI_execute_with_args(const char *src, + int nargs, Oid *argtypes, + Datum *Values, const char *Nulls, + bool read_only, long tcount); +extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); +extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, + int cursorOptions); +extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan); +extern int SPI_freeplan(SPIPlanPtr plan); + +extern Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex); +extern int SPI_getargcount(SPIPlanPtr plan); +extern bool SPI_is_cursor_plan(SPIPlanPtr plan); +extern const char *SPI_result_code_string(int code); + +extern HeapTuple SPI_copytuple(HeapTuple tuple); +extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc); +extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, + int *attnum, Datum *Values, const char *Nulls); +extern int SPI_fnumber(TupleDesc tupdesc, const char *fname); +extern char *SPI_fname(TupleDesc tupdesc, int fnumber); +extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber); +extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull); +extern char *SPI_gettype(TupleDesc tupdesc, int fnumber); +extern Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber); +extern char *SPI_getrelname(Relation rel); +extern char *SPI_getnspname(Relation rel); +extern void *SPI_palloc(Size size); +extern void *SPI_repalloc(void *pointer, Size size); +extern void SPI_pfree(void *pointer); +extern void SPI_freetuple(HeapTuple pointer); +extern void SPI_freetuptable(SPITupleTable *tuptable); + +extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, + Datum *Values, const char *Nulls, bool read_only); +extern Portal SPI_cursor_open_with_args(const char *name, + const char *src, + int nargs, Oid *argtypes, + Datum *Values, const char *Nulls, + bool read_only, int cursorOptions); +extern Portal SPI_cursor_find(const char *name); +extern void SPI_cursor_fetch(Portal portal, bool forward, long count); +extern void SPI_cursor_move(Portal portal, bool forward, long count); +extern void SPI_scroll_cursor_fetch(Portal, FetchDirection direction, long count); +extern void SPI_scroll_cursor_move(Portal, FetchDirection direction, long count); +extern void SPI_cursor_close(Portal portal); + +extern void AtEOXact_SPI(bool isCommit); +extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid); + +#endif /* SPI_H */ diff --git a/src/parser/actions.pm b/src/parser/actions.pm new file mode 100644 index 0000000..9ab11df --- /dev/null +++ b/src/parser/actions.pm @@ -0,0 +1,378 @@ +# $Id: actions.pm 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=begin comments + +C99::Grammar::Actions - ast transformations for C99 + +This file contains the methods that are used by the parse grammar +to build the PAST representation of an C program. +Each method below corresponds to a rule in F, +and is invoked at the point where C<{*}> appears in the rule, +with the current match object as the first argument. If the +line containing C<{*}> also has a C<#= key> comment, then the +value of the comment is passed as the second argument to the method. + +=end comments + +class C99::Grammar::Actions; + +method TOP($/) { + for $ { + my $fun := $( $_ ); + + ## Look for the "main" function, and set that as the result + ## object. + if $fun.name() eq 'main' { + make $fun; + } + } +} + +method external_declaration($/, $key) { + make $( $/{$key} ); +} + +method declaration($/) { + my $past := PAST::Stmts.new( :node($/) ); + + for $ { + $past.push( $( $_ ) ); + } + make $past; +} + +method init_declarator($/) { + make $( $ ); +} + +method function_definition($/) { + my $past := PAST::Block.new( :blocktype('declaration'), :node($/) ); + my $decl := $( $ ); + $past.name( $decl.name() ); + + my $body := $( $ ); + $past.push($body); + make $past; +} + +method declaration($/) { + +} + +method declarator($/) { + make $( $ ); +} + +method direct_declarator($/) { + my $past := $( $ ); + #my $past := $( $[0] ); + #$past.name($pref.name()); + make $past; +} + +method declarator_prefix($/, $key) { + make $( $/{$key} ); +} + +method declarator_suffix($/, $key) { + make $( $/{$key} ); +} + +method parameter_type_list($/) { + my $past := $( $ ); + if $ { + $past.push( PAST::Var.new( :name('@vararg'), :slurpy(1), :scope('parameter'), :node($/) ) ); + } + make $past; +} + +method parameter_list($/) { + ## create the function block here already; it's needed to store the parameters + my $past := PAST::Block.new( :blocktype('declaration'), :node($/) ); + for $ { + $past.push( $( $_ ) ); + } + make $past; +} + +method parameter_declaration($/, $key) { + make $( $/{$key} ); +} + +method statement($/, $key) { + make $( $/{$key} ); +} + +method jump_statement($/, $key) { + if $key eq 'return' { + my $past := PAST::Op.new( :pirop('return'), :node($/) ); + if $ { + $past.push( $( $[0] ) ); + } + make $past; + } + else { + $/.panic("$key is not implemented!"); + } +} + +method for1_statement($/) { + my $past := PAST::Stmts.new( :node($/) ); + my $body := $( $ ); + my $cond; + if $ { + $cond := $( $[0] ); + } + else { # a missing condition is true + $cond := PAST::Val.new( :returns('Integer'), :value('1'), :node($/) ); + } + + + + if $ { + my $init := $( $[0] ); + $past.unshift($init); + } + + + if $ { + my $step := $( $[0] ); + $body := PAST::Stmts.new( $body, $step, :node($/) ); + } + my $loop := PAST::Op.new( $cond, $body, :pasttype('while'), :node($/) ); + $past.push($loop); + + make $past; +} + +method for2_statement($/) { + my $past := PAST::Block.new( :blocktype('immediate'), :node($/) ); + my $loop := PAST::Op.new( :pasttype('while'), :node($/) ); + + $past.push( $( $ ) ); + my $body := $( $ ); + + if $ { + my $step := $( $[0] ); + } + my $cond; + if $ { + $cond := $( $[0] ); + } + else { + $cond := PAST::Val.new( :returns('Integer'), :value('1'), :node($/) ); + } + $loop.push($cond); + $loop.push($body); + + $past.push($loop); + make $past; +} + +method expression($/) { + if +$ != 1 { + my $past := PAST::Stmts.new( :node($/) ); + for $ { + $past.push( $( $_ ) ); + } + make $past; + } + else { + make $( $[0] ); + } +} + +method expression_statement($/) { + if $ { + make $( $[0] ); + } + else { + make PAST::Op.new( :inline(' # empty statement'), :node($/) ); + } +} + +method compound_statement($/) { + my $past := PAST::Block.new( :blocktype('immediate'), :node($/) ); + #my $past := PAST::Stmts.new( :node($/) ); + for $ { + $past.push( $($_) ); + } + make $past; +} + +method if_statement($/) { + my $cond := $( $ ); + my $then := $( $ ); + my $past := PAST::Op.new( $cond, $then, :pasttype('if'), :node($/) ); + if $ { + $past.push( $( $[0] ) ); + } + make $past; +} + +method do_while_statement($/) { + my $cond := $( $ ); + my $body := $( $ ); + make PAST::Op.new( $cond, $body, :pasttype('repeat_while'), :node($/) ); +} + +method while_statement($/) { + my $cond := $( $ ); + my $body := $( $ ); + make PAST::Op.new( $cond, $body, :pasttype('while'), :node($/) ); +} + +method block_item($/, $key) { + make $( $/{$key} ); +} + +method constant($/, $key) { + make $( $/{$key} ); +} + +method constant_expression($/) { + make $( $ ); +} + +method assignment_expression($/) { + make $( $ ); +} + +method conditional_expression($/) { + my $cond := $( $ ); + if $ { + my $then := $( $[0] ); + my $else := $( $[0] ); + make PAST::Op.new( $cond, $then, $else, :pasttype('if'), :node($/) ); + } + else { + make $cond; + } +} + +method postfix_expression_prefix($/, $key) { + make $( $/{$key} ); +} + +method postfix_expression_suffix($/, $key) { + make $( $/{$key} ); +} + +method index($/) { + my $expr := $( $ ); + ## XXX + make PAST::Op.new( $expr, :name('xxx_index'), :pasttype('call'), :node($/) ); +} + +method direct_field($/) { + my $field := $( $ ); + ## XXX + make PAST::Op.new( $field, :name('xxx_get_field'), :pasttype('call'), :node($/) ); +} + +method indirect_field($/) { + my $field := $( $ ); + ## XXX + make PAST::Op.new( $field, :name('xxx_get_indirect'), :pasttype('call'), :node($/) ); +} + +method inc_or_dec($/) { + my $opname := 'postfix:' ~ ~$; + my $past := PAST::Op.new( :name($opname), :pasttype('call'), :node($/) ); + make $past; +} + +method arguments($/) { + if $ { + make $( $[0] ); + } + else { + make PAST::Op.new( :pasttype('call'), :node($/) ); + } +} + +method argument_expression_list($/) { + my $past := PAST::Op.new( :pasttype('call'), :node($/) ); + for $ { + $past.push( $( $_ ) ); + } + make $past; +} + +method postfix_expression($/) { + my $past := $( $ ); + for $ { + ## XXX + my $args := $( $_ ); + $args.unshift($past); + $past := $args; + } + make $past; +} + +method prefix_expression($/) { + my $opname := 'prefix:' ~ ~$; + my $expr := $( $ ); + make PAST::Op.new( $expr, :name($opname), :pasttype('call'), :node($/) ); +} + +method primary_expression($/, $key) { + make $( $/{$key} ); +} + +method unary_expression($/, $key) { + make $( $/{$key} ); +} + +method integer_constant($/) { + make PAST::Val.new( :value( ~$/ ), :returns('Integer'), :node($/) ); +} + +method floating_constant($/) { + make PAST::Val.new( :value( ~$/ ), :returns('Float'), :node($/) ); +} + + +method c_string_literal($/) { + make PAST::Val.new( :value( ~$ ), :node($/) ); + #make PAST::Val.new( :value( ~$/ ), :node($/) ); +} + +method identifier($/) { + ## XXX fix scopes + ## XXX fix declarations so that :viviself can be removed + make PAST::Var.new( :name( ~$/ ), :scope('package'), :viviself('Integer'), :node($/) ); +} + +method cast_expression($/) { + make $( $ ); +} + +method logical_expression($/, $key) { + if ($key eq 'end') { + make $($); + } + else { + my $past := PAST::Op.new( :name($), + :pasttype($), + :pirop($), + :lvalue($), + :node($/) + ); + for @($/) { + $past.push( $($_) ); + } + make $past; + } + +} + + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: + diff --git a/src/parser/grammar.pg b/src/parser/grammar.pg new file mode 100644 index 0000000..60842e6 --- /dev/null +++ b/src/parser/grammar.pg @@ -0,0 +1,769 @@ +# $Id: grammar.pg 36833 2009-02-17 20:09:26Z allison $ +# Copyright (C) 2008, Parrot Foundation. + +=begin overview + +This is the grammar for C99 written as a sequence of Perl 6 rules. + + +taken from n869.pdf +google for n869.pdf + +=end overview + +grammar C99::Grammar is PCT::Grammar; + +## A.2.4 External definitions +## + +token TOP { + ^ + + + [ $ || <.panic: Syntax error> ] + {*} +} + +rule external_declaration { + | {*} #= declaration + | {*} #= function_definition +} + +rule function_definition { + + + * + + {*} +} + + +## A.2.2 +## + +rule declaration { + + [ [',' ]* ]? + ';' + {*} +} + +rule declaration_specifiers { + [ + | + | + | + ]+ +} + +rule function_specifier { + 'inline' +} + +rule init_declarator { + ['=' ]? + {*} +} + +rule storage_class_specifier { + | 'typedef' + | 'extern' + | 'static' + | 'auto' + | 'register' +} + +rule type_specifier { + | + | + | + | +} + +token builtin_type { + | 'void' + | 'char' + | 'short' + | 'int' + | 'long' + | 'float' + | 'double' + | 'signed' + | 'unsigned' + | '_Bool' + | '_Complex' + | '_Imaginary' +} + +rule struct_or_union_specifier { + $=['struct'|'union'] + [ + | + | + ] +} + +rule struct_or_union_definition { + ? '{' + '}' +} + +rule pre_declaration { + +} + +rule struct_declaration { + * ';' +} + +rule specifier_qualifier_list { + [ + | + | + ]+ +} + +rule struct_declarator_list { + [',' ]* +} + +rule struct_declarator { + | ? ':' + | +} + +rule enum_specifier { + | 'enum' ? '{' [',']? '}' + | 'enum' +} + +rule enumerator_list { + [',' ]* +} + +rule enumerator { + ['=' ]? +} + +rule type_qualifier { + $=['const'|'restrict'|'volatile'] +} + +rule declarator { + ? + + {*} +} + +rule direct_declarator { + + * + {*} +} + +rule declarator_prefix { + | '(' ')' {*} #= declarator + | {*} #= identifier +} + +rule declarator_suffix { + | '(' ')' {*} #= parameter_type_list + ## old-style C parameter declarations + | '(' ? ')' {*} #= identifier_list + | '[' ? ']' + | '[' '*' ']' +} + +rule pointer { + '*' * ['*']? +} + +rule parameter_type_list { + [$=[',' '...']]? + {*} +} + +rule parameter_list { + [',' ]* + {*} +} + +rule parameter_declaration { + + [ + | {*} #= declarator + | ? {*} #= abstract_declarator + ] +} + +rule identifier_list { + [',' ]* +} + +rule type_name { + ? +} + +rule abstract_declarator { + | '*' + | ['*']? +} + +rule direct_abstract_declarator { + [ + | '(' ')' + | '[' ? ']' + | '(' ')' + ] + * +} + +rule direct_abstract_declarator_1 { + | '[' ? ']' + | '[' '*' ']' + | '(' ')' +} + +rule typedef_name { + +## a typedef name can be a return type specifier. This is ambiguous, because +## the parser doesn't know if it's a return type thingie or the name of the +## function. Therefore, typedef'd names must be stored in a %hash, so that +## this rule is not calling , but inspecting the registered +## typedef'd names. For now, specify 'SOME_TYPEDEF_NAME' as the only typedef'd name. +## + # + 'SOME_TYPEDEF_NAME' +} + +rule initializer { + | + | '{' [',']? '}' +} + +rule initializer_list { + [',' ]* +} + +rule initializer_item { + ? +} + +rule designation { + + '=' +} + +rule designator { + | '[' ']' + | '.' +} + + +## A.2.3 Statements +## + +rule statement { + | + | {*} #= compound_statement + | {*} #= expression_statement + | {*} #= if_statement + | + | {*} #= while_statement + | {*} #= do_while_statement + | {*} #= for1_statement + | {*} #= for2_statement + | {*} #= jump_statement +} + +rule labeled_statement { + | ':' + | 'case' ':' + | 'default' ':' +} + +rule compound_statement { + '{' * '}' + {*} +} + +rule block_item { + | {*} #= declaration + | {*} #= statement +} + +rule expression_statement { + ? ';' + {*} +} + +rule if_statement { + 'if' '(' ')' ['else' $=]? + {*} +} + +rule switch_statement { + 'switch' '(' ')' +} + +rule while_statement { + 'while' '(' ')' + {*} +} + +rule do_while_statement { + 'do' 'while' '(' ')' ';' + {*} +} + +rule for1_statement { + 'for' '(' [$=]? ';' [$=]? ';' [$=]? ')' + + {*} +} + +rule for2_statement { + 'for' '(' [$=]? ';' [$=]? ')' + {*} +} + +rule jump_statement { + | 'goto' ';' {*} #= goto + | 'continue' ';' {*} #= continue + | 'break' ';' {*} #= break + | 'return' ? ';' {*} #= return +} + + +## A.1.1 Lexical elements +## +##rule token { +## | +## | +## | +## | +## | +##} + +regex preprocessing_token { + | + | + | + | + | + | + | + | <-[# \r\n\t]>\S* ## <-[#]-\S>\S* ##non-whitespace +} + +## A.1.2 Keywords +## +token keyword { + [ auto | enum | restrict | unsigned + | break | extern | return | void + | case | float | short | volatile + | char | for | signed | while + | const | goto | sizeof | _Bool + | continue | if | static | _Complex + | default | inline | struct | _Imaginary + | do | int | switch + | double | long | typedef + | else | register | union ]>> + +} + +token reserved_word { + +} + + +token identifier { + + [ | ]* + {*} +} + +token identifier_nondigit { + | <[_]> | +} + +## A.1.4 Universal character names +## +token universal_character_name { + | '\u' **{4} + | '\U' **{8} +} + + +## A.1.5 Constants +## +token constant { + | {*} #= floating_constant + | {*} #= integer_constant + | {*} #= enumeration_constant + | {*} #= character_constant +} + +token integer_constant { + [ + | + | + ] + ? + {*} +} + +token decimal_constant { + <[1..9]> * +} + +token octal_constant { + 0 <[0..7]>* +} + +token hexadecimal_constant { + 0 <[xX]> + +} + +token integer_suffix { + | <[uU]> [ll?|LL?]? + | [ll?|LL?] <[uU]>? +} + +token floating_constant { + [ + | + | + ] + {*} +} + +token decimal_floating_constant { + [ + | ? + | + ] + ? +} + +token hexadecimal_prefix { + 0 <[xX]> +} + +token hexadecimal_floating_constant { + + [ + | + | + ] + ? +} + +token fractional_constant { + | ? \. + | \. +} + +token exponent_part { + <[eE]> ['+'|'-']? +} + +token digit_sequence { + } + +token hexadecimal_fractional_constant { + | ? \. + | \. +} + +token binary_exponent_part { + <[pP]> ['+'|'-']? +} + +token hexadecimal_digit_sequence { + } + +token floating_suffix { <[fFlL]> } + +token enumeration_constant { } + +token character_constant { [L]? \' + \' } + +token { <-['\\\n]> | } + +token escape_sequence { + \\ + [ <['"?\\abfnrtv]> + | **{1..3} + | x + + | + ] +} + +## A.1.6 String literals +token c_string_literal { + [L]? + {*} +} + +##\" * \" + +token s_char { <-["\\\n]> | } + + +## A.2 Phrase structure grammar +## + +## A.2.1 Expressions +## + +rule constant_expression { + + {*} +} + +rule expression { + [',' ]* + {*} +} + +rule assignment_expression { + [ ]* + {*} +} + +rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' } + +rule conditional_expression { + ['?' ':' ]? + {*} +} + +rule logical_expression is optable { ... } + +proto 'infix:||' is precedence('1') { ... } + +proto 'infix:&&' is tighter('infix:||') { ... } + +proto 'infix:|' is tighter('infix:&&') { ... } + +proto 'infix:^' is tighter('infix:|') { ... } + +proto 'infix:&' is tighter('infix:^') { ... } + +proto 'infix:==' is tighter('infix:&') { ... } +proto 'infix:!=' is equal('infix:==') { ... } + +proto 'infix:<' is tighter('infix:==') { ... } +proto 'infix:>' is equal('infix:<') { ... } +proto 'infix:>=' is equal('infix:<') { ... } +proto 'infix:<=' is equal('infix:<') { ... } + +proto 'infix:<<' is tighter('infix:==') { ... } +proto 'infix:>>' is equal('infix:<<') { ... } + +proto 'infix:+' is tighter('infix:<<') is pirop('n_add') { ... } +proto 'infix:-' is equal('infix:+') is pirop('n_sub') { ... } + +proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... } +proto 'infix:/' is equal('infix:*') is pirop('n_div') { ... } +proto 'infix:%' is equal('infix:*') is pirop('n_mod') { ... } + +proto 'term:' is tighter('infix:*') + is parsed(&cast_expression) { ... } + + +rule postfix_expression_prefix { + | {*} #= primary_expression + | '(' ')' '{' [',']? '}' {*} #= type_name +} + +rule postfix_expression { + + * + {*} +} + +rule postfix_expression_suffix { + | {*} #= index + | {*} #= arguments + | {*} #= direct_field + | {*} #= indirect_field + | {*} #= inc_or_dec +} + +rule inc_or_dec { + $=['++'|'--'] + {*} +} + +rule index { + '[' ']' + {*} +} + +rule direct_field { + '.' + {*} +} + +rule indirect_field { + '->' + {*} +} + +rule arguments { + '(' ? ')' + {*} +} + +rule argument_expression_list { + [',' ]* + {*} +} + +rule unary_expression { + | {*} #= postfix_expression + | {*} #= prefix_expression + | + | 'sizeof' + | 'sizeof' '(' ')' +} + +rule prefix_expression { + $=['++'|'--'] + {*} +} + +rule unary_operator { + '&' | '*' | '+' | '-' | '~' | '!' +} + +rule cast_expression { + ['(' ')']* + {*} +} + +rule primary_expression { + | {*} #= identifier + | {*} #= constant + | {*} #= c_string_literal + | '(' ')' {*} #= expression +} + +token ws { + [ + | '//' \N* \n + | '/*' .*? '*/' + | \s+ + | '#' \N* \n + ]* +} + +## A.1.7 Punctuators +## + +token punctuator { + | \[ | \] | <[(){}.]> | '->' + | '++' | '--' | <[&*+\-~!/%]> + | '<<' | '>>' | '<' | '>' + | '<=' | '>=' | '==' | '!=' + | <[^|]> | '&&' | '||' + | <[?:;]> | '...' + | <[*/%+\-&^|]> | '<<' | '>>' | '=' + | <[,#]> | '##' + | '<:' | ':>' | '<%' | '%>' | '%:' | '%:%:' +} + + +## A.3 Preprocessing directives +## + +rule pre_processing_file { + ? +} + +rule group { + + +} + +rule group_part { + | ? + | + | +} + +rule if_section { + * ? +} + +rule if_group { + | '#' 'if' ? + | '#' 'ifdef' ? + | '#' 'ifndef' ? +} + +rule elif_group { + '#' 'elif' ? +} + +rule else_group { + '#' 'else' ? +} + +rule endif_line { + '#' 'endif' +} + +rule control_line { + | '#' 'include' + | '#' 'define' + | '#' 'define' ? ')' + | '#' 'define' '...' ')' + | '#' 'define' ',' '...' ')' + | '#' 'undef' + | '#' 'line' + | '#' 'error' ? + | '#' 'pragma' ? + | '#' +} + +rule pp_tokens { + + +} + +rule preprocessing_token { + | + | + | + | + | + | +} + +rule pp_number { + ['.']? * +} + +rule pp_number_suffix { + | '.' + | + | + | <[eEpP]> ['+'|'-'] +} + +rule replacement_list { + ? +} + +token lparen { + '(' +} + +token newline { + \n +} + +## A.1.8 Header names +token header_name { + | \< + \> + | \" + \" +} + +token h_char { <-[\n>]> } +token q_char { <-[\n"]> } diff --git a/src/preamble b/src/preamble new file mode 100644 index 0000000..2a1bb3b --- /dev/null +++ b/src/preamble @@ -0,0 +1,96 @@ +.macro kdump ( x ) + .local pmc it + it = get_root_global ['parrot'], '_dumper' + it(.x) +.endm + +.macro kdump2 ( x, d) + .local pmc it + it = get_root_global ['parrot'], '_dumper' + it(.x, .d) +.endm + +.macro dump_root + .local string it + .local pmc ns + ns = get_root_namespace [ 'parrot'; 'Cardinal::Grammar' ] + .local pmc iter + iter = new 'Iterator', ns + set iter, 0 + .label $iter_loop: + unless iter, .$iter_end + shift it, iter + print it + print "\n" + goto .$iter_loop + .label $iter_end: +.endm + +.macro dump_hll + .local string it + .local pmc ns + ns = get_hll_namespace + .local pmc iter + iter = new 'Iterator', ns + set iter, 0 + .label $iter_loop: + unless iter, .$iter_end + shift it, iter + print it + print "\n" + goto .$iter_loop + .label $iter_end: +.endm + +.macro dump_hll2 + .local string it + .local pmc ns + ns = get_hll_namespace + .local pmc iter + iter = new 'Iterator', ns + set iter, 0 + .label $iter_loop: + unless iter, .$iter_end + shift it, iter + print it + print "\n" + goto .$iter_loop + .label $iter_end: +.endm + +.macro dump_current + .local string it + .local pmc ns + ns = get_namespace + .local pmc iter + iter = new 'Iterator', ns + set iter, 0 + .label $iter_loop: + unless iter, .$iter_end + shift it, iter + print it + print "\n" + goto .$iter_loop + .label $iter_end: +.endm + +.macro gen_accessor(x) +.sub .x :method + .param pmc value :optional + .param int has_value :opt_flag + .return self.'attr'(.x, value, has_value) +.end +.endm + +.macro gen_get_accessor(x) +.sub .x :method + null $P0 + .return self.'attr'(.x, $P0, 0) +.end +.endm + +.macro gen_dumplist(x) +.sub '__dumplist' :method + .return (.x) +.end +.endm diff --git a/t/harness b/t/harness new file mode 100755 index 0000000..822b617 --- /dev/null +++ b/t/harness @@ -0,0 +1,7 @@ +#!/usr/bin/perl + +# $Id: harness 25985 2008-02-22 12:22:13Z kjs $ + +use FindBin; +use lib qw( . lib ../lib ../../lib ../../lib ); +use Parrot::Test::Harness language => 'c99', compiler => 'c99.pbc'; diff --git a/t/spi.t b/t/spi.t new file mode 100644 index 0000000..5e8a395 --- /dev/null +++ b/t/spi.t @@ -0,0 +1,33 @@ + + + +void main() { + puts("1..6"); + puts("ok 1"); + + if (0) + puts("nok 2"); + else { + puts("ok 2"); + } + + + if (1) { + puts("ok 3"); + } + else + puts("nok 3"); + + do { + puts("ok 4"); + } + while(0); + + while(0) { + puts("nok 5"); + } + puts("ok 5"); + + 1 ? puts("ok 6") : puts("nok 6"); +} +