From 45f82a1acf465c8420690a578192cdabf4bc7c04 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Fri, 2 Dec 2011 15:06:40 +0000 Subject: Add WIP for supporting existing asm files --- AsmParser.py | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 AsmParser.py (limited to 'AsmParser.py') diff --git a/AsmParser.py b/AsmParser.py new file mode 100644 index 0000000..40ad384 --- /dev/null +++ b/AsmParser.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +"""Compiles C into assembly for the practicum processor (PP2) + +All rights reserved, you may not redistribute or use this program without prior +permission from Peter Wu or Xander Houtman. Use of this program is entirely +your own risk. In no circumstances can the authors of this program be held +responsible for any damage including, but not limited to, financial damage or +data loss. Modification of this program is not allowed without prior +permission. The generated output (assembly and messages) are not subject to +this license. +""" + +__author__ = "Peter Wu" +__copyright__ = "Copyright 2011, Peter Wu" +__credits__ = ["Peter Wu"] +__license__ = "Proprietary" +__version__ = "1.0" +__maintainer__ = "Peter Wu" +__email__ = "uwretep@gmail.com" + +from Asm import Asm +import re + +class AsmParser(object): + def __init__(self, filename, parent=None): + if parent: + self.parent = parent + self.defined_names = parent.defined_names + else: + self.data = [] + self.code = [] + # defined labels for the assembly files. key: label, value: mapped + # label (to avoid name clashes with the other code) + self.labels = {} + # defined words/storage + self.defined_names = [] + + # valid values: None, DATA and CODE + self.in_section = None + # key: name, value: list of line numbers + self.constants = {} + + self.re_whitespace = re.compile("\s+") + self.asm = Asm() + + file = open(filename, "rU") + while True: + line = file.readline() + # line is empty if EoF, otherwise a string including newline + if line: + self.parseLine(line.split(";", 1)[0].strip()) + else: + break + file.close() + def parseLine(self, line): + """Processes the a line from assembly""" + if line.startswith("@"): + cmd, opts = re.split("\s+", line + " ", 1) + cmd = cmd[1:] + opts = opts.strip() + + if cmd == "CODE": + self.in_section = "CODE" + elif cmd == "DATA": + self.in_section = "DATA" + elif cmd == "END": + self.in_section = None + elif cmd == "INCLUDE": + if opts.count('"', 1, -1) == 0 and opts.count('"') == 2: + raise RuntimeError('Expected the format @INCLUDE "file", ' + "found '{}' instead".format(line)) + filename = opts[1:-1] + if not filename.endswith(".asm"): + filename += ".asm" + AsmParser(filename, self) + elif cmd in ("STACKSIZE", "STACK"): + # ignore + pass + else: + raise RuntimeError("Unrecognized command '{}'".format(cmd)) + elif self.in_section in ("DATA", "CODE"): + match = re.split(self.re_whitespace, line, 2) + if len(match) == 2: + name, what, data = match + if what == "EQU": + self.setConstant(name, data) + line = "" + elif what in ("DS", "DW"): + if self.in_section == "CODE": + raise RuntimeError("DS or DW found in @CODE section") + self.addName(name) + self.addData(line) + if line: + if self.in_section == "DATA": + raise RuntimeError("Found non definition data in @DATA") + label = self.asm.get_label(line) + self.addLabel(label) + self.addCode(line) + else: + # ignore other lines + pass + def setConstant(self, name, value): + """Defines a constant for the current assembly file + """ + if name in self.constants: + raise RuntimeError("Redefinition of constant '{}'".format(name)) + self.constants[name] = self.evaluateConstant(data) + def addCode(self, line): + """Add a line to the @CODE section""" + if self.parent: + self.parent.addCode(line) + else: + self.code.append(line) + def addData(self, line): + """Add a line to the @DATA section""" + if self.parent: + self.parent.addData(line) + else: + self.data.append(line) + def evaluateConstant(self, expression): + """Evaluates a constant expression in an EQU""" + if not expression.isdigit(): + raise RuntimeError("I am lazy and do not support values other than" + " digits in an EQU") + return expression + def addLabel(self, label): + """Adds a label to the list of labels""" + if self.parent: + self.parent.addLabel(label) + elif label in self.labels: + raise RuntimeError("Label '{}' is already defined".format(label)) + else: + self.labels[label] = label + def addName(self, name): + """Adds a name to the list of define words/ storage""" + if self.parent: + self.parent.addName(name) + elif name in self.defined_names: + raise RuntimeError("Name '{}' is already defined".format(name)) + else: + self.defined_names.append(name) + def mapLabel(self, label, new_label): + """Renames a label""" + if not name in self.labels: + raise RuntimeError("Attempt to rename an undefined '{}' to '{}'" + .format(label, new_label)) + self.labels[label] = new_label -- cgit v1.2.1