diff --git a/compilers/ncigen/MAINTAINER b/compilers/ncigen/MAINTAINER
new file mode 100644
index 0000000..f6d9926
--- /dev/null
+++ b/compilers/ncigen/MAINTAINER
@@ -0,0 +1,7 @@
+# $Id$
+
+N: Kevin Tew
+E: kevintew@tewk.com
+
+N: Klaas-Jan Stol (kjs)
+E: parrotcode@gmail.com
diff --git a/compilers/ncigen/NCIGEN.TODO b/compilers/ncigen/NCIGEN.TODO
new file mode 100644
index 0000000..6d146ad
--- /dev/null
+++ b/compilers/ncigen/NCIGEN.TODO
@@ -0,0 +1,4 @@
+Add option to generate dlfuncs for certain h files not all includes.
+Allow typedefs and structs with the same name in the symbol table.
+Generate ManagedStructs definitions for structs and typedefs.
+Generate parrot_builtin_type entries in the AST such as INT NUM STR o PMC
diff --git a/compilers/ncigen/c99.pir b/compilers/ncigen/c99.pir
new file mode 100644
index 0000000..df89854
--- /dev/null
+++ b/compilers/ncigen/c99.pir
@@ -0,0 +1,136 @@
+# $Id$
+# Copyright (C) 2008, The Perl 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 = split ' ', 'parse nci_ast gen_nci_pir'
+    setattribute $P0, '@stages', $P1
+    $P1 = split ' ', 'e=s help|h target=s trace|t=s encoding=s output|o=s combine version|v libname|l=s nsname|n=s raw|r'
+    setattribute $P0, '@cmdoptions', $P1
+
+    ##  set the $usage attribute
+    $P2 = new 'String'
+    $P2 = <<'USAGE'
+Usage: ncigen [switches] [--] [preprocessedfile] [arguments]
+  -l, --libname        library to load symbols from
+  -n  --nsname         pir namepsace to place symbols into
+  -r  --raw            dump dlfunc pir statements only
+
+Standard HLLCompiler Options:
+  -e program           one line of program
+  -h, --help           display this help text
+  --target=[stage]     specify compilation stage to emit
+  -t, --trace=[flags]  enable trace flags
+  --encoding=[mode]    specify string encoding mode
+  -o, --output=[name]  specify name of output file
+  -v, --version        display version information
+USAGE
+    setattribute $P0, '$usage', $P2
+
+    $P2 = $P0.'command_line'(args)
+.end
+    
+.namespace [ 'PCT::HLLCompiler' ]
+
+.sub 'nci_ast' :method
+    .param pmc source
+    .param pmc adverbs         :slurpy :named
+
+  compile_match:
+    push_eh err_past
+    .local pmc ast
+    ast = source.'item'()
+    pop_eh
+    $I0 = isa ast, 'c99AST::Decls'
+    unless $I0 goto err_past
+    .return (ast)
+
+  err_past:
+    $S0 = typeof source
+    .return self.'panic'('Unable to obtain c99AST from ', $S0)
+.end
+
+.sub 'gen_nci_pir' :method
+    .param pmc source
+    .param pmc adverbs         :slurpy :named
+
+    $P0 = compreg 'NCIPIR'
+    $P1 = $P0.'to_pir'(source, adverbs :flat :named)
+    say $P1
+    .return ($P1)
+.end
+
+
+.include 'src/c99AST.pir'
+.include 'src/NCIPIR.pir'
+.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/compilers/ncigen/config/makefiles/ncigen.in b/compilers/ncigen/config/makefiles/ncigen.in
new file mode 100644
index 0000000..e9a7809
--- /dev/null
+++ b/compilers/ncigen/config/makefiles/ncigen.in
@@ -0,0 +1,121 @@
+## $Id$
+
+## arguments we want to run parrot with
+PARROT_ARGS =
+
+## configuration settings
+BUILD_DIR     = @build_dir@
+LOAD_EXT      = @load_ext@
+O             = @o@
+
+## Setup some commands
+LN_S          = @lns@
+PERL          = @perl@
+RM_RF         = @rm_rf@
+CP            = @cp@
+PARROT        = ../../parrot@exe@
+CAT           = $(PERL) -MExtUtils::Command -e cat
+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: c99.pbc
+
+C_GROUP = $(PMC_DIR)/c_group$(LOAD_EXT)
+
+SOURCES = c99.pir \
+  src/gen_grammar.pir \
+  src/gen_actions.pir \
+  src/gen_builtins.pir \
+  src/c99AST.pir \
+  src/NCIPIR.pir \
+#  $(C_GROUP)
+
+BUILTINS_PIR = \
+  src/builtins/say.pir \
+
+# PMCS = c
+# PMC_SOURCES = $(PMC_DIR)/c.pmc
+
+# the default target
+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
+
+$(C_GROUP): $(PARROT) $(PMC_SOURCES)
+	cd $(PMC_DIR) && $(BUILD_DYNPMC) generate $(PMCS)
+	cd $(PMC_DIR) && $(BUILD_DYNPMC) compile $(PMCS)
+	cd $(PMC_DIR) && $(BUILD_DYNPMC) linklibs $(PMCS)
+	cd $(PMC_DIR) && $(BUILD_DYNPMC) copy --destination=$(PARROT_DYNEXT) $(PMCS)
+
+# 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 = \
+  c99.pbc \
+  src/gen_grammar.pir \
+  src/gen_actions.pir \
+  src/gen_builtins.pir \
+  $(PMC_DIR)/*.h \
+  $(PMC_DIR)/*.c \
+  $(PMC_DIR)/*.dump \
+  $(PMC_DIR)/*$(O) \
+  $(PMC_DIR)/*$(LOAD_EXT) \
+  $(PMC_DIR)/*.exp \
+  $(PMC_DIR)/*.ilk \
+  $(PMC_DIR)/*.manifest \
+  $(PMC_DIR)/*.pdb \
+  $(PMC_DIR)/*.lib \
+
+
+clean:
+	$(RM_RF) $(CLEANUPS)
+
+realclean: clean
+	$(RM_RF) Makefile
+
+distclean: realclean
+
+
diff --git a/compilers/ncigen/lib/Parrot/Test/C99AST.pm b/compilers/ncigen/lib/Parrot/Test/C99AST.pm
new file mode 100644
index 0000000..9edca06
--- /dev/null
+++ b/compilers/ncigen/lib/Parrot/Test/C99AST.pm
@@ -0,0 +1,167 @@
+# $Id$
+# Copyright (C) 2006-2008, The Perl Foundation.
+
+package Parrot::Test::C99AST;
+
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Spec;
+use File::Basename;
+use Parrot::Test;
+use Data::Dumper;
+
+use Parrot::Config;
+
+require Exporter;
+require Test::Builder;
+require Test::More;
+
+our @EXPORT = qw( ast parse plan skip like istypedef ispointer decl_ident_is type_is is_builtin parse_failure parse_success contains);
+our @EXPORT_OK = qw();
+
+use base qw( Exporter );
+
+# Memoize functions with a fixed output
+# Memoize::memoize('path_to_parrot');
+#
+# # Tell parrot it's being tested--disables searching of installed libraries.
+# # (see Parrot_get_runtime_prefix in src/library.c).
+# $ENV{PARROT_TEST} = 1 unless defined $ENV{PARROT_TEST};
+#
+my $builder = Test::Builder->new();
+
+our $ME = new();
+$ME->{builder}        = $builder;
+$ME->{path_to_parrot} = Parrot::Test::path_to_parrot();
+$ME->{parrot}         = File::Spec->join( $ME->{path_to_parrot}, 'parrot' . $PConfig{exe} );
+our $results;
+
+
+sub import {
+    my ( $class, $plan, @args ) = @_;
+
+    $builder->plan( $plan, @args );
+
+    __PACKAGE__->export_to_level( 1, __PACKAGE__ );
+}
+
+*plan = \&Test::More::plan;
+*skip = \&Test::More::skip;
+
+=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 ast {
+  my ( $code ) = @_;
+  $results = $ME->ncigenit($code, '--target=nci_ast');
+}
+
+sub parse {
+  my ( $code ) = @_;
+  $results = $ME->ncigenit($code, '--target=parse');
+}
+
+sub like {
+    return $ME->testit('like', @$results, @_);
+}
+
+sub istypedef {
+  return like( qr/c99AST::TypeDef/, @_);
+}
+sub ispointer {
+  return like( qr/<pointer> => 1/, @_);
+}
+
+sub decl_ident_is {
+  my $id = shift @_;
+  return like( qr/<name> => \"$id/, @_);
+}
+sub type_is {
+  my $id = shift @_;
+  return like( qr/<type> => \"$id/, @_);
+}
+sub is_builtin{
+  return like( qr/<builtin_type> => 1/, @_);
+}
+
+sub contains {
+  my $it = shift @_;
+  return like( qr/$it/, @_);
+}
+
+sub parse_failure {
+  $ME->{builder}->ok( $results->[3] == 1, @_ );
+}
+
+sub parse_success {
+  my $code = shift @_;
+  $results = $ME->ncigenit($code, '--target=parse');
+  $ME->{builder}->ok( $results->[3] == 0, @_ );
+}
+
+sub ncigenit {
+    my ( $self, $code, $c99args ) = @_;
+
+    my $count = $self->{builder}->current_test + 1;
+    my $parrotdir       = dirname $self->{parrot};
+
+    my @fns = map { File::Spec->rel2abs( Parrot::Test::per_test( $_, $count ) ) } ( '.c', '.out' );
+    my ( $lang_f, $out_f ) = @fns;
+
+    Parrot::Test::write_code_to_file( $code, $lang_f );
+
+    my $args = $ENV{TEST_PROG_ARGS} || '';
+
+    my $cmd       = "$self->{parrot} $args $parrotdir/compilers/ncigen/c99.pbc $c99args $lang_f";
+    my $exit_code = Parrot::Test::run_command(
+            $cmd,
+            CD     => $self->{relpath},
+            STDOUT => $out_f,
+            STDERR => $out_f
+            );
+    my $output = Parrot::Test::slurp_file($out_f);
+    
+    unless ( $ENV{POSTMORTEM} ) {
+        unlink $lang_f;
+        unlink $out_f;
+    }
+
+    my @results = ($code, $cmd, $output, $exit_code, $count);
+    wantarray ? return @results : return [ @results ];
+}
+
+sub testit() {
+    my ( $self, $method, $code, $cmd, $output, $exit_code, $count, $expected, $desc ) = @_;
+    #print "$cmd, $exit_code, $count, $expected, $desc \n";
+
+    $desc = "C99AST Test $count" unless $desc;
+    my $pass = $self->{builder}->$method( $output, $expected, $desc );
+    if ($exit_code or not $pass)  {
+      $self->{builder}->diag("'$cmd' failed with exit code $exit_code") if $exit_code or not $pass;
+      $self->{builder}->diag("CODE:\n$code"."CODE");
+    }
+
+    return $pass;
+}
+
+1;
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
diff --git a/compilers/ncigen/nci_gen.pl b/compilers/ncigen/nci_gen.pl
new file mode 100755
index 0000000..ef040fc
--- /dev/null
+++ b/compilers/ncigen/nci_gen.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use Pod::Usage;
+use File::Temp;
+use IPC::Run3;
+
+my $man = 0;
+my $help = 0;
+my $PARROT = "../../parrot";
+my $incpaths;
+
+GetOptions('help|?' => \$help, 
+            man     => \$man,
+            "I=s@"  => \$incpaths) or pod2usage(2);
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+#sub usage()
+
+sub cc_preprocess {
+  my ($file) = @_;
+  my $ofile = mktemp($file . "_XXXX");
+  #execit("gcc -x c -I /usr/include/postgresql -fdirectives-only -E $file > $ofile");
+  execit("gcc -x c -I /usr/include/postgresql -E $file > $ofile");
+  return $ofile;
+}
+
+sub dump_parse_tree {
+  my ( $file, $more_args ) = @_;
+  return execit("make; $PARROT c99.pbc $more_args $file");
+}
+
+sub execit {
+  my ($cmd) = @_;
+  print "$cmd\n";
+  my $output = `$cmd`;
+  return $output;
+}
+
+sub main {
+  my $more_args = "";
+  unless ( $ARGV[0] ) {
+    $ARGV[0] = 't/spi.c' unless $ARGV[0];
+  }
+  $more_args = "--libname=fred --nsname=GO::Mojo";
+
+  my $preproc_fn = cc_preprocess($ARGV[0]);
+
+  my $parse_tree = dump_parse_tree($preproc_fn, $more_args);
+  unlink($preproc_fn);
+  print $parse_tree;
+  print "$preproc_fn\n";
+}
+
+main();
+
+__END__
+
+=head1 NAME
+
+sample - Using nci_gen.pl
+
+=head1 SYNOPSIS
+
+nci_gen [options] [file ...]
+
+Options:
+-help            brief help message
+-man             full documentation
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-help>
+
+Print a brief help message and exits.
+
+=item B<-man>
+
+Prints the manual page and exits.
+
+=back
+
+=head1 DESCRIPTION
+
+B<nci_gen> will read the given input file c header file and create a pir interface file.
+
+=cut
+
diff --git a/compilers/ncigen/src/NCIPIR.pir b/compilers/ncigen/src/NCIPIR.pir
new file mode 100644
index 0000000..75de7b2
--- /dev/null
+++ b/compilers/ncigen/src/NCIPIR.pir
@@ -0,0 +1,336 @@
+=head1 NAME
+
+NCIPIR::Compiler - NCI PIR Compiler for c99AST trees.
+
+=head1 DESCRIPTION
+
+NCIPIR::Compiler defines a compiler that converts a c99AST tree into PIR
+
+=head1 METHODS
+
+=over
+
+=cut
+
+.namespace [ 'NCIPIR::Compiler' ]
+
+.sub '__onload' :load :init
+    .local pmc p6meta, cproto
+    p6meta = new 'P6metaclass'
+    cproto = p6meta.'new_class'('NCIPIR::Compiler', 'parent'=>'PCT::HLLCompiler', 'attr'=>'$!code')
+    cproto.'language'('NCIPIR')
+    $P1 = split ' ', 'pir evalpmc'
+    cproto.'stages'($P1)
+
+    $P0 = new 'String'
+    set_global '$?NAMESPACE', $P0
+    .return ()
+.end
+
+
+.sub 'to_pir' :method
+    .param pmc ast
+    .param pmc adverbs         :slurpy :named
+
+    .local pmc newself
+    newself = new 'NCIPIR::Compiler'
+
+    ##  start with empty code
+    .local pmc code
+    code = new 'CodeString'
+    newself.'code'(code)
+
+    ##  if the root node isn't a Sub, wrap it
+    $I0 = isa ast, 'c99AST::Decls'
+    if $I0 goto have_sub
+    $P0 = get_hll_global ['c99AST'], 'Decls'
+    ast = $P0.'new'(ast, 'name'=>'anon')
+  have_sub:
+
+    .local string raw
+
+    raw = adverbs['raw']
+    if raw goto Lgenpir
+    $P0 = newself.'gen_preamble'(adverbs :flat :named)
+  Lgenpir:
+    ##  now generate the pir
+    newself.'pir'(ast)
+
+    ##  and return whatever code was generated
+    .return newself.'code'()
+.end
+
+.sub 'gen_preamble' :method
+    .param pmc adverbs         :slurpy :named
+    .local string nsname
+    .local string libname
+    .local string fmt
+
+    nsname = adverbs['nsname']
+    libname = adverbs['libname']
+
+fmt = <<'FMT'
+.namespace ['%n']
+.sub __load_lib_dlfunc_init__ :anon :init :load
+FMT
+
+    .local pmc code
+    code = new 'CodeString'
+    code.'emit'(fmt, 'n'=>nsname)
+    if null libname goto LNOLIBNAME
+fmt = <<'FMT'
+loadlib $P1, '%l'
+if $P1 goto has_lib
+FMT
+    goto LEMITLIBNAME
+  LNOLIBNAME:
+fmt = <<'FMT'
+$P1 = null
+goto has_lib
+FMT
+  LEMITLIBNAME:
+    code.'emit'(fmt, 'l'=>libname)
+
+
+fmt = <<'FMT'
+$P2 = new 'Exception'
+$P2[0] = 'error loading %l - loadlib failed'
+throw $P2
+has_lib:
+FMT
+    code.'emit'(fmt, 'l'=>libname)
+    $P0 = self.'code'()
+    $P0 .= code
+    .return(code)
+.end
+
+
+=item code([str])
+
+Get/set the code generated by this compiler.
+
+=cut
+
+.sub 'code' :method
+    .param pmc code            :optional
+    .param int has_code        :opt_flag
+
+    if has_code goto set_code
+    code = getattribute self, '$!code'
+    .return (code)
+  set_code:
+    setattribute self, '$!code', code
+    .return (code)
+.end
+
+
+=item pir_children(node)
+
+Return generated PIR for C<node> and all of its children.
+
+=cut
+
+.sub 'pir_children' :method
+    .param pmc node
+    .local pmc code, iter
+    code = new 'CodeString'
+    iter = new 'Iterator', node
+  iter_loop:
+    unless iter goto iter_end
+    .local string key
+    .local pmc cast
+    key = shift iter
+    cast = node[key]
+    $P0 = self.'pir'(cast)
+    code .= $P0
+    goto iter_loop
+  iter_end:
+    .return (code)
+.end
+
+
+=item pir(Any node)
+
+Return generated pir for any POST::Node.  Returns
+the generated pir of C<node>'s children.
+
+=cut
+
+.sub 'pir' :method :multi(_,_)
+    .param pmc node
+    .local string code
+    code = self.'pir_children'(node)
+    $P0 = self.'code'()
+    $P0 .= code
+    .return ($P0)
+.end
+
+
+=item pir(POST::Op node)
+
+Return pir for an operation node.
+
+=cut
+
+.sub 'pir' :method :multi(_,['c99AST::FuncDecl'])
+    .param pmc node
+    
+    ##  get list of arguments to operation
+    .local pmc arglist
+    arglist = node.'list'()
+
+    .local string fmt, name, type
+    type = param_to_code(node, 1)
+
+    .local pmc itera
+    .local pmc param
+    iter itera, arglist
+    LIS:
+    unless itera, LI0
+    param = shift itera
+    $S0 = param_to_code(param)
+    #say $S0
+    type .= $S0
+    goto LIS
+
+    LI0:
+    name = node.'name'()
+    fmt = "dlfunc $P2, $P1, '%n', '%s'\nstore_global '%n', $P2"
+
+    #$S0 = "##"
+    #$S1 = node.'attr'('source', '', 0)
+    #$S0 .= $S1
+    #print $S0
+
+    .local pmc code
+    code = new 'CodeString'
+    code.'emit'(fmt, 's'=>type, 'n'=>name)
+    #$S0 = code
+    #say $S0
+
+    .return (code)
+.end
+
+.sub 'param_to_code'
+  .param pmc node
+  .param int returncode :optional
+  $I0 = node.'pointer'()
+  $S0 = node.'primitive_type'()
+
+  if $I0, LPOINTER
+  
+  iseq $I1, $S0, 'void'
+  unless $I1, LL2
+  if returncode, LL11
+    .return("")
+  LL11:
+    .return("v")
+  LL2:
+  iseq $I1, $S0, 'int'
+  unless $I1, LL3
+    .return("i")
+  LL3:
+  iseq $I1, $S0, 'long'
+  unless $I1, LL4
+    .return("l")
+  LL4:
+  iseq $I1, $S0, 'char'
+  unless $I1, LL5
+    .return("c")
+  LL5:
+  iseq $I1, $S0, 'short'
+  unless $I1, LL6
+    .return("s")
+  LL6:
+    .return("p")
+
+  LPOINTER:
+  iseq $I1, $S0, 'char'
+  unless $I1, LL7
+  $I0 = node.'pointer_cnt'()
+  iseq $I1, $I0, 1
+  unless $I1, LL7
+    .return("S")
+  LL7:
+    .return("p")
+.end
+
+=item pir(POST::Label node)
+
+Generate a label.
+
+=cut
+
+.sub 'pir' :method :multi(_, ['c99AST::TypeDef'])
+    .param pmc node
+    .return ('')
+    .return pir_dump(node)
+.end
+
+=item pir(POST::Label node)
+
+Generate a label.
+
+=cut
+
+.sub 'pir' :method :multi(_, ['c99AST::VarDecl'])
+    .param pmc node
+    .return ('')
+    .return pir_dump(node)
+.end
+
+=item pir(POST::Label node)
+
+Generate a label.
+
+=cut
+
+.sub 'pir_dump'
+    .param pmc node
+    .local string code
+    code = '#'
+    code .= 'typedef '
+    $S0 = node.'type'()
+    code .= $S0
+    code .= ' '
+    $S0 = node.'name'()
+    code .= $S0
+    $S0 = node.'builtin_type'()
+    unless $S0 goto LN1
+    code .= ' builtin '
+    code .= $S0
+  LN1:
+    $S0 = node.'pointer'()
+    unless $S0 goto LN2
+    code .= ' pointer '
+    code .= $S0
+  LN2:
+    code .= ":\n"
+    print code
+    .return ('')
+.end
+
+
+=back
+
+=head1 AUTHOR
+
+Patrick Michaud <pmichaud@pobox.com> is the author and maintainer.
+Please send patches and suggestions to the Parrot porters or
+Perl 6 compilers mailing lists.
+
+=head1 HISTORY
+
+2007-11-21  Significant refactor as part of Parrot Compiler Toolkit
+
+=head1 COPYRIGHT
+
+Copyright (C) 2006-2008, The Perl Foundation.
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
diff --git a/compilers/ncigen/src/builtins/say.pir b/compilers/ncigen/src/builtins/say.pir
new file mode 100644
index 0000000..53bfa6c
--- /dev/null
+++ b/compilers/ncigen/src/builtins/say.pir
@@ -0,0 +1,82 @@
+# $Id$
+
+=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/compilers/ncigen/src/c99.pg b/compilers/ncigen/src/c99.pg
new file mode 100644
index 0000000..50abd7f
--- /dev/null
+++ b/compilers/ncigen/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') { ... }
diff --git a/compilers/ncigen/src/c99AST.pir b/compilers/ncigen/src/c99AST.pir
new file mode 100644
index 0000000..91d9a0c
--- /dev/null
+++ b/compilers/ncigen/src/c99AST.pir
@@ -0,0 +1,325 @@
+=head1 NAME
+
+c99AST - c99 abstract syntax tree
+
+=head1 DESCRIPTION
+
+This file implements the various abstract syntax tree nodes
+for compiling c99 programs.
+
+=cut
+
+.namespace [ 'c99AST::Node' ]
+
+.sub 'onload' :anon :load :init
+    ##   create the c99AST::Node base class
+    .local pmc p6meta, base, vardecl
+    p6meta = new 'P6metaclass'
+    base = p6meta.'new_class'('c99AST::Node', 'parent'=>'PCT::Node')
+
+    vardecl = p6meta.'new_class'('c99AST::VarDecl', 'parent'=>base)
+    p6meta.'new_class'('c99AST::Decls',     'parent'=>base)
+
+    p6meta.'new_class'('c99AST::TypeDef',   'parent'=>vardecl)
+    p6meta.'new_class'('c99AST::FuncDecl',  'parent'=>vardecl)
+    p6meta.'new_class'('c99AST::Param',     'parent'=>vardecl)
+    p6meta.'new_class'('c99AST::Struct',    'parent'=>vardecl)
+    p6meta.'new_class'('c99AST::Union',     'parent'=>vardecl)
+
+    .return ()
+.end
+
+=head1 c99AST Node types
+
+=head2 c99AST::Node
+
+C<c99AST::Node> is the base class for all c99AST nodes, and is
+derived from PCT::Node.  A node has an array component to
+hold its children, and a hash component for its attributes.
+However, we tend to use accessor methods for accessing the node's
+attributes instead of accessing the hash directly.
+
+Every c99AST node inherits C<name>, C<source>, and C<pos> attributes
+from C<PCT::Node>.  The C<name> attribute is the node's name, if
+any, while C<source> and C<pos> are used to identify the location
+in the original source code for the node.  The C<source> and C<pos>
+values are generally set by the C<node> method inherited from
+C<PCT::Node>.
+
+Other node attributes are generally defined by subclasses of C<c99AST::Node>.
+
+=over 4
+
+=item returns([value])
+
+Accessor method -- sets/returns the return type for the invocant.
+
+=cut
+
+.sub 'returns' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('returns', value, has_value)
+.end
+
+
+=item arity([value])
+
+Accessor method -- sets/returns the arity (number of expected arguments)
+for the node.
+
+=cut
+
+.sub 'arity' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('arity', value, has_value)
+.end
+
+
+=item named([value])
+
+Accessor method -- for named arguments, sets/returns the name to be
+associated with the argument.
+
+=cut
+
+.sub 'named' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('named', value, has_value)
+.end
+
+
+=item flat([value]
+
+Accessor method -- sets/returns the "flatten" flag on arguments.
+
+=cut
+
+.sub 'flat' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('flat', value, has_value)
+.end
+
+
+=back
+
+=head2 c99AST::TypeDef
+
+C<c99AST::Val> nodes represent constant values in the abstract
+syntax tree.  The C<name> attribute represents the value of the
+node.
+
+=over 4
+
+=item value([value])
+
+Get/set the constant value for this node.
+
+=cut
+
+.namespace [ 'c99AST::TypeDef' ]
+
+.sub 'value' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('value', value, has_value)
+.end
+
+=back
+
+=head2 c99AST::Var
+
+C<c99AST::Var> nodes represent variables within the abstract
+syntax tree.  The variable name (if any) is given as the node's
+C<name> attribute.
+
+=over 4
+
+=item scope([value])
+
+Get/set the c99AST::Var node's "scope" (i.e., how the variable
+is accessed or set).  Allowable values include "package", "lexical",
+"parameter", and "keyed", representing HLL global, lexical, block
+parameter, and array/hash variables respectively.
+
+=cut
+
+.namespace [ 'c99AST::VarDecl' ]
+
+.sub 'type' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('type', value, has_value)
+.end
+
+.sub 'extern' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('extern', value, has_value)
+.end
+
+.sub 'pointer' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('pointer', value, has_value)
+.end
+
+.sub 'builtin_type' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('builtin_type', value, has_value)
+.end
+
+.sub 'complex' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('complex', value, has_value)
+.end
+
+.sub 'primitive_type' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('primitive_type', value, has_value)
+.end
+
+.sub 'pointer_cnt' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('pointer_cnt', value, has_value)
+.end
+
+.sub 'scope' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('scope', value, has_value)
+.end
+
+
+=item isdecl([flag])
+
+Get/set the node's C<isdecl> attribute (for lexical variables) to C<flag>.
+A true value of C<isdecl> indicates that the variable given by
+this node is to be created within the current lexical scope.
+Otherwise, the node refers to a lexical variable from an outer scope.
+
+=cut
+
+.sub 'isdecl' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('isdecl', value, has_value)
+.end
+
+
+=item lvalue([flag])
+
+Get/set the C<lvalue> attribute, which indicates whether this
+variable is being used in an lvalue context.
+
+=cut
+
+.sub 'lvalue' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('lvalue', value, has_value)
+.end
+
+
+=item namespace([namespace])
+
+Get/set the variable's namespace attribute to the array of strings
+given by C<namespace>.  Useful only for variables with a C<scope>
+of 'package'.
+
+=cut
+
+.sub 'namespace' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('namespace', value, has_value)
+.end
+
+
+=item slurpy([flag])
+
+Get/set the node's C<slurpy> attribute (for parameter variables) to C<flag>.
+A true value of C<slurpy> indicates that the parameter variable given by this
+node is to be created as a slurpy parameter (consuming all remaining arguments
+passed in).
+
+=cut
+
+.sub 'slurpy' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('slurpy', value, has_value)
+.end
+
+
+=item viviself([type])
+
+If the variable needs to be instantiated, then C<type> indicates
+either the type of the value to create for the node or (future
+implementation) a c99AST tree to create the value.
+
+=cut
+
+.sub 'viviself' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('viviself', value, has_value)
+.end
+
+
+=item vivibase([type])
+
+For keyed nodes, C<type> indicates the type of aggregate to
+create for the base if the base doesn't specify its own 'viviself'
+attribute.
+
+=cut
+
+.sub 'vivibase' :method
+    .param pmc value           :optional
+    .param int has_value       :opt_flag
+    .return self.'attr'('vivibase', value, has_value)
+.end
+
+
+=back
+
+=head2 c99AST::Op
+
+C<c99AST::Op> nodes represent the operations in an abstract syntax
+tree.  The primary function of the node is given by its C<pasttype>,
+secondary functions may be given by the node's C<name>, C<pirop>,
+or other attributes.
+
+=over 4
+=back
+
+=head1 AUTHOR
+
+Patrick Michaud <pmichaud@pobox.com> is the author and maintainer.
+Please send patches and suggestions to the Parrot porters or
+Perl 6 compilers mailing lists.
+
+=head1 HISTORY
+
+2006-11-20  Patrick Michaud added first draft of POD documentation.
+2007-11-21  Re-implementation with pdd26 compliance, compiler toolkit
+
+=head1 COPYRIGHT
+
+Copyright (C) 2006-2008, The Perl Foundation.
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
diff --git a/compilers/ncigen/src/parser/actions.pm b/compilers/ncigen/src/parser/actions.pm
new file mode 100644
index 0000000..73ce0af
--- /dev/null
+++ b/compilers/ncigen/src/parser/actions.pm
@@ -0,0 +1,238 @@
+# $Id$
+# Copyright (C) 2008, The Perl 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::Grammar::Actions;
+
+our $decls := c99AST::Decls.new();
+our $C99DEBUG :=0;
+
+method TOP($/) {
+    if $C99DEBUG { _dumper($decls); }
+    make $decls;
+}
+
+sub parse_decl_specs($/, $ast) {
+    if $/ {
+        for $/ {
+            $ast.attr( strip_spaces(~$_), 1, 1);
+        }
+    }
+}
+
+sub typedef($/) {
+    if $/ {
+        for $/ {
+            if ('typedef' eq strip_spaces(~$_) ) { return 1; }
+        }
+    }
+    return 0;
+}
+
+method declaration($/) {
+    my $ast := c99AST::VarDecl.new( :node($/) );
+    my $type := "";
+
+    #say("=================================================================================================");
+    #_dumper($/);
+#    make $decls;
+#    return 1;
+    my $decl_specs := $<declaration_specifiers><repeatable_declaration_specifiers>;
+    if typedef($decl_specs) {
+        $ast := c99AST::TypeDef.new( :node($/) );
+        $type := "TypeDef";
+    }
+    elsif $/<init_declarator><init_declarator><declarator><direct_declarator><declarator_suffix><declarator_suffix><parameter_type_list> {
+        $ast := c99AST::FuncDecl.new( :node($/) );
+        $type := "FuncDecl";
+    }
+#    elsif $<declaration_specifiers><type_specifier><type> {
+#        $ast := c99AST::Struct.new( :node($/) );
+#        $type := "Struct";
+#    }
+    else {
+        $ast := c99AST::VarDecl.new( :node($/) );
+        $type := "VarDecl";
+    }
+    parse_decl_specs( $<declaration_specifiers><repeatable_declaration_specifiers>, $ast );
+
+    #  TYPE
+    settype($<declaration_specifiers><type_specifier>, $ast);
+
+    if ($type eq "FuncDecl") {
+        if (+$<init_declarator> != 1) {
+            say("ERROR FuncDecl has more than one <init_declarator>");
+        }
+
+        #assert(+$<init_declarator><declarator><direct_declarator><declarator_suffix>  == 1);
+        my $params := $<init_declarator><declarator><declarator><direct_declarator><declarator_suffix><parameter_type_list><parameter_type_list><parameter_list><parameter_declaration>;
+        for $params {
+            my $param := c99AST::Param.new( :node( $_ ) );
+
+            settype($_<declaration_specifiers><type_specifier>, $param);
+            my $param_ident := $_<declarator>;
+            if $param_ident { setname( $_, $param ); }
+            ispointer($_, $param);
+            $ast.push( $param );
+        }
+        my $declarator := $<init_declarator><declarator>;
+        my $name := setname($declarator, $ast);
+        $decls{ $name } := $ast;
+        ispointer($declarator, $ast);
+        if $C99DEBUG { _dumper($ast); }
+        #say($name);
+    }
+    #elsif ($type eq "VarDecl") {
+    #elsif $<init_declarator> {
+    else {
+        for $<init_declarator> {
+            my $l_ast := $ast.clone();
+
+            my $name := setname($_, $l_ast);
+            $decls{ $name } := $l_ast;
+            ispointer($_, $l_ast);
+            if $C99DEBUG { _dumper($l_ast); }
+            #say($name);
+        }
+    }
+    #else {
+    #    say("OPAQUE STRUCT OR UNTION");
+    #    _dumper($/);
+    #}
+
+    make $decls;
+}
+
+sub ispointer($/, $ast) {
+    if $/ {
+        if $<declarator><pointer> {
+            $ast.pointer(1);
+        }
+    }
+
+    my $l_ast := $ast;
+    repeat {
+        if $l_ast.pointer() {
+            $ast.pointer(1);
+            my $pc := +$ast.pointer_cnt();
+            $pc++;
+            $ast.pointer_cnt($pc);
+        }
+        if $l_ast.builtin_type() {
+            $ast.primitive_type(~($l_ast.type()));
+            return 1;
+        }
+        my $type_name := $l_ast.type();
+        my $l_ast_name := $l_ast.name();
+
+        #FIXME struct or union typedef 
+        if ($l_ast.name() eq $type_name) {
+            return 1;
+        }
+        
+        $l_ast := $decls{$type_name};
+        unless $l_ast {
+            #_dumper($decls);
+            say("Parent " ~~ $l_ast_name ~~ " " ~~ $type_name ~~ " not defined");
+            return 1;
+        }
+    } while (1); 
+}
+
+sub settype($/, $ast) {
+    if $/ {
+        #is it a struct or union
+        my $struct_or_union := strip_spaces(~$<type>);
+        if $struct_or_union {
+            my $ident := $<struct_or_union_specifier><identifier><identifier>;
+            if $ident {
+                $ident := strip_spaces($ident.text());
+            }
+            else {
+                $ident := $<struct_or_union_specifier><identifier>;
+                if $ident {
+                    $ident := strip_spaces($ident.text());
+                }
+                else {
+                    $ident := "anonymous_" ~~ $struct_or_union~~ "1";
+                }
+            }
+            $ast.type($ident);
+            my $s_or_u := $<struct_or_union_specifier><struct_declaration>;
+            if $s_or_u {
+                my $su;
+                if ($struct_or_union eq "struct" ) {
+                    $su := c99AST::Struct.new( :node($/) );
+                }
+                else {
+                    $su := c99AST::Union.new( :node($/) );
+                }
+                $su.name($ident);
+                build_struct_or_union($s_or_u, $su);
+                $ast.complex($su);
+            }
+        }
+        else {
+            $ast.type(strip_spaces(~$/));
+            #  BUILTIN_TYPE
+            if $<builtin_type> { $ast.builtin_type(1); }
+        }
+    }
+    else {
+        say("ERROR no type specifier");
+    }
+}
+
+sub strip_spaces($_) {
+    $_.replace(' ', '');
+    return $_;
+}
+
+sub build_struct_or_union($/, $ast) {
+    for $/ {
+        my $smt := c99AST::VarDecl.new( :node($_) );
+        settype( $_<specifier_qualifier_list><type_specifier>, $smt );
+        for $_<struct_declarator_list> {
+            my $sm := $smt.clone();
+            my $declarator := $_<struct_declarator><declarator>;
+            $sm.name(strip_spaces($declarator.text()));
+            ispointer($declarator, $sm);
+            $ast.push($sm);
+        }
+    }    
+}
+
+sub setname($/, $ast) {
+    my $name_node := $<declarator><direct_declarator><declarator_prefix>;
+    if $name_node {
+        $ast.name( ~$name_node );
+        return ~$name_node;
+    }
+    else {
+        say("ERROR node doesn't have <direct_declarator><declarator_prefix>");
+        _dumper($/);
+    }
+}
+
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 syntax=perl6:
+
diff --git a/compilers/ncigen/src/parser/grammar.pg b/compilers/ncigen/src/parser/grammar.pg
new file mode 100644
index 0000000..4f2f052
--- /dev/null
+++ b/compilers/ncigen/src/parser/grammar.pg
@@ -0,0 +1,759 @@
+# $Id$
+# Copyright (C) 2008, The Perl 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 {
+    ^
+    <external_declaration>+
+    [ $ || <.panic: Syntax error> ]
+    {*}
+}
+
+rule external_declaration {
+    | <declaration> {*}                                   #= declaration
+    | <function_definition> {*}                           #= function_definition
+#    <declaration_specifiers>
+#    [
+#    | <declaration2>
+#    | <func_decl2>
+#    ]
+}
+
+rule func_decl2 {
+    <declarator>
+    <declaration>*
+    <compound_statement>
+    {*}
+}
+
+rule declaration2 {
+    [ <init_declarator> [',' <init_declarator>]* ]?
+    ';'
+    {*}
+}
+
+rule function_definition {
+    <declaration_specifiers>
+    <declarator>
+    <declaration>*
+    <compound_statement>
+    {*}
+}
+
+
+## A.2.2
+##
+
+rule declaration {
+    <declaration_specifiers>
+    [ <init_declarator> [',' <init_declarator>]* ]?
+    ';'
+    {*}
+}
+
+rule declaration_specifiers {
+    <repeatable_declaration_specifiers>*
+    <type_specifier>
+    <repeatable_declaration_specifiers>*
+    {*}
+}
+
+rule repeatable_declaration_specifiers {
+    [
+    | <storage_class_specifier>
+    | <type_qualifier>
+    | <function_specifier>
+    ]
+}
+
+rule function_specifier {
+    | 'inline'
+    | '__inline__'
+}
+
+rule init_declarator {
+    <declarator> ['=' <initializer>]?
+    {*}
+}
+
+rule storage_class_specifier {
+    [
+    | $<typedef>=['typedef']                    {*} #= typedef
+    | $<extern>=['extern']                      {*} #= extern
+    | $<static>=['static']                      {*} #= static
+    | $<auto>=['auto']                          {*} #= auto
+    | $<register>=['register']                  {*} #= register
+    | $<__extension__>=['__extension__']        {*} #= __extension__
+    ]
+}
+
+rule type_specifier {
+    | <builtin_type>
+    | $<type>=[ 'struct' | 'union' ] <struct_or_union_specifier>
+    | 'enum' <enum_specifier>
+    | $<typedef_name>=<identifier>
+}
+
+token builtin_type {
+    [
+      $<signed>=[ 'signed' | 'unsigned' ] <.ws> 
+    ]?
+    [
+    | 'void'
+    | 'char'
+    | 'short' <.ws> 'int' >>
+    | 'short'
+    | 'int'
+    | 'long' <.ws> 'long' <.ws> 'int' >>
+    | 'long' <.ws> 'int' >>
+    | 'long' <.ws> 'double' >>
+    | 'long'
+    | 'float'
+    | 'double'
+    | '_Bool'
+    | '_Complex'
+    | '_Imaginary'
+    ]
+    >>
+}
+
+rule struct_or_union_specifier {
+    | <identifier>? '{' <struct_declaration>+ '}'
+    | <identifier>
+}
+
+rule struct_declaration {
+    <specifier_qualifier_list> <struct_declarator_list>* ';'
+}
+
+rule specifier_qualifier_list {
+    <type_qualifier>*
+    <type_specifier>
+    <type_qualifier>*
+#    [
+#    | <type_specifier>
+#    | <type_qualifier>
+#    ]+
+}
+
+rule struct_declarator_list {
+    <struct_declarator> [',' <struct_declarator>]*
+}
+
+rule struct_declarator {
+    | <declarator>? ':' <constant_expression>
+    | <declarator>
+}
+
+rule enum_specifier {
+    | <identifier>? '{' <enumerator_list> [',']? '}'
+    | <identifier>
+}
+
+rule enumerator_list {
+    <enumerator> [',' <enumerator>]*
+}
+
+rule enumerator {
+    <enumeration_constant> ['=' <constant_expression>]?
+}
+
+rule type_qualifier {
+    $<qualifier>=[
+    |'const'
+    |'restrict'
+    |'volatile'
+    |'__const'       # gcc version of const
+    |'__restrict'    # gcc version of restricted
+    |'__volatile'    # gcc version of volatile
+    |'__extension__' # gcc extension
+    ]
+}
+
+rule declarator {
+    <pointer>?
+    <direct_declarator>
+    {*}
+}
+
+rule direct_declarator {
+    <declarator_prefix>
+    <declarator_suffix>*
+    <gcc_asm>?
+    <gcc_attribute>*
+    {*}
+}
+
+rule declarator_prefix {
+    | '(' <declarator> ')' {*}       #= declarator
+    | <identifier> {*}               #= identifier
+}
+
+rule declarator_suffix {
+    | '(' <parameter_type_list> ')' {*}    #= parameter_type_list
+    | '(' <identifier_list>? ')' {*}       #= identifier_list ## old-style C parameter declarations
+    | '[' <assignment_expression>? ']'
+    | '[' '*' ']'
+}
+
+rule gcc_attribute {
+    '__attribute__' '((' <gcc_attributes_list>'))'
+}
+
+rule gcc_attributes_list {
+    [<gcc_attr> [',' <gcc_attr>]* ]?
+
+}
+
+rule gcc_attr {
+    | 'noreturn'
+    | '__noreturn__'
+    | [ 'format' | '__format__' ] '(' <gcc_attr_formats> ',' <digit>+ ',' <digit>+ ')'
+    | '__const__'
+    | '__const'
+    | '__nothrow__'
+    | '__aligned__' '(' <digit>+ ')'
+    | '__format_arg__' '(' <digit>+ ')'
+    | '__nonnull__' '(' <digit_list_plus> ')'
+    | '__mode__' '(' <gcc_attr_mode> ')'
+    | '__malloc__'
+    | '__pure__'
+    | '__warn_unused_result__'
+}
+
+rule digit_list_plus {
+  <digit>+ [',' <digit>+ ]*
+  {*}
+}
+
+
+token gcc_attr_mode {
+    | '__QI__'
+    | '__DI__'
+    | '__SI__'
+    | '__HI__'
+    | 'byte'
+    | '__byte__'
+    | 'word'
+    | '__word__'
+    | 'pointer'
+    | '__pointer__'
+}
+
+token gcc_attr_formats {
+    | printf
+    | __printf__
+    | scanf
+    | strftime
+    | gnu_printf
+    | gnu_scanf
+    | gnu_strftime
+    | strfmon
+    | __printf__
+    | __scanf__
+    | __strftime__
+    | __strfmon__
+    | ms_printf
+    | ms_scanf
+    | ms_strftime
+}
+
+rule gcc_asm {
+    [ 'asm' | '__asm__' ]
+    '('
+    [<c_string_literal> ]*
+    ')'
+}
+
+rule pointer {
+    '*'+ <type_qualifier>* ['*']?
+}
+
+rule parameter_type_list {
+    <parameter_list>  [$<vararg>=[',' '...']]?
+    {*}
+}
+
+rule parameter_list {
+    <parameter_declaration> [',' <parameter_declaration>]*
+    {*}
+}
+
+rule parameter_declaration {
+    <declaration_specifiers>
+    [
+    | <declarator> {*}               #= declarator
+    | <abstract_declarator>? {*}     #= abstract_declarator
+    ]
+    <repeatable_declaration_specifiers>*
+}
+
+rule identifier_list {
+    <identifier> [',' <identifier>]*
+}
+
+rule type_name {
+    <specifier_qualifier_list> <abstract_declarator>?
+}
+
+rule abstract_declarator {
+    | '*'
+    | ['*']? <direct_abstract_declarator>
+}
+
+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_DEAD_CODE {
+
+## 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 <identifier>, but inspecting the registered
+## typedef'd names. For now, specify 'SOME_TYPEDEF_NAME' as the only typedef'd name.
+##
+    <identifier>
+    #'SOME_TYPEDEF_NAME'
+}
+
+rule initializer {
+    | <assignment_expression>
+    | '{' <initializer_list> [',']? '}'
+}
+
+rule initializer_list {
+    <initializer_item> [',' <initializer_item>]*
+}
+
+rule initializer_item {
+    <designation>? <initializer>
+}
+
+rule designation {
+    <designator>+ '='
+}
+
+rule designator {
+    | '[' <constant_expression> ']'
+    | '.' <identifier>
+}
+
+
+## A.2.3 Statements
+##
+
+rule statement {
+    | <labeled_statement>
+    | <compound_statement> {*}        #= compound_statement
+    | <expression_statement> {*}      #= expression_statement
+    | <if_statement> {*}              #= if_statement
+    | <switch_statement>
+    | <while_statement> {*}           #= while_statement
+    | <do_while_statement> {*}        #= do_while_statement
+    | <for1_statement> {*}            #= for1_statement
+    | <for2_statement> {*}            #= for2_statement
+    | <jump_statement> {*}            #= jump_statement
+}
+
+rule labeled_statement {
+    | <identifier> ':' <statement>
+    | 'case' <constant_expression> ':' <statement>
+    | 'default' ':' <statement>
+}
+
+rule compound_statement {
+    '{' <block_item>* '}'
+    {*}
+}
+
+rule block_item {
+    | <declaration> {*}    #= declaration
+    | <statement> {*}      #= statement
+}
+
+rule expression_statement {
+    <expression>? ';'
+    {*}
+}
+
+rule if_statement {
+    'if' '(' <expression> ')' <statement> ['else' $<else>=<statement>]?
+    {*}
+}
+
+rule switch_statement {
+    'switch' '(' <expression> ')' <statement>
+}
+
+rule while_statement {
+    'while' '(' <expression> ')' <statement>
+    {*}
+}
+
+rule do_while_statement {
+    'do' <statement> 'while' '(' <expression> ')' ';'
+    {*}
+}
+
+rule for1_statement {
+    'for' '(' [$<init>=<expression>]? ';' [$<cond>=<expression>]? ';' [$<step>=<expression>]? ')'
+    <statement>
+    {*}
+}
+
+rule for2_statement {
+    'for' '(' <declaration> [$<cond>=<expression>]? ';' [$<step>=<expression>]? ')' <statement>
+    {*}
+}
+
+rule jump_statement {
+    | 'goto' <identifier> ';' {*}         #= goto
+    | 'continue' ';' {*}                  #= continue
+    | 'break' ';' {*}                     #= break
+    | 'return' <expression>? ';' {*}      #= return
+}
+
+
+## A.1.1 Lexical elements
+##
+##rule token {
+##  | <keyword>
+##  | <identifier>
+##  | <constant>
+##  | <c_string_literal>
+##  | <punctuator>
+##}
+
+## 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 {
+    <keyword>
+}
+
+
+token identifier {
+    <!reserved_word>
+    <.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 {
+    | <floating_constant> {*}       #= floating_constant
+    | <integer_constant> {*}        #= integer_constant
+    | <enumeration_constant> {*}    #= enumeration_constant
+    | <character_constant> {*}      #= character_constant
+}
+
+token integer_constant {
+    [ <decimal_constant>
+    | <hexadecimal_constant>
+    | <octal_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_sequence>
+  ]
+  <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 constant_expression {
+    <conditional_expression>
+    {*}
+}
+
+rule expression {
+    <assignment_expression> [',' <assignment_expression>]*
+    {*}
+}
+
+rule assignment_expression {
+    [<unary_expression> <assign_op>]* <conditional_expression>
+    {*}
+}
+
+rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' }
+
+rule conditional_expression {
+    <logical_expression> ['?' <expression> ':' <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 equiv('infix:==') { ... }
+
+proto 'infix:<' is tighter('infix:==') { ... }
+proto 'infix:>' is equiv('infix:<') { ... }
+proto 'infix:>=' is equiv('infix:<') { ... }
+proto 'infix:<=' is equiv('infix:<') { ... }
+
+proto 'infix:<<' is equiv('infix:<') { ... }
+proto 'infix:>>' is equiv('infix:<') { ... }
+
+proto 'infix:+' is tighter('infix:<<') is pirop('n_add') { ... }
+proto 'infix:-' is equiv('infix:+') is pirop('n_sub') { ... }
+
+proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... }
+proto 'infix:/' is equiv('infix:*') is pirop('n_div') { ... }
+proto 'infix:%' is equiv('infix:*') is pirop('n_mod') { ... }
+
+proto 'term:' is tighter('infix:*')
+              is parsed(&cast_expression) { ... }
+
+
+rule postfix_expression_prefix {
+    | <primary_expression> {*}                                  #= primary_expression
+    | '(' <type_name> ')' '{' <initializer_list> [',']? '}' {*} #= #type_name
+}
+
+rule postfix_expression {
+    <postfix_expression_prefix>
+    <postfix_expression_suffix>*
+    {*}
+}
+
+rule postfix_expression_suffix {
+    | <index> {*}                           #= index
+    | <arguments>  {*}                      #= arguments
+    | <direct_field> {*}                    #= direct_field
+    | <indirect_field> {*}                  #= indirect_field
+    | <inc_or_dec> {*}                      #= inc_or_dec
+}
+
+rule inc_or_dec {
+    $<op>=['++'|'--']
+    {*}
+}
+
+rule index {
+    '[' <expression> ']'
+    {*}
+}
+
+rule direct_field {
+    '.' <identifier>
+    {*}
+}
+
+rule indirect_field {
+    '->' <identifier>
+    {*}
+}
+
+rule arguments {
+    '(' <argument_expression_list>? ')'
+    {*}
+}
+
+rule argument_expression_list {
+    <assignment_expression> [',' <assignment_expression>]*
+    {*}
+}
+
+rule unary_expression {
+    | <postfix_expression> {*}              #= postfix_expression
+    | <prefix_expression> {*}               #= prefix_expression
+    | <unary_operator> <cast_expression> {*} #= unary_operator
+    | 'sizeof' <unary_expression>        {*} #= sizeof
+    | 'sizeof' '(' <type_name> ')'       {*} #= sizeof_type
+}
+
+rule prefix_expression {
+    $<op>=['++'|'--'] <unary_expression>
+    {*}
+}
+
+rule unary_operator {
+    '&' | '*' | '+' | '-' | '~' | '!'
+}
+
+rule cast_expression {
+    ['(' <type_name> ')']* <unary_expression>
+    {*}
+}
+
+rule primary_expression {
+    | <identifier> {*}             #= identifier
+    | <constant> {*}               #= constant
+    | <c_string_literal> {*}       #= c_string_literal
+    | '(' <expression> ')' {*}     #= expression
+}
+
+token ws {
+  [
+  | '//' \N* \n
+  | '/*' .*? '*/'
+  | \s+
+  | <.gcc_preprocess_id>
+  #| ^^ '#' \N \n
+  #| '#' \N* \n {*} #= origin
+  ]*
+}
+
+token gcc_preprocess_id {
+  ^^ '#' \s+ $<line>=[<.digit>+] \s+ <c_string_literal> $<ilist>=[ \s+ <.digit>+ ]* $$ {*} #= origin
+}
diff --git a/compilers/ncigen/t/c99AST/struct_00.t b/compilers/ncigen/t/c99AST/struct_00.t
new file mode 100644
index 0000000..8d2a4b8
--- /dev/null
+++ b/compilers/ncigen/t/c99AST/struct_00.t
@@ -0,0 +1,18 @@
+#!/usr/bin/perl
+
+use lib ('./lib', '../../lib');
+use Parrot::Test::C99AST;
+
+plan tests => 1;
+ast(<<'CODE');
+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;
+CODE
+
+contains("<complex> => PMC 'c99AST::Struct'");
diff --git a/compilers/ncigen/t/c99AST/typedef_00.t b/compilers/ncigen/t/c99AST/typedef_00.t
new file mode 100644
index 0000000..b6696f6
--- /dev/null
+++ b/compilers/ncigen/t/c99AST/typedef_00.t
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+use lib ('./lib', '../../lib');
+use Parrot::Test::C99AST;
+
+plan tests => 10;
+ast('extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);');
+contains("Parent isCommit bool not defined");
+
+ast('typedef void * void_pointer_type;');
+istypedef;
+ispointer;
+decl_ident_is("void_pointer_type");
+type_is("void");
+is_builtin;
+
+ast('typedef int a, b, c;');
+decl_ident_is("a");
+decl_ident_is("b");
+decl_ident_is("c");
+
+parse('int a(), b(), c()');
+parse_failure;
diff --git a/compilers/ncigen/t/harness b/compilers/ncigen/t/harness
new file mode 100644
index 0000000..9a6116a
--- /dev/null
+++ b/compilers/ncigen/t/harness
@@ -0,0 +1,7 @@
+#!/usr/bin/perl
+
+# $Id$
+
+use FindBin;
+use lib qw( . lib ../lib ../../lib ../../lib );
+use Parrot::Test::Harness language => 'ncigen'
diff --git a/compilers/ncigen/t/parse_00.t b/compilers/ncigen/t/parse_00.t
new file mode 100644
index 0000000..94f7f39
--- /dev/null
+++ b/compilers/ncigen/t/parse_00.t
@@ -0,0 +1,175 @@
+#!/usr/bin/perl
+
+use lib ('./lib', '../../lib');
+use Parrot::Test::C99AST;
+
+plan tests => 20;
+
+parse_success(<<'CODE', '__extension__00.c');
+extern double strtod (__const char *__restrict __nptr, char **__restrict __endptr) __attribute__ ((__nothrow__)) __attribute__ ((__nonnull__ (1))) ;
+
+enum { MSG_OOB = 0x01 };
+__extension__ typedef signed long long int __int64_t;
+
+__extension__ typedef struct { int __val[2]; } __fsid_t;
+extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, __gnuc_va_list, int *__restrict);
+
+struct random_data
+{
+  int32_t rand_type;
+};
+
+struct _IO_FILE {
+char _unused2[15 * 6];
+char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
+};
+
+struct random_data
+{
+  int32_t rand_type;
+};
+
+int a = 8 - sizeof(int);
+char _unused2 = 15 + 6;
+int b = 12;
+int a = 10 * sizeof(int) * 13;
+int a = 8 * 3;
+typedef int Oid;
+int32_t Oid;
+int Oid;
+typedef unsigned int Oid;
+typedef union
+{
+  char __size[4];
+  int __align;
+} pthread_mutexattr_t;
+
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+
+  } __data;
+  char __size[24];
+  long int __align;
+} pthread_mutex_t;
+__extension__ typedef void * __timer_t;
+CODE
+
+parse_success(<<'CODE', '__attribute__.c');
+extern double strtod (__const char *__restrict __nptr, char **__restrict __endptr) __attribute__ ((__nothrow__)) __attribute__ ((__nonnull__ (1))) ;
+CODE
+
+parse_success(<<'CODE', 'enums.c');
+enum { MSG_OOB = 0x01 };
+CODE
+
+parse_success(<<'CODE', '__extension__01.c');
+__extension__ typedef signed long long int __int64_t;
+CODE
+
+parse_success(<<'CODE', '__extension__02.c');
+__extension__ typedef struct { int __val[2]; } __fsid_t;
+CODE
+
+parse_success(<<'CODE', 'gnu_va_arg.c');
+extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, __gnuc_va_list, int *__restrict);
+CODE
+
+parse_success(<<'CODE', 'int_32_t_declaration.c');
+struct random_data
+{
+  int32_t rand_type;
+};
+CODE
+
+parse_success(<<'CODE', 'struct_declaration_00.c');
+struct _IO_FILE {
+char _unused2[15 * 6];
+char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
+};
+CODE
+
+parse_success(<<'CODE', 'struct_declaration_01.c' );
+struct random_data
+{
+  int32_t rand_type;
+};
+CODE
+
+parse_success(<<'CODE', 'times_01.c');
+int a = 8 - sizeof(int);
+CODE
+
+parse_success(<<'CODE', 'times_02.c');
+char _unused2 = 15 + 6;
+CODE
+
+parse_success(<<'CODE', 'times_03.c');
+int b = 12;
+int a = 10 * sizeof(int) * 13;
+CODE
+
+parse_success(<<'CODE', 'times_04.c').c;
+int a = 8 * 3;
+CODE
+
+parse_success(<<'CODE', 'typedef_01.c');
+typedef int Oid;
+CODE
+
+parse_success(<<'CODE', 'typedef_02.c');
+int32_t Oid;
+CODE
+
+parse_success(<<'CODE', 'typedef_03.c');
+int Oid;
+CODE
+
+parse_success(<<'CODE', 'typedef.c');
+typedef unsigned int Oid;
+CODE
+
+parse_success(<<'CODE', 'typedef_union_00.c');
+typedef union
+{
+  char __size[4];
+  int __align;
+} pthread_mutexattr_t;
+CODE
+
+parse_success(<<'CODE', 'typedef_union_01.c');
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+
+  } __data;
+  char __size[24];
+  long int __align;
+} pthread_mutex_t;
+CODE
+
+parse_success(<<'CODE', 'void_star.c');
+__extension__ typedef void * __timer_t;
+CODE
diff --git a/compilers/ncigen/t/spi.c b/compilers/ncigen/t/spi.c
new file mode 100644
index 0000000..883dc66
--- /dev/null
+++ b/compilers/ncigen/t/spi.c
@@ -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/config/gen/makefiles.pm b/config/gen/makefiles.pm
index 506287a..8fd71e0 100644
--- a/config/gen/makefiles.pm
+++ b/config/gen/makefiles.pm
@@ -41,6 +41,8 @@ sub _init {
             conditioned_lines => 1,
         },
 
+        'compilers/ncigen/Makefile'  => 
+            { SOURCE => 'compilers/ncigen/config/makefiles/ncigen.in' },
         'compilers/nqp/Makefile'     =>
             { SOURCE => 'config/gen/makefiles/nqp.in' },
         'compilers/pct/Makefile'     =>
diff --git a/include/parrot/nci.h b/include/parrot/nci.h
index b58782b..1b85a73 100644
--- a/include/parrot/nci.h
+++ b/include/parrot/nci.h
@@ -15,7 +15,7 @@
 
 #include "parrot/parrot.h"
 
-void *build_call_func(PARROT_INTERP, SHIM(PMC *pmc_nci), NOTNULL(STRING *signature));
+void *build_call_func(PARROT_INTERP, SHIM(PMC *pmc_nci), NOTNULL(STRING *signature), NOTNULL(int *jitted));
 
 #endif /* PARROT_NCI_H_GUARD */
 
diff --git a/src/jit/i386/jit_emit.h b/src/jit/i386/jit_emit.h
index 81c1784..dccb70b 100644
--- a/src/jit/i386/jit_emit.h
+++ b/src/jit/i386/jit_emit.h
@@ -20,6 +20,116 @@
 #endif
 
 #  include <assert.h>
+#include "parrot/parrot.h"
+#include "parrot/hash.h"
+#include "parrot/oplib/ops.h"
+
+/*
+ * helper funcs - get argument n
+ */
+static INTVAL
+get_nci_I(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_int(st->val);
+}
+
+static FLOATVAL
+get_nci_N(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_num(st->val);
+}
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static STRING*
+get_nci_S(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    /* TODO or act like below? */
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_str(st->val);
+}
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static PMC*
+get_nci_P(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    /*
+     * exessive args are passed as NULL
+     * used by e.g. MMD infix like __add
+     */
+    if (n < st->src.n)
+        Parrot_fetch_arg_nci(interp, st);
+    else
+        UVal_pmc(st->val) = PMCNULL;
+
+    return UVal_pmc(st->val);
+}
+
+/*
+ * set return value
+ */
+static void
+set_nci_I(PARROT_INTERP, ARGOUT(call_state *st), INTVAL val)
+{
+    Parrot_init_ret_nci(interp, st, "I");
+    if (st->dest.i < st->dest.n) {
+        UVal_int(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_N(PARROT_INTERP, ARGOUT(call_state *st), FLOATVAL val)
+{
+    Parrot_init_ret_nci(interp, st, "N");
+    if (st->dest.i < st->dest.n) {
+        UVal_num(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_S(PARROT_INTERP, ARGOUT(call_state *st), STRING *val)
+{
+    Parrot_init_ret_nci(interp, st, "S");
+    if (st->dest.i < st->dest.n) {
+        UVal_str(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_P(PARROT_INTERP, ARGOUT(call_state *st), PMC* val)
+{
+    Parrot_init_ret_nci(interp, st, "P");
+    if (st->dest.i < st->dest.n) {
+        UVal_pmc(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
 
 #if defined HAVE_COMPUTED_GOTO && defined __GNUC__ && PARROT_I386_JIT_CGP
 #  define JIT_CGP
@@ -508,6 +618,9 @@ emit_movb_i_m(PARROT_INTERP, char *pc, char imm, int base, int i, int scale, lon
 #  define jit_emit_add_ri_i(interp, pc, reg, imm)   \
     emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg))
 
+#  define emitm_addl_i_r(pc, imm, reg)   \
+    emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg))
+
 #  define emitm_addl_i_m(pc, imm, b, i, s, d) \
     emitm_alul_i_m((pc), 0x81, emit_b000, (imm), (b), (i), (s), (d))
 
@@ -524,6 +637,7 @@ emit_movb_i_m(PARROT_INTERP, char *pc, char imm, int base, int i, int scale, lon
 
 #  define emitm_subl_i_r(pc, imm, reg) \
     emitm_alul_i_r((pc), 0x81, emit_b101, (imm), (reg))
+
 #  define jit_emit_sub_ri_i(interp, pc, r, i) emitm_subl_i_r((pc), (i), (r))
 
 #  define emitm_subl_r_m(pc, reg, b, i, s, d) \
@@ -1316,6 +1430,8 @@ static unsigned char *lastpc;
 
 /* Unconditional Jump/Call */
 
+#  define emitm_call_cfunc(pc, func) emitm_calll((pc), (char *)(func) - (pc) - 4)
+
 #  define emitm_calll(pc, disp) { \
     *((pc)++) = (char) 0xe8; \
     *(long *)(pc) = (disp); (pc) += 4; }
@@ -3678,12 +3794,12 @@ static int
 count_regs(PARROT_INTERP, char *sig, char *sig_start)
 {
     const char *typs[] = {
-        "lisc",         /* I */
-        "tbB",          /* S */
-        "pP234",        /* P */
-        "fd"            /* N */
+        "Ilisc",         /* I */
+        "StbB",          /* S */
+        "pP234",         /* P */
+        "Nfd"            /* N */
     };
-    int first_reg = 5;
+    int first_reg = 0;
     int i, found;
 
     /* char at sig is the type to look at */
@@ -3705,109 +3821,145 @@ count_regs(PARROT_INTERP, char *sig, char *sig_start)
     }
     return first_reg;
 }
+
+static size_t
+calc_signature_needs(const char *sig, int *strings)
+{
+    size_t stack_size = 0;
+    while (*sig) {
+        switch (*sig) {
+            case 't':
+                (*strings)++;
+                stack_size +=4;
+                break;
+            case 'd':
+                stack_size +=8;
+                break;
+            default:
+                stack_size +=4;
+                break;
+        }
+        sig++;
+    }
+    return stack_size;
+
+}
 /*
- * The function generated here is called as func(interp, nci_pmc)
- * interp ...  8(%ebp)
- * pmc    ... 12(%ebp)
+ * The function generated here is called as func(interp, nci_info)
+ * interp   ...  8(%ebp)
+ * nci_info ... 12(%ebp)
  *
  * The generate function for a specific signature looks quite similar to
  * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles
  * just compare the disassembly.
  */
 void *
-Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci,
-        STRING *signature)
+Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature)
 {
     Parrot_jit_info_t jit_info;
-    char *sig, *pc;
-    int next_n = 5;
-    int next_p = 5;
-    int next_s = 5;
-    int next_i = 5;
-    int st = 0;
-    int size = 100 + signature->bufused * 20;
+    int i = 0;
+    char *pc;
+    int arg_count = 0;
+    int strings   = 0;
+    const int ST_SIZE_OF = 124;
+    const int JIT_ALLOC_SIZE = 1024;
+
+    char *sig = (char *)signature->strstart + 1; /* skip over the result */
+    size_t stack_space_needed = calc_signature_needs(sig, &strings);
+
+    int st_offset = 16 + stack_space_needed;
+    int args_offset = 16;
+    int strings_offset = st_offset + ST_SIZE_OF;
+    int total_stack_needed = strings_offset + 4 * strings;
 
     /* this ought to be enough - the caller of this function
      * should free the function pointer returned here
      */
-    jit_info.native_ptr = jit_info.arena.start =
-        (char *)mem_alloc_executable(size);
-    pc = jit_info.native_ptr;
+    pc = jit_info.native_ptr = jit_info.arena.start = (char *)mem_alloc_executable(JIT_ALLOC_SIZE);
 
+
+    /* this generated jit function will be called as (INTERP (EBP 8), func_ptr (ESP 12), args signature (ESP 16)) */
     /* make stack frame, preserve %ebx */
     jit_emit_stack_frame_enter(pc);
-    emitm_pushl_r(pc, emit_EBX);
-    /* get interp into %ebx */
-    emitm_movl_m_r(interp, pc, emit_EBX, emit_EBP, 0, 1, 8);
-    /* get base pointer */
-    emitm_movl_m_r(interp, pc, emit_EBX, emit_EBX, 0, 1,
-            offsetof(struct parrot_interp_t, ctx.bp));
 
-    /* get rightmost param, assume ascii chars */
-    sig = (char *)signature->strstart + signature->bufused - 1;
-    /* as long as there are params */
-    while (sig > (char *)signature->strstart) {
+    emitm_subl_i_r(pc, total_stack_needed, emit_ESP);
+
+    /* Parrot_init_arg_nci(interp, &st, "S"); */
+    emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 16);
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+
+    /*&st*/
+    emitm_lea_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, st_offset);
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+
+    /*interpreter*/
+    emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8);
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 0);
+
+    if (sig && *sig)
+      emitm_call_cfunc(pc, Parrot_init_arg_nci);
+
+    while (*sig) {
+        emitm_movl_i_m(pc, arg_count, emit_ESP, 0, 1, 8);
+
         switch (*sig) {
             case '0':    /* null ptr or such - doesn't consume a reg */
                 jit_emit_bxor_rr_i(interp, pc, emit_EAX, emit_EAX);
-                emitm_pushl_r(pc, emit_EAX);
-                break;
-            /* I have no idea how to handle these */
-            case '2':
-            case '3':
-            case '4':
-                /* This might be right. Or not... */
-                /* we need the offset of PMC_int_val */
-                jit_emit_mov_RM_i(interp, pc, emit_EDX,
-                        REG_OFFS_PMC(count_regs(interp, sig, signature->strstart)));
-                emitm_lea_m_r(interp, pc, emit_EAX, emit_EDX, 0, 1,
-                        (size_t) &PMC_int_val((PMC *) 0));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'f':
-                /* get a double from next num reg and push it on stack */
-                jit_emit_fload_mb_n(interp, pc, emit_EBX,
-                        REG_OFFS_NUM(count_regs(interp, sig, signature->strstart)));
-                /* make room for float */
-                emitm_addb_i_r(pc, -4, emit_ESP);
-                emitm_fstps(interp, pc, emit_ESP, emit_None, 1, 0);
+                emitm_call_cfunc(pc, get_nci_N);
+                emitm_fstps(interp, pc, emit_ESP, 0, 1, args_offset);
                 break;
+            case 'N':
             case 'd':
-                /* get a double from next num reg and push it on stack */
-                jit_emit_fload_mb_n(interp, pc, emit_EBX,
-                        REG_OFFS_NUM(count_regs(interp, sig, signature->strstart)));
-                /* make room for double */
-                emitm_addb_i_r(pc, -8, emit_ESP);
-                emitm_fstpl(interp, pc, emit_ESP, emit_None, 1, 0);
-                st += 4;        /* extra stack for double */
+                emitm_call_cfunc(pc, get_nci_N);
+                emitm_fstpl(interp, pc, emit_ESP, 0, 1, args_offset);
+                args_offset += 4;
                 break;
             case 'I':   /* INTVAL */
             case 'l':   /* long */
             case 'i':   /* int */
-                jit_emit_mov_RM_i(interp, pc, emit_EAX,
-                        REG_OFFS_INT(count_regs(interp, sig, signature->strstart)));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_call_cfunc(pc, get_nci_I);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
+                break;
+            case 't':   /* string, pass a cstring */
+                emitm_call_cfunc(pc, get_nci_S);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+                emitm_call_cfunc(pc, string_to_cstring);
+
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
+                /* save off temporary allocation address */
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, strings_offset);
+                strings_offset += 4;
+
+                /* reset ESP(4) */
+                emitm_lea_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, st_offset);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
                 break;
             case 's':   /* short: movswl intreg_o(base), %eax */
-                emitm_movswl_r_m(interp, pc, emit_EAX, emit_EBX, 0, 1,
-                        REG_OFFS_INT(count_regs(interp, sig, signature->strstart)));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_call_cfunc(pc, get_nci_I);
+                emitm_movswl_r_r(pc, emit_EAX, emit_EAX)
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'c':   /* char: movsbl intreg_o(base), %eax */
-                emitm_movsbl_r_m(interp, pc, emit_EAX, emit_EBX, 0, 1,
-                        REG_OFFS_INT(count_regs(interp, sig, signature->strstart)));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_call_cfunc(pc, get_nci_I);
+                emitm_movsbl_r_r(pc, emit_EAX, emit_EAX);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
+                break;
+            case 'J':   /* interpreter */
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
+                arg_count--;
                 break;
             case 'p':   /* push pmc->data */
-                jit_emit_mov_RM_i(interp, pc, emit_EDX,
-                        REG_OFFS_PMC(count_regs(interp, sig, signature->strstart)));
+                emitm_call_cfunc(pc, get_nci_P);
 #  if ! PMC_DATA_IN_EXT
                 /* mov pmc, %edx
                  * mov 8(%edx), %eax
                  * push %eax
                  */
-                emitm_movl_m_r(interp, pc, emit_EAX, emit_EDX, 0, 1,
-                        offsetof(struct PMC, data));
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, data));
 #  else
                 /* push pmc->pmc_ext->data
                  * mov pmc, %edx
@@ -3815,61 +3967,63 @@ Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci,
                  * mov data(%eax), %eax
                  * push %eax
                  */
-                emitm_movl_m_r(interp, pc, emit_EAX, emit_EDX, 0, 1,
-                        offsetof(struct PMC, pmc_ext));
-                emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1,
-                        offsetof(struct PMC_EXT, data));
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, pmc_ext));
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC_EXT, data));
 #  endif
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'O':   /* push PMC * object in P2 */
-                jit_emit_mov_RM_i(interp, pc, emit_EAX, REG_OFFS_PMC(2));
-                goto preg;
             case 'P':   /* push PMC * */
-                jit_emit_mov_RM_i(interp, pc, emit_EAX,
-                        REG_OFFS_PMC(count_regs(interp, sig, signature->strstart)));
-preg:
+            case '@':
+                emitm_call_cfunc(pc, get_nci_P);
 #  if PARROT_CATCH_NULL
                 /* PMCNULL is a global */
                 jit_emit_cmp_rm_i(pc, emit_EAX, &PMCNULL);
                 emitm_jxs(pc, emitm_jne, 2); /* skip the xor */
                 jit_emit_bxor_rr_i(interp, pc, emit_EAX, emit_EAX);
 #  endif
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'v':
-                st -= 4;        /* undo default stack usage */
+                break;
+            case 'V':
+                emitm_call_cfunc(pc, get_nci_P);
+                emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, data));
+                //emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, 0);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'b':   /* buffer (void*) pass PObj_bufstart(SReg) */
-                jit_emit_mov_RM_i(interp, pc, emit_EDX,
-                        REG_OFFS_STR(count_regs(interp, sig, signature->strstart)));
-                emitm_movl_m_r(interp, pc, emit_EAX, emit_EDX, 0, 1,
-                        (size_t) &PObj_bufstart((STRING *) 0));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_call_cfunc(pc, get_nci_S);
+                emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, (size_t) &PObj_bufstart((STRING *) 0));
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             case 'B':   /* buffer (void**) pass &PObj_bufstart(SReg) */
-                jit_emit_mov_RM_i(interp, pc, emit_EDX,
-                        REG_OFFS_STR(count_regs(interp, sig, signature->strstart)));
-                emitm_lea_m_r(interp, pc, emit_EAX, emit_EDX, 0, 1,
-                        (size_t) &PObj_bufstart((STRING *) 0));
-                emitm_pushl_r(pc, emit_EAX);
+                emitm_call_cfunc(pc, get_nci_S);
+                emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, (size_t) &PObj_bufstart((STRING *) 0));
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
-            case 't':   /* string, pass a cstring */
-                jit_emit_mov_RM_i(interp, pc, emit_EAX,
-                        REG_OFFS_STR(count_regs(interp, sig, signature->strstart)));
-                emitm_pushl_r(pc, emit_EAX);
-                emitm_pushl_r(pc, emit_EBX);
-
-                /* this leaks horribly */
-                emitm_calll(pc, (char *)string_to_cstring - pc - 4);
-                emitm_addb_i_r(pc, 8, emit_ESP);
-                emitm_pushl_r(pc, emit_EAX);
+            case 'S':
+                emitm_call_cfunc(pc, get_nci_S);
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
-            case 'J':   /* interpreter */
-                emitm_movl_m_r(interp, pc, emit_ECX, emit_EBP, 0, 1, 8);
-                emitm_pushl_r(pc, emit_ECX);
+
+
+            /* I have no idea how to handle these */
+            case '2':
+            case '3':
+            case '4':
+                mem_free_executable(jit_info.native_ptr);
+                return NULL;
+                break;
+                /* This might be right. Or not... */
+                /* we need the offset of PMC_int_val */
+                emitm_call_cfunc(pc, get_nci_P);
+                emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, (size_t) &PMC_int_val((PMC *) 0));
+                emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, args_offset);
                 break;
             default:
+                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR,
+                    "Unknown arg Signature %c\n", *sig);
                 /*
                  * oops unknown signature:
                  * cleanup and try nci.c
@@ -3877,139 +4031,153 @@ preg:
                 mem_free_executable(jit_info.native_ptr);
                 return NULL;
         }
-        /* default stack usage */
-        st += 4;
-        --sig;
+        args_offset +=4;
+        arg_count++;
+        sig++;
     }
+
+    emitm_addl_i_r(pc, 16, emit_ESP);
     /* get the pmc from stack - movl 12(%ebp), %eax */
     emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 12);
-    /* call the thing in struct_val, i.e. offset 12 - call *(12)%eax */
-    emitm_callm(pc, emit_EAX, emit_None, emit_None,
-            (size_t) &PMC_struct_val((PMC *) 0));
-    /*
-     * TODO
-     * if we have strings in the signature, then we are leaking memory
-     * from string_to_cstring above:
-     * - allocate area of stack positions with strings
-     * - emit code to free these
-     */
+    emitm_callm(pc, emit_EAX, emit_None, emit_None, 0);
+    emitm_subl_i_r(pc, 16, emit_ESP);
+
+    /* SAVE OFF EAX */
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+
+    /*&st*/
+    emitm_lea_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, st_offset);
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+
+    /*interpreter*/
+    emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8);
+    emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 0);
 
-    /* adjust stack */
-    if (st)
-        emitm_addb_i_r(pc, st, emit_ESP);
+    /* RESTORE BACK EAX */
+    emitm_movl_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
 
     /* now place return value in registers */
     /* first in signature is the return value */
+    sig = (char *)signature->strstart; /* the result */
     switch (*sig) {
         /* I have no idea how to handle these */
         case '2':
         case '3':
         case '4':
             /* get integer from pointer - untested */
-            emitm_movl_m_r(interp, pc, emit_EDX, emit_EAX, 0, 1, 0);
+            emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, 0);
             if (*sig == 2)      /* short */
-                emitm_movswl_r_r(pc, emit_EDX, emit_EDX);
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_INT(next_i++), emit_EDX);
+                emitm_movswl_r_r(pc, emit_EAX, emit_EAX);
+            emitm_call_cfunc(pc, set_nci_I);
             break;
         case 'f':
         case 'd':
+            jit_emit_fstore_mb_n(interp, pc, emit_ESP, 8);
+            emitm_call_cfunc(pc, set_nci_N);
             /* pop num from st(0) and mov to reg */
-            jit_emit_fstore_mb_n(interp, pc, emit_EBX, REG_OFFS_NUM(next_n++));
             break;
         case 's':
-            /* movswl %ax, %edx */
-            emitm_movswl_r_r(pc, emit_EDX, emit_EAX);
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_INT(next_i++), emit_EDX);
+            /* movswl %ax, %eax */
+            emitm_movswl_r_r(pc, emit_EAX, emit_EAX);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+            emitm_call_cfunc(pc, set_nci_I);
             break;
         case 'c':
-            /* movsbl %al, %edx */
-            emitm_movsbl_r_r(pc, emit_EDX, emit_EAX);
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_INT(next_i++), emit_EDX);
+            /* movsbl %al, %eax */
+            emitm_movsbl_r_r(pc, emit_EAX, emit_EAX);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+            emitm_call_cfunc(pc, set_nci_I);
             break;
         case 'I':   /* INTVAL */
         case 'l':
         case 'i':
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_INT(next_i++), emit_EAX);
-            /* fall through */
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+            emitm_call_cfunc(pc, set_nci_I);
+            break;
         case 'v': /* void - do nothing */
             break;
         case 'P':
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_PMC(next_p++), emit_EAX);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+            emitm_call_cfunc(pc, set_nci_P);
             break;
         case 'p':   /* make a new unmanaged struct */
             /* save return value on stack */
-            emitm_movl_m_r(interp, pc, emit_ECX, emit_EBP, 0, 1, 8);
-            emitm_pushl_r(pc, emit_EAX);
+            
+            /* save pointer p */
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 12);
+
             /* make new pmc */
-            emitm_pushl_i(pc, enum_class_UnManagedStruct);
-            emitm_pushl_r(pc, emit_ECX);
-            emitm_calll(pc, (char*)pmc_new - pc - 4);
-            emitm_addb_i_r(pc, 8, emit_ESP);
+            emitm_movl_i_m(pc, enum_class_UnManagedStruct, emit_ESP, 0, 1, 4);
+            emitm_call_cfunc(pc, pmc_new);
+
+            /* restore pointer p to EDX */
+            emitm_movl_m_r(interp, pc, emit_EDX, emit_ESP, 0, 1, 12);
+           
+            /* copy UnManagedStruct to stack for set_nci_P call */
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+
             /* eax = PMC, get return value into edx */
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_PMC(next_p++), emit_EAX);
-            emitm_popl_r(pc, emit_EDX);
             /* stuff return value into pmc->data */
+
 #  if ! PMC_DATA_IN_EXT
             /* mov %edx, (data) %eax */
-            emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1,
-                    offsetof(struct PMC, data));
+            emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1, offsetof(struct PMC, data));
 #  else
             /* mov pmc_ext(%eax), %eax
                mov %edx, data(%eax) */
-            emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1,
-                    offsetof(struct PMC, pmc_ext));
-            emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1,
-                    offsetof(struct PMC_EXT, data));
+            emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, pmc_ext));
+            emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1, offsetof(struct PMC_EXT, data));
 #  endif
-            break;
-        case 'b':   /* (void *) = PObj_bufstart(new_buffer_header) */
-            /* preserve return value */
-            emitm_movl_m_r(interp, pc, emit_ECX, emit_EBP, 0, 1, 8);
-            emitm_pushl_r(pc, emit_EAX);
-            emitm_pushl_r(pc, emit_ECX);
-            emitm_calll(pc, (char*)new_buffer_header - pc - 4);
-            emitm_addb_i_r(pc, 4, emit_ESP);
-            /* *eax = buffer_header */
-            /* set external flag */
-            emitm_orl_i_m(pc, PObj_external_FLAG, emit_EAX, 0, 1,
-                    offsetof(PMC, flags));
-            emitm_popl_r(pc, emit_EDX);
-            /* mov %edx, (bufstart) %eax */
-            emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1,
-                        (size_t) &PObj_bufstart((STRING *) 0));
-            /* place result in SReg */
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_STR(next_s++), emit_EAX);
 
+            /* reset ESP(4) */
+            emitm_lea_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, st_offset);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+
+            emitm_call_cfunc(pc, set_nci_P);
             break;
         case 'S':
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_STR(next_s++), emit_EAX);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+            emitm_call_cfunc(pc, set_nci_S);
             break;
         case 't':   /* string */
             /* EAX is char* */
-            emitm_pushl_i(pc, 0);               /* len */
-            emitm_movl_m_r(interp, pc, emit_ECX, emit_EBP, 0, 1, 8);
-            emitm_pushl_r(pc, emit_EAX);        /* string */
-            emitm_pushl_r(pc, emit_ECX);        /* interpreter */
-            emitm_calll(pc, (char*)string_from_cstring - pc - 4);
-            emitm_addb_i_r(pc, 12, emit_ESP);
-            jit_emit_mov_MR_i(interp, pc, REG_OFFS_STR(next_s++), emit_EAX);
+            emitm_movl_i_m(pc, 0, emit_ESP, 0, 1, 8); /* len */
+
+            /* overrights addres of st in ESP(4) */
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+
+            emitm_call_cfunc(pc, string_from_cstring);
+
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 8);
+
+            /* reset ESP(4) */
+            emitm_lea_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, st_offset);
+            emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 4);
+
+            emitm_call_cfunc(pc, set_nci_S);
             break;
         default:
+            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR,
+                "Unknown return Signature %c\n", *sig);
+            /*
+             * oops unknown signature:
+             * cleanup and try nci.c
+             */
             mem_free_executable(jit_info.native_ptr);
             return NULL;
     }
-    /* set prototyped return */
-    jit_emit_mov_MI_i(interp, pc, REG_OFFS_INT(0), 1);
-    /* set return values in I,S,P,N regs */
-    jit_emit_mov_MI_i(interp, pc, REG_OFFS_INT(1), next_i-5);
-    jit_emit_mov_MI_i(interp, pc, REG_OFFS_INT(2), next_s-5);
-    jit_emit_mov_MI_i(interp, pc, REG_OFFS_INT(3), next_p-5);
-    jit_emit_mov_MI_i(interp, pc, REG_OFFS_INT(4), next_n-5);
-
-    emitm_popl_r(pc, emit_EBX);
+
+    /* free temporary strings */
+    strings_offset = st_offset + ST_SIZE_OF;
+    for (i=0; i<strings; i++) {
+        emitm_movl_m_r(interp, pc, emit_EAX, emit_ESP, 0, 1, strings_offset);
+        emitm_movl_r_m(interp, pc, emit_EAX, emit_ESP, 0, 1, 0);
+        emitm_call_cfunc(pc, string_cstring_free);
+    }
+
     jit_emit_stack_frame_leave(pc);
     emitm_ret(pc);
-    PARROT_ASSERT(pc - jit_info.arena.start <= size);
+    PARROT_ASSERT(pc - jit_info.arena.start <= JIT_ALLOC_SIZE);
     /* could shrink arena.start here to used size */
     PObj_active_destroy_SET(pmc_nci);
     return (void *)D2FPTR(jit_info.arena.start);
diff --git a/src/pmc/nci.pmc b/src/pmc/nci.pmc
index 00110fc..bbb0da3 100644
--- a/src/pmc/nci.pmc
+++ b/src/pmc/nci.pmc
@@ -20,10 +20,79 @@ The vtable functions for the native C call functions.
 
 #include "parrot/parrot.h"
 
+void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI * const nci_info);
+void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI * const nci_info) {
+        unsigned int i;
+        int j = 0;
+        char * sig_c = string_to_cstring(interp, sig);
+        size_t sig_length = strlen(sig_c);
+        char * param_sig = (char *) mem_sys_allocate(sig_length);
+        STRING *params;
+
+        for (i=1; i < sig_length; i++) {
+            switch (sig_c[i]) {
+                case '0':    /* null ptr or such - doesn't consume a reg */
+                    break;
+                case 'f':
+                case 'N':
+                case 'd':
+                    param_sig[j++] = 'N';
+                    break;
+                case 'I':   /* INTVAL */
+                case 'l':   /* long */
+                case 'i':   /* int */
+                case 's':   /* short */
+                case 'c':   /* char */
+                    param_sig[j++] = 'I';
+                    break;
+                case 'S':
+                case 't':   /* string, pass a cstring */
+                    param_sig[j++] = 'S';
+                    break;
+                case 'J':   /* interpreter */
+                    break;
+                case 'p':   /* push pmc->data */
+                case 'O':   /* push PMC * object in P2 */
+                case 'P':   /* push PMC * */
+                case 'V':   /* push PMC * */
+                    param_sig[j++] = 'P';
+                case 'v':
+                    break;
+                    /* I have no idea how to handle these */
+                case '2':
+                case '3':
+                case '4':
+                    param_sig[j++] = 'I';
+                    break;
+                case '@':
+                    param_sig[j++] = 'P';
+                    break;
+                case 'b':   /* buffer (void*) pass PObj_bufstart(SReg) */
+                case 'B':   /* buffer (void**) pass &PObj_bufstart(SReg) */
+                    param_sig[j++] = 'S';
+                    break;
+                default:
+                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR,
+                        "Unknown param Signature %c\n", sig_c[i]);
+                    break;
+            }
+        }
+        param_sig[j++] = 0;
+
+        params = string_make(interp, param_sig, strlen(param_sig), "ascii", 0);
+        nci_info->pcc_params_signature = params;
+
+        mem_sys_free(param_sig);
+        string_cstring_free(sig_c);
+    }
+
+
 pmclass NCI need_ext {
-    ATTR STRING    *signature;    /* The signature. */
-    ATTR void      *func;         /* Function pointer to what we'll call. */
-    ATTR INTVAL     arity;        /* Cached arity of the NCI. */
+    ATTR STRING    *signature;              /* The signature. */
+    ATTR void      *func;                   /* Function pointer to what we'll call. */
+    ATTR STRING    *pcc_params_signature;   /* The signature. */
+    ATTR INTVAL     arity;                  /* Cached arity of the NCI. */
+    ATTR INTVAL     jitted;                 /* Is this a jitted NCI stub. */
 
 /*
 
@@ -71,6 +140,7 @@ Initializes the NCI with a C<NULL> function pointer.
 
         /* Mark that we're not a raw NCI. */
         PObj_flag_CLEAR(private2, SELF);
+        PObj_custom_mark_SET(SELF);
         PObj_active_destroy_SET(SELF);
     }
 
@@ -91,16 +161,38 @@ Sets the specified function pointer and signature (C<*key>).
 
     VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
         Parrot_NCI * const nci_info = PARROT_NCI(SELF);
+        int jitted = 0;
 
         /* Store the original function and signature. */
         PMC_struct_val(SELF) = func;
         nci_info->signature  = key;
+        pcc_params(INTERP, key, nci_info);
 
         /* Arity is length of that string minus one (the return type). */
         nci_info->arity      = string_length(INTERP, key) - 1;
 
         /* Build call function. */
-        nci_info->func       = (PMC *)(build_call_func(INTERP, SELF, key));
+        nci_info->func       = (PMC *)(build_call_func(INTERP, SELF, key, &jitted));
+        nci_info->jitted = jitted;
+    }
+/*
+
+=item C<void mark()>
+
+Mark any referenced strings and PMCs.
+
+=cut
+
+*/
+    VTABLE void mark() {
+        if (PARROT_NCI(SELF)) {
+            Parrot_NCI * const nci_info = PARROT_NCI(SELF);
+
+            if (nci_info->signature)
+                pobject_lives(interp, (PObj*)nci_info->signature);
+            if (nci_info->pcc_params_signature)
+                pobject_lives(interp, (PObj*)nci_info->pcc_params_signature);
+        }
     }
 
 /*
@@ -117,10 +209,6 @@ Destroys the NCI, freeing any allocated memory.
         if (PMC_data(SELF)) {
             Parrot_NCI * const nci_info = PARROT_NCI(SELF);
 
-#if defined(CAN_BUILD_CALL_FRAMES)
-            if (nci_info->func)
-                mem_free_executable(nci_info->func);
-#endif
             mem_sys_free(nci_info);
             PMC_data(SELF) = NULL;
         }
@@ -150,9 +238,11 @@ Creates and returns a clone of the NCI.
          * the length of data here, to memcpy it
          * ManagedStruct or Buffer?
          */
-        nci_info_ret->func      = nci_info_self->func;
-        nci_info_ret->signature = nci_info_self->signature;
-        nci_info_ret->arity     = nci_info_self->arity;
+        nci_info_ret->func                  = nci_info_self->func;
+        nci_info_ret->signature             = nci_info_self->signature;
+        nci_info_ret->pcc_params_signature  = nci_info_self->pcc_params_signature;
+        nci_info_ret->arity                 = nci_info_self->arity;
+        nci_info_ret->jitted                = nci_info_self->arity;
         PObj_get_FLAGS(ret)    |= (PObj_get_FLAGS(SELF) & 0x7);
 
         return ret;
@@ -200,7 +290,23 @@ shifted down.
             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                 "attempt to call NULL function");
 
-        func(INTERP, SELF);
+        if (nci_info->jitted) {
+            typedef INTVAL (*nci_jit_sub_t)(PARROT_INTERP, PMC *, char *);
+
+            nci_jit_sub_t jit_func = (nci_jit_sub_t) D2FPTR(nci_info->func);
+
+            /* Parrot_eprintf(interp, "JITTED %S\n", nci_info->signature); */
+            jit_func(INTERP, SELF, (char *) nci_info->pcc_params_signature->strstart);
+        }
+        else {
+            if (PObj_flag_TEST(private2, SELF)) {
+                /* Parrot_eprintf(interp, "RAW NCI CALL\n"); */
+            }
+            else {
+                /* Parrot_eprintf(interp, "HACKED %S\n", nci_info->signature); */
+            }
+            func(INTERP, SELF);
+        }
         cont = INTERP->current_cont;
 
         /*
diff --git a/tools/build/NCIUtils.pm b/tools/build/NCIUtils.pm
new file mode 100644
index 0000000..c52e46c
--- /dev/null
+++ b/tools/build/NCIUtils.pm
@@ -0,0 +1,826 @@
+#! perl
+# Copyright (C) 2001-2007, The Perl Foundation.
+# $Id$
+
+=head1 NAME
+
+tools/build/nativecall.pl - Build up the native call routines
+
+=head1 SYNOPSIS
+
+    % perl tools/build/nativecall.pl src/call_list.txt
+
+=head1 DESCRIPTION
+
+This script creates the Native Call Interface file F<src/nci.c>. It
+parses a file of function signatures of the form:
+
+ <return-type-specifier><ws><parameter-type-specifiers>[<ws>][#<comment>]
+    ...
+Empty lines and lines containing only whitespace or comment are ignored.
+The types specifiers are documented in F<src/call_list.txt>.
+
+=head1 SEE ALSO
+
+F<src/call_list.txt>.
+F<docs/pdds/pdd16_native_call.pod>.
+
+=cut
+
+package NCIUtils;
+require Exporter;
+
+our @EXPORT = qw( %ret_type %ret_type_decl %proto_type %fix_name %other_decl %ret_assign %func_call_assign %sig_char );
+our @EXPORT_OK = qw( %ret_type %ret_type_decl %proto_type %fix_name %other_decl %ret_assign %func_call_assign %sig_char );
+
+
+use base qw( Exporter );
+
+use strict;
+use warnings;
+
+our %ret_type = (
+    p => "void *",
+    i => "int",
+    3 => "int *",
+    l => "long",
+    4 => "long *",
+    c => "char",
+    s => "short",
+    2 => "short *",
+    f => "float",
+    d => "double",
+    t => "char *",
+    v => "void",
+    #      b => "void *",
+    #      B => "void **",
+    P => "PMC *",
+    S => "STRING *",
+    I => "INTVAL",
+    N => "FLOATVAL",
+);
+our %ret_type_decl = (
+    p => "void *",
+    i => "int",
+    3 => "int *",
+    l => "long",
+    4 => "long *",
+    c => "char",
+    s => "short",
+    2 => "short *",
+    f => "float",
+    d => "double",
+    t => "char *",
+    v => "void *",
+    #      b => "void *",
+    #      B => "void **",
+    P => "PMC *",
+    S => "STRING *",
+    I => "INTVAL",
+    N => "FLOATVAL",
+);
+
+our %proto_type = (
+    p   => "void *",
+    i   => "int",
+    3   => "int *",
+    l   => "long",
+    4   => "long *",
+    c   => "char",
+    s   => "short",
+    2   => "short *",
+    f   => "float",
+    d   => "double",
+    t   => "char *",
+    v   => "void",
+    J   => "PARROT_INTERP",
+    P   => "PMC *",
+    O   => "PMC *",           # object
+    S   => "STRING *",
+    I   => "INTVAL",
+    N   => "FLOATVAL",
+    b   => "void *",
+    B   => "void **",
+    L   => "long *",
+    T   => "char **",
+    V   => "void **",
+    '@' => "PMC *",           # slurpy array
+);
+
+# to fix up signatures that don't translate directly
+# to C function names
+our %fix_name = ( '@' => 'xAT_' );
+
+our %other_decl = (
+    p => "PMC * const final_destination = pmc_new(interp, enum_class_UnManagedStruct);",
+    t => "STRING *final_destination;"
+
+        #     b => "Buffer *final_destination =
+        #     new_buffer_header(interp);\nPObj_external_SET(final_destination)",
+        #     B => "Buffer *final_destination =
+        #     new_buffer_header(interp);\nPObj_external_SET(final_destination)",
+);
+
+
+our %ret_assign = (
+    p => "PMC_data(final_destination) = return_data;    set_nci_P(interp, &st, final_destination);",
+    i => "set_nci_I(interp, &st, return_data);",
+    I => "set_nci_I(interp, &st, return_data);",
+    l => "set_nci_I(interp, &st, return_data);",
+    s => "set_nci_I(interp, &st, return_data);",
+    c => "set_nci_I(interp, &st, return_data);",
+    4 => "set_nci_I(interp, &st, *return_data);",
+    3 => "set_nci_I(interp, &st, *return_data);",
+    2 => "set_nci_I(interp, &st, *return_data);",
+    f => "set_nci_N(interp, &st, return_data);",
+    d => "set_nci_N(interp, &st, return_data);",
+    N => "set_nci_N(interp, &st, return_data);",
+    P => "set_nci_P(interp, &st, return_data);",
+    S => "set_nci_S(interp, &st, return_data);",
+    v => "",
+    t => "final_destination = string_from_cstring(interp, return_data, 0);\n    set_nci_S(interp, &st, final_destination);",
+
+#      b => "PObj_bufstart(final_destination) = return_data;\n    set_nci_S(interp, &st, final_destination);",
+#      B => "PObj_bufstart(final_destination) = *return_data;\n    set_nci_S(interp, &st, final_destination);",
+);
+
+our %func_call_assign = (
+    p => "return_data = ",
+    i => "return_data = ",
+    3 => "return_data = ",
+    2 => "return_data = ",
+    4 => "return_data = ",
+    l => "return_data = ",
+    c => "return_data = ",
+    s => "return_data = ",
+    f => "return_data = ",
+    d => "return_data = ",
+    b => "return_data = ",
+    t => "return_data = ",
+    P => "return_data = ",
+    S => "return_data = ",
+    I => "return_data = ",
+    N => "return_data = ",
+
+    #      B => "return_data = ",
+    v => "",
+);
+
+our %sig_char = (
+    p   => "P",
+    i   => "I",
+    3   => "P",
+    2   => "P",
+    4   => "P",
+    l   => "I",
+    c   => "I",
+    s   => "I",
+    f   => "N",
+    d   => "N",
+    b   => "S",
+    t   => "S",
+    P   => "P",
+    O   => "P",
+    S   => "S",
+    I   => "I",
+    N   => "N",
+    B   => "S",
+    v   => "v",
+    V   => "P",
+    J   => "",
+    '@' => '@',
+);
+
+sub slurp_signatures {
+    my ( $FH ) = @_; 
+    my $opt_warndups = 0;
+    my %seen;
+    my @results;
+    while (<$FH>) {
+        chomp;
+        s/#.*$//;    # comment till end of line
+            s/^\s*//;
+        s/\s*$//;
+        next unless $_;
+
+        my ( $ret, $args ) = split m/\s+/, $_;
+
+        $args = '' if not defined $args;
+
+        die "Invalid return signature char '$ret' on line $. of $ARGV\n"
+            unless exists $ret_assign{$ret};
+
+        if ( ( $seen{"$ret$args"} ||= $. ) != $. ) {
+            warn sprintf "Ignored signature '%s' on line %d (previously seen on line %d) of $ARGV",
+                 "$ret$args", $., $seen{"$ret$args"}
+            if $opt_warndups;
+            next;
+        }
+        push @results, [$ret, $args];
+    }
+    \@results;
+}
+
+sub main {
+    my $opt_warndups = 0;
+
+    # This file will eventually be compiled
+    open my $NCI, '>', 'src/nci.c' or die "Can't create nci.c: $!";
+
+    print_head( $NCI, \@ARGV );
+
+    my $temp_cnt = 0;
+    my @put_pointer;
+    my %seen;
+
+    while (<>) {
+        chomp;
+        s/#.*$//;    # comment till end of line
+        s/^\s*//;
+        s/\s*$//;
+        next unless $_;
+
+        my ( $ret, $args ) = split m/\s+/, $_;
+
+        $args = '' if not defined $args;
+
+        die "Invalid return signature char '$ret' on line $. of $ARGV\n"
+            unless exists $ret_assign{$ret};
+
+        if ( ( $seen{"$ret$args"} ||= $. ) != $. ) {
+            warn sprintf "Ignored signature '%s' on line %d (previously seen on line %d) of $ARGV",
+                "$ret$args", $., $seen{"$ret$args"}
+                if $opt_warndups;
+            next;
+        }
+
+        my @extra_preamble;
+        my @extra_postamble;
+        my @temps;
+        my @arg;
+        my $reg_num = 0;
+        my $sig     = '';
+
+        if ( defined $args and not $args =~ m/^\s*$/ ) {
+            foreach ( split m//, $args ) {
+                die "Invalid argument signature char '$_' on line $. of $ARGV"
+                    unless exists $sig_char{$_};
+                push @arg,
+                    make_arg( $_, $reg_num++, \$temp_cnt, \@temps, \@extra_preamble,
+                    \@extra_postamble );
+                $sig .= $sig_char{$_};
+                $_ eq 'J' && $reg_num--;
+            }
+        }
+
+        print_function(
+            $NCI, 
+            $sig, $ret,
+            $args, [@arg],
+            $ret_type{$ret},         $ret_type_decl{$ret},
+            $func_call_assign{$ret}, $other_decl{$ret},
+            $ret_assign{$ret},       \@temps,
+            \@extra_preamble, \@extra_postamble,
+            \@put_pointer,    \%proto_type
+        );
+    }
+
+    print_tail( $NCI, \@put_pointer );
+    print_coda( $NCI );
+    close $NCI;
+}
+
+sub print_coda {
+    my ($NCI) = @_;
+    # append the C code coda
+    print $NCI <<"EOCODA";
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
+EOCODA
+
+}
+
+sub print_head {
+    my ($NCI, $definitions) = @_;
+    print $NCI <<"HEAD";
+/* ex: set ro ft=c:
+ * !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
+ *
+ * This file is generated automatically by tools/build/nativecall.pl
+ * from definitions in @$definitions
+ *
+ * Any changes made here will be lost!
+ *
+ */
+
+/* nci.c
+ *  Copyright (C) 2001-2007, The Perl Foundation.
+ *  SVN Info
+ *     \$Id\$
+ *  Overview:
+ *     Native Call Interface routines. The code needed to build a
+ *     parrot to C call frame is in here
+ *  Data Structure and Algorithms:
+ *  History:
+ *  Notes:
+ *  References:
+ */
+#include "parrot/parrot.h"
+#include "parrot/hash.h"
+#include "parrot/oplib/ops.h"
+#include "nci.str"
+
+/* HEADERIZER HFILE: none */
+/* HEADERIZER STOP */
+
+/*
+ * if the architecture can build some or all of these signatures
+ * enable the define below
+ * - the JITed function will be called first
+ * - if it returns NULL, the hardcoded version will do the job
+ */
+
+#if defined(HAS_JIT) && defined(I386)
+#  include "parrot/exec.h"
+#  include "jit.h"
+#  define CAN_BUILD_CALL_FRAMES
+#endif
+
+/*
+ * helper funcs - get argument n
+ */
+static INTVAL
+get_nci_I(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_int(st->val);
+}
+
+static FLOATVAL
+get_nci_N(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_num(st->val);
+}
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static STRING*
+get_nci_S(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    /* TODO or act like below? */
+    if (n >= st->src.n)
+        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+            "too few arguments passed to NCI function");
+
+    Parrot_fetch_arg_nci(interp, st);
+
+    return UVal_str(st->val);
+}
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static PMC*
+get_nci_P(PARROT_INTERP, ARGMOD(call_state *st), int n)
+{
+    /*
+     * exessive args are passed as NULL
+     * used by e.g. MMD infix like __add
+     */
+    if (n < st->src.n)
+        Parrot_fetch_arg_nci(interp, st);
+    else
+        UVal_pmc(st->val) = PMCNULL;
+
+    return UVal_pmc(st->val);
+}
+
+#define GET_NCI_I(n) get_nci_I(interp, &st, n)
+#define GET_NCI_S(n) get_nci_S(interp, &st, n)
+#define GET_NCI_N(n) get_nci_N(interp, &st, n)
+#define GET_NCI_P(n) get_nci_P(interp, &st, n)
+
+/*
+ * set return value
+ */
+static void
+set_nci_I(PARROT_INTERP, ARGOUT(call_state *st), INTVAL val)
+{
+    Parrot_init_ret_nci(interp, st, "I");
+    if (st->dest.i < st->dest.n) {
+        UVal_int(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_N(PARROT_INTERP, ARGOUT(call_state *st), FLOATVAL val)
+{
+    Parrot_init_ret_nci(interp, st, "N");
+    if (st->dest.i < st->dest.n) {
+        UVal_num(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_S(PARROT_INTERP, ARGOUT(call_state *st), STRING *val)
+{
+    Parrot_init_ret_nci(interp, st, "S");
+    if (st->dest.i < st->dest.n) {
+        UVal_str(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+static void
+set_nci_P(PARROT_INTERP, ARGOUT(call_state *st), PMC* val)
+{
+    Parrot_init_ret_nci(interp, st, "P");
+    if (st->dest.i < st->dest.n) {
+        UVal_pmc(st->val) = val;
+        Parrot_convert_arg(interp, st);
+        Parrot_store_arg(interp, st);
+    }
+}
+
+/* All our static functions that call in various ways. Yes, terribly
+   hackish, but that is just fine */
+
+HEAD
+    return;
+}
+
+sub make_arg {
+
+    #
+    # we have to fetch all to temps, so that the call code
+    # can operate in sequence
+    #
+    my ( $argtype, $reg_num, $temp_cnt_ref, $temps_ref, $extra_preamble_ref, $extra_postamble_ref )
+        = @_;
+
+    local $_ = $argtype;
+    my $temp_num = ${$temp_cnt_ref}++;
+    /p/ && do {
+        push @{$temps_ref},          "PMC *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "PMC_data(t_$temp_num)";
+    };
+    /V/ && do {
+        push @{$temps_ref},          "PMC *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "(void**)&PMC_data(t_$temp_num)";
+    };
+    /i/ && do {
+        push @{$temps_ref},          "int t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (int)GET_NCI_I($reg_num);";
+        return "t_$temp_num";
+    };
+    /3/ && do {
+        push @{$temps_ref},          "PMC *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "(int*)&PMC_int_val(t_$temp_num)";
+    };
+    /l/ && do {
+        push @{$temps_ref},          "long t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (long)GET_NCI_I($reg_num);";
+        return "t_$temp_num";
+    };
+    /I/ && do {
+        push @{$temps_ref},          "INTVAL t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_I($reg_num);";
+        return "t_$temp_num";
+    };
+    /4/ && do {
+        push @{$temps_ref},          "PMC *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "(long*)&PMC_int_val(t_$temp_num)";
+    };
+    /s/ && do {
+        push @{$temps_ref},          "short t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (short)GET_NCI_I($reg_num);";
+        return "t_$temp_num";
+    };
+    /c/ && do {
+        push @{$temps_ref},          "char t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (char)GET_NCI_I($reg_num);";
+        return "t_$temp_num";
+    };
+    /2/ && do {
+        push @{$temps_ref},          "PMC* t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "(short*)&PMC_int_val(t_$temp_num)";
+    };
+    /f/ && do {
+        push @{$temps_ref},          "float t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (float)GET_NCI_N($reg_num);";
+        return "t_$temp_num";
+    };
+    /d/ && do {
+        push @{$temps_ref},          "double t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = (double)GET_NCI_N($reg_num);";
+        return "t_$temp_num";
+    };
+    /N/ && do {
+        push @{$temps_ref},          "FLOATVAL t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_N($reg_num);";
+        return "t_$temp_num";
+    };
+    /t/ && do {
+        push @{$temps_ref}, "char *t_$temp_num;";
+        push @{$extra_preamble_ref},
+            "t_$temp_num = string_to_cstring(interp, GET_NCI_S($reg_num));";
+        push @{$extra_postamble_ref}, "string_cstring_free(t_$temp_num);";
+        return "t_$temp_num";
+    };
+    /b/ && do {
+        push @{$temps_ref},          "STRING *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
+        return "PObj_bufstart(t_$temp_num)";
+    };
+    /B/ && do {
+        push @{$temps_ref},          "STRING *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
+        return "&PObj_bufstart(t_$temp_num)";
+    };
+    /J/ && do {
+        return "interp";
+    };
+    /[OP\@]/ && do {
+        push @{$temps_ref},          "PMC *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
+        return "PMC_IS_NULL(t_$temp_num) ? NULL : t_$temp_num";
+    };
+    /S/ && do {
+        push @{$temps_ref},          "STRING *t_$temp_num;";
+        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
+        return "t_$temp_num";
+    };
+    return;
+}
+
+sub print_function {
+    my (
+        $NCI,
+        $sig,          $return,        $params,             $args,
+        $ret_type,     $ret_type_decl, $return_assign,      $other_decl,
+        $final_assign, $temps_ref,     $extra_preamble_ref, $extra_postamble_ref,
+        $put_pointer_ref, $proto_type_ref
+    ) = @_;
+
+    $other_decl ||= "";
+
+    $other_decl .= join( "\n    ", @{$temps_ref} );
+    my $call_state      = 'call_state st;';
+    my $extra_preamble  = join( "\n    ", @{$extra_preamble_ref} );
+    my $extra_postamble = join( "\n    ", @{$extra_postamble_ref} );
+    my $return_data =
+        "$return_assign $final_assign" =~ /return_data/
+        ? qq{$ret_type_decl return_data;}
+        : q{};
+    my $fix_params = join '', map { $fix_name{$_} || $_ } split m//, $params;
+
+    if ( length $params ) {
+        my $proto = join ', ', map { $proto_type_ref->{$_} } split( m//, $params );
+
+        # This is an after-the-fact hack: real fix would be in make_arg
+        # or somewhere at that level.  The main point being that one cannot
+        # just cast pointers and expect things to magically align.  Instead
+        # of trying to: (int*)&something_not_int, one HAS to use temporary
+        # variables.  We detect and collect those to "temp".
+        my @temp;
+        for my $i ( 0 .. $#$args ) {
+            if ( $args->[$i] =~ /^\((.+)\*\)&(.+)$/ ) {
+                $temp[$i] = [ $1, $2 ];
+                $args->[$i] = "&arg$i";
+            }
+        }
+        my $call_params = join( ",", @$args );
+        my @tempi = grep { defined $temp[$_] } 0 .. $#$args;
+        my $temp_decl = join( "\n    ", map { "$temp[$_]->[0] arg$_;" } @tempi );
+        ## shorts need to be properly cast
+        my $temp_in = join( "\n    ",
+            map { "arg$_ = " . ( 'short' eq $temp[$_]->[0] ? '(short)' : '' ) . "$temp[$_]->[1];" }
+                @tempi );
+        my $temp_out = join( "\n    ", map { "$temp[$_]->[1] = arg$_;" } @tempi );
+
+        print $NCI <<"HEADER";
+static void
+pcf_${return}_$fix_params(PARROT_INTERP, PMC *self)
+{
+    typedef $ret_type (*func_t)($proto);
+    func_t pointer;
+    $call_state
+    $return_data
+    $temp_decl
+    $other_decl
+    Parrot_init_arg_nci(interp, &st, \"$sig\");
+    $extra_preamble
+
+    pointer =  (func_t)D2FPTR(PMC_struct_val(self));
+    $temp_in
+    $return_assign ($ret_type)(*pointer)($call_params);
+    $temp_out
+    $final_assign
+    $extra_postamble
+}
+HEADER
+    }
+    else {
+
+        # Things are more simple, when there are no params
+        # call state var not needed if there are no params and a void return
+        $call_state = '' if 'v' eq $return;
+        print $NCI <<"HEADER";
+static void
+pcf_${return}_(PARROT_INTERP, PMC *self)
+{
+    $ret_type (*pointer)(void);
+    $return_data
+    $other_decl
+    $call_state
+    $extra_preamble
+
+    pointer =  ($ret_type (*)(void))D2FPTR(PMC_struct_val(self));
+    $return_assign ($ret_type)(*pointer)();
+    $final_assign
+    $extra_postamble
+}
+HEADER
+    }
+
+    my ( $key, $value ) = (
+        defined $params
+        ? ( "$return$params", "pcf_${return}_$fix_params" )
+        : ( "$return", "pcf_${return}" )
+    );
+
+    push @{$put_pointer_ref}, <<"PUT_POINTER";
+        temp_pmc = pmc_new(interp, enum_class_UnManagedStruct);
+        PMC_data(temp_pmc) = (void *)$value;
+        VTABLE_set_pmc_keyed_str(interp, HashPointer, CONST_STRING(interp, "$key"), temp_pmc);
+PUT_POINTER
+
+    #        qq|        parrot_hash_put( interp, known_frames, const_cast("$key"), $value );|;
+    return;
+}
+
+sub print_tail {
+    my ($NCI, $put_pointer_ref) = @_;
+
+    my $put_pointer = join( "\n", @{$put_pointer_ref} );
+    print $NCI <<"TAIL";
+
+
+/* This function serves a single purpose. It takes the function
+   signature for a C function we want to call and returns a pointer
+   to a function that can call it. */
+void *
+build_call_func(PARROT_INTERP,
+#if defined(CAN_BUILD_CALL_FRAMES)
+PMC *pmc_nci,
+#else
+SHIM(PMC *pmc_nci),
+#endif
+NOTNULL(STRING *signature), NOTNULL(int *jitted))
+{
+    char       *c;
+    STRING     *ns, *message;
+    STRING     *jit_key_name;
+    PMC        *b;
+    PMC        *iglobals;
+    PMC        *temp_pmc;
+    UINTVAL    signature_len;
+
+    PMC        *HashPointer   = NULL;
+
+    /* And in here is the platform-independent way. Which is to say
+       "here there be hacks" */
+    signature_len = string_length(interp, signature);
+    if (0 == signature_len)
+       return F2DPTR(pcf_v_);
+    /* remove deprecated void argument 'v' character */
+    if (2 == signature_len && 'v' == string_index(interp, signature, 1)) {
+       Parrot_warn(interp, PARROT_WARNINGS_ALL_FLAG, "function signature argument character 'v' ignored");
+       string_chopn_inplace(interp, signature, 1);
+       signature_len = string_length(interp, signature);
+    }
+
+    iglobals = interp->iglobals;
+
+    if (PMC_IS_NULL(iglobals))
+        PANIC(interp, "iglobals isn't created yet");
+    HashPointer = VTABLE_get_pmc_keyed_int(interp, iglobals,
+            IGLOBALS_NCI_FUNCS);
+
+    if (!HashPointer) {
+        HashPointer = pmc_new(interp, enum_class_Hash);
+        VTABLE_set_pmc_keyed_int(interp, iglobals, IGLOBALS_NCI_FUNCS,
+                HashPointer);
+
+$put_pointer
+
+    }
+
+#if defined(CAN_BUILD_CALL_FRAMES)
+    /* Try if JIT code can build that signature. If yes, we are done */
+
+    jit_key_name = string_from_literal(interp, "_XJIT_");
+    jit_key_name = string_append(interp, jit_key_name, signature);
+    b = VTABLE_get_pmc_keyed_str(interp, HashPointer, jit_key_name);
+
+    if (b && b->vtable->base_type == enum_class_UnManagedStruct) {
+        *jitted = 1;
+        return F2DPTR(PMC_data(b));
+    }
+    else {
+        void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature);
+        if (result) {
+            *jitted = 1;
+            temp_pmc = pmc_new(interp, enum_class_UnManagedStruct);
+            PMC_data(temp_pmc) = (void*)result;
+            VTABLE_set_pmc_keyed_str(interp, HashPointer, jit_key_name, temp_pmc);
+            return result;
+        }
+    }
+
+#endif
+
+    b = VTABLE_get_pmc_keyed_str(interp, HashPointer, signature);
+
+    if (b && b->vtable->base_type == enum_class_UnManagedStruct)
+        return F2DPTR(PMC_data(b));
+
+    /*
+      These three lines have been added to aid debugging. I want to be able to
+      see which signature has an unknown type. I am sure someone can come up
+      with a neater way to do this.
+     */
+    ns = string_make(interp, " is an unknown signature type", 29, "ascii", 0);
+    message = string_concat(interp, signature, ns, 0);
+
+#if defined(CAN_BUILD_CALL_FRAMES)
+    ns = string_make(interp, ".\\nCAN_BUILD_CALL_FRAMES is enabled, this should not happen", 58, "ascii", 0);
+#else
+    ns = string_make(interp, ".\\nCAN_BUILD_CALL_FRAMES is disabled, add the signature to src/call_list.txt", 75, "ascii", 0);
+#endif
+    message = string_concat(interp, message, ns, 0);
+
+    /*
+     * I think there may be memory issues with this but if we get to here we are
+     * aborting.
+     */
+    c = string_to_cstring(interp, message);
+    PANIC(interp, c);
+}
+
+TAIL
+    return;
+}
+
+=begin example
+
+This is the template thing
+
+static void pcf_$funcname(PARROT_INTERP, PMC *self) {
+    $ret_type (*pointer)();
+    $ret_type return_data;
+
+    pointer = PMC_struct_val(self);
+    return_data = ($ret_type)(*pointer)($params);
+    $ret_reg  = return_data;
+    REG_INT(interp, 0) = $stack_returns;
+    REG_INT(interp, 1) = $int_returns;
+    REG_INT(interp, 2) = $string_returns;
+    REG_INT(interp, 3) = $pmc_returns;
+    REG_INT(interp, 4) = $num_returns;
+    return;
+}
+
+=cut
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
diff --git a/tools/build/nativecall.pl b/tools/build/nativecall.pl
index 4762306..b517957 100644
--- a/tools/build/nativecall.pl
+++ b/tools/build/nativecall.pl
@@ -29,725 +29,10 @@ F<docs/pdds/pdd16_native_call.pod>.
 
 use strict;
 use warnings;
+use lib "tools/build";
+use NCIUtils;
 
-my $opt_warndups = 0;
-
-# This file will eventually be compiled
-open my $NCI, '>', 'src/nci.c' or die "Can't create nci.c: $!";
-
-print_head( \@ARGV );
-
-my %ret_type = (
-    p => "void *",
-    i => "int",
-    3 => "int *",
-    l => "long",
-    4 => "long *",
-    c => "char",
-    s => "short",
-    2 => "short *",
-    f => "float",
-    d => "double",
-    t => "char *",
-    v => "void",
-
-    #      b => "void *",
-    #      B => "void **",
-    P => "PMC *",
-    S => "STRING *",
-    I => "INTVAL",
-    N => "FLOATVAL",
-);
-
-my %proto_type = (
-    p   => "void *",
-    i   => "int",
-    3   => "int *",
-    l   => "long",
-    4   => "long *",
-    c   => "char",
-    s   => "short",
-    2   => "short *",
-    f   => "float",
-    d   => "double",
-    t   => "char *",
-    v   => "void",
-    J   => "PARROT_INTERP",
-    P   => "PMC *",
-    O   => "PMC *",           # object
-    S   => "STRING *",
-    I   => "INTVAL",
-    N   => "FLOATVAL",
-    b   => "void *",
-    B   => "void **",
-    L   => "long *",
-    T   => "char **",
-    V   => "void **",
-    '@' => "PMC *",           # slurpy array
-);
-
-# to fix up signatures that don't translate directly
-# to C function names
-my %fix_name = ( '@' => 'xAT_' );
-
-my %other_decl = (
-    p => "PMC * const final_destination = pmc_new(interp, enum_class_UnManagedStruct);",
-    t => "STRING *final_destination;"
-
-        #     b => "Buffer *final_destination =
-        #     new_buffer_header(interp);\nPObj_external_SET(final_destination)",
-        #     B => "Buffer *final_destination =
-        #     new_buffer_header(interp);\nPObj_external_SET(final_destination)",
-);
-
-my %ret_type_decl = (
-    p => "void *",
-    i => "int",
-    3 => "int *",
-    l => "long",
-    4 => "long *",
-    c => "char",
-    s => "short",
-    2 => "short *",
-    f => "float",
-    d => "double",
-    t => "char *",
-    v => "void *",
-
-    #      b => "void *",
-    #      B => "void **",
-    P => "PMC *",
-    S => "STRING *",
-    I => "INTVAL",
-    N => "FLOATVAL",
-);
-
-my %ret_assign = (
-    p => "PMC_data(final_destination) = return_data;    set_nci_P(interp, &st, final_destination);",
-    i => "set_nci_I(interp, &st, return_data);",
-    I => "set_nci_I(interp, &st, return_data);",
-    l => "set_nci_I(interp, &st, return_data);",
-    s => "set_nci_I(interp, &st, return_data);",
-    c => "set_nci_I(interp, &st, return_data);",
-    4 => "set_nci_I(interp, &st, *return_data);",
-    3 => "set_nci_I(interp, &st, *return_data);",
-    2 => "set_nci_I(interp, &st, *return_data);",
-    f => "set_nci_N(interp, &st, return_data);",
-    d => "set_nci_N(interp, &st, return_data);",
-    N => "set_nci_N(interp, &st, return_data);",
-    P => "set_nci_P(interp, &st, return_data);",
-    S => "set_nci_S(interp, &st, return_data);",
-    v => "",
-    t =>
-"final_destination = string_from_cstring(interp, return_data, 0);\n    set_nci_S(interp, &st, final_destination);",
-
-#      b => "PObj_bufstart(final_destination) = return_data;\n    set_nci_S(interp, &st, final_destination);",
-#      B => "PObj_bufstart(final_destination) = *return_data;\n    set_nci_S(interp, &st, final_destination);",
-);
-
-my %func_call_assign = (
-    p => "return_data = ",
-    i => "return_data = ",
-    3 => "return_data = ",
-    2 => "return_data = ",
-    4 => "return_data = ",
-    l => "return_data = ",
-    c => "return_data = ",
-    s => "return_data = ",
-    f => "return_data = ",
-    d => "return_data = ",
-    b => "return_data = ",
-    t => "return_data = ",
-    P => "return_data = ",
-    S => "return_data = ",
-    I => "return_data = ",
-    N => "return_data = ",
-
-    #      B => "return_data = ",
-    v => "",
-);
-
-my %sig_char = (
-    p   => "P",
-    i   => "I",
-    3   => "P",
-    2   => "P",
-    4   => "P",
-    l   => "I",
-    c   => "I",
-    s   => "I",
-    f   => "N",
-    d   => "N",
-    b   => "S",
-    t   => "S",
-    P   => "P",
-    O   => "P",
-    S   => "S",
-    I   => "I",
-    N   => "N",
-    B   => "S",
-    v   => "v",
-    V   => "P",
-    J   => "",
-    '@' => '@',
-);
-
-my $temp_cnt = 0;
-my @put_pointer;
-my %seen;
-
-while (<>) {
-    chomp;
-    s/#.*$//;    # comment till end of line
-    s/^\s*//;
-    s/\s*$//;
-    next unless $_;
-
-    my ( $ret, $args ) = split m/\s+/, $_;
-
-    $args = '' if not defined $args;
-
-    die "Invalid return signature char '$ret' on line $. of $ARGV\n"
-        unless exists $ret_assign{$ret};
-
-    if ( ( $seen{"$ret$args"} ||= $. ) != $. ) {
-        warn sprintf "Ignored signature '%s' on line %d (previously seen on line %d) of $ARGV",
-            "$ret$args", $., $seen{"$ret$args"}
-            if $opt_warndups;
-        next;
-    }
-
-    my @extra_preamble;
-    my @extra_postamble;
-    my @temps;
-    my @arg;
-    my $reg_num = 0;
-    my $sig     = '';
-
-    if ( defined $args and not $args =~ m/^\s*$/ ) {
-        foreach ( split m//, $args ) {
-            die "Invalid argument signature char '$_' on line $. of $ARGV"
-                unless exists $sig_char{$_};
-            push @arg,
-                make_arg( $_, $reg_num++, \$temp_cnt, \@temps, \@extra_preamble,
-                \@extra_postamble );
-            $sig .= $sig_char{$_};
-            $_ eq 'J' && $reg_num--;
-        }
-    }
-
-    print_function(
-        $sig, $ret,
-        $args, [@arg],
-        $ret_type{$ret},         $ret_type_decl{$ret},
-        $func_call_assign{$ret}, $other_decl{$ret},
-        $ret_assign{$ret},       \@temps,
-        \@extra_preamble, \@extra_postamble,
-        \@put_pointer,    \%proto_type
-    );
-}
-
-print_tail( \@put_pointer );
-
-# append the C code coda
-print $NCI <<"EOC";
-
-/*
- * Local variables:
- *   c-file-style: "parrot"
- * End:
- * vim: expandtab shiftwidth=4:
- */
-EOC
-
-close $NCI;
-
-sub print_head {
-    my ($definitions) = @_;
-    print $NCI <<"HEAD";
-/* ex: set ro ft=c:
- * !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
- *
- * This file is generated automatically by tools/build/nativecall.pl
- * from definitions in @$definitions
- *
- * Any changes made here will be lost!
- *
- */
-
-/* nci.c
- *  Copyright (C) 2001-2007, The Perl Foundation.
- *  SVN Info
- *     \$Id\$
- *  Overview:
- *     Native Call Interface routines. The code needed to build a
- *     parrot to C call frame is in here
- *  Data Structure and Algorithms:
- *  History:
- *  Notes:
- *  References:
- */
-#include "parrot/parrot.h"
-#include "parrot/hash.h"
-#include "parrot/oplib/ops.h"
-#include "nci.str"
-
-/* HEADERIZER HFILE: none */
-/* HEADERIZER STOP */
-
-/*
- * if the architecture can build some or all of these signatures
- * enable the define below
- * - the JITed function will be called first
- * - if it returns NULL, the hardcoded version will do the job
- */
-
-#if defined(HAS_JIT) && defined(I386)
-#  include "parrot/exec.h"
-#  include "jit.h"
-/*#  define CAN_BUILD_CALL_FRAMES*/
-#endif
-
-/*
- * helper funcs - get argument n
- */
-static INTVAL
-get_nci_I(PARROT_INTERP, ARGMOD(call_state *st), int n)
-{
-    if (n >= st->src.n)
-        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-            "too few arguments passed to NCI function");
-
-    Parrot_fetch_arg_nci(interp, st);
-
-    return UVal_int(st->val);
-}
-
-static FLOATVAL
-get_nci_N(PARROT_INTERP, ARGMOD(call_state *st), int n)
-{
-    if (n >= st->src.n)
-        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-            "too few arguments passed to NCI function");
-
-    Parrot_fetch_arg_nci(interp, st);
-
-    return UVal_num(st->val);
-}
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CANNOT_RETURN_NULL
-static STRING*
-get_nci_S(PARROT_INTERP, ARGMOD(call_state *st), int n)
-{
-    /* TODO or act like below? */
-    if (n >= st->src.n)
-        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-            "too few arguments passed to NCI function");
-
-    Parrot_fetch_arg_nci(interp, st);
-
-    return UVal_str(st->val);
-}
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CANNOT_RETURN_NULL
-static PMC*
-get_nci_P(PARROT_INTERP, ARGMOD(call_state *st), int n)
-{
-    /*
-     * exessive args are passed as NULL
-     * used by e.g. MMD infix like __add
-     */
-    if (n < st->src.n)
-        Parrot_fetch_arg_nci(interp, st);
-    else
-        UVal_pmc(st->val) = PMCNULL;
-
-    return UVal_pmc(st->val);
-}
-
-#define GET_NCI_I(n) get_nci_I(interp, &st, n)
-#define GET_NCI_S(n) get_nci_S(interp, &st, n)
-#define GET_NCI_N(n) get_nci_N(interp, &st, n)
-#define GET_NCI_P(n) get_nci_P(interp, &st, n)
-
-/*
- * set return value
- */
-static void
-set_nci_I(PARROT_INTERP, ARGOUT(call_state *st), INTVAL val)
-{
-    Parrot_init_ret_nci(interp, st, "I");
-    if (st->dest.i < st->dest.n) {
-        UVal_int(st->val) = val;
-        Parrot_convert_arg(interp, st);
-        Parrot_store_arg(interp, st);
-    }
-}
-
-static void
-set_nci_N(PARROT_INTERP, ARGOUT(call_state *st), FLOATVAL val)
-{
-    Parrot_init_ret_nci(interp, st, "N");
-    if (st->dest.i < st->dest.n) {
-        UVal_num(st->val) = val;
-        Parrot_convert_arg(interp, st);
-        Parrot_store_arg(interp, st);
-    }
-}
-
-static void
-set_nci_S(PARROT_INTERP, ARGOUT(call_state *st), STRING *val)
-{
-    Parrot_init_ret_nci(interp, st, "S");
-    if (st->dest.i < st->dest.n) {
-        UVal_str(st->val) = val;
-        Parrot_convert_arg(interp, st);
-        Parrot_store_arg(interp, st);
-    }
-}
-
-static void
-set_nci_P(PARROT_INTERP, ARGOUT(call_state *st), PMC* val)
-{
-    Parrot_init_ret_nci(interp, st, "P");
-    if (st->dest.i < st->dest.n) {
-        UVal_pmc(st->val) = val;
-        Parrot_convert_arg(interp, st);
-        Parrot_store_arg(interp, st);
-    }
-}
-
-/* All our static functions that call in various ways. Yes, terribly
-   hackish, but that is just fine */
-
-HEAD
-    return;
-}
-
-sub make_arg {
-
-    #
-    # we have to fetch all to temps, so that the call code
-    # can operate in sequence
-    #
-    my ( $argtype, $reg_num, $temp_cnt_ref, $temps_ref, $extra_preamble_ref, $extra_postamble_ref )
-        = @_;
-
-    local $_ = $argtype;
-    my $temp_num = ${$temp_cnt_ref}++;
-    /p/ && do {
-        push @{$temps_ref},          "PMC *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "PMC_data(t_$temp_num)";
-    };
-    /V/ && do {
-        push @{$temps_ref},          "PMC *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "(void**)&PMC_data(t_$temp_num)";
-    };
-    /i/ && do {
-        push @{$temps_ref},          "int t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (int)GET_NCI_I($reg_num);";
-        return "t_$temp_num";
-    };
-    /3/ && do {
-        push @{$temps_ref},          "PMC *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "(int*)&PMC_int_val(t_$temp_num)";
-    };
-    /l/ && do {
-        push @{$temps_ref},          "long t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (long)GET_NCI_I($reg_num);";
-        return "t_$temp_num";
-    };
-    /I/ && do {
-        push @{$temps_ref},          "INTVAL t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_I($reg_num);";
-        return "t_$temp_num";
-    };
-    /4/ && do {
-        push @{$temps_ref},          "PMC *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "(long*)&PMC_int_val(t_$temp_num)";
-    };
-    /s/ && do {
-        push @{$temps_ref},          "short t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (short)GET_NCI_I($reg_num);";
-        return "t_$temp_num";
-    };
-    /c/ && do {
-        push @{$temps_ref},          "char t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (char)GET_NCI_I($reg_num);";
-        return "t_$temp_num";
-    };
-    /2/ && do {
-        push @{$temps_ref},          "PMC* t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "(short*)&PMC_int_val(t_$temp_num)";
-    };
-    /f/ && do {
-        push @{$temps_ref},          "float t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (float)GET_NCI_N($reg_num);";
-        return "t_$temp_num";
-    };
-    /d/ && do {
-        push @{$temps_ref},          "double t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = (double)GET_NCI_N($reg_num);";
-        return "t_$temp_num";
-    };
-    /N/ && do {
-        push @{$temps_ref},          "FLOATVAL t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_N($reg_num);";
-        return "t_$temp_num";
-    };
-    /t/ && do {
-        push @{$temps_ref}, "char *t_$temp_num;";
-        push @{$extra_preamble_ref},
-            "t_$temp_num = string_to_cstring(interp, GET_NCI_S($reg_num));";
-        push @{$extra_postamble_ref}, "string_cstring_free(t_$temp_num);";
-        return "t_$temp_num";
-    };
-    /b/ && do {
-        push @{$temps_ref},          "STRING *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
-        return "PObj_bufstart(t_$temp_num)";
-    };
-    /B/ && do {
-        push @{$temps_ref},          "STRING *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
-        return "&PObj_bufstart(t_$temp_num)";
-    };
-    /J/ && do {
-        return "interp";
-    };
-    /[OP\@]/ && do {
-        push @{$temps_ref},          "PMC *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_P($reg_num);";
-        return "PMC_IS_NULL(t_$temp_num) ? NULL : t_$temp_num";
-    };
-    /S/ && do {
-        push @{$temps_ref},          "STRING *t_$temp_num;";
-        push @{$extra_preamble_ref}, "t_$temp_num = GET_NCI_S($reg_num);";
-        return "t_$temp_num";
-    };
-    return;
-}
-
-sub print_function {
-    my (
-        $sig,          $return,        $params,             $args,
-        $ret_type,     $ret_type_decl, $return_assign,      $other_decl,
-        $final_assign, $temps_ref,     $extra_preamble_ref, $extra_postamble_ref,
-        $put_pointer_ref, $proto_type_ref
-    ) = @_;
-
-    $other_decl ||= "";
-
-    $other_decl .= join( "\n    ", @{$temps_ref} );
-    my $call_state      = 'call_state st;';
-    my $extra_preamble  = join( "\n    ", @{$extra_preamble_ref} );
-    my $extra_postamble = join( "\n    ", @{$extra_postamble_ref} );
-    my $return_data =
-        "$return_assign $final_assign" =~ /return_data/
-        ? qq{$ret_type_decl return_data;}
-        : q{};
-    my $fix_params = join '', map { $fix_name{$_} || $_ } split m//, $params;
-
-    if ( length $params ) {
-        my $proto = join ', ', map { $proto_type_ref->{$_} } split( m//, $params );
-
-        # This is an after-the-fact hack: real fix would be in make_arg
-        # or somewhere at that level.  The main point being that one cannot
-        # just cast pointers and expect things to magically align.  Instead
-        # of trying to: (int*)&something_not_int, one HAS to use temporary
-        # variables.  We detect and collect those to "temp".
-        my @temp;
-        for my $i ( 0 .. $#$args ) {
-            if ( $args->[$i] =~ /^\((.+)\*\)&(.+)$/ ) {
-                $temp[$i] = [ $1, $2 ];
-                $args->[$i] = "&arg$i";
-            }
-        }
-        my $call_params = join( ",", @$args );
-        my @tempi = grep { defined $temp[$_] } 0 .. $#$args;
-        my $temp_decl = join( "\n    ", map { "$temp[$_]->[0] arg$_;" } @tempi );
-        ## shorts need to be properly cast
-        my $temp_in = join( "\n    ",
-            map { "arg$_ = " . ( 'short' eq $temp[$_]->[0] ? '(short)' : '' ) . "$temp[$_]->[1];" }
-                @tempi );
-        my $temp_out = join( "\n    ", map { "$temp[$_]->[1] = arg$_;" } @tempi );
-
-        print $NCI <<"HEADER";
-static void
-pcf_${return}_$fix_params(PARROT_INTERP, PMC *self)
-{
-    typedef $ret_type (*func_t)($proto);
-    func_t pointer;
-    $call_state
-    $return_data
-    $temp_decl
-    $other_decl
-    Parrot_init_arg_nci(interp, &st, \"$sig\");
-    $extra_preamble
-
-    pointer =  (func_t)D2FPTR(PMC_struct_val(self));
-    $temp_in
-    $return_assign ($ret_type)(*pointer)($call_params);
-    $temp_out
-    $final_assign
-    $extra_postamble
-}
-HEADER
-    }
-    else {
-
-        # Things are more simple, when there are no params
-        # call state var not needed if there are no params and a void return
-        $call_state = '' if 'v' eq $return;
-        print $NCI <<"HEADER";
-static void
-pcf_${return}_(PARROT_INTERP, PMC *self)
-{
-    $ret_type (*pointer)(void);
-    $return_data
-    $other_decl
-    $call_state
-    $extra_preamble
-
-    pointer =  ($ret_type (*)(void))D2FPTR(PMC_struct_val(self));
-    $return_assign ($ret_type)(*pointer)();
-    $final_assign
-    $extra_postamble
-}
-HEADER
-    }
-
-    my ( $key, $value ) = (
-        defined $params
-        ? ( "$return$params", "pcf_${return}_$fix_params" )
-        : ( "$return", "pcf_${return}" )
-    );
-
-    push @{$put_pointer_ref}, <<"PUT_POINTER";
-        temp_pmc = pmc_new(interp, enum_class_UnManagedStruct);
-        PMC_data(temp_pmc) = (void *)$value;
-        VTABLE_set_pmc_keyed_str(interp, HashPointer, CONST_STRING(interp, "$key"), temp_pmc);
-PUT_POINTER
-
-    #        qq|        parrot_hash_put( interp, known_frames, const_cast("$key"), $value );|;
-    return;
-}
-
-sub print_tail {
-    my ($put_pointer_ref) = @_;
-
-    my $put_pointer = join( "\n", @{$put_pointer_ref} );
-    print $NCI <<"TAIL";
-
-
-/* This function serves a single purpose. It takes the function
-   signature for a C function we want to call and returns a pointer
-   to a function that can call it. */
-void *
-build_call_func(PARROT_INTERP, SHIM(PMC *pmc_nci), NOTNULL(STRING *signature))
-{
-    char       *c;
-    STRING     *ns, *message;
-    PMC        *b;
-    PMC        *iglobals;
-    PMC        *temp_pmc;
-    UINTVAL    signature_len;
-
-    PMC        *HashPointer   = NULL;
-
-#if defined(CAN_BUILD_CALL_FRAMES)
-    /* Try if JIT code can build that signature. If yes, we are done */
-    void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature);
-    if (result)
-        return result;
-#endif
-    /* And in here is the platform-independent way. Which is to say
-       "here there be hacks" */
-    signature_len = string_length(interp, signature);
-    if (0 == signature_len)
-       return F2DPTR(pcf_v_);
-    /* remove deprecated void argument 'v' character */
-    if (2 == signature_len && 'v' == string_index(interp, signature, 1)) {
-       Parrot_warn(interp, PARROT_WARNINGS_ALL_FLAG, "function signature argument character 'v' ignored");
-       string_chopn_inplace(interp, signature, 1);
-       signature_len = string_length(interp, signature);
-    }
-
-    iglobals = interp->iglobals;
-
-    if (PMC_IS_NULL(iglobals))
-        PANIC(interp, "iglobals isn't created yet");
-    HashPointer = VTABLE_get_pmc_keyed_int(interp, iglobals,
-            IGLOBALS_NCI_FUNCS);
-
-    if (!HashPointer) {
-        HashPointer = pmc_new(interp, enum_class_Hash);
-        VTABLE_set_pmc_keyed_int(interp, iglobals, IGLOBALS_NCI_FUNCS,
-                HashPointer);
-
-$put_pointer
-
-    }
-
-    b = VTABLE_get_pmc_keyed_str(interp, HashPointer, signature);
-
-    if (b && b->vtable->base_type == enum_class_UnManagedStruct)
-        return F2DPTR(PMC_data(b));
-
-    /*
-      These three lines have been added to aid debugging. I want to be able to
-      see which signature has an unknown type. I am sure someone can come up
-      with a neater way to do this.
-     */
-    ns = string_make(interp, " is an unknown signature type", 29, "ascii", 0);
-    message = string_concat(interp, signature, ns, 0);
-
-#if defined(CAN_BUILD_CALL_FRAMES)
-    ns = string_make(interp, ".\\nCAN_BUILD_CALL_FRAMES is enabled, this should not happen", 58, "ascii", 0);
-#else
-    ns = string_make(interp, ".\\nCAN_BUILD_CALL_FRAMES is disabled, add the signature to src/call_list.txt", 75, "ascii", 0);
-#endif
-    message = string_concat(interp, message, ns, 0);
-
-    /*
-     * I think there may be memory issues with this but if we get to here we are
-     * aborting.
-     */
-    c = string_to_cstring(interp, message);
-    PANIC(interp, c);
-}
-
-TAIL
-    return;
-}
-
-=begin example
-
-This is the template thing
-
-static void pcf_$funcname(PARROT_INTERP, PMC *self) {
-    $ret_type (*pointer)();
-    $ret_type return_data;
-
-    pointer = PMC_struct_val(self);
-    return_data = ($ret_type)(*pointer)($params);
-    $ret_reg  = return_data;
-    REG_INT(interp, 0) = $stack_returns;
-    REG_INT(interp, 1) = $int_returns;
-    REG_INT(interp, 2) = $string_returns;
-    REG_INT(interp, 3) = $pmc_returns;
-    REG_INT(interp, 4) = $num_returns;
-    return;
-}
-
-=cut
+NCIUtils::main();
 
 # Local Variables:
 #   mode: cperl
