# HG changeset patch # User Windel Bouwman # Date 1370080549 -7200 # Node ID ec2b423cdbea95a919d2839dbf99203eb88544f5 # Parent 37ac6c016e0f063cec382de4402f467ad1387e6d Merge asm and asmlib files diff -r 37ac6c016e0f -r ec2b423cdbea python/asm.py --- a/python/asm.py Fri May 31 21:06:44 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#!/usr/bin/python - -# Assembler - -import sys, argparse -import pdb - -import libasm - -parser = argparse.ArgumentParser(description="Assembler") -pdb.set_trace() -parser.add_argument('sourcefile', type=argparse.FileType('r'), help='the source file to assemble') -args = parser.parse_args() - - -a = libasm.Assembler() -obj = a.assemble(args.sourcefile.read()) - -print('object:', obj) - diff -r 37ac6c016e0f -r ec2b423cdbea python/libasm.py --- a/python/libasm.py Fri May 31 21:06:44 2013 +0200 +++ b/python/libasm.py Sat Jun 01 11:55:49 2013 +0200 @@ -1,6 +1,8 @@ import re import pyyacc from ppci import Token, CompilerError, SourceLocation +import sys, argparse + # Different instruction sets: class InstructionSet: @@ -98,8 +100,10 @@ class AExpression(ANode): def __add__(self, other): + assert isinstance(other, AExpression) return ABinop('+', self, other) def __mul__(self, other): + assert isinstance(other, AExpression) return ABinop('*', self, other) class ABinop(AExpression): @@ -138,6 +142,7 @@ g.add_production('asmline', ['label', 'instruction']) g.add_production('asmline', ['instruction']) g.add_production('asmline', ['label']) + g.add_production('asmline', []) g.add_production('label', ['ID', ':'], self.p_label) g.add_production('instruction', ['opcode', 'operands'], self.p_ins_1) g.add_production('instruction', ['opcode'], self.p_ins_2) @@ -186,33 +191,47 @@ n = int(n) return ANumber(n) - # Top level: + # Top level interface: def emit(self, a): + """ Emit a parsed instruction """ self.output.append(a) + # Determine the bit pattern from a lookup table: + # TODO + def parse_line(self, line): """ Parse line into asm AST """ tokens = tokenize(line) self.p.parse(tokens) - aast = 1 # TODO - return aast def assemble(self, asmsrc): - lxr = Lexer(asmsrc) - prsr = Parser(lxr) - instructions = prsr.parse() - return instructions + """ Assemble this source snippet """ + for line in asmsrc.split('\n'): + self.assemble_line(line) + self.back_patch() - def assembleLine(self, line): + def assemble_line(self, line): """ Assemble a single source line. Do not take newlines into account """ - aast = self.parseLine(line) - self.assemble_aast(aast) + self.parse_line(line) + self.assemble_aast() def assemble_aast(self, at): """ Assemble a parsed asm line """ pass + def back_patch(self): + """ Fix references to earlier labels """ + pass + +if __name__ == '__main__': + # When run as main file, try to grab command line arguments: + parser = argparse.ArgumentParser(description="Assembler") + parser.add_argument('sourcefile', type=argparse.FileType('r'), help='the source file to assemble') + args = parser.parse_args() + a = Assembler() + obj = a.assemble(args.sourcefile.read()) + diff -r 37ac6c016e0f -r ec2b423cdbea python/testasm.py --- a/python/testasm.py Fri May 31 21:06:44 2013 +0200 +++ b/python/testasm.py Sat Jun 01 11:55:49 2013 +0200 @@ -77,10 +77,23 @@ output = [] output.append(ALabel('lab1')) self.assertSequenceEqual(output, a.output) + + def testParse6(self): + # A line can be empty + a = libasm.Assembler() + a.parse_line('') def testX86(self): - # TODO - pass + testsrc = """ + begin: + mov rax, rbx + xor rcx, rbx + inc rcx + """ + a = libasm.Assembler() + a.assemble(testsrc) + # Compare with nasm output: + nasmbytes = [0x48, 0x89, 0xd8, 0x48, 0x31, 0xd9, 0x48, 0xff, 0xc1] if __name__ == '__main__': unittest.main()