1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
package CParse::Struct;
use 5.6.0;
use strict;
use warnings;
use File::Spec;
use CType::Struct;
use CType::Ref;
sub new
{
my $this = shift;
my $class = ref($this) || $this;
my $tag = shift;
my $declarations = shift;
my $attributes1 = shift;
my $attributes2 = shift;
my $self = {tag => $tag,
declarations => $declarations,
attributes1 => $attributes1,
attributes2 => $attributes2,
};
bless $self, $class;
return $self;
}
sub dump_c
{
my $self = shift;
my $str = '';
$str .= "struct";
if ($self->{attributes1})
{
$str .= " " . $self->{attributes1}->dump_c;
}
if ($self->{tag})
{
$str .= " $self->{tag}";
}
$str .= "\n{\n";
foreach my $declaration (@{$self->{declarations}})
{
my @dump = split /\n/, $declaration->dump_c;
$str .= join('', map {" $_\n"} @dump);
}
$str .= "}";
if ($self->{attributes2})
{
$str .= " " . $self->{attributes2}->dump_c;
}
return $str;
}
sub construct_type
{
my $self = shift;
my $namespace = shift;
my @attributes;
push @attributes, $self->{attributes1}->attributes if $self->{attributes1};
push @attributes, $self->{attributes2}->attributes if $self->{attributes2};
my @members = map {$_->get_members($namespace)} @{$self->{declarations}};
return new CType::Struct \@members, \@attributes, $CParse::current_location;
}
sub process
{
my $self = shift;
my $namespace = shift;
if ($self->{tag})
{
# Heuristic: we'll ignore redefinitions that occur at the same file:line
my $old = $namespace->get('struct', $self->{tag});
if ($old and
(File::Spec->canonpath($old->{file}) ne File::Spec->canonpath($CParse::current_location->{file})
or $old->{line} ne $CParse::current_location->{line}))
{
die "Redefinition of struct $self->{tag}\n (old definition at $old->{file}:$old->{line})\n";
}
my $type = $self->construct_type($namespace);
$namespace->set('struct', $self->{tag}, $type);
}
}
sub get_type
{
my $self = shift;
my $namespace = shift;
if ($self->{tag})
{
return new CType::Ref 'struct', $self->{tag}, $namespace;
}
else
{
return $self->construct_type($namespace);
}
}
1;
|