[Tinyos] genc.pm and genpgsql.pm
doolin at ce.berkeley.edu
doolin at ce.berkeley.edu
Mon Aug 1 13:33:51 PDT 2005
Some perl scripts for using mig to generate c and
postgres code are attached. They are derived from
genjava.pm. Comments welcome.
-dmd
-------------- next part --------------
# 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.
##
## Code based on genjava.pm written by David Gay (?)
## authors David Gay (? + others?), Dave Doolin
true;
sub gen() {
my %struct_hash;
my ($tmp,$fmtstr);
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;
$structname = $java_classname."P";
}
$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 '$structname'\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 \"$structname\_private.h\"\n";
print "/** Not the best way to handle xbow dependencies. */\n";
print "#ifdef TELOS_MOTE\n";
print "#include \"../xdb.h\"\n";
print "#include \"../xsensors.h\"\n";
print "#endif\n";
print $medskip;
print "/** These need to be moved to a header file. */\n";
print "typedef struct _$structname $structname;\n";
print "#ifndef TELOS_MOTE\n";
print "typedef struct _XbowSensorboardPacket XbowSensorboardPacket;\n";
print "#endif\n";
print $medskip
print "/** The Active Message type associated with this message. */\n";
print "//static const int AM_TYPE = $amtype;\n\n";
print "//#define AM_TYPE $amtype\n\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 _$structname {\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 "};";
print $medskip;
&gen_struct();
print $medskip;
&gen_get_set();
print $medskip;
print "//Format string generated automatically,\n";
$tmp = @format[$#format-1];
$tmp =~ s/,//g;
$fmtstr = "@format[0..($#format-1)] $tmp";
#print "Fmt: $fmtstr\n";
print "//static char formatstring[] = \"@format[0..($#format-1)] $tmp\";\n\n\n";
print "//static char formatstring[] = \"$fmtstr\";\n\n\n";
&gen_insert_stmt($fmtstr);
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 "$structname\_cook\_packet($structname * 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;
## 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 "$structname *\n $structname\_convert(char * data) {\n";
print " // Just to keep gcc happy.\n";
print " return ($structname*)data;\n";
print "}\n";
print $medskip;
## Start printing output functions.
&gen_byte_output();
&gen_cooked_output();
#&gen_cooked_with_tabs();
&gen_handler_table();
# print "package $package;\n\n" if $package;
# print "public class $structname 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 "/** If incomplete types are used, we need to provide a way\n";
print " * to manage memory.\n";
print " */\n";
print "$structname *\n";
print "$structname\_new() {\n";
print " $structname * userdata = ($structname*)malloc(sizeof($structname));\n";
print " memset((void*)userdata,0xda,sizeof($structname));\n";
print " return userdata;\n";
print "}\n";
print $medskip;
print "void\n";
print "$structname\_delete($structname * userdata) {\n";
print " memset((void*)userdata,0xdd,sizeof($structname));\n";
print " free(userdata);\n";
print "}\n";
}
sub gen_insert_stmt () {
my($fmtstr1) = $_[0];
my($fmtstr);
my ($tmp,$fmtstr);
$i = 0;
$numfields = $#fields;
print "static char insert_stmt[] = \"INSERT into $structname (\"\n";
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;
if ($i < $numfields) {
printf "\"$field,\"\n";
} else {
printf "\"$field) values (";
}
$i++;
}
$tmp = @format[$#format-1];
$tmp =~ s/,//g;
$fmtstr = "@format[0..($#format-1)] $tmp";
print "$fmtstr)\";\n\n\n";
&gen_struct_array();
print "void\n$structname\_pg\_log(XbowSensorboardPacket * userdata) {\n";
print "char pg_command[255];\n";
print "$structname * data = ($structname*)userdata;\n";
print "sprintf(pg_command,insert_stmt,\n";
# traverse struct here.
$i = 0;
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;
if ($i < $numfields) {
print "data->$field,\n"
} else {
print "data->$field);\n";
}
$i++;
}
print "#ifdef TELOS_MOTE\n";
print "xdb_execute(pg_command);\n";
print "#endif\n";
print "}\n";
}
sub gen_cooked_with_tabs() {
print "/** Print cooked with tabs. */\n";
print "void\n$structname\_print\_tabbed (XbowSensorboardPacket *packet) {\n\n";
print "$I$structname * userdata = ($structname*)packet->data;\n";
print "}\n\n";
}
sub gen_byte_output() {
print "/** Print the bytes of the packet. */\n";
print "void\n$structname\_print\_raw (XbowSensorboardPacket *packet) {\n\n";
# print "$I$structname * userdata = ($structname*)packet->data;\n";
print " printf(\"$structname print raw.\\n\");\n";
print "}\n\n";
}
sub gen_handler_table() {
print "#ifdef TELOS_MOTE\n";
print "XPacketHandler $structname\_packet\_handler = {\n";
print "// This should be replaced with the AM_TYPE\n";
print " $amtype,\n";
print " \"\$Id: \$\",\n";
print " $structname\_print\_raw,\n";
print " $structname\_print\_cooked,\n";
print " $structname\_print\_raw,\n";
print " $structname\_print\_cooked,\n";
print " $structname\_pg\_log,\n";
print " {0}\n";
print "};\n\n\n";
### Add handler table to xlisten.
print "void\n$structname\_initialize() {\n";
print "xpacket_add_type(&$structname\_packet\_handler);\n";
print "}\n";
print "#endif\n";
}
sub gen_cooked_output() {
print "/** Print cooked output. */\n";
print "void\n$structname\_print\_cooked (XbowSensorboardPacket * userdata) {\n\n";
print "$I$structname * data = ($structname*)userdata;\n";
print " printf(\"$structname print cooked:\\n\");\n";
for (@fields) {
($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
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;
print " printf(\"$I$field: ".&formatstring($type, $bitlength, 0)."\\n\",data->$field);\n";
}
print "}\n\n";
}
sub gen_struct() {
print "struct _$structname {\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_struct_array() {
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;
$struct_hash{$field} = $ctype;
}
}
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 "$structname\_set\_$field($structname * userdata, $ctype $field) {\n";
print " userdata->$field = $field;\n";
print "}\n\n";
#### Get methods
print "$ctype\n";
print "$structname\_get\_$field($structname * 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";
}
}
-------------- next part --------------
# 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.
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;
}
print "/**\n";
print " * This class is automatically generated by mig. DO NOT EDIT THIS FILE.\n";
print " * This class implements a Java interface to the '$java_classname'\n";
print " * message type.\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 " public static final int DEFAULT_MESSAGE_SIZE = $size;\n\n";
print " /** The Active Message type associated with this message. */\n";
print " public static final int AM_TYPE = $amtype;\n\n";
print " /** Create a new $java_classname of size $size. */\n";
print " public $java_classname() {\n";
print " super(DEFAULT_MESSAGE_SIZE);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /** Create a new $java_classname of the given data_length. */\n";
print " public $java_classname(int data_length) {\n";
print " super(data_length);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname with the given data_length\n";
print " * and base offset.\n";
print " */\n";
print " public $java_classname(int data_length, int base_offset) {\n";
print " super(data_length, base_offset);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname using the given byte array\n";
print " * as backing store.\n";
print " */\n";
print " public $java_classname(byte[] data) {\n";
print " super(data);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname using the given byte array\n";
print " * as backing store, with the given base offset.\n";
print " */\n";
print " public $java_classname(byte[] data, int base_offset) {\n";
print " super(data, base_offset);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname using the given byte array\n";
print " * as backing store, with the given base offset and data length.\n";
print " */\n";
print " public $java_classname(byte[] data, int base_offset, int data_length) {\n";
print " super(data, base_offset, data_length);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname embedded in the given message\n";
print " * at the given base offset.\n";
print " */\n";
print " public $java_classname(net.tinyos.message.Message msg, int base_offset) {\n";
print " super(msg, base_offset, DEFAULT_MESSAGE_SIZE);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " * Create a new $java_classname embedded in the given message\n";
print " * at the given base offset and length.\n";
print " */\n";
print " public $java_classname(net.tinyos.message.Message msg, int base_offset, int data_length) {\n";
print " super(msg, base_offset, data_length);\n";
print " amTypeSet(AM_TYPE);\n";
print " }\n\n";
print " /**\n";
print " /* Return a String representation of this message. Includes the\n";
print " * message type name and the non-indexed field values.\n";
print " */\n";
print " public String toString() {\n";
print " String s = \"Message <$java_classname> \\n\";\n";
for (@fields) {
($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
print " try {\n";
$javafield = $field;
$javafield =~ s/\./_/g;
if (!@$amax) {
($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, 0);
if ($javatype eq "float") {
print " s += \" [$field=\"+Float.toString(get_$javafield())+\"]\\n\";\n";
} else {
print " s += \" [$field=0x\"+Long.toHexString(get_$javafield())+\"]\\n\";\n";
}
} elsif (@$amax == 1 && $$amax[0] != 0) {
($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, @$amax);
print " s += \" [$field=\";\n";
print " for (int i = 0; i < $$amax[0]; i++) {\n";
if ($javatype eq "float") {
print " s += Float.toString(getElement_$javafield(i))+\" \";\n";
} else {
if ($bitlength > 32) {
print " s += \"0x\"+Long.toHexString(getElement_$javafield(i))+\" \";\n";
}
elsif (bitlength > 16) {
print " s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xffffffff)+\" \";\n";
}
elsif (bitlength > 8) {
print " s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xffff)+\" \";\n";
}
else {
print " s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xff)+\" \";\n";
}
}
print " }\n";
print " s += \"]\\n\";\n";
}
print " } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }\n";
}
print " return s;\n";
print " }\n\n";
print " // Message-type-specific access methods appear below.\n\n";
for (@fields) {
($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
# Determine if array
if (@$amax) {
$isarray = 1;
$arraydims = @$amax;
$arraysize_bits = $$amax[0] * $$abitsize[0];
$index = 0;
@args = map { $index++; "int index$index" } @{$amax};
$argspec = join(", ", @args);
$index = 0;
@passargs = map { $index++; "index$index" } @{$amax};
$passargs = join(", ", @passargs);
} else {
$isarray = 0;
$arraydims = 0;
$arraysize_bits = 0;
$argspec = "";
$passargs = "";
}
# Determine if signed
if ($basetype eq "U") {
$signed = 0; $signedstr = ", unsigned";
} elsif ($basetype eq "I") {
$signed = 1; $signedstr = ", signed";
} elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") {
$signed = 1; $signstr = "";
}
# Get field type and accessor
$javafield = $field;
$javafield =~ s/\./_/g;
($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, $arraydims);
print " /////////////////////////////////////////////////////////\n";
print " // Accessor methods for field: $field\n";
if ($isarray) {
print " // Field type: $javatype$arrayspec$signedstr\n";
print " // Offset (bits): $offset\n";
print " // Size of each element (bits): $bitlength\n";
} else {
print " // Field type: $javatype$signedstr\n";
print " // Offset (bits): $offset\n";
print " // Size (bits): $bitlength\n";
}
print " /////////////////////////////////////////////////////////\n\n";
### isSigned
if ($signed) { $strue = "true"; } else { $strue = "false"; }
print " /**\n";
print " * Return whether the field '$field' is signed ($strue).\n";
print " */\n";
print " public static boolean isSigned_$javafield() {\n";
print " return $strue;\n";
print " }\n\n";
### isArray
if ($isarray) { $atrue = "true"; } else { $atrue = "false"; }
print " /**\n";
print " * Return whether the field '$field' is an array ($atrue).\n";
print " */\n";
print " public static boolean isArray_$javafield() {\n";
print " return $atrue;\n";
print " }\n\n";
### Offset
print " /**\n";
print " * Return the offset (in bytes) of the field '$field'\n";
if ((int($offset) % 8) != 0) {
print " * WARNING: This field is not byte-aligned (bit offset $offset).\n";
}
print " */\n";
print " public static int offset_$javafield($argspec) {\n";
if ($isarray) {
printoffset($base + $offset, $amax, $abitsize, $aoffset, 0);
} else {
print " return ($offset / 8);\n";
}
print " }\n\n";
print " /**\n";
print " * Return the offset (in bits) of the field '$field'\n";
print " */\n";
print " public static int offsetBits_$javafield($argspec) {\n";
if ($isarray) {
printoffset($base + $offset, $amax, $abitsize, $aoffset, 1);
} else {
print " return $offset;\n";
}
print " }\n\n";
if (!$isarray) {
### For non-array fields
### Get
print " /**\n";
print " * Return the value (as a $javatype) of the field '$field'\n";
print " */\n";
print " public $javatype get_$javafield() {\n";
print " return ($javatype)get$java_access(offsetBits_$javafield(), $bitlength);\n";
print " }\n\n";
### Set
print " /**\n";
print " * Set the value of the field '$field'\n";
print " */\n";
print " public void set_$javafield($javatype value) {\n";
print " set$java_access(offsetBits_$javafield(), $bitlength, value);\n";
print " }\n\n";
### Size
print " /**\n";
print " * Return the size, in bytes, of the field '$field'\n";
if ((int($bitlength) % 8) != 0) {
print " * WARNING: This field is not an even-sized number of bytes ($bitlength bits).\n";
}
print " */\n";
print " public static int size_$javafield() {\n";
if ((int($bitlength) % 8) != 0) {
print " return ($bitlength / 8) + 1;\n";
} else {
print " return ($bitlength / 8);\n";
}
print " }\n\n";
print " /**\n";
print " * Return the size, in bits, of the field '$field'\n";
print " */\n";
print " public static int sizeBits_$javafield() {\n";
print " return $bitlength;\n";
print " }\n\n";
} else {
### For array fields
### Get
print " /**\n";
print " * Return the entire array '$field' as a $javatype$arrayspec\n";
print " */\n";
print " public $javatype$arrayspec get_$javafield() {\n";
&printarrayget($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize);
print " }\n\n";
### Set
print " /**\n";
print " * Set the contents of the array '$field' from the given $javatype$arrayspec\n";
print " */\n";
print " public void set_$javafield($javatype$arrayspec value) {\n";
&printarrayset($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize);
print " }\n\n";
### GetElement
print " /**\n";
print " * Return an element (as a $javatype) of the array '$field'\n";
print " */\n";
print " public $javatype getElement_$javafield($argspec) {\n";
print " return ($javatype)get$java_access(offsetBits_$javafield($passargs), $bitlength);\n";
print " }\n\n";
### SetElement
print " /**\n";
print " * Set an element of the array '$field'\n";
print " */\n";
print " public void setElement_$javafield($argspec, $javatype value) {\n";
print " set$java_access(offsetBits_$javafield($passargs), $bitlength, value);\n";
print " }\n\n";
if ($arraysize_bits != 0) {
### Total size (when array size is known)
print " /**\n";
print " * Return the total size, in bytes, of the array '$field'\n";
if ((int($arraysize_bits) % 8) != 0) {
print " * WARNING: This array is not an even-sized number of bytes ($arraysize_bits bits).\n";
}
print " */\n";
print " public static int totalSize_$javafield() {\n";
print " return ($arraysize_bits / 8);\n";
print " }\n\n";
print " /**\n";
print " * Return the total size, in bits, of the array '$field'\n";
print " */\n";
print " public static int totalSizeBits_$javafield() {\n";
print " return $arraysize_bits;\n";
print " }\n\n";
}
### Element size
print " /**\n";
print " * Return the size, in bytes, of each element of the array '$field'\n";
if ((int($bitlength) % 8) != 0) {
print " * WARNING: This field is not an even-sized number of bytes ($bitlength bits).\n";
}
print " */\n";
print " public static int elementSize_$javafield() {\n";
print " return ($bitlength / 8);\n";
print " }\n\n";
print " /**\n";
print " * Return the size, in bits, of each element of the array '$field'\n";
print " */\n";
print " public static int elementSizeBits_$javafield() {\n";
print " return $bitlength;\n";
print " }\n\n";
### Number of dimensions
print " /**\n";
print " * Return the number of dimensions in the array '$field'\n";
print " */\n";
print " public static int numDimensions_$javafield() {\n";
print " return $arraydims;\n";
print " }\n\n";
### Number of elements
if ($arraydims == 1 && $$amax[0] != 0) {
# For 1D arrays where the size of the array is known
print " /**\n";
print " * Return the number of elements in the array '$field'\n";
print " */\n";
print " public static int numElements_$javafield() {\n";
print " return $$amax[0];\n";
print " }\n\n";
}
print " /**\n";
print " * Return the number of elements in the array '$field'\n";
print " * for the given dimension.\n";
print " */\n";
print " public static int numElements_$javafield(int dimension) {\n";
print " int array_dims[] = { ";
foreach $e (@$amax) { print "$e, "; }
print " };\n";
print " if (dimension < 0 || dimension >= $arraydims) throw new ArrayIndexOutOfBoundsException();\n";
print " if (array_dims[dimension] == 0) throw new IllegalArgumentException(\"Array dimension \"+dimension+\" has unknown size\");\n";
print " return array_dims[dimension];\n";
print " }\n\n";
### String conversions (for 1D arrays of 8-bit values)
if ($arraydims == 1 && $bitlength == 8) {
print " /**\n";
print " * Fill in the array '$field' with a String\n";
print " */\n";
print " public void setString_$javafield(String s) { \n";
if ($amax[0] != 0) {
print " int len = Math.min(s.length(), $$amax[0]-1);\n";
} else {
print " int len = s.length();\n";
}
print " int i;\n";
print " for (i = 0; i < len; i++) {\n";
print " setElement_$javafield(i, ($javatype)s.charAt(i));\n";
print " }\n";
print " setElement_$javafield(i, ($javatype)0); //null terminate\n";
print " }\n\n";
print " /**\n";
print " * Read the array '$field' as a String\n";
print " */\n";
print " public String getString_$javafield() { \n";
if ($$amax[0] == 0) {
print " char carr[] = new char[net.tinyos.message.Message.MAX_CONVERTED_STRING_LENGTH];\n";
} else {
print " char carr[] = new char[Math.min(net.tinyos.message.Message.MAX_CONVERTED_STRING_LENGTH,$$amax[0])];\n";
}
print " int i;\n";
print " for (i = 0; i < carr.length; i++) {\n";
print " if ((char)getElement_$javafield(i) == (char)0) break;\n";
print " carr[i] = (char)getElement_$javafield(i);\n";
print " }\n";
print " return new String(carr,0,i);\n";
print " }\n\n";
}
}
}
print "}\n";
}
sub javabasetype()
{
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 = "byte"; }
elsif ($bitlength < 16) { $jtype = "short"; }
elsif ($bitlength < 32) { $jtype = "int"; }
else { $jtype = "long"; }
}
elsif ($basetype eq "I") {
$acc = "SIntElement";
if ($bitlength <= 8) { $jtype = "byte"; }
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);
}
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";
}
}
More information about the Tinyos
mailing list