|
1 # Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 # All rights reserved. |
|
3 # This component and the accompanying materials are made available |
|
4 # under the terms of "Eclipse Public License v1.0" |
|
5 # which accompanies this distribution, and is available |
|
6 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 # |
|
8 # Initial Contributors: |
|
9 # Nokia Corporation - initial contribution. |
|
10 # |
|
11 # Contributors: |
|
12 # Mike Kinghan, mikek@symbian.org, for Symbian Foundation |
|
13 # |
|
14 # Description: |
|
15 # e32toolp\e32util\armasm2as.pl |
|
16 # Convert an ARMASM assembler source or include file to AS format |
|
17 # Syntax: |
|
18 # perl armasm2as.pl <input> <output> |
|
19 # |
|
20 # |
|
21 |
|
22 if (scalar(@ARGV)!=2) { |
|
23 die "perl armasm2as.pl <input> <output>\n"; |
|
24 } |
|
25 my ($infile, $outfile) = @ARGV; |
|
26 open IN, $infile or die "Can't open $infile for input\n"; |
|
27 my $gccfile; |
|
28 my @input; |
|
29 while (<IN>) { |
|
30 push @input, $_; |
|
31 next if defined($gccfile); |
|
32 next if (/^\s*$/); |
|
33 if (/^\s*\@/) { |
|
34 $gccfile = 1; # If first non-blank line starts with @, assume already in GCC format |
|
35 } else { |
|
36 $gccfile = 0; |
|
37 } |
|
38 } |
|
39 close IN; |
|
40 my @output; |
|
41 my $outref = \@output; |
|
42 if ($gccfile) { |
|
43 $outref = \@input; |
|
44 } else { |
|
45 process(\@input, \@output); |
|
46 } |
|
47 open OUT, ">$outfile" or die "Can't open $outfile for write\n"; |
|
48 print OUT @$outref; |
|
49 close OUT; |
|
50 |
|
51 |
|
52 |
|
53 sub process($$) { |
|
54 my $level=0; |
|
55 my @block; |
|
56 my ($inref, $outref) = @_; |
|
57 foreach $line (@$inref) { |
|
58 $line=~s/\s*$//; |
|
59 my $comment; |
|
60 if ($line =~ /\;(.*)$/o) { |
|
61 $comment = $1; |
|
62 $line =~ s/\;(.*)$//o; |
|
63 if ($line =~ /^\s*$/o and $level==0) { |
|
64 push @$outref, "$line\@$comment\n"; |
|
65 next; |
|
66 } |
|
67 $comment = "\t\@$comment"; |
|
68 } |
|
69 if ($line =~ /^\s+PRESERVE8/) { |
|
70 next; |
|
71 } |
|
72 if ($level == 1) { |
|
73 if ($line =~ /^\s+MEND/i) { |
|
74 process_macro(\@block, $outref); |
|
75 $level = 0; |
|
76 } else { |
|
77 push @block, $line; |
|
78 } |
|
79 next; |
|
80 } elsif ($level == 0) { |
|
81 if ($line =~ /^\s+MACRO\s*$/i) { |
|
82 @block = (); |
|
83 $level = 1; |
|
84 next; |
|
85 } |
|
86 } |
|
87 if ($line =~ /^\s+GBLL\s+(\S+)/i) { |
|
88 push @$outref, "\t.set\t$1, 0$comment\n"; |
|
89 next; |
|
90 } |
|
91 if ($line =~ /^\s+GBLA\s+(\S+)/i) { |
|
92 push @$outref, "\t.set\t$1, 0$comment\n"; |
|
93 next; |
|
94 } |
|
95 if ($line =~ /^\s+INCLUDE\s+(\S+)/i) { |
|
96 my $arg = $1; |
|
97 if ($arg =~ /(\w+)\.inc/io) { |
|
98 $arg = $1.'.ginc'; |
|
99 } |
|
100 push @$outref, "\t.include\t\"$arg\"$comment\n"; |
|
101 next; |
|
102 } |
|
103 if ($line =~ /^\s+IMPORT\s+(\S+)/i) { |
|
104 push @$outref, "\t.extern\t$1$comment\n"; |
|
105 next; |
|
106 } |
|
107 if ($line =~ /^\s+EXPORT\s+(\S+)/i) { |
|
108 push @$outref, "\t.global\t$1$comment\n"; |
|
109 next; |
|
110 } |
|
111 if ($line =~ /^\s+ELSE/i or $line =~ /^\s+\|/i ) { |
|
112 push @$outref, "\t.else$comment\n"; |
|
113 next; |
|
114 } |
|
115 if ($line =~ /^\s+ENDIF/i or $line =~ /^\s+\]/i) { |
|
116 push @$outref, "\t.endif$comment\n"; |
|
117 next; |
|
118 } |
|
119 if ($line =~ /^\s+LTORG/i) { |
|
120 push @$outref, "\t.ltorg$comment\n"; |
|
121 next; |
|
122 } |
|
123 if ($line =~ /^\s+END$/i) { |
|
124 next; |
|
125 } |
|
126 if ($line =~ /^\s+\!\s*(\d+)\,\s*(.*?)$/) { |
|
127 my $msg = $2; |
|
128 push @$outref, "\t.print $msg\n\t.err$comment\n"; |
|
129 next; |
|
130 } |
|
131 if ($line =~ /^\s+INIT_LOGICAL_SYMBOL\s+(\w+)(.*?)$/) { |
|
132 process_init_logical_symbol($1, $2, $outref, $comment); |
|
133 next; |
|
134 } |
|
135 if ($line =~ /^\s+INIT_NUMERIC_SYMBOL\s+(\w+)\s*\,\s*(.*?)$/) { |
|
136 process_init_numeric_symbol($1, $2, $outref, $comment); |
|
137 next; |
|
138 } |
|
139 if ($line =~ /^\s+AREA\s+(.*?)$/) { |
|
140 process_area($1, $outref, $comment); |
|
141 next; |
|
142 } |
|
143 if ($line =~ /^\s+\%\s+(.*?)$/) { |
|
144 my $expr = process_numeric_expr($1, $outref); |
|
145 push @$outref, "\t.space $expr$comment\n"; |
|
146 next; |
|
147 } |
|
148 if ($line =~ /^\s+ALIGN\s*(.*?)$/) { |
|
149 process_align($1, $outref, $comment); |
|
150 next; |
|
151 } |
|
152 |
|
153 # Strip label if there is one |
|
154 my $label; |
|
155 if ($line =~ /^(\S+)\s*(.*?)$/) { |
|
156 $label = $1; |
|
157 $line = $2; |
|
158 } else { |
|
159 $line =~ s/^\s*//; |
|
160 } |
|
161 if ($line =~ /^SETL\s+(\S+)/i) { |
|
162 my $val = $1; |
|
163 my $expr = process_logical_expr($val, $outref); |
|
164 push @$outref, "\t.set\t$label,$expr$comment\n"; |
|
165 next; |
|
166 } |
|
167 if ($line =~ /^SETA\s+(.*?)$/i) { |
|
168 my $val = $1; |
|
169 my $expr = process_numeric_expr($val, $outref); |
|
170 push @$outref, "\t.set\t$label,$expr$comment\n"; |
|
171 next; |
|
172 } |
|
173 if ($line =~ /^(EQU|\*)\s+(.*?)$/i) { |
|
174 my $val = $2; |
|
175 my $expr = process_numeric_expr($val, $outref); |
|
176 push @$outref, "\t.equ\t$label,$expr$comment\n"; |
|
177 next; |
|
178 } |
|
179 if ($line =~ /^(if|\[)\s+(.*?)$/i) { |
|
180 my $cond = $2; |
|
181 if ($cond =~ /^\s*(\:LNOT\:)?\s*\:DEF\:\s*(.*?)$/i) { |
|
182 my $n = $1; |
|
183 my $sym = $2; |
|
184 if ($sym =~ /^(\w|\\|\:)+$/) { |
|
185 if (uc($n) eq ':LNOT:') { |
|
186 push @$outref, "\t.ifndef\t$sym$comment\n"; |
|
187 } else { |
|
188 push @$outref, "\t.ifdef\t$sym$comment\n"; |
|
189 } |
|
190 next; |
|
191 } |
|
192 } |
|
193 my $expr = process_logical_expr($cond, $outref); |
|
194 push @$outref, "\t.if $expr$comment\n"; |
|
195 next; |
|
196 } |
|
197 if ($line =~ /^(\=|DCB)\s*(.*?)$/) { |
|
198 process_dcb($label, $2, $outref, $comment); |
|
199 next; |
|
200 } |
|
201 if ($line =~ /^DCW\s*(.*?)$/) { |
|
202 process_dcw($label, $1, $outref, $comment); |
|
203 next; |
|
204 } |
|
205 if ($line =~ /^DCD\s*(.*?)$/) { |
|
206 process_dcd($label, $1, $outref, $comment); |
|
207 next; |
|
208 } |
|
209 if ($line =~ /^ROUT\s*$/) { |
|
210 $line = ''; |
|
211 } |
|
212 if ($line =~ /^(\w+)\s+\%(\w+)\s*$/o) { |
|
213 # ARMASM local label reference |
|
214 my $inst = $1; |
|
215 my $llab = $2; |
|
216 if ($llab =~ /F\w?(\d+)/o) { |
|
217 $line = "$inst $1f"; |
|
218 } elsif ($llab =~ /B\w?(\d+)/o) { |
|
219 $line = "$inst $1b"; |
|
220 } else { |
|
221 die "Can't determine local label direction\n"; |
|
222 } |
|
223 } |
|
224 if ($line =~ /^(\w+)\s+(\w+)\s*\,\s*\%(\w+)\s*$/o) { |
|
225 # ARMASM local label reference |
|
226 my $inst = $1; |
|
227 my $op1 = $2; |
|
228 my $llab = $3; |
|
229 if ($llab =~ /F\w?(\d+)/o) { |
|
230 $line = "$inst $op1\, $1f"; |
|
231 } elsif ($llab =~ /B\w?(\d+)/o) { |
|
232 $line = "$inst $op1\, $1b"; |
|
233 } else { |
|
234 die "Can't determine local label direction\n"; |
|
235 } |
|
236 } |
|
237 |
|
238 $line = process_numeric_expr($line, $outref); |
|
239 if (defined($label)) { |
|
240 push @$outref, "$label\:\t$line$comment\n"; |
|
241 } else { |
|
242 push @$outref, "\t$line$comment\n"; |
|
243 } |
|
244 } |
|
245 } |
|
246 |
|
247 |
|
248 sub process_macro($$) { |
|
249 my ($inref, $outref) = @_; |
|
250 my $line; |
|
251 while(1) { |
|
252 $line = shift @$inref; |
|
253 last if ($line !~ /^\s*$/); |
|
254 } |
|
255 unless ($line =~ /^\s+(\w+)\s*(.*?)$/) { |
|
256 die "Bad macro - no name\n"; |
|
257 } |
|
258 my $macro_name = $1; |
|
259 if ($macro_name eq 'INIT_LOGICAL_SYMBOL' or $macro_name eq 'INIT_NUMERIC_SYMBOL') { |
|
260 return; |
|
261 } |
|
262 $line = $2; |
|
263 my @args = split ( '\s*,\s*', $line ); |
|
264 foreach (@args) { |
|
265 die "Bad macro argument name\n" unless (/^\$\w+$/); |
|
266 s/^\$//; |
|
267 } |
|
268 my $ev = ''; |
|
269 foreach $arg (@args) { |
|
270 $ev.="s/\\\$$arg(\\W\|\$)/\\\\$arg\$1/go;"; |
|
271 } |
|
272 foreach (@$inref) { |
|
273 eval $ev; |
|
274 } |
|
275 push @$outref, "\t.macro $macro_name ".join(',',@args)."\n"; |
|
276 process($inref, $outref); |
|
277 push @$outref, "\t.endm\n"; |
|
278 } |
|
279 |
|
280 |
|
281 sub process_logical_expr($$) { |
|
282 my ($val, $outref) = @_; |
|
283 $val = process_numeric_expr($val, $outref); |
|
284 $val =~ s/\<\=/________LE________/g; # protect <= and >= during expansion of = |
|
285 $val =~ s/\>\=/________GE________/g; |
|
286 $val =~ s/\=/\=\=/g; # equality operator is = on ARMASM, == on AS |
|
287 $val =~ s/________LE________/\<\=/g; |
|
288 $val =~ s/________GE________/\>\=/g; |
|
289 $val =~ s/\{TRUE\}/(1)/g; |
|
290 $val =~ s/\{FALSE\}/(0)/g; |
|
291 |
|
292 my @lops = split( /(\s*\:LAND\:\s*|\s*\:LOR\:\s*|\s*\:LNOT\:\s*|\s*\:DEF\:\s*|\s*\(\s*|\s*\)\s*)/, $val ); |
|
293 foreach (@lops) { |
|
294 s/\s*\:LAND\:\s*/\:LAND\:/go; |
|
295 s/\s*\:LOR\:\s*/\:LOR\:/go; |
|
296 s/\s*\:LNOT\:\s*/\:LNOT\:/go; |
|
297 s/\s*\:DEF\:\s*/\:DEF\:/go; |
|
298 s/\s*\(\s*/\(/go; |
|
299 s/\s*\)\s*/\)/go; |
|
300 } |
|
301 my @lops2; |
|
302 while (scalar (@lops)) { |
|
303 my $x = shift @lops; |
|
304 if ($x eq ':DEF:') { |
|
305 my $sym = shift @lops; |
|
306 $sym =~ s/^\s*//; |
|
307 $sym =~ s/\s*$//; |
|
308 if ($sym =~ /^(\w|\$|\\)+$/) { |
|
309 push @$outref, "\t.ifdef $sym\n\t.set __defined__$sym, 1\n\t.else\n\t.set __defined__$sym, 0\n\t.endif\n"; |
|
310 push @lops2, " __defined__$sym "; |
|
311 } else { |
|
312 die "Bad :DEF: operand $sym\n"; |
|
313 } |
|
314 } elsif ($x eq ':LAND:') { |
|
315 push @lops2, ' && '; |
|
316 } elsif ($x eq ':LOR:') { |
|
317 push @lops2, ' || '; |
|
318 } else { |
|
319 push @lops2, $x; |
|
320 } |
|
321 } |
|
322 my @lops3; |
|
323 while (scalar (@lops2)) { |
|
324 my $x = shift @lops2; |
|
325 if ($x eq ':LNOT:') { |
|
326 my $operand = shift @lops2; |
|
327 while (@lops2 && $operand =~ /^\s*$/) { |
|
328 $operand = shift @lops2; |
|
329 } |
|
330 if ($operand eq '(') { |
|
331 my $balance = 1; |
|
332 my $compound = $operand; |
|
333 while($balance > 0 && @lops2) { |
|
334 $operand = shift @lops2; |
|
335 if ($operand eq '(') { |
|
336 ++$balance; |
|
337 } |
|
338 elsif ($operand eq ')') { |
|
339 --$balance; |
|
340 } |
|
341 $compound .= $operand; |
|
342 } |
|
343 push @lops3, "(0==$compound)"; |
|
344 } |
|
345 else { |
|
346 push @lops3, "(0==($operand))"; |
|
347 } |
|
348 } else { |
|
349 push @lops3, $x; |
|
350 } |
|
351 } |
|
352 return join('',@lops3); |
|
353 } |
|
354 |
|
355 sub process_numeric_expr($$) { |
|
356 my ($val, $outref) = @_; |
|
357 $val =~ s/\&/0x/g; # ARMASM accepts hex numbers starting with & or 0x, AS only accepts 0x |
|
358 $val =~ s/(\W|^)2_([0|1]+)(\W|$)/$1 0b$2$3/g; # Binary numbers start with 2_ on ARMASM, 0b on AS |
|
359 $val =~ s/\:AND\:/\&/g; |
|
360 $val =~ s/\:OR\:/\|/g; |
|
361 $val =~ s/\:SHL\:/\<\</g; |
|
362 $val =~ s/\:SHR\:/\>\>/g; |
|
363 return $val; |
|
364 } |
|
365 |
|
366 sub process_init_logical_symbol($$$$) { |
|
367 my ($name, $rest, $outref, $comment) = @_; |
|
368 my $counter; |
|
369 if ($rest =~ /^\s*\,\s*(\w+)\s*$/) { |
|
370 $counter = $1; |
|
371 } elsif ($rest !~ /^\s*$/) { |
|
372 die "Bad INIT_LOGICAL_SYMBOL\n"; |
|
373 } |
|
374 push @$outref, "\t.ifndef $name$comment\n\t.set $name, 0\n\t.else\n\t.set $name, 1\n"; |
|
375 if ($counter) { |
|
376 push @$outref, "\t.set $counter, $counter \+ 1\n"; |
|
377 } |
|
378 push @$outref, "\t.endif\n"; |
|
379 } |
|
380 |
|
381 sub process_init_numeric_symbol($$$$) { |
|
382 my ($name, $value, $outref, $comment) = @_; |
|
383 my $expr = process_numeric_expr($value, $outref); |
|
384 push @$outref, "\t.ifndef $name$comment\n\t.set $name, $expr\n\t.endif\n"; |
|
385 } |
|
386 |
|
387 sub process_area($$$) { |
|
388 my ($line, $outref, $comment) = @_; |
|
389 my @args = split(',',$line); |
|
390 my $align = 0; |
|
391 foreach (@args) { |
|
392 if (/^\s*ALIGN\s*\=\s*(\d+)\s*$/) { |
|
393 $align = $1; |
|
394 } |
|
395 } |
|
396 push @$outref, "\t.text$comment\n\t.p2align $align\n"; |
|
397 } |
|
398 |
|
399 sub process_align($$$) { |
|
400 my ($line, $outref, $comment) = @_; |
|
401 if ($line =~ /^\s*$/o) { |
|
402 push @$outref, "\t.align$comment\n"; |
|
403 } else { |
|
404 push @$outref, "\t.balign $line$comment\n"; |
|
405 } |
|
406 } |
|
407 |
|
408 sub process_dcb($$$$) { |
|
409 my ($label, $args, $outref, $comment) = @_; |
|
410 if (defined($label)) { |
|
411 push @$outref, "$label\:"; |
|
412 } |
|
413 while ($args !~ /^\s*$/) { |
|
414 my $arg; |
|
415 $args =~ s/^\s*//; |
|
416 if ($args =~ /^\"/) { |
|
417 $args =~ s/\\\"/________ESCAPED_QUOTE________/go; |
|
418 $args =~ /\"(.*?)\"\s*(.*?)$/o or die "Unterminated string literal\n"; |
|
419 $arg = $1; |
|
420 $args = $2; |
|
421 $arg =~ s/________ESCAPED_QUOTE________/\\\"/go; |
|
422 push @$outref, "\t.ascii \"$arg\"$comment\n"; |
|
423 undef $comment; |
|
424 last if ($args !~ /\s*\,(.*?)$/o); |
|
425 $args = $1; |
|
426 } else { |
|
427 $args =~ /(.*?)\s*(\,|$)(.*?)$/o; |
|
428 $arg = $1; |
|
429 $args = $3; |
|
430 my $expr = process_numeric_expr($arg, $outref); |
|
431 push @$outref, "\t.byte $expr$comment\n"; |
|
432 undef $comment; |
|
433 } |
|
434 } |
|
435 } |
|
436 |
|
437 sub process_dcw($$$$) { |
|
438 my ($label, $args, $outref, $comment) = @_; |
|
439 if (defined($label)) { |
|
440 push @$outref, "$label\:"; |
|
441 } |
|
442 while ($args !~ /^\s*$/) { |
|
443 my $arg; |
|
444 $args =~ s/^\s*//; |
|
445 $args =~ /(.*?)\s*(\,|$)(.*?)$/o; |
|
446 $arg = $1; |
|
447 $args = $3; |
|
448 my $expr = process_numeric_expr($arg, $outref); |
|
449 push @$outref, "\t.hword $expr$comment\n"; |
|
450 undef $comment; |
|
451 } |
|
452 } |
|
453 |
|
454 sub process_dcd($$$$) { |
|
455 my ($label, $args, $outref, $comment) = @_; |
|
456 if (defined($label)) { |
|
457 push @$outref, "$label\:"; |
|
458 } |
|
459 while ($args !~ /^\s*$/) { |
|
460 my $arg; |
|
461 $args =~ s/^\s*//; |
|
462 $args =~ /(.*?)\s*(\,|$)(.*?)$/o; |
|
463 $arg = $1; |
|
464 $args = $3; |
|
465 my $expr = process_numeric_expr($arg, $outref); |
|
466 push @$outref, "\t.word $expr$comment\n"; |
|
467 undef $comment; |
|
468 } |
|
469 } |
|
470 |
|
471 |
|
472 |