Permalink
Browse files

[c99] Relocating c99 language to languages repository from

  • Loading branch information...
0 parents commit f1c2b76684ef6a11fa80f04d92d0e84358efedd2 @allisonrandal allisonrandal committed Mar 10, 2009
7 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
80 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<PCT::HLLCompiler>
+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<args>
+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:
+
102 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:
113 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:
90 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:
190 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 <tewk@tewk.com>
+
+=cut
336 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 <tewk@tewk.com>
+
+=cut
300 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<C99::CPP::PAST::Node::unique([string fmt])>
+
+Each call to C<unique> returns a unique number, or if a C<fmt>
+parameter is given it returns a unique string beginning with
+C<fmt>. (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:
92 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:
82 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:
+
581 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 {
+ | <keyword>
+ | <identifier>
+ | <constant>
+ | <string_literal>
+ | <punctuator>
+}
+
+token pound { <'\#'> }
+
+regex preprocessing_token {
+ | <header_name>
+ | <identifier>
+ | <pp_number>
+ | <character_constant>
+ | <string_literal>
+ | <!pound> <punctuator>
+ | <universal_character_name>
+ | <-[# \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 { <identifier_nondigit> [ <identifier_nondigit> | \d ]* }
+token identifier { <?identifier_nondigit> [ <?identifier_nondigit> | <?digit> ]* }
+
+token identifier_nondigit { <alpha> | <[_]> | <universal_character_name> }
+
+## A.1.4 Universal character names
+token universal_character_name {
+ | <'\u'> <xdigit>**{4}
+ | <'\U'> <xdigit>**{8}
+}
+
+## A.1.5 Constants
+token constant {
+ | <integer_constant>
+ | <floating_constant>
+ | <enumeration_constant>
+ | <character_constant>
+}
+
+token integer_constant {
+ [ <decimal_constant>
+ | <octal_constant>
+ | <hexadecimal_constant>
+ ] <integer_sufffix>?
+}
+
+token decimal_constant { <[1..9]> <digit> }
+#token decimal_constant { <[1..9]> \d* }
+token octal_constant { 0 <[0..7]>+ }
+token hexadecimal_constant { 0 <[xX]> <xdigit>+ }
+
+token integer_suffix {
+ | <[uU]> [ll?|LL?]?
+ | [ll?|LL?] <[uU]>?
+}
+
+token floating_constant {
+ | <decimal_floating_constant>
+ | <hexadecimal_floating_constant>
+}
+
+token decimal_floating_constant {
+ [ <fractional_constant> <exponent_part>?
+ | <digit_sequence> <exponent_part>
+ ] <floating_suffix>?
+}
+
+token hexadecimal_prefix
+{
+ 0 <[xX]>
+}
+
+token hexadecimal_floating_constant {
+ <hexadecimal_prefix>
+ [ <hexadecimal_fractional_constant>
+ | <hexadecimal_digit_constant>
+ ] <binary_exponent_part> <floating_suffix>?
+}
+
+token fractional_constant {
+ | <digit_sequence>? \. <digit_sequence>
+ | <digit_sequence> \.
+}
+
+token exponent_part {
+ <[eE]> <[\+\-]>? <digit_sequence>
+}
+
+#token digit_sequence { \d+ }
+token digit_sequence { <digit>+ }
+
+token hexadecimal_fractional_constant {
+ | <hexadecimal_digit_sequence>? \. <hexadecimal_digit_sequence>
+ | <hexadecimal_digit_sequence> \.
+}
+
+token binary_exponent_part {
+ <[pP]> <[\+\-]>? <digit_sequence>
+}
+
+token hexadecimal_digit_sequence { <xdigit>+ }
+
+token floating_suffix { <[fFlL]> }
+
+token enumeration_constant { <identifier> }
+
+token character_constant { <[L]>? \' <c_char>+ \' }
+
+token <c_char> { <-['\\\n]> | <escape_sequence> }
+
+token escape_sequence {
+ \\
+ [ <['"?\\abfnrtv]>
+ | <octal_digit>**{1..3}
+ | x <xdigit>+
+ | <universal_character_name>
+ ]
+}
+
+## A.1.6 String literals
+token string_literal { <[L]>? " <s_char>* " }
+
+token s_char { <-["\\\n]> | <escape_sequence> }
+
+## A.1.7 Punctuators
+token punctuator {
+ | \[ | \] | <[(){}.]> | <'->'>
+ | <'++'> | <'--'> | <[&*+\-~!/%]>
+ | <'<<'> | <'>>'> | <[<>]>
+ | <'<='> | <'>='> | <'=='> | <'!='>
+ | <[^|]> | <'&&'> | <'||'>
+ | <[?:;]> | <'...'>
+ | [ <[*/%+\-&^|]> | <'<<'> | <'>>'> ] <'='>
+ | <[,#]> | <'##'>
+ | <'<:'> | <':>'> | <'<%'> | <'%>'> | <'%:'> | <'%:%:'>
+}
+
+## A.1.8 Header names
+token header_name {
+ | \< $<name:>=<?h_char>+ \>
+ | " $<name>:=<?q_char>+ "
+}
+
+token h_char { <-[\n>]> }
+token q_char { <-[\n"]> }
+
+## A.1.9 Preprocessing numbers
+token pp_number { \.? \d [ \d | <identifier_nondigit> | <[eEpP]> <[\+\-]> | \. ]* }
+
+## A.2 Phrase structure grammar
+## XXX: see below
+
+## A.2.2 Declarations
+rule declaration { <declaration_specifier>+ <init_declarator_list>? ; }
+
+rule declaration_specifier {
+ | <storage_class_specifier>
+ | <type_specifier>
+ | <type_qualifier>
+ | <function_specifier>
+}
+
+rule init_declarator_list { init_declarator [ , <init_declarator> ]* }
+
+rule init_declarator { <declarator> [ = <initializer> ]? }
+
+token storage_class_specifier { typedef | extern | static | auto | register }
+
+rule type_specifier {
+ | void | char | short | int
+ | long | float | double | signed
+ | unsigned | _Bool | _Complex | _Imaginary
+ | <struct_or_union_specifier>
+ | <enum_specifier>
+ | <typedef_name>
+}
+
+rule struct_or_union_specifier {
+ [ $<struct>:=<'struct'> | $<union>:=<'union'> ] [ <identifier> | <identifier>? \{ <struct_declaration>+ \} ]
+}
+
+rule struct_declaration { [<type_specifier>|<type_qualifier>]+ <struct_declarator>+ ; }
+
+rule struct_declarator { <declarator> | <declarator>? : <constant_expression> }
+
+rule enum_specifier { enum [ <identifier>? \{ <enumerator> [ , <enumerator> ]+ [,]? \}| <identifier> ] }
+
+rule enumerator { <enumeration_constant> [ = <constant_expression> ]? }
+
+token type_qualifier { const | restrict | volatile }
+
+token function_specifier { inline }
+
+rule declarator { <pointer>? <direct_declarator> }
+
+rule direct_declarator {
+ [ <identifier> | \( <declarator> \) ]
+ [
+ | \[ <assignment_expression>? \]
+ | \[ \* \]
+ | \( <parameter_type_list> \)
+ | \( <identifier_list>? \)
+ ]*
+}
+
+rule pointer { [\* <type_qualifier>* ]+ }
+
+rule parameter_type_list { <parameter_declaration> [ , <parameter_declaration> ]* [ , <'...'>]? }
+
+rule parameter_declaration { <declaration_specifier>+ [ <declarator> | <abstract_declatator> ]? }
+
+rule identifier_list { <identifier> [ , <identifier> ]* }
+
+rule type_name { <specifier_qualifier_list> <abstract_declatator>? }
+
+rule abstract_declatator {
+ <pointer>? <direct_abstract_declarator>
+ |<pointer>
+}
+
+rule direct_abstract_declarator {
+ [
+ | \( <abstract_declatator> \)
+ | \[ <assignment_expression>? \]
+ | \( <parameter_type_list> \)
+ ]
+ <direct_abstract_declarator_1>*
+}
+
+rule direct_abstract_declarator_1 {
+ | \[ <assignment_expression>? \]
+ | \[ * \]
+ | \( <parameter_type_list> \)
+}
+
+rule typedef_name { <identifier> }
+
+rule initializer { <assignment_expression> | \{ <initializer_list> [,]? \} }
+
+rule initializer_list { <designation>? <initializer> [, <designation>? <initializer> ]* }
+
+rule designation { <designator>+ = }
+
+rule designator {
+ | \[ <constant_expression> \]
+ | \. <identifier>
+}
+
+## A.2.3 Statements
+rule statement {
+ | <labeled_statement>
+ | <compound_statement>
+ | <expression_statement>
+ | <selection_statement>
+ | <iteration_statement>
+ | <jump_statement>
+}
+
+rule labeled_statement {
+ [ <identifier> \:
+ | case <constant_expression> \:
+ | default \:
+ ] <statement>
+}
+
+rule compound_statement { \{ [ <declaration> | <statement> ]* \} }
+
+rule expression_statement { <expression>? ; }
+
+rule selection_statement {
+ | if \( <expresssion> \) <statement> [else <statement>]?
+ | switch \( <expression> \) <statement>
+}
+
+rule iteration_statement {
+ | while \( <expression> \) <statement>
+ | do <statement> while \( <expression> \) ;
+ | for \( [ <expression>? ; <expression>? ; <expression>? | <declaration> <expression>? ; <expression>? ] \) <statement>
+}
+
+rule jump_statement {
+ | goto <identifier> ;
+ | continue ;
+ | break ;
+ | return <expression>? ;
+}
+
+
+## A.2.4 External definitions
+rule translation_unit { [ <function_definition> | <declaration> ]+ }
+
+rule function_definition { <declaration_specifier>+ <declarator> <declaration>* <compound_statement> }
+
+
+## A.3 preprocessing directives
+token wsnws {
+ <?ws_minus_n>? \n <?ws>?
+}
+
+regex prereprocessing_file { <group> }
+
+regex group { <group_line>+ }
+
+regex group_line {
+ | <if_section>
+ | <control_line>
+ | <source_line>? $<wsnws>:=<?wsnws>
+}
+
+regex source_line {
+ <?pp_tokens>
+}
+
+
+rule if_section { <if_group> <elif_group>* <else_group>? <endif_line> }
+
+token ws_minus_n
+{
+ [
+ | <'//'> \N* \n
+ | <'/*'> .*? <'*/'>
+ | \t
+ | <' '>
+ ## | <\s-<[\n]>
+ ]*
+}
+
+regex if_group {
+ [
+ | \# <?ws>? $<ifndef>:=<'ifndef'> <?ws> <identifier>
+ | \# <?ws>? $<ifdef>:=<'ifdef'> <?ws> <identifier>
+ | \# <?ws>? $<if>:=<'if'> <?ws> <constant_expression>
+ ] <?wsnws> <group>?
+}
+
+regex elif_group { \# <?ws> $<elif>:=<'elif'> <?ws> <constant_expression> <?wsnws> <group>? }
+regex else_group { \# <?ws> $<else>:=<'else'> <?wsnws> <group>? }
+regex endif_line { \# <?ws> $<endif>:=<'endif'> <?wsnws> }
+regex control_line {
+ | \# <?ws>? $<include>:=<'include'> <?ws_minus_n> $<value>:=<pp_tokens> <?wsnws>
+ | \# <?ws>? $<define>:=<'define'> <?ws>
+ [
+ | $<define_name>:=<identifier>
+ | $<define_function>:=(<identifier_p> [ <identifier_list> [, \.\.\.]? | [ \.\.\.] ]? \))
+ ] <?ws_minus_n>? $<value>:=<pp_tokens>?
+ | \# ?<ws>? $<undefine>:=<'undefine'> <?ws_minus_n> <identifier> <?wsnws>
+ | \# ?<ws>? $<line>:=<'line'> <?ws_minus_n> $<value>:=<pp_tokens> <?wsnws>
+ | \# ?<ws>? $<error>:=<'error'> <?ws_minus_n> $<value>:=<pp_tokens>? <?wsnws>
+ | \# ?<ws>? $<pragma>:=<'pragma'> <?ws_minus_n> $<value>:=<pp_tokens>? <?wsnws>
+ | \# <?wsnws>
+
+}
+
+token identifier_p { <identifier> \( }
+regex pp_tokens { <preprocessing_token> [<?ws_minus_n> <preprocessing_token>]* }
+
+
+## A.2.1 Expressions
+rule primary_expression {
+ | <identifier>
+ | <constant>
+ | <string_literal>
+ | \( <expression> \)
+}
+
+rule postfix_expression {
+ [ <primary_expression>
+ | \( <type_name> \) \{ <initializer_list> [\,]? \} ]
+
+ [ <'++'>
+ | <'--'>
+ | \[ <expression> \]
+ | \( [ <assignment_expression> [ \, <assignment_expression> ]* ]? \)
+ | \. <identifier>
+ | <'->'> <identifier>
+ | \( <type_name> \) \{ <initializer_list> [\,]? \}
+ ]*
+}
+
+rule unary_expression {
+ [<'++'>|<'--'>|<'sizeof'>]?
+
+ [ <postfix_expression>
+ | $<unary_op>:=<[&*+\-~!]> <cast_expression>
+ | <'sizeof'> \( <type_name> \)
+ ]
+}
+
+rule cast_expression { [ \( <type_name> \) ]* <unary_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 { <postfix_expression> \[ <expression> \] }
+#proto 'postcircumfix:()' is equiv('postfix:++') { ... }
+#rule postfix_expression { <postfix_expression> \( [ <assignment_expression> [\, <assignment_expression>]* ]? \) }
+#proto 'infix:.' is equiv('postfix:++') { ... }
+#rule postfix_expression { <postfix_expression> . <identifier> }
+#proto 'infix:->' is equiv('postfix:++') { ... }
+#rule postfix_expression { <postfix_expression> \-\> <identifier> }
+#proto 'postfix:--' is equiv('postfix:++') { ... }
+#rule postfix_expression { \( <type_name> \) \{ <initializer_list> [,]? \} }
+
+## 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 <unary_expression> }
+#rule unary_expression { sizeof [\( <type_name> \) ] }
+
+## cast-expression
+## XXX: PGE doesn't have a precircumfix:() function (yet?)
+#proto 'precircumfix:()' is precedence('17=') {...}
+#rule cast_expression { [\( <type_name> \) ]* <unary_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 { <operator_precedence_parser> [ \? <expression> : <operator_precedence_parser> ]* }
+
+rule assignment_expression { [ <unary_expression> <assignment_operator> ]* <constant_expression> }
+
+token assignment_operator {
+ | <'*='>
+ | <'/='>
+ | <'%='>
+ | <'+='>
+ | <'-='>
+ | <'<<='>
+ | <'>>='>
+ | <'&='>
+ | <'^='>
+ | <'|='>
+}
+
+rule expression { <assignment_expression> [, <assignment_expression> ] }
+rule constant_expression { <conditional_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') { ... }
60 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 <kevintew@tewk.com>
+
+=cut
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
106 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:
80 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<PCT::HLLCompiler>
+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<args>
+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:
+
82 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:
+
31 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<src/parser/grammar.pg>,
+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:
+
431 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*
+ | <multilinecomment>
+}
+
+token TOP {
+ ^
+ <pre_processing_file>
+ [ $ || <.panic: Syntax error> ]
+ {*}
+}
+
+## A.1.5 Constants
+##
+token constant {
+ | <floating_constant> {*} #= floating_constant
+ | <integer_constant> {*} #= integer_constant
+ | <enumeration_constant> {*} #= enumeration_constant
+ | <character_constant> {*} #= character_constant
+}
+
+token integer_constant {
+ [ <decimal_constant>
+ | <octal_constant>
+ | <hexadecimal_constant>
+ ]
+ <integer_suffix>?
+ {*}
+}
+
+token decimal_constant {
+ <[1..9]> <digit>*
+}
+
+token octal_constant {
+ 0 <[0..7]>*
+}
+
+token hexadecimal_constant {
+ 0 <[xX]> <xdigit>+
+}
+
+token integer_suffix {
+ | <[uU]> [ll?|LL?]?
+ | [ll?|LL?] <[uU]>?
+}
+
+token floating_constant {
+ [
+ | <decimal_floating_constant>
+ | <hexadecimal_floating_constant>
+ ]
+ {*}
+}
+
+token decimal_floating_constant {
+ [
+ | <fractional_constant> <exponent_part>?
+ | <digit_sequence> <exponent_part>
+ ]
+ <floating_suffix>?
+}
+
+token hexadecimal_prefix {
+ 0 <[xX]>
+}
+
+token hexadecimal_floating_constant {
+ <hexadecimal_prefix>
+ [
+ | <hexadecimal_fractional_constant>
+ | <hexadecimal_digit_constant>
+ ]
+ <binary_exponent_part> <floating_suffix>?
+}
+
+token fractional_constant {
+ | <digit_sequence>? \. <digit_sequence>
+ | <digit_sequence> \.
+}
+
+token exponent_part {
+ <[eE]> ['+'|'-']? <digit_sequence>
+}
+
+token digit_sequence { <digit>+ }
+
+token hexadecimal_fractional_constant {
+ | <hexadecimal_digit_sequence>? \. <hexadecimal_digit_sequence>
+ | <hexadecimal_digit_sequence> \.
+}
+
+token binary_exponent_part {
+ <[pP]> ['+'|'-']? <digit_sequence>
+}
+
+token hexadecimal_digit_sequence { <xdigit>+ }
+
+token floating_suffix { <[fFlL]> }
+
+token enumeration_constant { <identifier> }
+
+token character_constant { [L]? \' <c_char>+ \' }
+
+token <c_char> { <-['\\\n]> | <escape_sequence> }
+
+token escape_sequence {
+ \\
+ [ <['"?\\abfnrtv]>
+ | <octal_digit>**{1..3}
+ | x <xdigit>+
+ | <universal_character_name>
+ ]
+}
+
+## A.1.6 String literals
+token c_string_literal {
+ [L]? <string_literal: '"'>
+ {*}
+}
+
+##\" <s_char>* \"
+
+token s_char { <-["\\\n]> | <escape_sequence> }
+
+
+## A.2 Phrase structure grammar
+##
+
+## A.2.1 Expressions
+##
+
+rule expression {
+ <constant_expression>
+ {*}
+}
+
+rule constant_expression {
+ <conditional_expression>
+ {*}
+}
+
+rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' }
+