Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- import sys
- from Plex import *
- from mc import mnemonic2op, no_operands, MAXINT
- from string import ascii_letters
- letter = Range("AZaz")
- bit = Str('0') | Str('1')
- digit = Range('09')
- hexdigit = digit | Range('afAF')
- integer = Opt(Str('-')) + Rep1(digit)
- hexint = Str('0x') + hexdigit + Opt(hexdigit)
- binint = Str('0b') + Rep1(bit)
- space = Any(" \t")
- ident = letter + Rep(letter | digit)
- label = Bol + ident
- filename = ident + Str('.') + Alt(Str('py'), Str('asm'))
- include = Bol + Str('#') + NoCase(Str('include')) + space
- comment = Str(';')
- star = Str('*') + Opt(Opt(space) + Alt(Str('+'), Str('-')) + Opt(space) + Rep1(digit))
- reladdress = ident + Opt(space) + Alt(Str('+'), Str('-')) + Opt(space) + Rep1(digit)
- number = integer | hexint | binint
- macrodef = label + NoCase(Str('MACRO'))
- eol = Str('\n') | Eof
- sq_string = (
- Str("'") +
- Rep(AnyBut("\\\n'") | (Str("\\") + AnyChar)) +
- Str("'"))
- dq_string = (
- Str('"') +
- Rep(AnyBut('\\\n"') | (Str("\\") + AnyChar)) +
- Str('"'))
- astring = sq_string | dq_string
- plist = Alt(number, ident, astring) + Rep1(Opt(space) + Str(',') + Opt(space) + Alt(number, ident, astring))
- class AsmSource(object):
- def __init__(self):
- self.lineno = 0
- self._frommacro = False
- self.macgen = 0
- self._incsect = False
- self.expanded = False
- self.label = ''
- self.mnemonic = ''
- self.operand = None
- self.lc = 0
- self.opcode = None
- self.operand_base = None
- self.operand_offset = 0
- self.operand_value = None
- self.comment = ''
- self.errors = []
- self.raw = ''
- def getfrommacro(self):
- return self._frommacro
- def setfrommacro(self, value):
- self._frommacro = value
- frommacro = property(getfrommacro, setfrommacro)
- def getincsect(self):
- """boolean indicating whether line is in the CSECT"""
- return self._incsect
- def setincsest(self, value):
- self._incsect = value
- incsect = property(getincsect, setincsest)
- def __str__(self):
- s = []
- for x in sorted(vars(self)):
- s.append('%s: %s' % (x, getattr(self, x)))
- return '\n'.join(s)
- def isa(self, *mnemonics):
- for mnemonic in mnemonics:
- if mnemonic.upper() == self.mnemonic.upper():
- return True
- return False
- def isacomment(self):
- # Empty line is assumed to be a comment?
- return not(self.label or self.mnemonic or self.operand)
- def error(self, text, col=0):
- self.errors.append( (text, col) )
- class AsmScanner(Scanner):
- def col(self):
- return self.position()[2]
- def report(self, text):
- self.srcline.error(text, self.col())
- def gotlabel(self, scanner, text):
- self.srcline.label = text
- def gotident(self, scanner, text):
- if not self.srcline.mnemonic:
- # This ident token is the mnemonic
- self.srcline.mnemonic = text
- try:
- self.srcline.opcode = mnemonic2op[text.upper()]
- except KeyError:
- pass # Maybe a macro call and the macro is not yet defined
- if text == 'EQU' and not self.srcline.label:
- self.report('Unlabeled EQU')
- elif not self.srcline.operand:
- # This ident token is an operand
- if self.srcline.mnemonic.upper() in self.macros or self.srcline.isa('MACRO'):
- self.gotplist(scanner, text)
- else:
- self.srcline.operand = text
- else:
- self.report('Unexpected operand: "%s"' % (text))
- def gotnumber(self, scanner, text):
- if self.srcline.operand:
- self.report('Unexpected operand: "%s"' % (text))
- else:
- if not self.srcline.mnemonic:
- self.report('Missing mnemonic')
- else:
- self.srcline.operand = text
- if self.srcline.operand.startswith('0x'):
- base = 16
- elif self.srcline.operand.startswith('0b'):
- base = 2
- text = text[2:]
- else:
- base = 10
- self.srcline.operand_value = int(text, base)
- if self.srcline.operand_value > MAXINT:
- self.report('Operand (%d) exceeds MAXINT (%d)' % (self.srcline.operand_value, MAXINT))
- if self.srcline.operand_value < 0:
- self.srcline.operand_value = 256 + self.srcline.operand_value # 2's complement
- def gotplist(self, scanner, text):
- self.srcline.operand = text
- text = text.replace(' ', '')
- self.srcline.operand_value = text.split(',')
- def gotstar(self, scanner, text):
- if not self.srcline.mnemonic:
- # we have a mnemonic with a signed number: looks like a reladdress
- parts = text.split()
- if len(parts) == 2:
- self.gotident(scanner, parts[0])
- self.gotnumber(scanner, parts[1])
- return
- self.srcline.operand = text
- parts = text.split()
- if len(parts) == 3:
- self.srcline.operand_base = parts[0] # * or ident
- self.srcline.operand_offset = int(parts[2]) if parts[1] == '+' else -int(parts[2])
- else:
- self.srcline.operand_base = text
- def gotstring(self, scanner, text):
- self.srcline.operand = text
- astring = eval(text)
- self.srcline.operand_value = [ord(x) for x in list(astring)]
- #self.srcline.operand_value = [ord(x) for x in list(text[1:-1])]
- #self.srcline.operand_value.append(0)
- def startcomment(self, scanner, text):
- self.comment = [text]
- scanner.begin('comment')
- def endcomment(self, scanner, text):
- self.srcline.comment = ''.join(self.comment)
- scanner.begin('')
- def goteol(self, scanner, text):
- if self.srcline.operand and self.srcline.mnemonic.upper() in no_operands:
- self.report('Unexpected operand: "%s" (%s has no operands).' % (self.srcline.operand, self.srcline.mnemonic.upper()))
- if self.srcline.isa('EQU'):
- if self.srcline.operand is None:
- self.report('EQU without operand')
- if not self.srcline.label:
- self.report('EQU without label')
- elif self.srcline.isa('ORG') and not self.srcline.operand:
- self.report('ORG without operand')
- elif self.srcline.isa('DC') and self.srcline.operand is None:
- self.report('DC without operand')
- elif self.srcline.isa('MACRO'):
- if not self.srcline.label:
- self.report('MACRO without label')
- if not self.srcline.operand_value:
- self.srcline.operand_value = []
- if isinstance(self.srcline.operand_value, list) and not self.srcline.isa('DC', 'MACRO') \
- and self.srcline.mnemonic.upper() not in self.macros:
- if len(self.srcline.operand_value) != 1:
- self.report('String operand must be exactly one character')
- else:
- self.srcline.operand_value = self.srcline.operand_value[0]
- self.srcline.lineno = self.position()[1]
- self.srclines.append(self.srcline)
- self.srcline = AsmSource()
- def gotfilename(self, scanner, text):
- self.srcline.filename = text
- def eof(self):
- #print 'There are %d sourcelines' % len(self.srclines)
- for oLine in self.srclines:
- if oLine.errors:
- self.errors += len(oLine.errors)
- def __init__(self, afile):
- self.errors = 0
- self.filename = '<stream>'
- self.comment = ''
- self.srclines = []
- self.srcline = AsmSource()
- self.lexicon = Lexicon([
- (label, self.gotlabel),
- (ident, self.gotident),
- (number, self.gotnumber),
- (astring, self.gotstring),
- (filename, self.gotfilename),
- (star, self.gotstar),
- (reladdress, self.gotstar),
- (plist, self.gotplist),
- (space, IGNORE),
- (include, IGNORE),
- (eol, self.goteol),
- (comment, self.startcomment),
- (State('comment', [
- (AnyBut('\n'), lambda s, t: self.comment.append(t)),
- ((Eol | Eof), self.endcomment),
- ])),
- (State('Error', [
- (AnyBut('\n'), IGNORE),
- ((Eol|Eof), Begin(''))
- ])),
- ])
- Scanner.__init__(self, self.lexicon, afile, self.filename)
- class Lexer(object):
- def __init__(self, filename):
- print >>sys.stdout, '%s: Lexing...' % (os.path.basename(filename))
- self.errors = 0
- import cStringIO
- stream = cStringIO.StringIO()
- infile = open(filename, 'U')
- for line in infile:
- stream.write(line)
- if line.lower().startswith('#include'):
- incfilename = line.strip().split()[1]
- if incfilename.endswith('.asm'):
- self.addinclude(stream, incfilename)
- stream.seek(0)
- macrolabels = self.getmacrolabels(stream)
- stream.seek(0)
- scanner = AsmScanner(stream)
- scanner.macros = macrolabels
- while True:
- try:
- if scanner.read()[0] is None:
- break
- except Errors.UnrecognizedInput, e:
- scanner.srcline.error(str(e))
- scanner.begin('Error')
- self.srclines = scanner.srclines
- assert self.srclines
- stream.seek(0)
- lines = stream.readlines()
- for n, line in enumerate(lines):
- self.srclines[n].raw = lines[n].rstrip()
- stream.close()
- self.errors += scanner.errors
- def addinclude(self, stream, incfilename):
- infile = open(incfilename)
- for line in infile:
- stream.write(line)
- if line.lower().startswith('#include'):
- incfilename = line.strip().split()[1]
- if filename.endswith('.asm'):
- self.addinclude(stream, incfilename)
- def getmacrolabels(self, stream):
- macrolabels = []
- for line in stream:
- if line[0] in ascii_letters:
- parts = line.split()
- if parts[1].lower() == 'macro':
- macrolabels.append(parts[0].upper())
- return macrolabels
- if __name__ == '__main__':
- import StringIO
- stream = StringIO.StringIO('START INI ;here we gooooo!')
- stream = open('test.asm')
- stream = open('bits.asm')
- scanner = AsmScanner(stream)
- scanner.read()
- for asmline in scanner.srclines:
- print '%-8s %3s %-8s %s' % (asmline.label, asmline.mnemonic, asmline.operand, asmline.comment)
- for text, col in asmline.errors:
- print '%s: Line: %d Col: %d %s' % (scanner.filename, asmline.lineno, col, text)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement