1 | # @file ConvertMasmToNasm.py
|
---|
2 | # This script assists with conversion of MASM assembly syntax to NASM
|
---|
3 | #
|
---|
4 | # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
|
---|
5 | #
|
---|
6 | # This program and the accompanying materials
|
---|
7 | # are licensed and made available under the terms and conditions of the BSD License
|
---|
8 | # which accompanies this distribution. The full text of the license may be found at
|
---|
9 | # http://opensource.org/licenses/bsd-license.php
|
---|
10 | #
|
---|
11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
13 | #
|
---|
14 |
|
---|
15 | #
|
---|
16 | # Import Modules
|
---|
17 | #
|
---|
18 | import os.path
|
---|
19 | import re
|
---|
20 | import StringIO
|
---|
21 | import subprocess
|
---|
22 | import sys
|
---|
23 | from optparse import OptionParser
|
---|
24 |
|
---|
25 |
|
---|
26 | class UnsupportedConversion(Exception):
|
---|
27 | pass
|
---|
28 |
|
---|
29 |
|
---|
30 | class NoSourceFile(Exception):
|
---|
31 | pass
|
---|
32 |
|
---|
33 |
|
---|
34 | class UnsupportedArch(Exception):
|
---|
35 | unsupported = ('aarch64', 'arm', 'ebc', 'ipf')
|
---|
36 |
|
---|
37 |
|
---|
38 | class CommonUtils:
|
---|
39 |
|
---|
40 | # Version and Copyright
|
---|
41 | VersionNumber = "0.01"
|
---|
42 | __version__ = "%prog Version " + VersionNumber
|
---|
43 | __copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved."
|
---|
44 | __usage__ = "%prog [options] source.asm [destination.nasm]"
|
---|
45 |
|
---|
46 | def __init__(self, clone=None):
|
---|
47 | if clone is None:
|
---|
48 | (self.Opt, self.Args) = self.ProcessCommandLine()
|
---|
49 | else:
|
---|
50 | (self.Opt, self.Args) = (clone.Opt, clone.Args)
|
---|
51 |
|
---|
52 | self.unsupportedSyntaxSeen = False
|
---|
53 | self.src = self.Args[0]
|
---|
54 | assert(os.path.exists(self.src))
|
---|
55 | self.dirmode = os.path.isdir(self.src)
|
---|
56 | srcExt = os.path.splitext(self.src)[1]
|
---|
57 | assert (self.dirmode or srcExt != '.nasm')
|
---|
58 | self.infmode = not self.dirmode and srcExt == '.inf'
|
---|
59 | self.diff = self.Opt.diff
|
---|
60 | self.git = self.Opt.git
|
---|
61 | self.force = self.Opt.force
|
---|
62 |
|
---|
63 | if clone is None:
|
---|
64 | self.rootdir = os.getcwd()
|
---|
65 | self.DetectGit()
|
---|
66 | else:
|
---|
67 | self.rootdir = clone.rootdir
|
---|
68 | self.gitdir = clone.gitdir
|
---|
69 | self.gitemail = clone.gitemail
|
---|
70 |
|
---|
71 | def ProcessCommandLine(self):
|
---|
72 | Parser = OptionParser(description=self.__copyright__,
|
---|
73 | version=self.__version__,
|
---|
74 | prog=sys.argv[0],
|
---|
75 | usage=self.__usage__
|
---|
76 | )
|
---|
77 | Parser.add_option("-q", "--quiet", action="store_true", type=None,
|
---|
78 | help="Disable all messages except FATAL ERRORS.")
|
---|
79 | Parser.add_option("--git", action="store_true", type=None,
|
---|
80 | help="Use git to create commits for each file converted")
|
---|
81 | Parser.add_option("--diff", action="store_true", type=None,
|
---|
82 | help="Show diff of conversion")
|
---|
83 | Parser.add_option("-f", "--force", action="store_true", type=None,
|
---|
84 | help="Force conversion even if unsupported")
|
---|
85 |
|
---|
86 | (Opt, Args) = Parser.parse_args()
|
---|
87 |
|
---|
88 | if not Opt.quiet:
|
---|
89 | print self.__copyright__
|
---|
90 | Parser.print_version()
|
---|
91 |
|
---|
92 | return (Opt, Args)
|
---|
93 |
|
---|
94 | def RootRelative(self, path):
|
---|
95 | result = path
|
---|
96 | if result.startswith(self.rootdir):
|
---|
97 | result = result[len(self.rootdir):]
|
---|
98 | while len(result) > 0 and result[0] in '/\\':
|
---|
99 | result = result[1:]
|
---|
100 | return result
|
---|
101 |
|
---|
102 | def MatchAndSetMo(self, regexp, string):
|
---|
103 | self.mo = regexp.match(string)
|
---|
104 | return self.mo is not None
|
---|
105 |
|
---|
106 | def SearchAndSetMo(self, regexp, string):
|
---|
107 | self.mo = regexp.search(string)
|
---|
108 | return self.mo is not None
|
---|
109 |
|
---|
110 | def ReplacePreserveSpacing(self, string, find, replace):
|
---|
111 | if len(find) >= len(replace):
|
---|
112 | padded = replace + (' ' * (len(find) - len(replace)))
|
---|
113 | return string.replace(find, padded)
|
---|
114 | elif find.find(replace) >= 0:
|
---|
115 | return string.replace(find, replace)
|
---|
116 | else:
|
---|
117 | lenDiff = len(replace) - len(find)
|
---|
118 | result = string
|
---|
119 | for i in range(lenDiff, -1, -1):
|
---|
120 | padded = find + (' ' * i)
|
---|
121 | result = result.replace(padded, replace)
|
---|
122 | return result
|
---|
123 |
|
---|
124 | def DetectGit(self):
|
---|
125 | lastpath = os.path.realpath(self.src)
|
---|
126 | self.gitdir = None
|
---|
127 | while True:
|
---|
128 | path = os.path.split(lastpath)[0]
|
---|
129 | if path == lastpath:
|
---|
130 | return
|
---|
131 | candidate = os.path.join(path, '.git')
|
---|
132 | if os.path.isdir(candidate):
|
---|
133 | self.gitdir = candidate
|
---|
134 | self.gitemail = self.FormatGitEmailAddress()
|
---|
135 | return
|
---|
136 | lastpath = path
|
---|
137 |
|
---|
138 | def FormatGitEmailAddress(self):
|
---|
139 | if not self.git or not self.gitdir:
|
---|
140 | return ''
|
---|
141 |
|
---|
142 | cmd = ('git', 'config', 'user.name')
|
---|
143 | name = self.RunAndCaptureOutput(cmd).strip()
|
---|
144 | cmd = ('git', 'config', 'user.email')
|
---|
145 | email = self.RunAndCaptureOutput(cmd).strip()
|
---|
146 | if name.find(',') >= 0:
|
---|
147 | name = '"' + name + '"'
|
---|
148 | return name + ' <' + email + '>'
|
---|
149 |
|
---|
150 | def RunAndCaptureOutput(self, cmd, checkExitCode=True, pipeIn=None):
|
---|
151 | if pipeIn:
|
---|
152 | subpStdin = subprocess.PIPE
|
---|
153 | else:
|
---|
154 | subpStdin = None
|
---|
155 | p = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stdin=subpStdin)
|
---|
156 | (stdout, stderr) = p.communicate(pipeIn)
|
---|
157 | if checkExitCode:
|
---|
158 | if p.returncode != 0:
|
---|
159 | print 'command:', ' '.join(cmd)
|
---|
160 | print 'stdout:', stdout
|
---|
161 | print 'stderr:', stderr
|
---|
162 | print 'return:', p.returncode
|
---|
163 | assert p.returncode == 0
|
---|
164 | return stdout
|
---|
165 |
|
---|
166 | def FileUpdated(self, path):
|
---|
167 | if not self.git or not self.gitdir:
|
---|
168 | return
|
---|
169 |
|
---|
170 | cmd = ('git', 'add', path)
|
---|
171 | self.RunAndCaptureOutput(cmd)
|
---|
172 |
|
---|
173 | def FileAdded(self, path):
|
---|
174 | self.FileUpdated(path)
|
---|
175 |
|
---|
176 | def RemoveFile(self, path):
|
---|
177 | if not self.git or not self.gitdir:
|
---|
178 | return
|
---|
179 |
|
---|
180 | cmd = ('git', 'rm', path)
|
---|
181 | self.RunAndCaptureOutput(cmd)
|
---|
182 |
|
---|
183 | def FileConversionFinished(self, pkg, module, src, dst):
|
---|
184 | if not self.git or not self.gitdir:
|
---|
185 | return
|
---|
186 |
|
---|
187 | if not self.Opt.quiet:
|
---|
188 | print 'Committing: Conversion of', dst
|
---|
189 |
|
---|
190 | prefix = ' '.join(filter(lambda a: a, [pkg, module]))
|
---|
191 | message = ''
|
---|
192 | if self.unsupportedSyntaxSeen:
|
---|
193 | message += 'ERROR! '
|
---|
194 | message += '%s: Convert %s to NASM\n' % (prefix, src)
|
---|
195 | message += '\n'
|
---|
196 | message += 'The %s script was used to convert\n' % sys.argv[0]
|
---|
197 | message += '%s to %s\n' % (src, dst)
|
---|
198 | message += '\n'
|
---|
199 | message += 'Contributed-under: TianoCore Contribution Agreement 1.0\n'
|
---|
200 | message += 'Signed-off-by: %s\n' % self.gitemail
|
---|
201 |
|
---|
202 | cmd = ('git', 'commit', '-F', '-')
|
---|
203 | self.RunAndCaptureOutput(cmd, pipeIn=message)
|
---|
204 |
|
---|
205 |
|
---|
206 | class ConvertAsmFile(CommonUtils):
|
---|
207 |
|
---|
208 | def __init__(self, src, dst, clone):
|
---|
209 | CommonUtils.__init__(self, clone)
|
---|
210 | self.ConvertAsmFile(src, dst)
|
---|
211 | self.FileAdded(dst)
|
---|
212 | self.RemoveFile(src)
|
---|
213 |
|
---|
214 | def ConvertAsmFile(self, inputFile, outputFile=None):
|
---|
215 | self.globals = set()
|
---|
216 | self.unsupportedSyntaxSeen = False
|
---|
217 | self.inputFilename = inputFile
|
---|
218 | if not outputFile:
|
---|
219 | outputFile = os.path.splitext(inputFile)[0] + '.nasm'
|
---|
220 | self.outputFilename = outputFile
|
---|
221 |
|
---|
222 | fullSrc = os.path.realpath(inputFile)
|
---|
223 | srcParentDir = os.path.basename(os.path.split(fullSrc)[0])
|
---|
224 | maybeArch = srcParentDir.lower()
|
---|
225 | if maybeArch in UnsupportedArch.unsupported:
|
---|
226 | raise UnsupportedArch
|
---|
227 | self.ia32 = maybeArch == 'ia32'
|
---|
228 | self.x64 = maybeArch == 'x64'
|
---|
229 |
|
---|
230 | self.inputFileBase = os.path.basename(self.inputFilename)
|
---|
231 | self.outputFileBase = os.path.basename(self.outputFilename)
|
---|
232 | if self.outputFilename == '-' and not self.diff:
|
---|
233 | self.output = sys.stdout
|
---|
234 | else:
|
---|
235 | self.output = StringIO.StringIO()
|
---|
236 | if not self.Opt.quiet:
|
---|
237 | dirpath, src = os.path.split(self.inputFilename)
|
---|
238 | dirpath = self.RootRelative(dirpath)
|
---|
239 | dst = os.path.basename(self.outputFilename)
|
---|
240 | print 'Converting:', dirpath, src, '->', dst
|
---|
241 | lines = open(self.inputFilename).readlines()
|
---|
242 | self.Convert(lines)
|
---|
243 | if self.outputFilename == '-':
|
---|
244 | if self.diff:
|
---|
245 | sys.stdout.write(self.output.getvalue())
|
---|
246 | self.output.close()
|
---|
247 | else:
|
---|
248 | f = open(self.outputFilename, 'wb')
|
---|
249 | f.write(self.output.getvalue())
|
---|
250 | f.close()
|
---|
251 | self.output.close()
|
---|
252 |
|
---|
253 | endOfLineRe = re.compile(r'''
|
---|
254 | \s* ( ; .* )? \n $
|
---|
255 | ''',
|
---|
256 | re.VERBOSE | re.MULTILINE
|
---|
257 | )
|
---|
258 | begOfLineRe = re.compile(r'''
|
---|
259 | \s*
|
---|
260 | ''',
|
---|
261 | re.VERBOSE
|
---|
262 | )
|
---|
263 |
|
---|
264 | def Convert(self, lines):
|
---|
265 | self.proc = None
|
---|
266 | self.anonLabelCount = -1
|
---|
267 | output = self.output
|
---|
268 | self.oldAsmEmptyLineCount = 0
|
---|
269 | self.newAsmEmptyLineCount = 0
|
---|
270 | for line in lines:
|
---|
271 | mo = self.begOfLineRe.search(line)
|
---|
272 | assert mo is not None
|
---|
273 | self.indent = mo.group()
|
---|
274 | lineWithoutBeginning = line[len(self.indent):]
|
---|
275 | mo = self.endOfLineRe.search(lineWithoutBeginning)
|
---|
276 | if mo is None:
|
---|
277 | endOfLine = ''
|
---|
278 | else:
|
---|
279 | endOfLine = mo.group()
|
---|
280 | oldAsm = line[len(self.indent):len(line) - len(endOfLine)]
|
---|
281 | self.originalLine = line.rstrip()
|
---|
282 | if line.strip() == '':
|
---|
283 | self.oldAsmEmptyLineCount += 1
|
---|
284 | self.TranslateAsm(oldAsm, endOfLine)
|
---|
285 | if line.strip() != '':
|
---|
286 | self.oldAsmEmptyLineCount = 0
|
---|
287 |
|
---|
288 | procDeclRe = re.compile(r'''
|
---|
289 | ([\w@][\w@0-9]*) \s+
|
---|
290 | PROC
|
---|
291 | (?: \s+ NEAR | FAR )?
|
---|
292 | (?: \s+ C )?
|
---|
293 | (?: \s+ (PUBLIC | PRIVATE) )?
|
---|
294 | (?: \s+ USES ( (?: \s+ \w[\w0-9]* )+ ) )?
|
---|
295 | \s* $
|
---|
296 | ''',
|
---|
297 | re.VERBOSE | re.IGNORECASE
|
---|
298 | )
|
---|
299 |
|
---|
300 | procEndRe = re.compile(r'''
|
---|
301 | ([\w@][\w@0-9]*) \s+
|
---|
302 | ENDP
|
---|
303 | \s* $
|
---|
304 | ''',
|
---|
305 | re.VERBOSE | re.IGNORECASE
|
---|
306 | )
|
---|
307 |
|
---|
308 | varAndTypeSubRe = r' (?: [\w@][\w@0-9]* ) (?: \s* : \s* \w+ )? '
|
---|
309 | publicRe = re.compile(r'''
|
---|
310 | PUBLIC \s+
|
---|
311 | ( %s (?: \s* , \s* %s )* )
|
---|
312 | \s* $
|
---|
313 | ''' % (varAndTypeSubRe, varAndTypeSubRe),
|
---|
314 | re.VERBOSE | re.IGNORECASE
|
---|
315 | )
|
---|
316 |
|
---|
317 | varAndTypeSubRe = re.compile(varAndTypeSubRe, re.VERBOSE | re.IGNORECASE)
|
---|
318 |
|
---|
319 | macroDeclRe = re.compile(r'''
|
---|
320 | ([\w@][\w@0-9]*) \s+
|
---|
321 | MACRO
|
---|
322 | \s* $
|
---|
323 | ''',
|
---|
324 | re.VERBOSE | re.IGNORECASE
|
---|
325 | )
|
---|
326 |
|
---|
327 | sectionDeclRe = re.compile(r'''
|
---|
328 | ([\w@][\w@0-9]*) \s+
|
---|
329 | ( SECTION | ENDS )
|
---|
330 | \s* $
|
---|
331 | ''',
|
---|
332 | re.VERBOSE | re.IGNORECASE
|
---|
333 | )
|
---|
334 |
|
---|
335 | externRe = re.compile(r'''
|
---|
336 | EXTE?RN \s+ (?: C \s+ )?
|
---|
337 | ([\w@][\w@0-9]*) \s* : \s* (\w+)
|
---|
338 | \s* $
|
---|
339 | ''',
|
---|
340 | re.VERBOSE | re.IGNORECASE
|
---|
341 | )
|
---|
342 |
|
---|
343 | externdefRe = re.compile(r'''
|
---|
344 | EXTERNDEF \s+ (?: C \s+ )?
|
---|
345 | ([\w@][\w@0-9]*) \s* : \s* (\w+)
|
---|
346 | \s* $
|
---|
347 | ''',
|
---|
348 | re.VERBOSE | re.IGNORECASE
|
---|
349 | )
|
---|
350 |
|
---|
351 | protoRe = re.compile(r'''
|
---|
352 | ([\w@][\w@0-9]*) \s+
|
---|
353 | PROTO
|
---|
354 | (?: \s+ .* )?
|
---|
355 | \s* $
|
---|
356 | ''',
|
---|
357 | re.VERBOSE | re.IGNORECASE
|
---|
358 | )
|
---|
359 |
|
---|
360 | defineDataRe = re.compile(r'''
|
---|
361 | ([\w@][\w@0-9]*) \s+
|
---|
362 | ( db | dw | dd | dq ) \s+
|
---|
363 | ( .*? )
|
---|
364 | \s* $
|
---|
365 | ''',
|
---|
366 | re.VERBOSE | re.IGNORECASE
|
---|
367 | )
|
---|
368 |
|
---|
369 | equRe = re.compile(r'''
|
---|
370 | ([\w@][\w@0-9]*) \s+ EQU \s+ (\S.*?)
|
---|
371 | \s* $
|
---|
372 | ''',
|
---|
373 | re.VERBOSE | re.IGNORECASE
|
---|
374 | )
|
---|
375 |
|
---|
376 | ignoreRe = re.compile(r'''
|
---|
377 | \. (?: const |
|
---|
378 | mmx |
|
---|
379 | model |
|
---|
380 | xmm |
|
---|
381 | x?list |
|
---|
382 | [3-6]86p?
|
---|
383 | ) |
|
---|
384 | page
|
---|
385 | (?: \s+ .* )?
|
---|
386 | \s* $
|
---|
387 | ''',
|
---|
388 | re.VERBOSE | re.IGNORECASE
|
---|
389 | )
|
---|
390 |
|
---|
391 | whitespaceRe = re.compile(r'\s+', re.MULTILINE)
|
---|
392 |
|
---|
393 | def TranslateAsm(self, oldAsm, endOfLine):
|
---|
394 | assert(oldAsm.strip() == oldAsm)
|
---|
395 |
|
---|
396 | endOfLine = endOfLine.replace(self.inputFileBase, self.outputFileBase)
|
---|
397 |
|
---|
398 | oldOp = oldAsm.split()
|
---|
399 | if len(oldOp) >= 1:
|
---|
400 | oldOp = oldOp[0]
|
---|
401 | else:
|
---|
402 | oldOp = ''
|
---|
403 |
|
---|
404 | if oldAsm == '':
|
---|
405 | newAsm = oldAsm
|
---|
406 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
407 | elif oldOp in ('#include', ):
|
---|
408 | newAsm = oldAsm
|
---|
409 | self.EmitLine(oldAsm + endOfLine)
|
---|
410 | elif oldOp.lower() in ('end', 'title', 'text'):
|
---|
411 | newAsm = ''
|
---|
412 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
413 | elif oldAsm.lower() == '@@:':
|
---|
414 | self.anonLabelCount += 1
|
---|
415 | self.EmitLine(self.anonLabel(self.anonLabelCount) + ':')
|
---|
416 | elif self.MatchAndSetMo(self.ignoreRe, oldAsm):
|
---|
417 | newAsm = ''
|
---|
418 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
419 | elif oldAsm.lower() == 'ret':
|
---|
420 | for i in range(len(self.uses) - 1, -1, -1):
|
---|
421 | register = self.uses[i]
|
---|
422 | self.EmitNewContent('pop ' + register)
|
---|
423 | newAsm = 'ret'
|
---|
424 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
425 | self.uses = tuple()
|
---|
426 | elif oldOp.lower() == 'lea':
|
---|
427 | newAsm = self.ConvertLea(oldAsm)
|
---|
428 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
429 | elif oldAsm.lower() == 'end':
|
---|
430 | newAsm = ''
|
---|
431 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
432 | self.uses = tuple()
|
---|
433 | elif self.MatchAndSetMo(self.equRe, oldAsm):
|
---|
434 | equ = self.mo.group(1)
|
---|
435 | newAsm = '%%define %s %s' % (equ, self.mo.group(2))
|
---|
436 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
437 | elif self.MatchAndSetMo(self.externRe, oldAsm) or \
|
---|
438 | self.MatchAndSetMo(self.protoRe, oldAsm):
|
---|
439 | extern = self.mo.group(1)
|
---|
440 | self.NewGlobal(extern)
|
---|
441 | newAsm = 'extern ' + extern
|
---|
442 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
443 | elif self.MatchAndSetMo(self.externdefRe, oldAsm):
|
---|
444 | newAsm = ''
|
---|
445 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
446 | elif self.MatchAndSetMo(self.macroDeclRe, oldAsm):
|
---|
447 | newAsm = '%%macro %s 0' % self.mo.group(1)
|
---|
448 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
449 | elif oldOp.lower() == 'endm':
|
---|
450 | newAsm = r'%endmacro'
|
---|
451 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
452 | elif self.MatchAndSetMo(self.sectionDeclRe, oldAsm):
|
---|
453 | name = self.mo.group(1)
|
---|
454 | ty = self.mo.group(2)
|
---|
455 | if ty.lower() == 'section':
|
---|
456 | newAsm = '.' + name
|
---|
457 | else:
|
---|
458 | newAsm = ''
|
---|
459 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
460 | elif self.MatchAndSetMo(self.procDeclRe, oldAsm):
|
---|
461 | proc = self.proc = self.mo.group(1)
|
---|
462 | visibility = self.mo.group(2)
|
---|
463 | if visibility is None:
|
---|
464 | visibility = ''
|
---|
465 | else:
|
---|
466 | visibility = visibility.lower()
|
---|
467 | if visibility != 'private':
|
---|
468 | self.NewGlobal(self.proc)
|
---|
469 | proc = 'ASM_PFX(' + proc + ')'
|
---|
470 | self.EmitNewContent('global ' + proc)
|
---|
471 | newAsm = proc + ':'
|
---|
472 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
473 | uses = self.mo.group(3)
|
---|
474 | if uses is not None:
|
---|
475 | uses = filter(None, uses.split())
|
---|
476 | else:
|
---|
477 | uses = tuple()
|
---|
478 | self.uses = uses
|
---|
479 | for register in self.uses:
|
---|
480 | self.EmitNewContent(' push ' + register)
|
---|
481 | elif self.MatchAndSetMo(self.procEndRe, oldAsm):
|
---|
482 | newAsm = ''
|
---|
483 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
484 | elif self.MatchAndSetMo(self.publicRe, oldAsm):
|
---|
485 | publics = re.findall(self.varAndTypeSubRe, self.mo.group(1))
|
---|
486 | publics = map(lambda p: p.split(':')[0].strip(), publics)
|
---|
487 | for i in range(len(publics) - 1):
|
---|
488 | name = publics[i]
|
---|
489 | self.EmitNewContent('global ASM_PFX(%s)' % publics[i])
|
---|
490 | self.NewGlobal(name)
|
---|
491 | name = publics[-1]
|
---|
492 | self.NewGlobal(name)
|
---|
493 | newAsm = 'global ASM_PFX(%s)' % name
|
---|
494 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
495 | elif self.MatchAndSetMo(self.defineDataRe, oldAsm):
|
---|
496 | name = self.mo.group(1)
|
---|
497 | ty = self.mo.group(2)
|
---|
498 | value = self.mo.group(3)
|
---|
499 | if value == '?':
|
---|
500 | value = 0
|
---|
501 | newAsm = '%s: %s %s' % (name, ty, value)
|
---|
502 | newAsm = self.CommonConversions(newAsm)
|
---|
503 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
504 | else:
|
---|
505 | newAsm = self.CommonConversions(oldAsm)
|
---|
506 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
507 |
|
---|
508 | def NewGlobal(self, name):
|
---|
509 | regex = re.compile(r'(?<![_\w\d])(?<!ASM_PFX\()(' + re.escape(name) +
|
---|
510 | r')(?![_\w\d])')
|
---|
511 | self.globals.add(regex)
|
---|
512 |
|
---|
513 | def ConvertAnonymousLabels(self, oldAsm):
|
---|
514 | newAsm = oldAsm
|
---|
515 | anonLabel = self.anonLabel(self.anonLabelCount)
|
---|
516 | newAsm = newAsm.replace('@b', anonLabel)
|
---|
517 | newAsm = newAsm.replace('@B', anonLabel)
|
---|
518 | anonLabel = self.anonLabel(self.anonLabelCount + 1)
|
---|
519 | newAsm = newAsm.replace('@f', anonLabel)
|
---|
520 | newAsm = newAsm.replace('@F', anonLabel)
|
---|
521 | return newAsm
|
---|
522 |
|
---|
523 | def anonLabel(self, count):
|
---|
524 | return '.%d' % count
|
---|
525 |
|
---|
526 | def EmitString(self, string):
|
---|
527 | self.output.write(string)
|
---|
528 |
|
---|
529 | def EmitLineWithDiff(self, old, new):
|
---|
530 | newLine = (self.indent + new).rstrip()
|
---|
531 | if self.diff:
|
---|
532 | if old is None:
|
---|
533 | print '+%s' % newLine
|
---|
534 | elif newLine != old:
|
---|
535 | print '-%s' % old
|
---|
536 | print '+%s' % newLine
|
---|
537 | else:
|
---|
538 | print '', newLine
|
---|
539 | if newLine != '':
|
---|
540 | self.newAsmEmptyLineCount = 0
|
---|
541 | self.EmitString(newLine + '\r\n')
|
---|
542 |
|
---|
543 | def EmitLine(self, string):
|
---|
544 | self.EmitLineWithDiff(self.originalLine, string)
|
---|
545 |
|
---|
546 | def EmitNewContent(self, string):
|
---|
547 | self.EmitLineWithDiff(None, string)
|
---|
548 |
|
---|
549 | def EmitAsmReplaceOp(self, oldAsm, oldOp, newOp, endOfLine):
|
---|
550 | newAsm = oldAsm.replace(oldOp, newOp, 1)
|
---|
551 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
552 |
|
---|
553 | hexNumRe = re.compile(r'0*((?=[\da-f])\d*(?<=\d)[\da-f]*)h', re.IGNORECASE)
|
---|
554 |
|
---|
555 | def EmitAsmWithComment(self, oldAsm, newAsm, endOfLine):
|
---|
556 | for glblRe in self.globals:
|
---|
557 | newAsm = glblRe.sub(r'ASM_PFX(\1)', newAsm)
|
---|
558 |
|
---|
559 | newAsm = self.hexNumRe.sub(r'0x\1', newAsm)
|
---|
560 |
|
---|
561 | newLine = newAsm + endOfLine
|
---|
562 | emitNewLine = ((newLine.strip() != '') or
|
---|
563 | ((oldAsm + endOfLine).strip() == ''))
|
---|
564 | if emitNewLine and newLine.strip() == '':
|
---|
565 | self.newAsmEmptyLineCount += 1
|
---|
566 | if self.newAsmEmptyLineCount > 1:
|
---|
567 | emitNewLine = False
|
---|
568 | if emitNewLine:
|
---|
569 | self.EmitLine(newLine.rstrip())
|
---|
570 | elif self.diff:
|
---|
571 | print '-%s' % self.originalLine
|
---|
572 |
|
---|
573 | leaRe = re.compile(r'''
|
---|
574 | (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)
|
---|
575 | \s* $
|
---|
576 | ''',
|
---|
577 | re.VERBOSE | re.IGNORECASE
|
---|
578 | )
|
---|
579 |
|
---|
580 | def ConvertLea(self, oldAsm):
|
---|
581 | newAsm = oldAsm
|
---|
582 | if self.MatchAndSetMo(self.leaRe, oldAsm):
|
---|
583 | lea = self.mo.group(1)
|
---|
584 | dst = self.mo.group(2)
|
---|
585 | src = self.mo.group(3)
|
---|
586 | if src.find('[') < 0:
|
---|
587 | src = '[' + src + ']'
|
---|
588 | newAsm = lea + dst + ', ' + src
|
---|
589 | newAsm = self.CommonConversions(newAsm)
|
---|
590 | return newAsm
|
---|
591 |
|
---|
592 | ptrRe = re.compile(r'''
|
---|
593 | (?<! \S )
|
---|
594 | ([dfq]?word|byte) \s+ (?: ptr ) (\s*)
|
---|
595 | (?= [[\s] )
|
---|
596 | ''',
|
---|
597 | re.VERBOSE | re.IGNORECASE
|
---|
598 | )
|
---|
599 |
|
---|
600 | def ConvertPtr(self, oldAsm):
|
---|
601 | newAsm = oldAsm
|
---|
602 | while self.SearchAndSetMo(self.ptrRe, newAsm):
|
---|
603 | ty = self.mo.group(1)
|
---|
604 | if ty.lower() == 'fword':
|
---|
605 | ty = ''
|
---|
606 | else:
|
---|
607 | ty += self.mo.group(2)
|
---|
608 | newAsm = newAsm[:self.mo.start(0)] + ty + newAsm[self.mo.end(0):]
|
---|
609 | return newAsm
|
---|
610 |
|
---|
611 | labelByteRe = re.compile(r'''
|
---|
612 | (?: \s+ label \s+ (?: [dfq]?word | byte ) )
|
---|
613 | (?! \S )
|
---|
614 | ''',
|
---|
615 | re.VERBOSE | re.IGNORECASE
|
---|
616 | )
|
---|
617 |
|
---|
618 | def ConvertLabelByte(self, oldAsm):
|
---|
619 | newAsm = oldAsm
|
---|
620 | if self.SearchAndSetMo(self.labelByteRe, newAsm):
|
---|
621 | newAsm = newAsm[:self.mo.start(0)] + ':' + newAsm[self.mo.end(0):]
|
---|
622 | return newAsm
|
---|
623 |
|
---|
624 | unaryBitwiseOpRe = re.compile(r'''
|
---|
625 | ( NOT )
|
---|
626 | (?= \s+ \S )
|
---|
627 | ''',
|
---|
628 | re.VERBOSE | re.IGNORECASE
|
---|
629 | )
|
---|
630 | binaryBitwiseOpRe = re.compile(r'''
|
---|
631 | ( \S \s+ )
|
---|
632 | ( AND | OR | SHL | SHR )
|
---|
633 | (?= \s+ \S )
|
---|
634 | ''',
|
---|
635 | re.VERBOSE | re.IGNORECASE
|
---|
636 | )
|
---|
637 | bitwiseOpReplacements = {
|
---|
638 | 'not': '~',
|
---|
639 | 'and': '&',
|
---|
640 | 'shl': '<<',
|
---|
641 | 'shr': '>>',
|
---|
642 | 'or': '|',
|
---|
643 | }
|
---|
644 |
|
---|
645 | def ConvertBitwiseOp(self, oldAsm):
|
---|
646 | newAsm = oldAsm
|
---|
647 | while self.SearchAndSetMo(self.binaryBitwiseOpRe, newAsm):
|
---|
648 | prefix = self.mo.group(1)
|
---|
649 | op = self.bitwiseOpReplacements[self.mo.group(2).lower()]
|
---|
650 | newAsm = newAsm[:self.mo.start(0)] + prefix + op + \
|
---|
651 | newAsm[self.mo.end(0):]
|
---|
652 | while self.SearchAndSetMo(self.unaryBitwiseOpRe, newAsm):
|
---|
653 | op = self.bitwiseOpReplacements[self.mo.group(1).lower()]
|
---|
654 | newAsm = newAsm[:self.mo.start(0)] + op + newAsm[self.mo.end(0):]
|
---|
655 | return newAsm
|
---|
656 |
|
---|
657 | sectionRe = re.compile(r'''
|
---|
658 | \. ( code |
|
---|
659 | data
|
---|
660 | )
|
---|
661 | (?: \s+ .* )?
|
---|
662 | \s* $
|
---|
663 | ''',
|
---|
664 | re.VERBOSE | re.IGNORECASE
|
---|
665 | )
|
---|
666 |
|
---|
667 | segmentRe = re.compile(r'''
|
---|
668 | ( code |
|
---|
669 | data )
|
---|
670 | (?: \s+ SEGMENT )
|
---|
671 | (?: \s+ .* )?
|
---|
672 | \s* $
|
---|
673 | ''',
|
---|
674 | re.VERBOSE | re.IGNORECASE
|
---|
675 | )
|
---|
676 |
|
---|
677 | def ConvertSection(self, oldAsm):
|
---|
678 | newAsm = oldAsm
|
---|
679 | if self.MatchAndSetMo(self.sectionRe, newAsm) or \
|
---|
680 | self.MatchAndSetMo(self.segmentRe, newAsm):
|
---|
681 | name = self.mo.group(1).lower()
|
---|
682 | if name == 'code':
|
---|
683 | if self.x64:
|
---|
684 | self.EmitLine('DEFAULT REL')
|
---|
685 | name = 'text'
|
---|
686 | newAsm = 'SECTION .' + name
|
---|
687 | return newAsm
|
---|
688 |
|
---|
689 | fwordRe = re.compile(r'''
|
---|
690 | (?<! \S )
|
---|
691 | fword
|
---|
692 | (?! \S )
|
---|
693 | ''',
|
---|
694 | re.VERBOSE | re.IGNORECASE
|
---|
695 | )
|
---|
696 |
|
---|
697 | def FwordUnsupportedCheck(self, oldAsm):
|
---|
698 | newAsm = oldAsm
|
---|
699 | if self.SearchAndSetMo(self.fwordRe, newAsm):
|
---|
700 | newAsm = self.Unsupported(newAsm, 'fword used')
|
---|
701 | return newAsm
|
---|
702 |
|
---|
703 | __common_conversion_routines__ = (
|
---|
704 | ConvertAnonymousLabels,
|
---|
705 | ConvertPtr,
|
---|
706 | FwordUnsupportedCheck,
|
---|
707 | ConvertBitwiseOp,
|
---|
708 | ConvertLabelByte,
|
---|
709 | ConvertSection,
|
---|
710 | )
|
---|
711 |
|
---|
712 | def CommonConversions(self, oldAsm):
|
---|
713 | newAsm = oldAsm
|
---|
714 | for conv in self.__common_conversion_routines__:
|
---|
715 | newAsm = conv(self, newAsm)
|
---|
716 | return newAsm
|
---|
717 |
|
---|
718 | def Unsupported(self, asm, message=None):
|
---|
719 | if not self.force:
|
---|
720 | raise UnsupportedConversion
|
---|
721 |
|
---|
722 | self.unsupportedSyntaxSeen = True
|
---|
723 | newAsm = '%error conversion unsupported'
|
---|
724 | if message:
|
---|
725 | newAsm += '; ' + message
|
---|
726 | newAsm += ': ' + asm
|
---|
727 | return newAsm
|
---|
728 |
|
---|
729 |
|
---|
730 | class ConvertInfFile(CommonUtils):
|
---|
731 |
|
---|
732 | def __init__(self, inf, clone):
|
---|
733 | CommonUtils.__init__(self, clone)
|
---|
734 | self.inf = inf
|
---|
735 | self.ScanInfAsmFiles()
|
---|
736 | if self.infmode:
|
---|
737 | self.ConvertInfAsmFiles()
|
---|
738 |
|
---|
739 | infSrcRe = re.compile(r'''
|
---|
740 | \s*
|
---|
741 | ( [\w@][\w@0-9/]* \.(asm|s) )
|
---|
742 | \s* (?: \| [^#]* )?
|
---|
743 | \s* (?: \# .* )?
|
---|
744 | $
|
---|
745 | ''',
|
---|
746 | re.VERBOSE | re.IGNORECASE
|
---|
747 | )
|
---|
748 |
|
---|
749 | def GetInfAsmFileMapping(self):
|
---|
750 | srcToDst = {'order': []}
|
---|
751 | for line in self.lines:
|
---|
752 | line = line.rstrip()
|
---|
753 | if self.MatchAndSetMo(self.infSrcRe, line):
|
---|
754 | src = self.mo.group(1)
|
---|
755 | srcExt = self.mo.group(2)
|
---|
756 | dst = os.path.splitext(src)[0] + '.nasm'
|
---|
757 | if src not in srcToDst:
|
---|
758 | srcToDst[src] = dst
|
---|
759 | srcToDst['order'].append(src)
|
---|
760 | return srcToDst
|
---|
761 |
|
---|
762 | def ScanInfAsmFiles(self):
|
---|
763 | src = self.inf
|
---|
764 | assert os.path.isfile(src)
|
---|
765 | f = open(src)
|
---|
766 | self.lines = f.readlines()
|
---|
767 | f.close()
|
---|
768 |
|
---|
769 | path = os.path.realpath(self.inf)
|
---|
770 | (self.dir, inf) = os.path.split(path)
|
---|
771 | parent = os.path.normpath(self.dir)
|
---|
772 | (lastpath, self.moduleName) = os.path.split(parent)
|
---|
773 | self.packageName = None
|
---|
774 | while True:
|
---|
775 | lastpath = os.path.normpath(lastpath)
|
---|
776 | (parent, basename) = os.path.split(lastpath)
|
---|
777 | if parent == lastpath:
|
---|
778 | break
|
---|
779 | if basename.endswith('Pkg'):
|
---|
780 | self.packageName = basename
|
---|
781 | break
|
---|
782 | lastpath = parent
|
---|
783 |
|
---|
784 | self.srcToDst = self.GetInfAsmFileMapping()
|
---|
785 |
|
---|
786 | self.dstToSrc = {'order': []}
|
---|
787 | for src in self.srcToDst['order']:
|
---|
788 | srcExt = os.path.splitext(src)[1]
|
---|
789 | dst = self.srcToDst[src]
|
---|
790 | if dst not in self.dstToSrc:
|
---|
791 | self.dstToSrc[dst] = [src]
|
---|
792 | self.dstToSrc['order'].append(dst)
|
---|
793 | else:
|
---|
794 | self.dstToSrc[dst].append(src)
|
---|
795 |
|
---|
796 | def __len__(self):
|
---|
797 | return len(self.dstToSrc['order'])
|
---|
798 |
|
---|
799 | def __iter__(self):
|
---|
800 | return iter(self.dstToSrc['order'])
|
---|
801 |
|
---|
802 | def ConvertInfAsmFiles(self):
|
---|
803 | notConverted = []
|
---|
804 | unsupportedArchCount = 0
|
---|
805 | for dst in self:
|
---|
806 | didSomething = False
|
---|
807 | fileChanged = self.UpdateInfAsmFile(dst)
|
---|
808 | try:
|
---|
809 | self.UpdateInfAsmFile(dst)
|
---|
810 | didSomething = True
|
---|
811 | except UnsupportedConversion:
|
---|
812 | if not self.Opt.quiet:
|
---|
813 | print 'MASM=>NASM conversion unsupported for', dst
|
---|
814 | notConverted.append(dst)
|
---|
815 | except NoSourceFile:
|
---|
816 | if not self.Opt.quiet:
|
---|
817 | print 'Source file missing for', reldst
|
---|
818 | notConverted.append(dst)
|
---|
819 | except UnsupportedArch:
|
---|
820 | unsupportedArchCount += 1
|
---|
821 | else:
|
---|
822 | if didSomething:
|
---|
823 | self.ConversionFinished(dst)
|
---|
824 | if len(notConverted) > 0 and not self.Opt.quiet:
|
---|
825 | for dst in notConverted:
|
---|
826 | reldst = self.RootRelative(dst)
|
---|
827 | print 'Unabled to convert', reldst
|
---|
828 | if unsupportedArchCount > 0 and not self.Opt.quiet:
|
---|
829 | print 'Skipped', unsupportedArchCount, 'files based on architecture'
|
---|
830 |
|
---|
831 | def UpdateInfAsmFile(self, dst, IgnoreMissingAsm=False):
|
---|
832 | infPath = os.path.split(os.path.realpath(self.inf))[0]
|
---|
833 | asmSrc = os.path.splitext(dst)[0] + '.asm'
|
---|
834 | fullSrc = os.path.join(infPath, asmSrc)
|
---|
835 | fullDst = os.path.join(infPath, dst)
|
---|
836 | srcParentDir = os.path.basename(os.path.split(fullSrc)[0])
|
---|
837 | if srcParentDir.lower() in UnsupportedArch.unsupported:
|
---|
838 | raise UnsupportedArch
|
---|
839 | elif not os.path.exists(fullSrc):
|
---|
840 | if not IgnoreMissingAsm:
|
---|
841 | raise NoSourceFile
|
---|
842 | else: # not os.path.exists(fullDst):
|
---|
843 | conv = ConvertAsmFile(fullSrc, fullDst, self)
|
---|
844 | self.unsupportedSyntaxSeen = conv.unsupportedSyntaxSeen
|
---|
845 |
|
---|
846 | lastLine = ''
|
---|
847 | fileChanged = False
|
---|
848 | for i in range(len(self.lines)):
|
---|
849 | line = self.lines[i].rstrip()
|
---|
850 | updatedLine = line
|
---|
851 | for src in self.dstToSrc[dst]:
|
---|
852 | assert self.srcToDst[src] == dst
|
---|
853 | updatedLine = self.ReplacePreserveSpacing(
|
---|
854 | updatedLine, src, dst)
|
---|
855 |
|
---|
856 | lineChanged = updatedLine != line
|
---|
857 | if lineChanged:
|
---|
858 | if lastLine.strip() == updatedLine.strip():
|
---|
859 | self.lines[i] = None
|
---|
860 | else:
|
---|
861 | self.lines[i] = updatedLine + '\r\n'
|
---|
862 |
|
---|
863 | if self.diff:
|
---|
864 | if lineChanged:
|
---|
865 | print '-%s' % line
|
---|
866 | if self.lines[i] is not None:
|
---|
867 | print '+%s' % updatedLine
|
---|
868 | else:
|
---|
869 | print '', line
|
---|
870 |
|
---|
871 | fileChanged |= lineChanged
|
---|
872 | if self.lines[i] is not None:
|
---|
873 | lastLine = self.lines[i]
|
---|
874 |
|
---|
875 | if fileChanged:
|
---|
876 | self.lines = filter(lambda l: l is not None, self.lines)
|
---|
877 |
|
---|
878 | for src in self.dstToSrc[dst]:
|
---|
879 | if not src.endswith('.asm'):
|
---|
880 | fullSrc = os.path.join(infPath, src)
|
---|
881 | if os.path.exists(fullSrc):
|
---|
882 | self.RemoveFile(fullSrc)
|
---|
883 |
|
---|
884 | if fileChanged:
|
---|
885 | f = open(self.inf, 'wb')
|
---|
886 | f.writelines(self.lines)
|
---|
887 | f.close()
|
---|
888 | self.FileUpdated(self.inf)
|
---|
889 |
|
---|
890 | def ConversionFinished(self, dst):
|
---|
891 | asmSrc = os.path.splitext(dst)[0] + '.asm'
|
---|
892 | self.FileConversionFinished(
|
---|
893 | self.packageName, self.moduleName, asmSrc, dst)
|
---|
894 |
|
---|
895 |
|
---|
896 | class ConvertInfFiles(CommonUtils):
|
---|
897 |
|
---|
898 | def __init__(self, infs, clone):
|
---|
899 | CommonUtils.__init__(self, clone)
|
---|
900 | infs = map(lambda i: ConvertInfFile(i, self), infs)
|
---|
901 | infs = filter(lambda i: len(i) > 0, infs)
|
---|
902 | dstToInfs = {'order': []}
|
---|
903 | for inf in infs:
|
---|
904 | for dst in inf:
|
---|
905 | fulldst = os.path.realpath(os.path.join(inf.dir, dst))
|
---|
906 | pair = (inf, dst)
|
---|
907 | if fulldst in dstToInfs:
|
---|
908 | dstToInfs[fulldst].append(pair)
|
---|
909 | else:
|
---|
910 | dstToInfs['order'].append(fulldst)
|
---|
911 | dstToInfs[fulldst] = [pair]
|
---|
912 |
|
---|
913 | notConverted = []
|
---|
914 | unsupportedArchCount = 0
|
---|
915 | for dst in dstToInfs['order']:
|
---|
916 | didSomething = False
|
---|
917 | try:
|
---|
918 | for inf, reldst in dstToInfs[dst]:
|
---|
919 | inf.UpdateInfAsmFile(reldst, IgnoreMissingAsm=didSomething)
|
---|
920 | didSomething = True
|
---|
921 | except UnsupportedConversion:
|
---|
922 | if not self.Opt.quiet:
|
---|
923 | print 'MASM=>NASM conversion unsupported for', reldst
|
---|
924 | notConverted.append(dst)
|
---|
925 | except NoSourceFile:
|
---|
926 | if not self.Opt.quiet:
|
---|
927 | print 'Source file missing for', reldst
|
---|
928 | notConverted.append(dst)
|
---|
929 | except UnsupportedArch:
|
---|
930 | unsupportedArchCount += 1
|
---|
931 | else:
|
---|
932 | if didSomething:
|
---|
933 | inf.ConversionFinished(reldst)
|
---|
934 | if len(notConverted) > 0 and not self.Opt.quiet:
|
---|
935 | for dst in notConverted:
|
---|
936 | reldst = self.RootRelative(dst)
|
---|
937 | print 'Unabled to convert', reldst
|
---|
938 | if unsupportedArchCount > 0 and not self.Opt.quiet:
|
---|
939 | print 'Skipped', unsupportedArchCount, 'files based on architecture'
|
---|
940 |
|
---|
941 |
|
---|
942 | class ConvertDirectories(CommonUtils):
|
---|
943 |
|
---|
944 | def __init__(self, paths, clone):
|
---|
945 | CommonUtils.__init__(self, clone)
|
---|
946 | self.paths = paths
|
---|
947 | self.ConvertInfAndAsmFiles()
|
---|
948 |
|
---|
949 | def ConvertInfAndAsmFiles(self):
|
---|
950 | infs = list()
|
---|
951 | for path in self.paths:
|
---|
952 | assert(os.path.exists(path))
|
---|
953 | for path in self.paths:
|
---|
954 | for root, dirs, files in os.walk(path):
|
---|
955 | for d in ('.svn', '.git'):
|
---|
956 | if d in dirs:
|
---|
957 | dirs.remove(d)
|
---|
958 | for f in files:
|
---|
959 | if f.lower().endswith('.inf'):
|
---|
960 | inf = os.path.realpath(os.path.join(root, f))
|
---|
961 | infs.append(inf)
|
---|
962 |
|
---|
963 | ConvertInfFiles(infs, self)
|
---|
964 |
|
---|
965 |
|
---|
966 | class ConvertAsmApp(CommonUtils):
|
---|
967 |
|
---|
968 | def __init__(self):
|
---|
969 | CommonUtils.__init__(self)
|
---|
970 |
|
---|
971 | numArgs = len(self.Args)
|
---|
972 | assert(numArgs >= 1)
|
---|
973 | if self.infmode:
|
---|
974 | ConvertInfFiles(self.Args, self)
|
---|
975 | elif self.dirmode:
|
---|
976 | ConvertDirectories(self.Args, self)
|
---|
977 | elif not self.dirmode:
|
---|
978 | assert(numArgs <= 2)
|
---|
979 | src = self.Args[0]
|
---|
980 | if numArgs > 1:
|
---|
981 | dst = self.Args[1]
|
---|
982 | else:
|
---|
983 | dst = None
|
---|
984 | ConvertAsmFile(src, dst, self)
|
---|
985 |
|
---|
986 | ConvertAsmApp()
|
---|