]> git.proxmox.com Git - mirror_edk2.git/commitdiff
BaseTools: Add ConvertMasmToNasm.py script
authorJordan Justen <jordan.l.justen@intel.com>
Fri, 31 Oct 2014 19:55:15 +0000 (19:55 +0000)
committerjljusten <jljusten@Edk2>
Fri, 31 Oct 2014 19:55:15 +0000 (19:55 +0000)
This script is intended to assist with MASM to NASM syntax
conversions.

The output should be manually inspected and adjusted as needed, since
this script does not provide a perfect conversion.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Acked-by: Yingke D Liu <yingke.d.liu@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16285 6f19259b-4bc3-4df7-8a09-765794883524

BaseTools/Scripts/ConvertMasmToNasm.py [new file with mode: 0755]

diff --git a/BaseTools/Scripts/ConvertMasmToNasm.py b/BaseTools/Scripts/ConvertMasmToNasm.py
new file mode 100755 (executable)
index 0000000..7ad0bd2
--- /dev/null
@@ -0,0 +1,986 @@
+# @file ConvertMasmToNasm.py\r
+# This script assists with conversion of MASM assembly syntax to NASM\r
+#\r
+#  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+#\r
+# Import Modules\r
+#\r
+import os.path\r
+import re\r
+import StringIO\r
+import subprocess\r
+import sys\r
+from optparse import OptionParser\r
+\r
+\r
+class UnsupportedConversion(Exception):\r
+    pass\r
+\r
+\r
+class NoSourceFile(Exception):\r
+    pass\r
+\r
+\r
+class UnsupportedArch(Exception):\r
+    unsupported = ('aarch64', 'arm', 'ebc', 'ipf')\r
+\r
+\r
+class CommonUtils:\r
+\r
+    # Version and Copyright\r
+    VersionNumber = "0.01"\r
+    __version__ = "%prog Version " + VersionNumber\r
+    __copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved."\r
+    __usage__ = "%prog [options] source.asm [destination.nasm]"\r
+\r
+    def __init__(self, clone=None):\r
+        if clone is None:\r
+            (self.Opt, self.Args) = self.ProcessCommandLine()\r
+        else:\r
+            (self.Opt, self.Args) = (clone.Opt, clone.Args)\r
+\r
+        self.unsupportedSyntaxSeen = False\r
+        self.src = self.Args[0]\r
+        assert(os.path.exists(self.src))\r
+        self.dirmode = os.path.isdir(self.src)\r
+        srcExt = os.path.splitext(self.src)[1]\r
+        assert (self.dirmode or srcExt != '.nasm')\r
+        self.infmode = not self.dirmode and srcExt == '.inf'\r
+        self.diff = self.Opt.diff\r
+        self.git = self.Opt.git\r
+        self.force = self.Opt.force\r
+\r
+        if clone is None:\r
+            self.rootdir = os.getcwd()\r
+            self.DetectGit()\r
+        else:\r
+            self.rootdir = clone.rootdir\r
+            self.gitdir = clone.gitdir\r
+            self.gitemail = clone.gitemail\r
+\r
+    def ProcessCommandLine(self):\r
+        Parser = OptionParser(description=self.__copyright__,\r
+                              version=self.__version__,\r
+                              prog=sys.argv[0],\r
+                              usage=self.__usage__\r
+                              )\r
+        Parser.add_option("-q", "--quiet", action="store_true", type=None,\r
+                          help="Disable all messages except FATAL ERRORS.")\r
+        Parser.add_option("--git", action="store_true", type=None,\r
+                          help="Use git to create commits for each file converted")\r
+        Parser.add_option("--diff", action="store_true", type=None,\r
+                          help="Show diff of conversion")\r
+        Parser.add_option("-f", "--force", action="store_true", type=None,\r
+                          help="Force conversion even if unsupported")\r
+\r
+        (Opt, Args) = Parser.parse_args()\r
+\r
+        if not Opt.quiet:\r
+            print self.__copyright__\r
+            Parser.print_version()\r
+\r
+        return (Opt, Args)\r
+\r
+    def RootRelative(self, path):\r
+        result = path\r
+        if result.startswith(self.rootdir):\r
+            result = result[len(self.rootdir):]\r
+            while len(result) > 0 and result[0] in '/\\':\r
+                result = result[1:]\r
+        return result\r
+\r
+    def MatchAndSetMo(self, regexp, string):\r
+        self.mo = regexp.match(string)\r
+        return self.mo is not None\r
+\r
+    def SearchAndSetMo(self, regexp, string):\r
+        self.mo = regexp.search(string)\r
+        return self.mo is not None\r
+\r
+    def ReplacePreserveSpacing(self, string, find, replace):\r
+        if len(find) >= len(replace):\r
+            padded = replace + (' ' * (len(find) - len(replace)))\r
+            return string.replace(find, padded)\r
+        elif find.find(replace) >= 0:\r
+            return string.replace(find, replace)\r
+        else:\r
+            lenDiff = len(replace) - len(find)\r
+            result = string\r
+            for i in range(lenDiff, -1, -1):\r
+                padded = find + (' ' * i)\r
+                result = result.replace(padded, replace)\r
+            return result\r
+\r
+    def DetectGit(self):\r
+        lastpath = os.path.realpath(self.src)\r
+        self.gitdir = None\r
+        while True:\r
+            path = os.path.split(lastpath)[0]\r
+            if path == lastpath:\r
+                return\r
+            candidate = os.path.join(path, '.git')\r
+            if os.path.isdir(candidate):\r
+                self.gitdir = candidate\r
+                self.gitemail = self.FormatGitEmailAddress()\r
+                return\r
+            lastpath = path\r
+\r
+    def FormatGitEmailAddress(self):\r
+        if not self.git or not self.gitdir:\r
+            return ''\r
+\r
+        cmd = ('git', 'config', 'user.name')\r
+        name = self.RunAndCaptureOutput(cmd).strip()\r
+        cmd = ('git', 'config', 'user.email')\r
+        email = self.RunAndCaptureOutput(cmd).strip()\r
+        if name.find(',') >= 0:\r
+            name = '"' + name + '"'\r
+        return name + ' <' + email + '>'\r
+\r
+    def RunAndCaptureOutput(self, cmd, checkExitCode=True, pipeIn=None):\r
+        if pipeIn:\r
+            subpStdin = subprocess.PIPE\r
+        else:\r
+            subpStdin = None\r
+        p = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stdin=subpStdin)\r
+        (stdout, stderr) = p.communicate(pipeIn)\r
+        if checkExitCode:\r
+            if p.returncode != 0:\r
+                print 'command:', ' '.join(cmd)\r
+                print 'stdout:', stdout\r
+                print 'stderr:', stderr\r
+                print 'return:', p.returncode\r
+            assert p.returncode == 0\r
+        return stdout\r
+\r
+    def FileUpdated(self, path):\r
+        if not self.git or not self.gitdir:\r
+            return\r
+\r
+        cmd = ('git', 'add', path)\r
+        self.RunAndCaptureOutput(cmd)\r
+\r
+    def FileAdded(self, path):\r
+        self.FileUpdated(path)\r
+\r
+    def RemoveFile(self, path):\r
+        if not self.git or not self.gitdir:\r
+            return\r
+\r
+        cmd = ('git', 'rm', path)\r
+        self.RunAndCaptureOutput(cmd)\r
+\r
+    def FileConversionFinished(self, pkg, module, src, dst):\r
+        if not self.git or not self.gitdir:\r
+            return\r
+\r
+        if not self.Opt.quiet:\r
+            print 'Committing: Conversion of', dst\r
+\r
+        prefix = ' '.join(filter(lambda a: a, [pkg, module]))\r
+        message = ''\r
+        if self.unsupportedSyntaxSeen:\r
+            message += 'ERROR! '\r
+        message += '%s: Convert %s to NASM\n' % (prefix, src)\r
+        message += '\n'\r
+        message += 'The %s script was used to convert\n' % sys.argv[0]\r
+        message += '%s to %s\n' % (src, dst)\r
+        message += '\n'\r
+        message += 'Contributed-under: TianoCore Contribution Agreement 1.0\n'\r
+        message += 'Signed-off-by: %s\n' % self.gitemail\r
+\r
+        cmd = ('git', 'commit', '-F', '-')\r
+        self.RunAndCaptureOutput(cmd, pipeIn=message)\r
+\r
+\r
+class ConvertAsmFile(CommonUtils):\r
+\r
+    def __init__(self, src, dst, clone):\r
+        CommonUtils.__init__(self, clone)\r
+        self.ConvertAsmFile(src, dst)\r
+        self.FileAdded(dst)\r
+        self.RemoveFile(src)\r
+\r
+    def ConvertAsmFile(self, inputFile, outputFile=None):\r
+        self.globals = set()\r
+        self.unsupportedSyntaxSeen = False\r
+        self.inputFilename = inputFile\r
+        if not outputFile:\r
+            outputFile = os.path.splitext(inputFile)[0] + '.nasm'\r
+        self.outputFilename = outputFile\r
+\r
+        fullSrc = os.path.realpath(inputFile)\r
+        srcParentDir = os.path.basename(os.path.split(fullSrc)[0])\r
+        maybeArch = srcParentDir.lower()\r
+        if maybeArch in UnsupportedArch.unsupported:\r
+            raise UnsupportedArch\r
+        self.ia32 = maybeArch == 'ia32'\r
+        self.x64 = maybeArch == 'x64'\r
+\r
+        self.inputFileBase = os.path.basename(self.inputFilename)\r
+        self.outputFileBase = os.path.basename(self.outputFilename)\r
+        if self.outputFilename == '-' and not self.diff:\r
+            self.output = sys.stdout\r
+        else:\r
+            self.output = StringIO.StringIO()\r
+        if not self.Opt.quiet:\r
+            dirpath, src = os.path.split(self.inputFilename)\r
+            dirpath = self.RootRelative(dirpath)\r
+            dst = os.path.basename(self.outputFilename)\r
+            print 'Converting:', dirpath, src, '->', dst\r
+        lines = open(self.inputFilename).readlines()\r
+        self.Convert(lines)\r
+        if self.outputFilename == '-':\r
+            if self.diff:\r
+                sys.stdout.write(self.output.getvalue())\r
+                self.output.close()\r
+        else:\r
+            f = open(self.outputFilename, 'wb')\r
+            f.write(self.output.getvalue())\r
+            f.close()\r
+            self.output.close()\r
+\r
+    endOfLineRe = re.compile(r'''\r
+                                 \s* ( ; .* )? \n $\r
+                             ''',\r
+                             re.VERBOSE | re.MULTILINE\r
+                             )\r
+    begOfLineRe = re.compile(r'''\r
+                                 \s*\r
+                             ''',\r
+                             re.VERBOSE\r
+                             )\r
+\r
+    def Convert(self, lines):\r
+        self.proc = None\r
+        self.anonLabelCount = -1\r
+        output = self.output\r
+        self.oldAsmEmptyLineCount = 0\r
+        self.newAsmEmptyLineCount = 0\r
+        for line in lines:\r
+            mo = self.begOfLineRe.search(line)\r
+            assert mo is not None\r
+            self.indent = mo.group()\r
+            lineWithoutBeginning = line[len(self.indent):]\r
+            mo = self.endOfLineRe.search(lineWithoutBeginning)\r
+            if mo is None:\r
+                endOfLine = ''\r
+            else:\r
+                endOfLine = mo.group()\r
+            oldAsm = line[len(self.indent):len(line) - len(endOfLine)]\r
+            self.originalLine = line.rstrip()\r
+            if line.strip() == '':\r
+                self.oldAsmEmptyLineCount += 1\r
+            self.TranslateAsm(oldAsm, endOfLine)\r
+            if line.strip() != '':\r
+                self.oldAsmEmptyLineCount = 0\r
+\r
+    procDeclRe = re.compile(r'''\r
+                                ([\w@][\w@0-9]*) \s+\r
+                                PROC\r
+                                (?: \s+ NEAR | FAR )?\r
+                                (?: \s+ C )?\r
+                                (?: \s+ (PUBLIC | PRIVATE) )?\r
+                                (?: \s+ USES ( (?: \s+ \w[\w0-9]* )+ ) )?\r
+                                \s* $\r
+                            ''',\r
+                            re.VERBOSE | re.IGNORECASE\r
+                            )\r
+\r
+    procEndRe = re.compile(r'''\r
+                               ([\w@][\w@0-9]*) \s+\r
+                               ENDP\r
+                               \s* $\r
+                           ''',\r
+                           re.VERBOSE | re.IGNORECASE\r
+                           )\r
+\r
+    varAndTypeSubRe = r' (?: [\w@][\w@0-9]* ) (?: \s* : \s* \w+ )? '\r
+    publicRe = re.compile(r'''\r
+                              PUBLIC \s+\r
+                              ( %s (?: \s* , \s* %s )* )\r
+                              \s* $\r
+                          ''' % (varAndTypeSubRe, varAndTypeSubRe),\r
+                          re.VERBOSE | re.IGNORECASE\r
+                          )\r
+\r
+    varAndTypeSubRe = re.compile(varAndTypeSubRe, re.VERBOSE | re.IGNORECASE)\r
+\r
+    macroDeclRe = re.compile(r'''\r
+                                 ([\w@][\w@0-9]*) \s+\r
+                                 MACRO\r
+                                 \s* $\r
+                             ''',\r
+                             re.VERBOSE | re.IGNORECASE\r
+                             )\r
+\r
+    sectionDeclRe = re.compile(r'''\r
+                                   ([\w@][\w@0-9]*) \s+\r
+                                   ( SECTION | ENDS )\r
+                                   \s* $\r
+                               ''',\r
+                               re.VERBOSE | re.IGNORECASE\r
+                               )\r
+\r
+    externRe = re.compile(r'''\r
+                              EXTE?RN \s+ (?: C \s+ )?\r
+                              ([\w@][\w@0-9]*) \s* : \s* (\w+)\r
+                              \s* $\r
+                           ''',\r
+                          re.VERBOSE | re.IGNORECASE\r
+                          )\r
+\r
+    externdefRe = re.compile(r'''\r
+                                 EXTERNDEF \s+ (?: C \s+ )?\r
+                                 ([\w@][\w@0-9]*) \s* : \s* (\w+)\r
+                                 \s* $\r
+                             ''',\r
+                             re.VERBOSE | re.IGNORECASE\r
+                             )\r
+\r
+    protoRe = re.compile(r'''\r
+                             ([\w@][\w@0-9]*) \s+\r
+                             PROTO\r
+                             (?: \s+ .* )?\r
+                             \s* $\r
+                         ''',\r
+                         re.VERBOSE | re.IGNORECASE\r
+                         )\r
+\r
+    defineDataRe = re.compile(r'''\r
+                                  ([\w@][\w@0-9]*) \s+\r
+                                  ( db | dw | dd | dq ) \s+\r
+                                  ( .*? )\r
+                                  \s* $\r
+                              ''',\r
+                              re.VERBOSE | re.IGNORECASE\r
+                              )\r
+\r
+    equRe = re.compile(r'''\r
+                           ([\w@][\w@0-9]*) \s+ EQU \s+ (\S.*?)\r
+                           \s* $\r
+                       ''',\r
+                       re.VERBOSE | re.IGNORECASE\r
+                       )\r
+\r
+    ignoreRe = re.compile(r'''\r
+                              \. (?: const |\r
+                                     mmx |\r
+                                     model |\r
+                                     xmm |\r
+                                     x?list |\r
+                                     [3-6]86p?\r
+                                 ) |\r
+                              page\r
+                              (?: \s+ .* )?\r
+                              \s* $\r
+                          ''',\r
+                          re.VERBOSE | re.IGNORECASE\r
+                          )\r
+\r
+    whitespaceRe = re.compile(r'\s+', re.MULTILINE)\r
+\r
+    def TranslateAsm(self, oldAsm, endOfLine):\r
+        assert(oldAsm.strip() == oldAsm)\r
+\r
+        endOfLine = endOfLine.replace(self.inputFileBase, self.outputFileBase)\r
+\r
+        oldOp = oldAsm.split()\r
+        if len(oldOp) >= 1:\r
+            oldOp = oldOp[0]\r
+        else:\r
+            oldOp = ''\r
+\r
+        if oldAsm == '':\r
+            newAsm = oldAsm\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif oldOp in ('#include', ):\r
+            newAsm = oldAsm\r
+            self.EmitLine(oldAsm + endOfLine)\r
+        elif oldOp.lower() in ('end', 'title', 'text'):\r
+            newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif oldAsm.lower() == '@@:':\r
+            self.anonLabelCount += 1\r
+            self.EmitLine(self.anonLabel(self.anonLabelCount) + ':')\r
+        elif self.MatchAndSetMo(self.ignoreRe, oldAsm):\r
+            newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif oldAsm.lower() == 'ret':\r
+            for i in range(len(self.uses) - 1, -1, -1):\r
+                register = self.uses[i]\r
+                self.EmitNewContent('pop     ' + register)\r
+            newAsm = 'ret'\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+            self.uses = tuple()\r
+        elif oldOp.lower() == 'lea':\r
+            newAsm = self.ConvertLea(oldAsm)\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif oldAsm.lower() == 'end':\r
+            newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+            self.uses = tuple()\r
+        elif self.MatchAndSetMo(self.equRe, oldAsm):\r
+            equ = self.mo.group(1)\r
+            newAsm = '%%define %s %s' % (equ, self.mo.group(2))\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.externRe, oldAsm) or \\r
+                self.MatchAndSetMo(self.protoRe, oldAsm):\r
+            extern = self.mo.group(1)\r
+            self.NewGlobal(extern)\r
+            newAsm = 'extern ' + extern\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.externdefRe, oldAsm):\r
+            newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.macroDeclRe, oldAsm):\r
+            newAsm = '%%macro %s 0' % self.mo.group(1)\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif oldOp.lower() == 'endm':\r
+            newAsm = r'%endmacro'\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.sectionDeclRe, oldAsm):\r
+            name = self.mo.group(1)\r
+            ty = self.mo.group(2)\r
+            if ty.lower() == 'section':\r
+                newAsm = '.' + name\r
+            else:\r
+                newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.procDeclRe, oldAsm):\r
+            proc = self.proc = self.mo.group(1)\r
+            visibility = self.mo.group(2)\r
+            if visibility is None:\r
+                visibility = ''\r
+            else:\r
+                visibility = visibility.lower()\r
+            if visibility != 'private':\r
+                self.NewGlobal(self.proc)\r
+                proc = 'ASM_PFX(' + proc + ')'\r
+                self.EmitNewContent('global ' + proc)\r
+            newAsm = proc + ':'\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+            uses = self.mo.group(3)\r
+            if uses is not None:\r
+                uses = filter(None, uses.split())\r
+            else:\r
+                uses = tuple()\r
+            self.uses = uses\r
+            for register in self.uses:\r
+                self.EmitNewContent('    push    ' + register)\r
+        elif self.MatchAndSetMo(self.procEndRe, oldAsm):\r
+            newAsm = ''\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.publicRe, oldAsm):\r
+            publics = re.findall(self.varAndTypeSubRe, self.mo.group(1))\r
+            publics = map(lambda p: p.split(':')[0].strip(), publics)\r
+            for i in range(len(publics) - 1):\r
+                name = publics[i]\r
+                self.EmitNewContent('global ASM_PFX(%s)' % publics[i])\r
+                self.NewGlobal(name)\r
+            name = publics[-1]\r
+            self.NewGlobal(name)\r
+            newAsm = 'global ASM_PFX(%s)' % name\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        elif self.MatchAndSetMo(self.defineDataRe, oldAsm):\r
+            name = self.mo.group(1)\r
+            ty = self.mo.group(2)\r
+            value = self.mo.group(3)\r
+            if value == '?':\r
+                value = 0\r
+            newAsm = '%s: %s %s' % (name, ty, value)\r
+            newAsm = self.CommonConversions(newAsm)\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+        else:\r
+            newAsm = self.CommonConversions(oldAsm)\r
+            self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+\r
+    def NewGlobal(self, name):\r
+        regex = re.compile(r'(?<![_\w\d])(?<!ASM_PFX\()(' + re.escape(name) +\r
+                           r')(?![_\w\d])')\r
+        self.globals.add(regex)\r
+\r
+    def ConvertAnonymousLabels(self, oldAsm):\r
+        newAsm = oldAsm\r
+        anonLabel = self.anonLabel(self.anonLabelCount)\r
+        newAsm = newAsm.replace('@b', anonLabel)\r
+        newAsm = newAsm.replace('@B', anonLabel)\r
+        anonLabel = self.anonLabel(self.anonLabelCount + 1)\r
+        newAsm = newAsm.replace('@f', anonLabel)\r
+        newAsm = newAsm.replace('@F', anonLabel)\r
+        return newAsm\r
+\r
+    def anonLabel(self, count):\r
+        return '.%d' % count\r
+\r
+    def EmitString(self, string):\r
+        self.output.write(string)\r
+\r
+    def EmitLineWithDiff(self, old, new):\r
+        newLine = (self.indent + new).rstrip()\r
+        if self.diff:\r
+            if old is None:\r
+                print '+%s' % newLine\r
+            elif newLine != old:\r
+                print '-%s' % old\r
+                print '+%s' % newLine\r
+            else:\r
+                print '', newLine\r
+        if newLine != '':\r
+            self.newAsmEmptyLineCount = 0\r
+        self.EmitString(newLine + '\r\n')\r
+\r
+    def EmitLine(self, string):\r
+        self.EmitLineWithDiff(self.originalLine, string)\r
+\r
+    def EmitNewContent(self, string):\r
+        self.EmitLineWithDiff(None, string)\r
+\r
+    def EmitAsmReplaceOp(self, oldAsm, oldOp, newOp, endOfLine):\r
+        newAsm = oldAsm.replace(oldOp, newOp, 1)\r
+        self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+\r
+    hexNumRe = re.compile(r'0*((?=[\da-f])\d*(?<=\d)[\da-f]*)h', re.IGNORECASE)\r
+\r
+    def EmitAsmWithComment(self, oldAsm, newAsm, endOfLine):\r
+        for glblRe in self.globals:\r
+            newAsm = glblRe.sub(r'ASM_PFX(\1)', newAsm)\r
+\r
+        newAsm = self.hexNumRe.sub(r'0x\1', newAsm)\r
+\r
+        newLine = newAsm + endOfLine\r
+        emitNewLine = ((newLine.strip() != '') or\r
+                       ((oldAsm + endOfLine).strip() == ''))\r
+        if emitNewLine and newLine.strip() == '':\r
+            self.newAsmEmptyLineCount += 1\r
+            if self.newAsmEmptyLineCount > 1:\r
+                emitNewLine = False\r
+        if emitNewLine:\r
+            self.EmitLine(newLine.rstrip())\r
+        elif self.diff:\r
+            print '-%s' % self.originalLine\r
+\r
+    leaRe = re.compile(r'''\r
+                           (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)\r
+                           \s* $\r
+                       ''',\r
+                       re.VERBOSE | re.IGNORECASE\r
+                       )\r
+\r
+    def ConvertLea(self, oldAsm):\r
+        newAsm = oldAsm\r
+        if self.MatchAndSetMo(self.leaRe, oldAsm):\r
+            lea = self.mo.group(1)\r
+            dst = self.mo.group(2)\r
+            src = self.mo.group(3)\r
+            if src.find('[') < 0:\r
+                src = '[' + src + ']'\r
+            newAsm = lea + dst + ', ' + src\r
+        newAsm = self.CommonConversions(newAsm)\r
+        return newAsm\r
+\r
+    ptrRe = re.compile(r'''\r
+                           (?<! \S )\r
+                           ([dfq]?word|byte) \s+ (?: ptr ) (\s*)\r
+                           (?= [[\s] )\r
+                       ''',\r
+                       re.VERBOSE | re.IGNORECASE\r
+                       )\r
+\r
+    def ConvertPtr(self, oldAsm):\r
+        newAsm = oldAsm\r
+        while self.SearchAndSetMo(self.ptrRe, newAsm):\r
+            ty = self.mo.group(1)\r
+            if ty.lower() == 'fword':\r
+                ty = ''\r
+            else:\r
+                ty += self.mo.group(2)\r
+            newAsm = newAsm[:self.mo.start(0)] + ty + newAsm[self.mo.end(0):]\r
+        return newAsm\r
+\r
+    labelByteRe = re.compile(r'''\r
+                                 (?: \s+ label \s+ (?: [dfq]?word | byte ) )\r
+                                 (?! \S )\r
+                             ''',\r
+                             re.VERBOSE | re.IGNORECASE\r
+                             )\r
+\r
+    def ConvertLabelByte(self, oldAsm):\r
+        newAsm = oldAsm\r
+        if self.SearchAndSetMo(self.labelByteRe, newAsm):\r
+            newAsm = newAsm[:self.mo.start(0)] + ':' + newAsm[self.mo.end(0):]\r
+        return newAsm\r
+\r
+    unaryBitwiseOpRe = re.compile(r'''\r
+                                      ( NOT )\r
+                                      (?= \s+ \S )\r
+                                  ''',\r
+                                  re.VERBOSE | re.IGNORECASE\r
+                                  )\r
+    binaryBitwiseOpRe = re.compile(r'''\r
+                                       ( \S \s+ )\r
+                                       ( AND | OR | SHL | SHR )\r
+                                       (?= \s+ \S )\r
+                                   ''',\r
+                                   re.VERBOSE | re.IGNORECASE\r
+                                   )\r
+    bitwiseOpReplacements = {\r
+        'not': '~',\r
+        'and': '&',\r
+        'shl': '<<',\r
+        'shr': '>>',\r
+        'or': '|',\r
+    }\r
+\r
+    def ConvertBitwiseOp(self, oldAsm):\r
+        newAsm = oldAsm\r
+        while self.SearchAndSetMo(self.binaryBitwiseOpRe, newAsm):\r
+            prefix = self.mo.group(1)\r
+            op = self.bitwiseOpReplacements[self.mo.group(2).lower()]\r
+            newAsm = newAsm[:self.mo.start(0)] + prefix + op + \\r
+                newAsm[self.mo.end(0):]\r
+        while self.SearchAndSetMo(self.unaryBitwiseOpRe, newAsm):\r
+            op = self.bitwiseOpReplacements[self.mo.group(1).lower()]\r
+            newAsm = newAsm[:self.mo.start(0)] + op + newAsm[self.mo.end(0):]\r
+        return newAsm\r
+\r
+    sectionRe = re.compile(r'''\r
+                               \. ( code |\r
+                                    data\r
+                                  )\r
+                               (?: \s+ .* )?\r
+                               \s* $\r
+                           ''',\r
+                           re.VERBOSE | re.IGNORECASE\r
+                           )\r
+\r
+    segmentRe = re.compile(r'''\r
+                               ( code |\r
+                                 data )\r
+                               (?: \s+ SEGMENT )\r
+                               (?: \s+ .* )?\r
+                               \s* $\r
+                           ''',\r
+                           re.VERBOSE | re.IGNORECASE\r
+                           )\r
+\r
+    def ConvertSection(self, oldAsm):\r
+        newAsm = oldAsm\r
+        if self.MatchAndSetMo(self.sectionRe, newAsm) or \\r
+           self.MatchAndSetMo(self.segmentRe, newAsm):\r
+            name = self.mo.group(1).lower()\r
+            if name == 'code':\r
+                if self.x64:\r
+                    self.EmitLine('DEFAULT REL')\r
+                name = 'text'\r
+            newAsm = 'SECTION .' + name\r
+        return newAsm\r
+\r
+    fwordRe = re.compile(r'''\r
+                             (?<! \S )\r
+                             fword\r
+                             (?! \S )\r
+                         ''',\r
+                         re.VERBOSE | re.IGNORECASE\r
+                         )\r
+\r
+    def FwordUnsupportedCheck(self, oldAsm):\r
+        newAsm = oldAsm\r
+        if self.SearchAndSetMo(self.fwordRe, newAsm):\r
+            newAsm = self.Unsupported(newAsm, 'fword used')\r
+        return newAsm\r
+\r
+    __common_conversion_routines__ = (\r
+        ConvertAnonymousLabels,\r
+        ConvertPtr,\r
+        FwordUnsupportedCheck,\r
+        ConvertBitwiseOp,\r
+        ConvertLabelByte,\r
+        ConvertSection,\r
+    )\r
+\r
+    def CommonConversions(self, oldAsm):\r
+        newAsm = oldAsm\r
+        for conv in self.__common_conversion_routines__:\r
+            newAsm = conv(self, newAsm)\r
+        return newAsm\r
+\r
+    def Unsupported(self, asm, message=None):\r
+        if not self.force:\r
+            raise UnsupportedConversion\r
+\r
+        self.unsupportedSyntaxSeen = True\r
+        newAsm = '%error conversion unsupported'\r
+        if message:\r
+            newAsm += '; ' + message\r
+        newAsm += ': ' + asm\r
+        return newAsm\r
+\r
+\r
+class ConvertInfFile(CommonUtils):\r
+\r
+    def __init__(self, inf, clone):\r
+        CommonUtils.__init__(self, clone)\r
+        self.inf = inf\r
+        self.ScanInfAsmFiles()\r
+        if self.infmode:\r
+            self.ConvertInfAsmFiles()\r
+\r
+    infSrcRe = re.compile(r'''\r
+                              \s*\r
+                              ( [\w@][\w@0-9/]* \.(asm|s) )\r
+                              \s* (?: \| [^#]* )?\r
+                              \s* (?: \# .* )?\r
+                              $\r
+                          ''',\r
+                          re.VERBOSE | re.IGNORECASE\r
+                          )\r
+\r
+    def GetInfAsmFileMapping(self):\r
+        srcToDst = {'order': []}\r
+        for line in self.lines:\r
+            line = line.rstrip()\r
+            if self.MatchAndSetMo(self.infSrcRe, line):\r
+                src = self.mo.group(1)\r
+                srcExt = self.mo.group(2)\r
+                dst = os.path.splitext(src)[0] + '.nasm'\r
+                if src not in srcToDst:\r
+                    srcToDst[src] = dst\r
+                    srcToDst['order'].append(src)\r
+        return srcToDst\r
+\r
+    def ScanInfAsmFiles(self):\r
+        src = self.inf\r
+        assert os.path.isfile(src)\r
+        f = open(src)\r
+        self.lines = f.readlines()\r
+        f.close()\r
+\r
+        path = os.path.realpath(self.inf)\r
+        (self.dir, inf) = os.path.split(path)\r
+        parent = os.path.normpath(self.dir)\r
+        (lastpath, self.moduleName) = os.path.split(parent)\r
+        self.packageName = None\r
+        while True:\r
+            lastpath = os.path.normpath(lastpath)\r
+            (parent, basename) = os.path.split(lastpath)\r
+            if parent == lastpath:\r
+                break\r
+            if basename.endswith('Pkg'):\r
+                self.packageName = basename\r
+                break\r
+            lastpath = parent\r
+\r
+        self.srcToDst = self.GetInfAsmFileMapping()\r
+\r
+        self.dstToSrc = {'order': []}\r
+        for src in self.srcToDst['order']:\r
+            srcExt = os.path.splitext(src)[1]\r
+            dst = self.srcToDst[src]\r
+            if dst not in self.dstToSrc:\r
+                self.dstToSrc[dst] = [src]\r
+                self.dstToSrc['order'].append(dst)\r
+            else:\r
+                self.dstToSrc[dst].append(src)\r
+\r
+    def __len__(self):\r
+        return len(self.dstToSrc['order'])\r
+\r
+    def __iter__(self):\r
+        return iter(self.dstToSrc['order'])\r
+\r
+    def ConvertInfAsmFiles(self):\r
+        notConverted = []\r
+        unsupportedArchCount = 0\r
+        for dst in self:\r
+            didSomething = False\r
+            fileChanged = self.UpdateInfAsmFile(dst)\r
+            try:\r
+                self.UpdateInfAsmFile(dst)\r
+                didSomething = True\r
+            except UnsupportedConversion:\r
+                if not self.Opt.quiet:\r
+                    print 'MASM=>NASM conversion unsupported for', dst\r
+                notConverted.append(dst)\r
+            except NoSourceFile:\r
+                if not self.Opt.quiet:\r
+                    print 'Source file missing for', reldst\r
+                notConverted.append(dst)\r
+            except UnsupportedArch:\r
+                unsupportedArchCount += 1\r
+            else:\r
+                if didSomething:\r
+                    self.ConversionFinished(dst)\r
+        if len(notConverted) > 0 and not self.Opt.quiet:\r
+            for dst in notConverted:\r
+                reldst = self.RootRelative(dst)\r
+                print 'Unabled to convert', reldst\r
+        if unsupportedArchCount > 0 and not self.Opt.quiet:\r
+            print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+\r
+    def UpdateInfAsmFile(self, dst, IgnoreMissingAsm=False):\r
+        infPath = os.path.split(os.path.realpath(self.inf))[0]\r
+        asmSrc = os.path.splitext(dst)[0] + '.asm'\r
+        fullSrc = os.path.join(infPath, asmSrc)\r
+        fullDst = os.path.join(infPath, dst)\r
+        srcParentDir = os.path.basename(os.path.split(fullSrc)[0])\r
+        if srcParentDir.lower() in UnsupportedArch.unsupported:\r
+            raise UnsupportedArch\r
+        elif not os.path.exists(fullSrc):\r
+            if not IgnoreMissingAsm:\r
+                raise NoSourceFile\r
+        else:  # not os.path.exists(fullDst):\r
+            conv = ConvertAsmFile(fullSrc, fullDst, self)\r
+            self.unsupportedSyntaxSeen = conv.unsupportedSyntaxSeen\r
+\r
+        lastLine = ''\r
+        fileChanged = False\r
+        for i in range(len(self.lines)):\r
+            line = self.lines[i].rstrip()\r
+            updatedLine = line\r
+            for src in self.dstToSrc[dst]:\r
+                assert self.srcToDst[src] == dst\r
+                updatedLine = self.ReplacePreserveSpacing(\r
+                    updatedLine, src, dst)\r
+\r
+            lineChanged = updatedLine != line\r
+            if lineChanged:\r
+                if lastLine.strip() == updatedLine.strip():\r
+                    self.lines[i] = None\r
+                else:\r
+                    self.lines[i] = updatedLine + '\r\n'\r
+\r
+            if self.diff:\r
+                if lineChanged:\r
+                    print '-%s' % line\r
+                    if self.lines[i] is not None:\r
+                        print '+%s' % updatedLine\r
+                else:\r
+                    print '', line\r
+\r
+            fileChanged |= lineChanged\r
+            if self.lines[i] is not None:\r
+                lastLine = self.lines[i]\r
+\r
+        if fileChanged:\r
+            self.lines = filter(lambda l: l is not None, self.lines)\r
+\r
+        for src in self.dstToSrc[dst]:\r
+            if not src.endswith('.asm'):\r
+                fullSrc = os.path.join(infPath, src)\r
+                if os.path.exists(fullSrc):\r
+                    self.RemoveFile(fullSrc)\r
+\r
+        if fileChanged:\r
+            f = open(self.inf, 'wb')\r
+            f.writelines(self.lines)\r
+            f.close()\r
+            self.FileUpdated(self.inf)\r
+\r
+    def ConversionFinished(self, dst):\r
+        asmSrc = os.path.splitext(dst)[0] + '.asm'\r
+        self.FileConversionFinished(\r
+            self.packageName, self.moduleName, asmSrc, dst)\r
+\r
+\r
+class ConvertInfFiles(CommonUtils):\r
+\r
+    def __init__(self, infs, clone):\r
+        CommonUtils.__init__(self, clone)\r
+        infs = map(lambda i: ConvertInfFile(i, self), infs)\r
+        infs = filter(lambda i: len(i) > 0, infs)\r
+        dstToInfs = {'order': []}\r
+        for inf in infs:\r
+            for dst in inf:\r
+                fulldst = os.path.realpath(os.path.join(inf.dir, dst))\r
+                pair = (inf, dst)\r
+                if fulldst in dstToInfs:\r
+                    dstToInfs[fulldst].append(pair)\r
+                else:\r
+                    dstToInfs['order'].append(fulldst)\r
+                    dstToInfs[fulldst] = [pair]\r
+\r
+        notConverted = []\r
+        unsupportedArchCount = 0\r
+        for dst in dstToInfs['order']:\r
+            didSomething = False\r
+            try:\r
+                for inf, reldst in dstToInfs[dst]:\r
+                    inf.UpdateInfAsmFile(reldst, IgnoreMissingAsm=didSomething)\r
+                    didSomething = True\r
+            except UnsupportedConversion:\r
+                if not self.Opt.quiet:\r
+                    print 'MASM=>NASM conversion unsupported for', reldst\r
+                notConverted.append(dst)\r
+            except NoSourceFile:\r
+                if not self.Opt.quiet:\r
+                    print 'Source file missing for', reldst\r
+                notConverted.append(dst)\r
+            except UnsupportedArch:\r
+                unsupportedArchCount += 1\r
+            else:\r
+                if didSomething:\r
+                    inf.ConversionFinished(reldst)\r
+        if len(notConverted) > 0 and not self.Opt.quiet:\r
+            for dst in notConverted:\r
+                reldst = self.RootRelative(dst)\r
+                print 'Unabled to convert', reldst\r
+        if unsupportedArchCount > 0 and not self.Opt.quiet:\r
+            print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+\r
+\r
+class ConvertDirectories(CommonUtils):\r
+\r
+    def __init__(self, paths, clone):\r
+        CommonUtils.__init__(self, clone)\r
+        self.paths = paths\r
+        self.ConvertInfAndAsmFiles()\r
+\r
+    def ConvertInfAndAsmFiles(self):\r
+        infs = list()\r
+        for path in self.paths:\r
+            assert(os.path.exists(path))\r
+        for path in self.paths:\r
+            for root, dirs, files in os.walk(path):\r
+                for d in ('.svn', '.git'):\r
+                    if d in dirs:\r
+                        dirs.remove(d)\r
+                for f in files:\r
+                    if f.lower().endswith('.inf'):\r
+                        inf = os.path.realpath(os.path.join(root, f))\r
+                        infs.append(inf)\r
+\r
+        ConvertInfFiles(infs, self)\r
+\r
+\r
+class ConvertAsmApp(CommonUtils):\r
+\r
+    def __init__(self):\r
+        CommonUtils.__init__(self)\r
+\r
+        numArgs = len(self.Args)\r
+        assert(numArgs >= 1)\r
+        if self.infmode:\r
+            ConvertInfFiles(self.Args, self)\r
+        elif self.dirmode:\r
+            ConvertDirectories(self.Args, self)\r
+        elif not self.dirmode:\r
+            assert(numArgs <= 2)\r
+            src = self.Args[0]\r
+            if numArgs > 1:\r
+                dst = self.Args[1]\r
+            else:\r
+                dst = None\r
+            ConvertAsmFile(src, dst, self)\r
+\r
+ConvertAsmApp()\r