pmacs3/mode/nasm.py

77 lines
3.8 KiB
Python

from mode import Fundamental
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
from mode.python import StringGrammar1, StringGrammar2, StringGrammar3, StringGrammar4
from method import Method, arg
from subprocess import Popen, PIPE, STDOUT
chr1 = '[a-zA-Z_.?]'
chr2 = '[a-zA-Z0-9_.?$#@~]'
word = chr1 + chr2 + '*'
class NasmGrammar(Grammar):
rules = [
PatternRule('comment', ';.*$'),
RegionRule('comment', '%if +0', Grammar, r'%%endif'),
# for use with ndisasm files
PatternMatchRule('x', '^([0-9a-fA-F]{8})( )([0-9a-fA-F]+)', 'nasm.integer', 'spaces', 'nasm.address'),
PatternRule('nasm.address', '^[0-9a-fA-F]{8} [0-9a-fA-F]+'),
PatternRule('spaces', ' +'),
PatternRule("nasm.integer", "(0[xX][0-9a-fA-F]+|0|[1-9][0-9]*|0[0-7]+)[lL]?"),
PatternRule('nasm.register', "(?:eax|ebx|ecx|edx|ax|ah|al|bx|bh|bl|bp|cx|ch|cl|cmpsb|dh|di|dl|ds|dx|esi|es|edi|esp|ebp|si|sp|stosd)(?!" + chr2 + ")"),
PatternRule('nasm.pseudo', "(?:a16|a32|byte|db|dd|do|dq|dt|dword|qword|tword|fs|gs|near|o16|o32|short)(?!" + chr2 + ")"),
PatternRule('nasm.instruction', "(?:jg|jeq|jecxz|jne|ja|jmp|push|pushad|pushfd|call|ret|sub|adc|add|popad|popaw|popa|popfd|pop|call|and|arpl|bound|cwd|cdq|clc|cld|cli|cmp|cmpxchg|cpuid|das|dec|divpd|div|enter|leave|fadd|fld|fmul|fsqrt|fsub|fs|hlt|imul|inc|insb|insd|insw|ins|int|int3|in|jcxz|jc|jna|jnc|jnz|jo|js|jz|lea|lldt|loadsb|lock|loopne|movzx|movd|mov|mul|neg|not|nop|or|outsb|outsd|outsw|repe|retf|rol|sal|sar|sbb|scasw|shl|shr|shld|shrd|sldt|syscall|sysenter|sysexit|test|xchg|xadd|xor)(?!" + chr2 + ")"),
PatternRule('nasm.macro', "\%(?:define|undef|assign|strlen|macro|endmacro|if|elif|else|endif|ifdef|ifndef|include|push|pop|stacksize)(?!" + chr2 + ")"),
PatternRule('nasm.keyword', "(?:section|global|extern)(?!" + chr2 + ")"),
PatternRule('nasm.prefix', "(?:dword|word|lock)(?!" + chr2 + ")"),
PatternMatchRule('x', '(' + word + ')(:)', 'nasm.label', 'delimiter'),
PatternRule("nasm.identifier", r'\$?' + word),
PatternRule("nasm.float", r"[0-9]+\.[0-9]*|\.[0-9]+|([0-9]|[0-9]+\.[0-9]*|\.[0-9]+)[eE][\+-]?[0-9]+"),
PatternRule('delimiter', r'(?://|%%|<<|>>|[~!\.\*/%\-\+\(\)\[\],\|\^\&])'),
# TODO: nasm strings seem like they are single-line only
RegionRule('string', '"""', StringGrammar4, '"""'),
RegionRule('string', "'''", StringGrammar3, "'''"),
RegionRule('string', '"', StringGrammar2, '"'),
RegionRule('string', "'", StringGrammar1, "'"),
PatternRule('eol', '\n'),
PatternRule('continuation', r'\\\n$'),
]
class NasmDisassembleFile(Method):
args = [arg("path", dt='path', p="Path: "),
arg('flags', p='Flags: ', dv=lambda w: '-b 16', ld=True)]
def _execute(self, w, **vargs):
p = Popen(['ndisasm', vargs['path']], stdout=PIPE, stderr=STDOUT)
output = p.stdout.read()
retval = p.wait()
modename = None
bufname = '*Disasm:%s*' % vargs['path']
w.application.data_buffer(bufname, output, switch_to=True,
modename=modename)
class Nasm(Fundamental):
name = 'nasm'
extensions = ['.s']
grammar = NasmGrammar
commentc = ';'
colors = {
'nasm.address': ('cyan', 'default'),
'nasm.pseudo': ('cyan', 'default'),
'nasm.keyword': ('cyan', 'default'),
'nasm.macro': ('blue', 'default'),
'nasm.register': ('yellow', 'default'),
'nasm.instruction': ('magenta', 'default'),
'nasm.label': ('blue', 'default'),
'nasm.integer': ('green', 'default'),
}
_bindings = {
'close-paren': (')',),
'close-brace': ('}',),
'close-bracket': (']',),
}
actions = [NasmDisassembleFile]
install = Nasm.install