# Copyright (c) 2003-2005 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Gabe Black from __future__ import print_function import os import sys import re import string import traceback # get type names from types import * from ply import lex from ply import yacc ########################################################################## # # Base classes for use outside of the assembler # ########################################################################## class Micro_Container(object): def __init__(self, name): self.microops = [] self.name = name self.directives = {} self.micro_classes = {} self.labels = {} def add_microop(self, mnemonic, microop): self.microops.append(microop) def __str__(self): string = "%s:\n" % self.name for microop in self.microops: string += " %s\n" % microop return string class Combinational_Macroop(Micro_Container): pass class Rom_Macroop(object): def __init__(self, name, target): self.name = name self.target = target def __str__(self): return "%s: %s\n" % (self.name, self.target) class Rom(Micro_Container): def __init__(self, name): super(Rom, self).__init__(name) self.externs = {} ########################################################################## # # Support classes # ########################################################################## class Label(object): def __init__(self): self.extern = False self.name = "" class Block(object): def __init__(self): self.statements = [] class Statement(object): def __init__(self): self.is_microop = False self.is_directive = False self.params = "" class Microop(Statement): def __init__(self): super(Microop, self).__init__() self.mnemonic = "" self.labels = [] self.is_microop = True class Directive(Statement): def __init__(self): super(Directive, self).__init__() self.name = "" self.is_directive = True ########################################################################## # # Functions that handle common tasks # ########################################################################## def print_error(message): print() print("*** %s" % message) print() def handle_statement(parser, container, statement): if statement.is_microop: if statement.mnemonic not in parser.microops.keys(): raise Exception, "Unrecognized mnemonic: %s" % statement.mnemonic parser.symbols["__microopClassFromInsideTheAssembler"] = \ parser.microops[statement.mnemonic] try: microop = eval('__microopClassFromInsideTheAssembler(%s)' % statement.params, {}, parser.symbols) except: print_error("Error creating microop object with mnemonic %s." % \ statement.mnemonic) raise try: for label in statement.labels: container.labels[label.text] = microop if label.is_extern: container.externs[label.text] = microop container.add_microop(statement.mnemonic, microop) except: print_error("Error adding microop.") raise elif statement.is_directive: if statement.name not in container.directives.keys(): raise Exception, "Unrecognized directive: %s" % statement.name parser.symbols["__directiveFunctionFromInsideTheAssembler"] = \ container.directives[statement.name] try: eval('__directiveFunctionFromInsideTheAssembler(%s)' % statement.params, {}, parser.symbols) except: print_error("Error executing directive.") print(container.directives) raise else: raise Exception, "Didn't recognize the type of statement", statement ########################################################################## # # Lexer specification # ########################################################################## # Error handler. Just call exit. Output formatted to work under # Emacs compile-mode. Optional 'print_traceback' arg, if set to True, # prints a Python stack backtrace too (can be handy when trying to # debug the parser itself). def error(lineno, string, print_traceback = False): # Print a Python stack backtrace if requested. if (print_traceback): traceback.print_exc() if lineno != 0: line_str = "%d:" % lineno else: line_str = "" sys.exit("%s %s" % (line_str, string)) reserved = ('DEF', 'MACROOP', 'ROM', 'EXTERN') tokens = reserved + ( # identifier 'ID', # arguments for microops and directives 'PARAMS', 'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'COLON', 'SEMI', 'DOT', 'NEWLINE' ) # New lines are ignored at the top level, but they end statements in the # assembler states = ( ('asm', 'exclusive'), ('params', 'exclusive'), ) reserved_map = { } for r in reserved: reserved_map[r.lower()] = r # Ignore comments def t_ANY_COMMENT(t): r'\#[^\n]*(?=\n)' def t_ANY_MULTILINECOMMENT(t): r'/\*([^/]|((?