updated decoder generator with class structure
[dyninst.git] / instructionAPI / ppc_manual_parser.pl
1 #!/usr/bin/perl
2
3 use HTML::LinkExtor;
4 use HTML::Parser;
5 use LWP::UserAgent;
6 use URI::URL;
7 use strict;
8
9 my $url = "http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixassem/alangref/frame9_toc.htm";
10
11 my %unique_links;
12 sub callback {
13     my ($tag, %attr) = @_;
14     return if $tag ne 'a';
15     foreach my $v (values %attr)
16     {
17         $unique_links{$v} = 1 unless $v =~ /javascript|appendix|instr/;
18     }
19
20 }
21 my $ua = LWP::UserAgent->new;
22
23 my $p = HTML::LinkExtor->new(\&callback);
24
25 my $res = $ua->request(HTTP::Request->new(GET => $url),
26                     sub { $p->parse($_[0])});
27
28 my $base = $res->base;
29
30
31 my @links = keys %unique_links;
32 for (@links) { s/\#.*$//; }
33 @links = map {$_ = url($_, $base)->abs; } (@links);
34
35 my $column = 0;
36 my $mnemonic;
37 my %mnemonic_info;
38 my $suffix = undef;
39
40 sub set_mnemonic
41 {
42     my ($self, $text) = @_;
43     ($mnemonic) = ($text =~ /(\S*)\s+/);
44     $self->handler(text => "");
45 }
46
47 sub handle_text
48 {
49     my($self, $text) = @_;
50     chomp $text;
51     return unless($text =~ /^[\w|\d|\/|\s]+$/);
52     $text =~ s/^A$/RA/;
53     $text =~ s/^B$/RB/;
54     $text =~ s/^S$/RS/;
55     $text =~ s/^T$/RT/;
56     $text =~ s/^SIMM$/SI/;
57     $text =~ s/^SI\/D$/SI/;
58     $text =~ s/^SI\/UI$/SI/;
59     $text =~ s/^sh$/SH/;
60     $text =~ s/^me$/ME/;
61     $text =~ s/^mb$/MB/;
62     $text =~ s/^ds$/DS/;
63     $mnemonic_info{$mnemonic} .= "$text ";
64     $self->handler(text => "");
65 }
66
67
68 sub handle_table_entries
69 {
70     my($self, $tag, $attr) = @_;
71     if($tag =~ /td/i)
72     {
73         if($attr->{'headers'} =~ /COL2/i)
74         {
75             $self->handler(text => \&handle_text, "self, dtext");
76         }
77     }
78 }
79
80 sub restore_default_handler
81 {
82     my ($self, $tag) = @_;
83     if($tag =~ /table/i)
84     {
85         $self->handler(start => \&check_table_headers, "self, tagname, attr");
86     }
87 }
88
89
90 sub check_for_value
91 {
92     my($self, $text) = @_;
93     if($text =~ /Value/)
94     {
95         $self->handler(start => \&handle_table_entries, "self, tagname, attr");
96         $self->handler(end => \&restore_default_handler, "self, tagname");
97         if(defined $suffix)
98         {
99             $mnemonic .= $suffix;
100         }
101         else
102         {
103             $suffix = "s";
104         }
105     }
106 }
107
108 sub check_table_headers
109 {
110     my($self, $tag, $attr) = @_;
111     if($tag =~ /th/i)
112     {
113         if($attr->{'id'} =~ /COL2/i)
114         {
115             $self->handler(text => \&check_for_value, "self, dtext");
116         }
117     }
118     if($tag =~ /h2/i)
119     {
120         $self->handler(text => \&set_mnemonic, "self, dtext");
121     }
122 }
123
124
125 my $instructionParser = HTML::Parser->new(api_version => 3,
126                                        handlers => [start => [\&check_table_headers, "self, tagname, attr"],
127                                                     ],
128                                        marked_sections => 1);
129
130 while (my $url = shift(@links))
131 {
132     $mnemonic = undef;
133     $suffix = undef;
134     $instructionParser->handler(start => \&check_table_headers, "self, tagname, attr");
135     $res = $ua->request(HTTP::Request->new(GET => $url),
136                     sub { $instructionParser->parse($_[0])});
137
138 }
139
140
141 my @main_opcode_array;
142 my %extended_opcode_array;
143 my %mnemonics;
144
145 foreach my $k(keys %mnemonic_info)
146 {
147     my @vals = split(/\s+/, $mnemonic_info{$k});
148     my $primary_opcode = shift @vals;
149     unshift(@vals, $k);
150     if(exists $main_opcode_array[$primary_opcode])
151     {
152         my $i = $#vals;
153         my $extended_opcode;
154         while($i > 0 and not $extended_opcode)
155         {
156             --$i;
157             $extended_opcode = $vals[$i] if ($vals[$i] =~ /^\d+$/);
158         }
159         if(defined $extended_opcode)
160         {
161             if($main_opcode_array[$primary_opcode][0] ne "extended")
162             {
163                 my $tmp_extended_opcode;
164                 my $aref = $main_opcode_array[$primary_opcode];
165                 my @tmp_vals = @$aref;
166                 $i = $#tmp_vals;
167                 while($i > 0 and not $tmp_extended_opcode)
168                 {
169                     --$i;
170                     $tmp_extended_opcode = $tmp_vals[$i] if ($tmp_vals[$i] =~ /^\d+$/);
171                 }
172                 print "@tmp_vals\n" if $tmp_vals[0] =~ /D/;
173                 $extended_opcode_array{$primary_opcode}{$tmp_extended_opcode} = [@tmp_vals];
174                 $main_opcode_array[$primary_opcode] = ["extended"];
175             }
176             print "@vals\n" if $vals[0] =~ /D/;
177             $extended_opcode_array{$primary_opcode}{$extended_opcode} = [@vals];
178             $mnemonics{$vals[0]} = 1;
179
180         }
181     }
182     else
183     {
184         $main_opcode_array[$primary_opcode] = [@vals];
185         $mnemonics{$vals[0]} = 1;
186     }
187 }
188
189 my %size_to_result_type = (
190                            b => 'u8',
191                            h => 'u16',
192                            w => 'u32',
193                            d => 'u64',
194                            q => 'u64',
195                            fs => 'sp_float',
196                            fd => 'dp_float',
197                            fiw => 'u32',
198                            fq => 'dbl128',
199                            mw => 'u32',
200                            sw => 'u8',
201                            scb => 'u8');
202
203 sub print_table_entry
204 {
205     my ($primary_opcode, @data) = @_;
206     my @opcode_data;
207     map {push (@opcode_data, $_) unless /^[\/\d]*$/; } @data;
208     my $mnem = shift @opcode_data;
209     if(!$mnem)
210     {
211         $mnem = "INVALID";
212     }
213     my ($load, $width, $update, $index) = $mnem =~ /^(l|st)((?:f|m|s|sc|fi)?\w?)(?:z|ar|a|br|c|i)?(u?)(x?)\.?$/;
214
215     for my $i(0..$#opcode_data)
216     {
217         if($opcode_data[$i] eq "D" and $i < $#opcode_data)
218         {
219             $opcode_data[$i] = "RT";
220         }
221         if($load and $opcode_data[$i] eq "RA")
222         {
223             my $load_operand = $load . $update . $index;
224             $load_operand =~ tr/[a-z]/[A-Z]/;
225             splice @opcode_data, $i, 2, "$load_operand<$size_to_result_type{$width}>";
226         }
227     }
228
229     my $operands = "operandSpec()";
230     my $next_table = "NULL";
231     if($mnem eq "extended")
232     {
233         $next_table = "fn(extended_op_$primary_opcode)";
234     }
235     if(@opcode_data)
236     {
237         $operands = "list_of(fn(";
238         $operands .= join("))(fn(", @opcode_data);
239         $operands .= "))";
240     }
241     my $enum = $mnem;
242     $enum =~ s/\./_rc/g;
243     print "power_op_$enum, \"$mnem\", $next_table, $operands";
244
245 }
246
247 print "enum powerOpcodes {\n";
248 for my $mnem(keys %mnemonics)
249 {
250     $mnem =~ s/\./_rc/g;
251     print "\tpower_op_$mnem,\n";
252 }
253 print "};\n";
254
255 print "power_entry power_entry::main_opcode_table\[\] = {\n";
256 for my $i(0..$#main_opcode_array)
257 {
258     print "\t{";
259     print_table_entry($i, @{$main_opcode_array[$i]});
260     print "},\n";
261 }
262 print "};\n";
263
264 foreach my $primary(sort {$a <=> $b} keys %extended_opcode_array)
265 {
266     print "std::map<unsigned int,power_entry> power_entry::extended_op_$primary = map_list_of\n";
267     foreach my $extended(sort {$a <=> $b} keys %{$extended_opcode_array{$primary}})
268     {
269         print "\t($extended, power_entry(";
270         print_table_entry($primary, @{$extended_opcode_array{$primary}{$extended}});
271         print "))\n";
272     }
273     print ";\n"
274 }