[Firebug-cvs] fireboard/beta/tools/src/xlisten genc.pm,NONE,1.1
Brought to you by:
doolin
From: David M. D. <do...@us...> - 2005-06-28 20:04:40
|
Update of /cvsroot/firebug/fireboard/beta/tools/src/xlisten In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29067 Added Files: genc.pm Log Message: Added perl module for autogenning c code from tos structs. --- NEW FILE: genc.pm --- # This file is part of the nesC compiler. # Copyright (C) 2002 Intel Corporation # # The attached "nesC" software is provided to you under the terms and # conditions of the GNU General Public License Version 2 as published by the # Free Software Foundation. # # nesC is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with nesC; see the file COPYING. If not, write to # the Free Software Foundation, 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. ## TODO for autogenerating C code. ## ---------------------------------------------------------- ## Several things need to be done to make this viable for the ## kinds of messages we want to process. The first part is ## to get rid of the java type conversions, and preserve the ## structure as defined the tinyos header file. We can do this ## because nesc native types are identical to c native types. ## ## Parts of this code were written for the NSF_ITR funded ## firebug project. true; sub gen() { my ($classname, @spec) = @_; require migdecode; &decode(@spec); &usage("no classname name specified") if !defined($java_classname); $java_extends = "net.tinyos.message.Message" if !defined($java_extends); # See if name has a package specifier if ($java_classname =~ /(.*)\.([^.]*)$/) { $package = $1; $java_classname = $2; } $I = " "; $smallskip = "\n\n"; $medskip = "\n\n\n\n"; $bigskip = "\n\n\n\n\n\n"; print "/**\n"; print " * This class is automatically generated by mig. DO NOT EDIT THIS FILE.\n"; print " * This code implements C interface to the '$java_classname'\n"; print " * message type.\n"; print " */\n\n"; print "#include <stdio.h>\n"; print "#include <stdlib.h>\n"; print "#include <memory.h>\n"; print $medskip; print "/** Private header is programmer specified for handling\n"; print " * conversion functions, etc.\n */\n"; print "//#include \"$java_classname\_private.h\"\n"; print $medskip; print "/** These need to be moved to a header file. */\n"; print "typedef struct _$java_classname $java_classname;\n"; print "typedef struct _XbowSensorboardPacket XbowSensorboardPacket;\n"; print $smallskip; print "// This struct is defined to keep gcc happy while the module\n"; print "// is under development. At some point in the near future, a\n"; print "// a convention for passing arguments into the functions will\n"; print "// have to be defined.\n"; print "struct _XbowSensorboardPacket {\n"; print " unsigned char data[29];\n"; print "};\n"; print $medskip; # print "struct _$java_classname {\n"; # for (@fields) { # ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_}; # ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0); # if ($field =~ /(.*)\.([^.]*)$/) { # $struct = $1; # $member = $2; # } # push(@format, &formatstring($type, $bitlength, 0)); # $field =~ s/\./_/g; # printf "$I$ctype $field;\n"; # } # print "};"; &gen_struct(); print $medskip; &gen_get_set(); print $medskip; ## Default behavior is to return the input as output. ## User is responsible for "cooking" the data. for (@fields) { ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_}; ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0); $field =~ s/\./_/g; print "/** \@brief Default behavior is to return the input as output.\n"; print " * User is responsible for \"cooking\" the data.\n */\n"; print "static $ctype\n"; print "$field\_convert($ctype $field) {\n"; print " return $field;\n"; print "}\n\n"; } ## Function for cooking whole packet. Fields are ## by calling the individual "cook" functions for ## each member. print "void\n"; print "$java_classname\_cook\_packet($java_classname * userdata) {\n"; for (@fields) { ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_}; ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0); $field =~ s/\./_/g; print " userdata->$field = $field\_convert(userdata->$field);\n"; } print "}\n\n"; print $medskip; print "//Format string can be generated automatically,\n"; print "//then the delimiters added later: @format\n"; print $medskip; ## In the code for the xlisten boards, the conversions are ## in the print statement. If the conversions were done ## before the print statement, then the conversion function ## becomes the only function needing to be stubbed. The ## runtime differences are neglible. print "/** User has to fill in any conversion code\n"; print " * necessary for processing.\n"; print " */\n"; print "$java_classname * convert(char * data) {\n"; print " // Just to keep gcc happy.\n"; print " return ($java_classname*)data;\n"; print "}\n"; print $medskip; ## Start printing output functions. print "/** Print the bytes of the packet. */\n"; print "void $java_classname\_print\_raw (XbowSensorboardPacket *packet) {\n\n"; print "$I$java_classname * userdata = ($java_classname*)packet->data;\n"; print "}\n\n"; print "/** Print typed output. */\n"; print "void $java_classname\_print\_cooked (XbowSensorboardPacket *packet) {\n\n"; print "$I$java_classname * userdata = ($java_classname*)packet->data;\n"; print "}\n\n"; print "/** Print cooked with tabs. */\n"; print "void $java_classname\_print\_tabbed (XbowSensorboardPacket *packet) {\n\n"; print "$I$java_classname * userdata = ($java_classname*)packet->data;\n"; print "}\n\n"; # print "package $package;\n\n" if $package; # print "public class $java_classname extends $java_extends {\n\n"; print "/** The default size of this message type in bytes. */\n"; print "static int DEFAULT_MESSAGE_SIZE = $size;\n\n"; print "/** The Active Message type associated with this message. */\n"; print "static int AM_TYPE = $amtype;\n\n"; print "/** If incomplete types are used, we need to provide a way\n"; print " * to manage memory.\n"; print " */\n"; print "$java_classname *\n"; print "$java_classname\_new() {\n"; print " $java_classname * userdata = ($java_classname*)malloc(sizeof($java_classname));\n"; print " memset((void*)userdata,0xda,sizeof($java_classname));\n"; print " return userdata;\n"; print "}\n"; print $medskip; print "void\n"; print "$java_classname\_delete($java_classname * userdata) {\n"; print " memset((void*)userdata,0xdd,sizeof($java_classname));\n"; print " free(userdata);\n"; print "}\n"; } sub gen_struct() { print "struct _$java_classname {\n"; ## todo move this to sub print_msg_struct(). for (@fields) { ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_}; ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0); # This is clunky but will work. A better way to do it would be to store # the nested struct internally in the field array somehow. # Maybe a perl guru can figure that out. # What needs to be done is to find one of these, then # store it until all the members written out, # then print it. if ($field =~ /(.*)\.([^.]*)$/) { $struct = $1; $member = $2; #print STDERR $struct;#.", "$member."\n"; } ## Gets an array of format specifiers useful in *print* functions ## in libc. the @format array can be passed push(@format, &formatstring($type, $bitlength, 0)); $field =~ s/\./_/g; printf "$I$ctype $field;\n"; } print "};"; } sub gen_get_set() { ## The get/set code is more to investigate the mechanics of ## the autogeneration of structs. It's probably more useful ## use the defined type directly, at least for now. ## ## todo move this to sub_get_set_methods() for (@fields) { ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_}; ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0); $field =~ s/\./_/g; print "void\n"; print "$java_classname\_set\_$field($java_classname * userdata, $ctype $field) {\n"; print " userdata->$field = $field;\n"; print "}\n\n"; #### Get methods print "$ctype\n"; print "$java_classname\_get\_$field($java_classname * userdata) {\n"; print " return userdata->$field;\n"; print "}\n\n"; } } ## TODO Change all these back to the base types available in c, which are ## the same as in nesc. Probably need to add a "bitfield" handler to ## do it right. sub cbasetype() { my ($basetype, $bitlength, $arraydims) = @_; my $jtype, $acc; # Pick the java type whose range is closest to the corresponding C type if ($basetype eq "U") { $acc = "UIntElement"; if ($bitlength < 8) { $jtype = "unsigned char"; } elsif ($bitlength < 16) { $jtype = "uint8_t"; } elsif ($bitlength < 32) { $jtype = "uint16_t"; } else { $jtype = "uint32_t"; } } elsif ($basetype eq "I") { $acc = "SIntElement"; if ($bitlength <= 8) { $jtype = "char"; } elsif ($bitlength <= 16) { $jtype = "short"; } elsif ($bitlength <= 32) { $jtype = "int"; } else { $jtype = "long"; } } elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") { $acc = "FloatElement"; $jtype = "float"; } if ($arraydims > 0) { # For array types $arrayspec = ""; for ($i = 0; $i < $arraydims; $i++) { $arrayspec = "[]" . $arrayspec; } } return ($jtype, $acc, $arrayspec); } ## TODO Get rid of all the superfluous code, ## or move the functionality into cbasetype. sub formatstring() { my ($basetype, $bitlength, $arraydims) = @_; my $jtype, $acc, $formatstring; # Pick the java type whose range is closest to the corresponding C type if ($basetype eq "U") { $acc = "UIntElement"; if ($bitlength < 8) { $jtype = "byte"; $formatstring = "c";} elsif ($bitlength < 16) { $jtype = "short"; $formatstring = "i";} elsif ($bitlength < 32) { $jtype = "int"; $formatstring = "i";} else { $jtype = "long"; $formatstring = "%i"} } elsif ($basetype eq "I") { $acc = "SIntElement"; if ($bitlength <= 8) { $jtype = "byte"; $formatstring = "c";} elsif ($bitlength <= 16) { $jtype = "short"; $formatstring = "i";} elsif ($bitlength <= 32) { $jtype = "int"; $formatstring = "i";} else { $jtype = "long"; } } elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") { $acc = "FloatElement"; $jtype = "float"; $formatstring = "f"; } if ($arraydims > 0) { # For array types $arrayspec = ""; for ($i = 0; $i < $arraydims; $i++) { $arrayspec = "[]" . $arrayspec; } } #return ($jtype, $acc, $arrayspec, $formatstring); return ($formatstring); } sub printoffset() { my ($offset, $max, $bitsize, $aoffset, $inbits) = @_; print " int offset = $offset;\n"; for ($i = 1; $i <= @$max; $i++) { # check index bounds. 0-sized arrays don't get an upper-bound check # (they represent variable size arrays. Normally they should only # occur as the first-dimension of the last element of the structure) if ($$max[$i - 1] != 0) { print " if (index$i < 0 || index$i >= $$max[$i - 1]) throw new ArrayIndexOutOfBoundsException();\n"; } else { print " if (index$i < 0) throw new ArrayIndexOutOfBoundsException();\n"; } print " offset += $$aoffset[$i - 1] + index$i * $$bitsize[$i - 1];\n"; } if ($inbits) { print " return offset;\n"; } else { print " return (offset / 8);\n"; } } sub printarrayget() { my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_; # Check whether array has known size for ($i = 0; $i < @$amax; $i++) { if ($$amax[$i] == 0) { print " throw new IllegalArgumentException(\"Cannot get field as array - unknown size\");\n"; return; } } print " $javatype$arrayspec tmp = new $javatype"; for ($i = 0; $i < @$amax; $i++) { print "[$$amax[$i]]"; } print ";\n"; $indent = " "; for ($i = 0; $i < @$amax; $i++) { print " $indent for (int index$i = 0; index$i < numElements_$javafield($i); index$i++) {\n"; $indent = $indent . " "; } $indent = $indent . " "; print " $indent tmp"; for ($i = 0; $i < @$amax; $i++) { print "[index$i]"; } print " = getElement_$javafield("; for ($i = 0; $i < @$amax; $i++) { print "index$i"; if ($i != @$amax-1) { print ","; } } print ");\n"; $indent = substr($indent, 0, length($indent)-2); for ($i = 0; $i < @$amax; $i++) { $indent = substr($indent, 0, length($indent)-2); print " $indent }\n"; } print " return tmp;\n"; } sub printarrayset() { my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_; $indent = " "; $val = ""; for ($i = 0; $i < @$amax; $i++) { print " $indent for (int index$i = 0; index$i < value$val.length; index$i++) {\n"; $val = $val . "[index$i]"; $indent = $indent . " "; } $indent = $indent . " "; print " $indent setElement_$javafield("; for ($i = 0; $i < @$amax; $i++) { print "index$i"; if ($i != @$amax-1) { print ","; } } print ", value"; for ($i = 0; $i < @$amax; $i++) { print "[index$i]"; } print ");\n"; $indent = substr($indent, 0, length($indent)-2); for ($i = 0; $i < @$amax; $i++) { $indent = substr($indent, 0, length($indent)-2); print " $indent }\n"; } } |