From: Gabe Black Date: Tue, 29 Sep 2020 07:58:36 +0000 (-0700) Subject: arch: Split utility methods/variables out of the ISA parser. X-Git-Tag: develop-gem5-snapshot~652 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2c17978be77141c34ad95513c99dffc92d83a248;p=gem5.git arch: Split utility methods/variables out of the ISA parser. Change-Id: Ifbff4bc6633cd11f98b02ba1291a91c3ad189285 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35279 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- diff --git a/src/arch/isa_parser/isa_parser.py b/src/arch/isa_parser/isa_parser.py index c147caf62..f6707763f 100755 --- a/src/arch/isa_parser/isa_parser.py +++ b/src/arch/isa_parser/isa_parser.py @@ -47,60 +47,10 @@ from types import * from m5.util.grammar import Grammar from .operand_types import * +from .util import * debug=False -################### -# 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) - -# -# 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) - #################### # Template objects. # @@ -119,7 +69,7 @@ class Template(object): # Protect non-Python-dict substitutions (e.g. if there's a printf # in the templated C++ code) - template = self.parser.protectNonSubstPercents(self.template) + template = protectNonSubstPercents(self.template) # Build a dict ('myDict') to use for the template substitution. # Start with the template namespace. Make a copy since we're @@ -763,54 +713,6 @@ class InstObjParams(object): else: self.fp_enable_check = '' -############## -# 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 - ####################### # @@ -1285,7 +1187,7 @@ class ISAParser(Grammar): # indicate template substitutions by doubling them first so that the # format operation will reduce them back to single '%'s. def process_output(self, s): - s = self.protectNonSubstPercents(s) + s = protectNonSubstPercents(s) return substBitOps(s % self.templateMap) def p_output(self, t): @@ -1790,12 +1692,6 @@ StaticInstPtr # create new object and store in global map self.formatMap[id] = Format(id, params, code) - def protectNonSubstPercents(self, s): - '''Protect any non-dict-substitution '%'s in a format string - (i.e. those not followed by '(')''' - - return re.sub(r'%(?!\()', '%%', s) - def buildOperandNameMap(self, user_dict, lineno): operand_name = {} for op_name, val in user_dict.items(): diff --git a/src/arch/isa_parser/util.py b/src/arch/isa_parser/util.py new file mode 100755 index 000000000..1a1be2601 --- /dev/null +++ b/src/arch/isa_parser/util.py @@ -0,0 +1,145 @@ +# 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) + +# +# 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