ruby: clean helper with offsetof

develop
jj 2012-04-21 21:20:51 +02:00
parent 9317143909
commit 6fc17b3e1f
2 changed files with 86 additions and 38 deletions

@ -6,6 +6,9 @@ if(RUBY_FOUND)
DEPENDS ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml codegen.pl DEPENDS ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml codegen.pl
) )
ADD_EXECUTABLE(ruby-autogen ruby-autogen.cpp) ADD_EXECUTABLE(ruby-autogen ruby-autogen.cpp)
if(CMAKE_COMPILER_IS_GNUCC)
set_target_properties (ruby-autogen PROPERTIES COMPILE_FLAGS "-Wno-invalid-offsetof")
endif(CMAKE_COMPILER_IS_GNUCC)
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT ruby-autogen.offsets OUTPUT ruby-autogen.offsets
COMMAND ruby-autogen ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.offsets COMMAND ruby-autogen ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.offsets

@ -147,37 +147,35 @@ sub render_global_class {
my $rbparent = ($parent ? rb_ucase($parent) : 'MemHack::Compound'); my $rbparent = ($parent ? rb_ucase($parent) : 'MemHack::Compound');
my $cppvar = "v_$cpp_var_counter"; my $cppns = "df::$name";
$cpp_var_counter++;
push @lines_cpp, "}" if @include_cpp; push @lines_cpp, "}" if @include_cpp;
push @lines_cpp, "void cpp_$name(FILE *fout) {"; push @lines_cpp, "void cpp_$name(FILE *fout) {";
push @lines_cpp, " df::$name *$cppvar = (df::$name*)moo;";
push @include_cpp, $name; push @include_cpp, $name;
push @lines_rb, "class $rbname < $rbparent"; push @lines_rb, "class $rbname < $rbparent";
indent_rb { indent_rb {
my $sz = query_cpp("sizeof(*$cppvar)"); my $sz = query_cpp("sizeof($cppns)");
push @lines_rb, "sizeof $sz"; push @lines_rb, "sizeof $sz";
push @lines_rb, "rtti_classname '$rtti_name'" if $has_rtti; push @lines_rb, "rtti_classname '$rtti_name'" if $has_rtti;
render_struct_fields($type, "(*$cppvar)"); render_struct_fields($type, "$cppns");
}; };
push @lines_rb, "end\n"; push @lines_rb, "end\n";
} }
sub render_struct_fields { sub render_struct_fields {
my ($type, $cppvar) = @_; my ($type, $cppns) = @_;
for my $field ($type->findnodes('child::ld:field')) { for my $field ($type->findnodes('child::ld:field')) {
my $name = $field->getAttribute('name'); my $name = $field->getAttribute('name');
$name = $field->getAttribute('ld:anon-name') if (!$name); $name = $field->getAttribute('ld:anon-name') if (!$name);
if (!$name and $field->getAttribute('ld:anon-compound')) { if (!$name and $field->getAttribute('ld:anon-compound')) {
render_struct_fields($field, $cppvar); render_struct_fields($field, $cppns);
} }
next if (!$name); next if (!$name);
my $offset = get_offset($cppvar, $name); my $offset = get_offset($cppns, $name);
push @lines_rb, "field(:$name, $offset) {"; push @lines_rb, "field(:$name, $offset) {";
indent_rb { indent_rb {
render_item($field, "$cppvar.$name"); render_item($field, "$cppns");
}; };
push @lines_rb, "}"; push @lines_rb, "}";
} }
@ -204,7 +202,7 @@ sub render_global_objects {
push @lines_rb, "field(:$oname, $addr) {"; push @lines_rb, "field(:$oname, $addr) {";
my $item = $obj->findnodes('child::ld:item')->[0]; my $item = $obj->findnodes('child::ld:item')->[0];
indent_rb { indent_rb {
render_item($item, "(*df::global::$oname)"); render_item($item, 'df::global');
}; };
push @lines_rb, "}"; push @lines_rb, "}";
@ -224,27 +222,27 @@ sub render_global_objects {
sub render_item { sub render_item {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
return if (!$item); return if (!$item);
my $meta = $item->getAttribute('ld:meta'); my $meta = $item->getAttribute('ld:meta');
my $renderer = $item_renderer{$meta}; my $renderer = $item_renderer{$meta};
if ($renderer) { if ($renderer) {
$renderer->($item, $cppvar); $renderer->($item, $pns);
} else { } else {
print "no render item $meta\n"; print "no render item $meta\n";
} }
} }
sub render_item_global { sub render_item_global {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $typename = $item->getAttribute('type-name'); my $typename = $item->getAttribute('type-name');
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
if ($subtype and $subtype eq 'enum') { if ($subtype and $subtype eq 'enum') {
render_item_number($item, $cppvar); render_item_number($item, $pns);
} else { } else {
my $rbname = rb_ucase($typename); my $rbname = rb_ucase($typename);
push @lines_rb, "global :$rbname"; push @lines_rb, "global :$rbname";
@ -252,7 +250,7 @@ sub render_item_global {
} }
sub render_item_number { sub render_item_number {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
$subtype = $item->getAttribute('base-type') if (!$subtype or $subtype eq 'enum' or $subtype eq 'bitfield'); $subtype = $item->getAttribute('base-type') if (!$subtype or $subtype eq 'enum' or $subtype eq 'bitfield');
@ -282,14 +280,15 @@ sub render_item_number {
} }
sub render_item_compound { sub render_item_compound {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $cppns = $pns . '::' . $item->getAttribute('ld:typedef-name');
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
if (!$subtype || $subtype eq 'bitfield') { if (!$subtype || $subtype eq 'bitfield') {
push @lines_rb, "compound {"; push @lines_rb, "compound {";
indent_rb { indent_rb {
if (!$subtype) { if (!$subtype) {
render_struct_fields($item, $cppvar); render_struct_fields($item, $cppns);
} else { } else {
render_bitfield_fields($item); render_bitfield_fields($item);
} }
@ -299,14 +298,14 @@ sub render_item_compound {
# declare constants # declare constants
render_enum_fields($item); render_enum_fields($item);
# actual field # actual field
render_item_number($item, $cppvar); render_item_number($item, $cppns);
} else { } else {
print "no render compound $subtype\n"; print "no render compound $subtype\n";
} }
} }
sub render_item_container { sub render_item_container {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
my $rbmethod = join('_', split('-', $subtype)); my $rbmethod = join('_', split('-', $subtype));
@ -315,11 +314,11 @@ sub render_item_container {
if ($rbmethod eq 'df_linked_list') { if ($rbmethod eq 'df_linked_list') {
push @lines_rb, "$rbmethod {"; push @lines_rb, "$rbmethod {";
} else { } else {
my $tglen = get_tglen($tg, $cppvar); my $tglen = get_tglen($tg, $pns);
push @lines_rb, "$rbmethod($tglen) {"; push @lines_rb, "$rbmethod($tglen) {";
} }
indent_rb { indent_rb {
render_item($tg, "${cppvar}[0]"); render_item($tg, $pns);
}; };
push @lines_rb, "}"; push @lines_rb, "}";
} else { } else {
@ -328,37 +327,37 @@ sub render_item_container {
} }
sub render_item_pointer { sub render_item_pointer {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $tg = $item->findnodes('child::ld:item')->[0]; my $tg = $item->findnodes('child::ld:item')->[0];
my $ary = $item->getAttribute('is-array'); my $ary = $item->getAttribute('is-array');
if ($ary and $ary eq 'true') { if ($ary and $ary eq 'true') {
my $tglen = get_tglen($tg, $cppvar); my $tglen = get_tglen($tg, $pns);
push @lines_rb, "pointer_ary($tglen) {"; push @lines_rb, "pointer_ary($tglen) {";
} else { } else {
push @lines_rb, "pointer {"; push @lines_rb, "pointer {";
} }
indent_rb { indent_rb {
render_item($tg, "${cppvar}[0]"); render_item($tg, $pns);
}; };
push @lines_rb, "}"; push @lines_rb, "}";
} }
sub render_item_staticarray { sub render_item_staticarray {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $count = $item->getAttribute('count'); my $count = $item->getAttribute('count');
my $tg = $item->findnodes('child::ld:item')->[0]; my $tg = $item->findnodes('child::ld:item')->[0];
my $tglen = get_tglen($tg, $cppvar); my $tglen = get_tglen($tg, $pns);
push @lines_rb, "static_array($count, $tglen) {"; push @lines_rb, "static_array($count, $tglen) {";
indent_rb { indent_rb {
render_item($tg, "${cppvar}[0]"); render_item($tg, $pns);
}; };
push @lines_rb, "}"; push @lines_rb, "}";
} }
sub render_item_primitive { sub render_item_primitive {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
if ($subtype eq 'stl-string') { if ($subtype eq 'stl-string') {
@ -369,7 +368,7 @@ sub render_item_primitive {
} }
sub render_item_bytes { sub render_item_bytes {
my ($item, $cppvar) = @_; my ($item, $pns) = @_;
my $subtype = $item->getAttribute('ld:subtype'); my $subtype = $item->getAttribute('ld:subtype');
if ($subtype eq 'padding') { if ($subtype eq 'padding') {
@ -382,15 +381,13 @@ sub render_item_bytes {
} }
sub get_offset { sub get_offset {
my ($cppvar, $fname) = @_; my ($cppns, $fname) = @_;
# GCC fails with this return query_cpp("offsetof($cppns, $fname)");
#return query_cpp("offsetof(typeof($cppvar), $fname)");
return query_cpp("((char*)&$cppvar.$fname - (char*)&$cppvar)");
} }
sub get_tglen { sub get_tglen {
my ($tg, $cppvar) = @_; my ($tg, $cppns) = @_;
if (!$tg) { if (!$tg) {
return 'nil'; return 'nil';
@ -401,17 +398,67 @@ sub get_tglen {
return $tg->getAttribute('ld:bits')/8; return $tg->getAttribute('ld:bits')/8;
} elsif ($meta eq 'pointer') { } elsif ($meta eq 'pointer') {
return 4; return 4;
} elsif ($meta eq 'container') {
my $subtype = $tg->getAttribute('ld:subtype');
if ($subtype eq 'stl-vector') {
return query_cpp("sizeof(std::vector<int>)");
} elsif ($subtype eq 'df-linked-list') {
return 12;
} else { } else {
return query_cpp("sizeof(${cppvar}[0])"); print "cannot tglen container $subtype\n";
}
} elsif ($meta eq 'compound') {
my $cname = $tg->getAttribute('ld:typedef-name');
return query_cpp("sizeof(${cppns}::$cname)");
} elsif ($meta eq 'static-array') {
my $count = $tg->getAttribute('count');
my $ttg = $tg->findnodes('child::ld:item')->[0];
my $ttgl = get_tglen($ttg, $cppns);
if ($ttgl =~ /^\d+$/) {
return $count * $ttgl;
} else {
return "$count*$ttgl";
}
} elsif ($meta eq 'global') {
my $typename = $tg->getAttribute('type-name');
my $subtype = $tg->getAttribute('ld:subtype');
if ($subtype and $subtype eq 'enum') {
my $base = $tg->getAttribute('base-type') || 'int32_t';
if ($base eq 'int32_t') {
return 4;
} elsif ($base eq 'int16_t') {
return 2;
} elsif ($base eq 'int8_t') {
return 1;
} else {
print "cannot tglen enum $base\n";
}
} else {
return query_cpp("sizeof(df::$typename)");
}
} elsif ($meta eq 'primitive') {
my $subtype = $tg->getAttribute('ld:subtype');
if ($subtype eq 'stl-string') {
return query_cpp("sizeof(std::string)");
} else {
print "cannot tglen primitive $subtype\n";
}
} else {
print "cannot tglen $meta\n";
} }
} }
my %query_cpp_cache;
sub query_cpp { sub query_cpp {
my ($query) = @_; my ($query) = @_;
my $ans = $offsets{$query}; my $ans = $offsets{$query};
return $ans if (defined($ans)); return $ans if (defined($ans));
my $cached = $query_cpp_cache{$query};
return $cached if (defined($cached));
$query_cpp_cache{$query} = 1;
push @lines_cpp, " fprintf(fout, \"%s = %d\\n\", \"$query\", $query);"; push @lines_cpp, " fprintf(fout, \"%s = %d\\n\", \"$query\", $query);";
return "'$query'"; return "'$query'";
} }
@ -464,14 +511,12 @@ if ($output =~ /\.cpp$/) {
print FH "#include \"DataDefs.h\"\n"; print FH "#include \"DataDefs.h\"\n";
print FH "#include \"df/$_.h\"\n" for @include_cpp; print FH "#include \"df/$_.h\"\n" for @include_cpp;
print FH "#include <stdio.h>\n"; print FH "#include <stdio.h>\n";
print FH "static void *moo[1024];\n"; print FH "#include <stddef.h>\n";
print FH "$_\n" for @lines_cpp; print FH "$_\n" for @lines_cpp;
print FH "}\n"; print FH "}\n";
print FH "int main(int argc, char **argv) {\n"; print FH "int main(int argc, char **argv) {\n";
print FH " FILE *fout;\n"; print FH " FILE *fout;\n";
print FH " if (argc < 2) return 1;\n"; print FH " if (argc < 2) return 1;\n";
# sometimes gcc will generate accesses to the structures at 0 just for a sizeof/offsetof, this works around the segfaults...
print FH " for (int i=0 ; i<1024 ; i++) moo[i] = &moo;\n";
print FH " fout = fopen(argv[1], \"w\");\n"; print FH " fout = fopen(argv[1], \"w\");\n";
print FH " cpp_$_(fout);\n" for @include_cpp; print FH " cpp_$_(fout);\n" for @include_cpp;
print FH " fclose(fout);\n"; print FH " fclose(fout);\n";