# Copyright (c) 2014, 2016, 2018-2019 ARM Limited # All rights reserved # # The license below extends only to copyright in the software and shall # not be construed as granting a license to any other intellectual # property including but not limited to intellectual property relating # to a hardware implementation of the functionality of the software # licensed hereunder. You may use the software subject to the license # terms below provided that you ensure that this notice is replicated # unmodified and in its entirety in all distributions of the software, # modified or unmodified, in source code or in binary form. # # Copyright (c) 2003-2005 The Regents of The University of Michigan # Copyright (c) 2013,2015 Advanced Micro Devices, Inc. # 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. import re ################### # Utility functions # # Indent every line in string 's' by two spaces # (except preprocessor directives). # Used to make nested code blocks look pretty. # def indent(s): return re.sub(r"(?m)^(?!#)", " ", s) # Regular expression object to match C++ strings stringRE = re.compile(r'"([^"\\]|\\.)*"') # Regular expression object to match C++ comments # (used in findOperands()) commentRE = re.compile( r"(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?", re.DOTALL | re.MULTILINE, ) # Regular expression object to match assignment statements (used in # findOperands()). If the code immediately following the first # appearance of the operand matches this regex, then the operand # appears to be on the LHS of an assignment, and is thus a # destination. basically we're looking for an '=' that's not '=='. # The heinous tangle before that handles the case where the operand # has an array subscript. assignRE = re.compile(r"(\[[^\]]+\])?\s*=(?!=)", re.MULTILINE) # # Munge a somewhat arbitrarily formatted piece of Python code # (e.g. from a format 'let' block) into something whose indentation # will get by the Python parser. # # The two keys here are that Python will give a syntax error if # there's any whitespace at the beginning of the first line, and that # all lines at the same lexical nesting level must have identical # indentation. Unfortunately the way code literals work, an entire # let block tends to have some initial indentation. Rather than # trying to figure out what that is and strip it off, we prepend 'if # 1:' to make the let code the nested block inside the if (and have # the parser automatically deal with the indentation for us). # # We don't want to do this if (1) the code block is empty or (2) the # first line of the block doesn't have any whitespace at the front. def fixPythonIndentation(s): # get rid of blank lines first s = re.sub(r"(?m)^\s*\n", "", s) if s != "" and re.match(r"[ \t]", s[0]): s = "if 1:\n" + s return s class ISAParserError(Exception): """Exception class for parser errors""" def __init__(self, first, second=None): if second is None: self.lineno = 0 self.string = first else: self.lineno = first self.string = second def __str__(self): return self.string def error(*args): raise ISAParserError(*args) def protectNonSubstPercents(s): """Protect any non-dict-substitution '%'s in a format string (i.e. those not followed by '(')""" return re.sub(r"%(?!\()", "%%", s) ############## # Stack: a simple stack object. Used for both formats (formatStack) # and default cases (defaultStack). Simply wraps a list to give more # stack-like syntax and enable initialization with an argument list # (as opposed to an argument that's a list). class Stack(list): def __init__(self, *items): list.__init__(self, items) def push(self, item): self.append(item) def top(self): return self[-1] # Format a file include stack backtrace as a string def backtrace(filename_stack): fmt = "In file included from %s:" return "\n".join([fmt % f for f in filename_stack]) ####################### # # LineTracker: track filenames along with line numbers in PLY lineno fields # PLY explicitly doesn't do anything with 'lineno' except propagate # it. This class lets us tie filenames with the line numbers with a # minimum of disruption to existing increment code. # class LineTracker(object): def __init__(self, filename, lineno=1): self.filename = filename self.lineno = lineno # Overload '+=' for increments. We need to create a new object on # each update else every token ends up referencing the same # constantly incrementing instance. def __iadd__(self, incr): return LineTracker(self.filename, self.lineno + incr) def __str__(self): return "%s:%d" % (self.filename, self.lineno) # In case there are places where someone really expects a number def __int__(self): return self.lineno