Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl -w
- ##### !!!! Copyright !!!! #####
- # if you see this code #
- # you must kill yourself. #
- ###############################
- ### ## ## ### # # # #### ## #
- ## Example of input file syntax
- # sourceinclude <malloc.h>
- # class MegaClass
- # unsigned int lolol
- # float vah = 1.4f, duh = ( 3+ 5), * doh, deh
- # char *name = "hehehe", noname = 'k'
- # float *** testptr
- #
- # float method( int a, float b, char* c)
- # int multimethod( float a), mmethod( int g )
- #
- # void * retutn()
- # {
- # #this is comment?
- # // this is commmnet
- # return NULL;
- # }
- #
- #
- # class llass
- # int lolol
- package KlassGen;
- use strict;
- use warnings;
- use Encode;
- binmode STDOUT, ":utf8";
- binmode STDIN, ":utf8";
- binmode STDERR, ":utf8";
- if ( $#ARGV + 1 < 1 ) { die "you must specify the name of file as argument\n"; }
- my $filename = $ARGV[0];
- unless ( (-e "$filename") and (-r "$filename") and (not -d "$filename") and (-f "$filename") )
- {
- die "you must specify the name of file as argument\n";
- }
- open( SOURCEF, "<:utf8", $filename ) or die "Can't open file $filename: $!\n";
- # {
- # my( $curpos, $chi );
- # while ( read SOURCEF, my $char, 1 )
- # {
- # $curpos = tell( SOURCEF );
- # $chi = ord( $char );
- # print "$curpos $chi $char\n";
- # }
- # seek( SOURCEF, -7, 1 );
- # while ( read SOURCEF, my $char, 1 )
- # {
- # $curpos = tell( SOURCEF );
- # print "$curpos $char\n";
- # }
- # }
- {
- my $outfname = $filename;
- $outfname =~ s/\..*//;
- my %classes = ();
- my @sourceincludes = ( '"' . $outfname . '.h' . '"',);
- my @headerincludes = ();
- my $curclass = 0;
- my $curmember = 0;
- my $curmethod = 0;
- my $method_body = '';
- my %defvals = ('char' => '0', 'int' => '0', 'float' => '0.0f', 'double' => '0.0',
- 'void' => '', );
- my @premods = ( 'unsigned', 'long' );
- my $indent = ' ';
- my $deftype = 'int';
- my $parsemode = 'file';
- sub trim {
- my($string)=@_;
- for ($string)
- {
- s/^\s+//;
- s/\s+$//;
- }
- return $string;
- }
- sub escapebad {
- my ($string) = @_;
- $string =~ s/([\\\/\^\.\$\*\+\?\@\{\}\[\]\(\)\<\>])/\\$&/g;
- #bad chars turned good
- return ($string);
- }
- sub add_class_byname {
- my ($classname) = @_;
- $curclass = $classes{ $classname } = {
- 'name' => $classname,
- 'members' => [],
- 'methods' => [],
- };
- }
- sub parse_methods {
- my ($methodstring) = @_;
- my @moutput = ();
- my @methods = split( '\s*;\s*' , $methodstring );
- foreach my $method (@methods)
- {
- $method = trim($method);
- my ($methoddef,$params) = split( '\s*\(\s*', $method );
- $params =~ s/\s*\)\s*//;
- $params = trim( $params );
- my @methoda = parse_members( $methoddef );
- my @paramsa = parse_members( $params );
- $methoda[0]->{'params'} = \@paramsa;
- $curmethod = $methoda[0];
- push( @moutput, $methoda[0] );
- }
- return @moutput;
- }
- sub parse_members {
- my ($memberstring) = @_;
- my @members = split( '\s*,\s*' , $memberstring );
- my @moutput = ();
- foreach my $member (@members)
- {
- $member = trim($member);
- my $memberdef = '';
- my $initval = '';
- my $membertype = '';
- my $ptr = '';
- my $membername = '';
- if ( $member =~ m/=/ )
- {
- ($memberdef, $initval) = split('\s*=\s*', $member);
- $initval = trim($initval);
- $memberdef = trim($memberdef);
- }
- else
- {
- $memberdef = $member;
- }
- ($ptr) = $memberdef =~ m/(\*+)/;
- if ( $ptr )
- {
- my $ptrescaped = escapebad($ptr);
- $memberdef =~ s/\s*$ptrescaped\s*/ /;
- $memberdef = trim($memberdef);
- }
- my @memberparts = split( '\s+', $memberdef );
- if ( $#memberparts +1 < 1 )
- {
- die "WTF???: " . $memberstring;
- }
- elsif ( $#memberparts + 1 < 2 )
- {
- $membertype = $deftype;
- }
- elsif ( $#memberparts + 1 >= 2 )
- {
- for( my $i = 0, my $spc=''; $i < $#memberparts; $i++, $spc=' ' )
- {
- $membertype .= $spc . $memberparts[$i];
- }
- $deftype = $membertype;
- }
- else
- {
- die "WTF???: " . $memberstring;
- }
- if ( $ptr )
- {
- $membertype = $membertype . " " . $ptr;
- $initval = 'NULL';
- }
- $membername = $memberparts[$#memberparts];
- if ( !$initval )
- {
- if (exists $defvals{$membertype} )
- {
- $initval = $defvals{$membertype};
- }
- else
- {
- for my $k (keys(%defvals))
- {
- if( $membertype =~ m/\b$k$/ )
- {
- $initval = $defvals{$k};
- }
- }
- }
- }
- $curmember = {
- 'name' => $membername,
- 'type' => $membertype,
- 'initval' => $initval,
- };
- push( @moutput, $curmember );
- }
- return @moutput;
- }
- sub flush_method_body {
- $curmethod->{'body'} = $method_body;
- $method_body = '';
- }
- sub parse_includes {
- my $type = shift;
- for my $inc (@_)
- {
- if ( $type eq 'sourceinclude' )
- {
- push(@sourceincludes, $inc);
- }
- elsif ( $type eq 'headerinclude' )
- {
- push(@headerincludes, $inc);
- }
- }
- }
- while ( my $line = <SOURCEF> )
- {
- # my $rawline = $line;
- $line = trim($line);
- if(!$line){ next; }
- if(index($line, '#') == 0){ next; }
- elsif($line eq ';'){ $parsemode = 'file'; next; }
- elsif($line eq '{'){ $parsemode = 'methodbody'; next; }
- elsif($line eq '}'){ flush_method_body(); $parsemode = 'class'; next; }
- elsif($line =~ '^class'){ $parsemode = 'file'; }
- if ( $parsemode eq 'file' )
- {
- my @parts = split( '\s+', $line );
- if ( $parts[0] eq 'class' )
- {
- $parsemode = 'class';
- add_class_byname( $parts[1] );
- }
- elsif ( $parts[0] =~ m/include/ )
- {
- parse_includes(@parts);
- }
- else
- {
- die 'here must go a defenition of class \'eg. class classname\''
- }
- }
- elsif ( $parsemode eq 'class' )
- {
- if( ( $line =~ m/\(/ ) and ( $line !~ m/=/ ) )
- {
- $line =~ s/\)\s*,\s*/\);/;
- my @new_methods = parse_methods($line);
- push(@{$curclass->{'methods'}}, @new_methods);
- }
- else
- {
- my @new_members = parse_members($line);
- push(@{$curclass->{'members'}}, @new_members);
- }
- }
- elsif ( $parsemode eq 'methodbody' )
- {
- $method_body .= $line . "\n";
- }
- }
- sub add_gettersetters
- {
- for my $classname (keys(%classes))
- {
- for my $member (@{$classes{$classname}{'members'}})
- {
- my $methodstr = ${$member}{'type'} . ' ' . 'get' . ${$member}{'name'} . '()' ;
- my @gsetter = parse_methods($methodstr);
- $gsetter[0]{'body'} = 'return self->' . ${$member}{'name'} . ';';
- push(@{$classes{$classname}{'methods'}}, @gsetter);
- $methodstr = 'void' . ' ' . 'set' . ${$member}{'name'} . '(' . ${$member}{'type'} . ' ' . ${$member}{'name'} . ')' ;
- @gsetter = parse_methods($methodstr);
- $gsetter[0]{'body'} = 'self->' . ${$member}{'name'} . ' = _' . ${$member}{'name'} . ';';
- push(@{$classes{$classname}{'methods'}}, @gsetter);
- }
- }
- }
- sub gen_member_decl {
- my ($member, $indent) = (@_);
- return $indent . ${$member}{'type'} . " " . ${$member}{'name'};
- }
- sub gen_members_decl {
- my ($classname, $indent) = (@_);
- my $ret = '';
- for my $member (@{$classes{$classname}{'members'}})
- {
- $ret .= gen_member_decl( $member, $indent ) . ";\n";
- }
- return $ret;
- }
- sub gen_member_def {
- my ($member, $indent) = (@_);
- return $indent . ${$member}{'type'} . " " . ${$member}{'name'} .
- " = " . ${$member}{'initval'};
- }
- sub gen_members_def {
- my ($classname, $indent) = (@_);
- my $ret = '';
- for my $member (@{$classes{$classname}{'members'}})
- {
- $ret .= gen_member_def( $member, $indent ) . ";\n";
- }
- return $ret;
- }
- sub gen_params_string {
- my @paramsa = @_;
- my $ret = '';
- my $comma = '';
- for my $param (@paramsa)
- {
- # print $param->{'name'};
- if( $param->{'name'} )
- {
- $ret .= $comma . $param->{'type'} . " _" . $param->{'name'};
- $comma = ', ';
- }
- else
- {
- $ret .= $comma . $param->{'type'};
- }
- }
- return $ret;
- }
- sub gen_method_params_string {
- my ($classname, $params) = @_;
- my @paramsa = @{$params};
- my $ret = $classname . '_t * self';
- for my $param (@paramsa)
- {
- $ret .= ', ' . $param->{'type'} . " _" . $param->{'name'};
- }
- return $ret;
- }
- sub gen_func_decl {
- my($type,$name,$paramstring) = (@_);
- return $type . " " . $name . "( " . $paramstring . " )";
- }
- sub gen_func_def {
- my($type,$name,$paramstring,$body) = (@_);
- my $ret = gen_func_decl($type,$name,$paramstring);
- $ret .= "\n{\n" . $body . "\n}\n";
- return $ret;
- }
- sub gen_std_funcs_decl {
- my ($classname) = (@_);
- my $classtype = $classname . '_t *';
- my $ret = gen_func_decl( 'void *', $classname . '_malloc', 'void' ) . ";\n";
- $ret .= gen_func_decl( $classtype , $classname . '_new', 'void' ) . ";\n";
- $ret .= gen_func_decl( $classtype, $classname . '_Init',
- gen_params_string(@{$classes{$classname}{'members'}} ) ) . ";\n";
- $ret .= gen_func_decl( 'void', $classname . '_Destroy', $classtype . " self" ) . ";\n";
- return $ret;
- }
- sub gen_member_new_def {
- my ($member, $indent) = (@_);
- return $indent . 'self->' . ${$member}{'name'} . " = " . ${$member}{'initval'};
- }
- sub gen_members_new_def {
- my ($classname, $indent) = (@_);
- my $ret = '';
- for my $member (@{$classes{$classname}{'members'}})
- {
- $ret .= gen_member_new_def( $member, $indent ) . ";\n";
- }
- return $ret;
- }
- sub gen_member_init_def {
- my ($member, $indent) = (@_);
- return $indent . 'self->' . ${$member}{'name'} . " = _" . ${$member}{'name'};
- }
- sub gen_members_init_def {
- my ($classname, $indent) = (@_);
- my $ret = '';
- for my $member (@{$classes{$classname}{'members'}})
- {
- $ret .= gen_member_init_def( $member, $indent ) . ";\n";
- }
- return $ret;
- }
- sub gen_std_funcs_def {
- my ($classname, $indent) = (@_);
- my $classt = $classname . '_t';
- my $classtype = $classname . '_t *';
- my $ret = gen_func_def( 'void *', $classname . '_malloc', 'void',
- $indent . "return malloc( sizeof( " . $classt . " ) );" );
- $ret .= gen_func_def( $classtype, $classname . '_new', 'void',
- $indent . $classtype . ' self = '
- . $classname . "_malloc();\n"
- . gen_members_new_def( $classname, $indent )
- . $indent . "return self;" );
- $ret .= gen_func_def( $classtype, $classname . '_Init',
- gen_params_string(@{$classes{$classname}{'members'}}),
- $indent . $classtype . ' self = '
- . $classname . "_malloc();\n"
- . gen_members_init_def( $classname, $indent )
- . $indent . "return self;" );
- $ret .= gen_func_def( 'void', $classname . '_Destroy', $classtype . ' self',
- $indent . '//TODO: fix me. Destructors can\'t be properly autogenerated :-|'
- ."\n".$indent . 'free(self);');
- return $ret;
- }
- sub gen_method_decl {
- my($method, $classname) = (@_);
- my $classtype = $classname . "_t";
- my $ret = gen_func_decl( ${$method}{'type'}, $classname ."_". ${$method}{'name'},
- gen_method_params_string($classname, ${$method}{'params'}) );
- return $ret;
- }
- sub gen_methods_decl {
- my ($classname) = (@_);
- my $ret = '';
- for my $method (@{$classes{$classname}{'methods'}})
- {
- $ret .= gen_method_decl( $method, $classname ) . ";\n";
- }
- return $ret;
- }
- sub gen_method_def {
- my ($methodref, $classname, $indent) = @_;
- my %method = %{$methodref};
- my $ret = gen_method_decl( \%method, $classname ) . "\n{\n";
- if ($method{'body'})
- {
- $method{'body'} =~ s/\n/\n$_[2]/g;
- $method{'body'} =~ s/\s+$//;
- $ret .= $indent . $method{'body'} . "\n}\n";
- }
- else
- {
- $ret .= $indent . "//TODO: I'm autogenerated, so make me do something useful\n";
- $ret .= $indent . "return " . $method{'initval'} . ";\n}\n";
- }
- return $ret;
- }
- sub gen_methods_def {
- my $ret = '';
- for my $method (@{$classes{$_[0]}{'methods'}})
- {
- $ret .= gen_method_def( $method, $_[0], $_[1] );
- }
- return $ret;
- }
- sub gen_class_decl {
- my ($classname) = @_;
- my $ret = 'typedef struct ';
- $ret .= $classname . "_s\n{\n";
- $ret .= gen_members_decl($classname, $indent) . "\n} " . $classname . "_t;\n\n";
- $ret .= gen_std_funcs_decl($classname) . "\n";
- $ret .= gen_methods_decl($classname) . "\n";
- return $ret;
- }
- sub gen_classes_decl {
- my $ret = '';
- my $sep = '';
- for my $classname (keys(%classes))
- {
- $ret .= $sep . gen_class_decl($classname);
- $sep = "\n\n";
- }
- return $ret;
- }
- sub gen_class_def {
- my ($classname) = @_;
- my $ret = gen_std_funcs_def($classname, $indent) . "\n";
- $ret .= gen_methods_def($classname, $indent);
- return $ret;
- }
- sub gen_classes_def {
- my $ret = '';
- my $sep = '';
- for my $classname (keys(%classes))
- {
- $ret .= $sep . gen_class_def($classname);
- $sep = "\n\n";
- }
- return $ret;
- }
- sub gen_includes {
- my $ret = '';
- for my $inc (@_)
- {
- $ret .= '#include ' . $inc . "\n";
- }
- return $ret;
- }
- open( HEADER, ">:utf8", $outfname . '.h' ) or die "Can't open file". $outfname. ".h for writing: $!\n";
- open( SOURCE, ">:utf8", $outfname . '.c' ) or die "Can't open file". $outfname. ".c for writing: $!\n";
- print HEADER '#ifndef ' . uc($outfname) . '_H'."\n"
- .'#define ' . uc($outfname) . '_H'."\n\n";
- print HEADER gen_includes(@headerincludes) . "\n\n";
- print SOURCE gen_includes(@sourceincludes) . "\n\n";
- add_gettersetters();
- print HEADER gen_classes_decl();
- print SOURCE gen_classes_def();
- print HEADER "\n#endif\n";
- close(HEADER);
- close(SOURCE);
- }
- close(SOURCEF);
Advertisement
Add Comment
Please, Sign In to add comment