1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00

Almost finished, need to assemble opcode

This commit is contained in:
Ross Wilson 2016-01-25 16:27:06 +07:00
parent 01d2d7b60d
commit 86a6f7bb14

View File

@ -64,6 +64,9 @@ BackpatchList = []
CurrentLine = None
CurrentLineNumber = None
# Any undefined label
Undefined = None
######
# Mostly constant stuff
######
@ -119,9 +122,11 @@ def write_list(code, addr, lnum, line):
code_str = '%06o' % code if code else ''
addr_str = '%04o' % addr if addr else ''
lnum_str = '%04d:' % lnum if lnum else ''
line_str = '%s' % line if line else ''
ListFileHandle.write('%6s %4s %04d: %s\n'
% (code_str, addr_str, lnum, line))
ListFileHandle.write('%6s %4s %s %s\n'
% (code_str, addr_str, lnum_str, line_str))
ListFileHandle.flush()
def eval_expression(expr, dot):
@ -131,12 +136,27 @@ def eval_expression(expr, dot):
dot current code address (the "." symbol value)
Valid expressions are:
# <expr> ::= <string> | <numeric_expression>
# <string> ::= ('|") <characters> ('|")
<expr> ::= <string> | <numeric_expression>
<string> ::= ('|") <characters> ('|")
<numeric_expression> ::= (<numeric_const>|<name_const>|".") [ (+|-) <numeric_expression> ]
<name_const> ::= <name_characters>
"""
global Undefined
print('eval_expression: expr=%s' % expr)
# if no expression, do nothing
if expr is None:
return None
# if expression is a string, return an iterable of ASCII values
if expr[0] in "'\"":
delim = expr[0]
if expr[-1] != delim:
error("Badly formed string value: '%s'" % expr)
return expr[1:-1]
# replace any "." value with "dot" defined in the symbol table
expr = string.replace(expr, '.', 'dot')
expr = expr.upper()
@ -149,6 +169,11 @@ def eval_expression(expr, dot):
except TypeError as e:
error('ORG pseudo-opcode expression contains unsatisfied references\n'
'%d: %s' % (CurrentLineNumber, CurrentLine))
except NameError as e:
Undefined = e.message
if 'is not defined' in e.message:
Undefined = e.message[len("name '"):-len("' is not defined")]
raise
return result
@ -211,8 +236,11 @@ def assemble_oblock(oblock):
if label:
error('%d: %s\nORG opcode may not have a label'
% (lnum, line))
address = eval_expression(addr, address)
code = None
try:
address = eval_expression(addr, address)
except NameError as e:
error("%d: %s\nName '%s' is undefined"
% (lnum, line, Undefined))
cblock = [address, []]
write_list(None, None, lnum, line)
continue
@ -220,20 +248,46 @@ def assemble_oblock(oblock):
# END pseudo-op, terminate assembly
start_addr = None
if addr:
start_addr = eval_expression(addr, address)
try:
start_addr = eval_expression(addr, address)
except NameError as e:
error("%d: %s\nName '%s' is undefined"
% (lnum, line, undefined))
write_list(None, start_addr, lnum, line)
return cblock
elif opcode == 'EQU':
if label is None:
error('%d: %s\nEQU opcode missing a label'
% (lnum, line))
value = eval_expression(addr, None)
try:
value = eval_expression(addr, None)
except NameError as e:
error("%d: %s\nName '%s' is undefined"
% (lnum, line, Undefined))
define_label(label, value, lnum)
write_list(None, None, lnum, line)
continue
elif opcode == 'DATA':
try:
value = eval_expression(addr, address)
except NameError as e:
error("%d: %s\nName '%s' is undefined"
% (lnum, line, Undefined))
ln = lnum
li = line
if isinstance(value, basestring):
# ASCII constant
for ch in value:
write_list(ord(ch), address, ln, li)
address += 1
ln = None
li = None
else:
write_list(value, address, lnum, line)
address += 1
else:
code = assemble_line(lnum, opcode, addr)
cblock[1].append(code)
cblock[1].append((code, addr))
write_list(code, address, lnum, line)
if label:
define_label(label, address, lnum)
@ -243,6 +297,8 @@ def assemble_oblock(oblock):
define_label(label, address, lnum)
write_list(None, None, lnum, line)
return cblock
def assemble_org_blocks(blocks):
"""Assemble org blocks producing a code blocks list."""
@ -304,7 +360,7 @@ def split_fields(line):
if ndx == -1:
error('Unbalanced string delimiter:\n'
'%d: %s' % (CurrentLineNumber, CurrentLine))
address = remainder[:ndx].strip()
address = '"' + remainder[:ndx].strip() + '"'
remainder = remainder[ndx+1:].strip()
else:
# strip off any comment
@ -354,6 +410,72 @@ def split_orgs(asm_lines):
return result
def check_org_overlap(code_blocks):
"""Check that we don't have overlapping ORG blocks."""
# remember org block span: [(start, end), (start', end'), ...]
block_span = []
for cb in code_blocks:
(address, code) = cb
if address is None and not code:
# empty code block, ignore
continue
(block_start, code) = cb
block_end = block_start + len(code) - 1
print('block: %06o,%06o' % (block_start, block_end))
for (start, end) in block_span:
print('check block: %06o,%06o' % (start, end))
if start <= block_start <= end:
error('ORG block at address %06o overwrites previous block at [%06o,%06o]'
% (block_start, start, end))
if start <= block_end <= end:
error('ORG block at address %06o overwrites previous block at [%06o,%06o]'
% (block_start, start, end))
block_span.append((block_start, block_end))
def allocate_literals(code_blocks):
"""Allocate space for literal blocks."""
pass
def backpatch(code_blocks):
"""Generate final code values, evaluate address fields.
Returns a simplified code block list: [[address, [code, code, ...]], ...].
"""
print('backpatch: code_blocks=%s' % str(code_blocks))
result = []
for cb in code_blocks:
print('cb=%s' % str(cb))
(address, codes) = cb
if address is None and not codes:
# empty code block, ignore
continue
# got a code_block that has code
dot = address
new_code = []
for (code, addr) in codes:
try:
addr_value = eval_expression(addr, dot)
except NameError as e:
error("Name '%s' is undefined" % Undefined)
if addr_value:
code |= addr_value
new_code.append(code)
dot += 1
result.append([address, new_code])
return [address, new_code]
def assemble_file():
"""Assemble the file and produce listing, output files."""
@ -372,6 +494,14 @@ def assemble_file():
print('SymTable=%s' % str(SymTable))
print('SymTableLine=%s' % str(SymTableLine))
# allow programmer to overlap ORG blocks
# check_org_overlap(code_blocks)
allocate_literals(code_blocks)
patched_code_blocks = backpatch(code_blocks)
print('patched_code_blocks=%s' % str(patched_code_blocks))
def main():
"""The assembler."""