Source code for pepper.symbol_table
# This file is a part of the Pepper project, https://github.com/devosoft/Pepper
# (C) Michigan State University, under the MIT License
# See LICENSE.txt for more information
"""
The Symbol Table module implements a class to track declarations and usages of identifiers
"""
import sys
import platform
import re # because we need more performance issues
#: The global symboltable
TABLE = dict() # Identifier/argment list length pairs.
#: The stack of files we're reading from
FILE_STACK = []
#: The stack of ifdef/ifndef/if control structures we're processing
IFDEF_STACK = []
#: The list of paths to search when doing a system include
SYSTEM_INCLUDE_PATHS = []
EXPANDED_MACRO = False
#: Switch to test internal error handling
TRIGGER_INTERNAL_ERROR = False
#: The default linux paths to search for includes-
LINUX_DEFAULTS = [
"/usr/include/c++/7",
"/usr/include/x86_64-linux-gnu/c++/7",
"/usr/include/c++/7/backward",
"/usr/lib/gcc/x86_64-linux-gnu/7/include",
"/usr/local/include",
"/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed",
"/usr/include/x86_64-linux-gnu",
"/usr/include"
]
MAC_DEFAULTS = [
"/usr/local/include",
"/Library/Developer/CommandLineTools/usr/include/c++/v1",
"/Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include",
"/Library/Developer/CommandLineTools/usr/include",
"/usr/include"
]
if platform.system() == "Linux":
SYSTEM_INCLUDE_PATHS = LINUX_DEFAULTS
elif platform.system() == "Darwin":
SYSTEM_INCLUDE_PATHS = MAC_DEFAULTS
[docs]class PepperSyntaxError(Exception):
def __init__(self, msg=None):
self.msg = msg
[docs]class PepperInternalError(Exception):
def __init__(self, msg=None):
self.msg = msg
[docs]class MacroExpansion():
"Expands an identifier into a macro expansion, possibly with arguments"
def __init__(self, name, expansion, args=None):
self.name = name
self.expansion = ""
self.args = args
self.variadic = False
if self.args is not None:
for index, arg in enumerate(self.args):
if arg.endswith("..."):
if index != len(self.args) - 1:
raise PepperSyntaxError("Variadic macro argument must be at the end of the"
" argument definition list")
self.variadic = True
for item in expansion:
self.expansion += item.preprocess()
if self.name in TABLE.keys():
print(f"Warning: Redefining macro '{self.name}'", file=sys.stderr)
TABLE[self.name] = self
def _validate_args(self, args):
"Internal arg validator, broken out since it was getting long"
if self.variadic:
if len(args) <= len(self.args) - 1:
raise PepperSyntaxError(f"Macro {self.name} was given {len(args)} arguments,"
f" but takes a minimum of {len(self.args) + 1}")
elif self.args is None and args is not None:
raise PepperSyntaxError(f"Macro {self.name} doesn't take any args,"
f" but was given {len(args)}")
elif self.args is None and args is None:
pass
elif len(args) != len(self.args):
raise PepperSyntaxError(f"Wrong number of arguments in macro expansion for {self.name};"
f" expected {len(self.args)}, got {len(args)}")
[docs] def expand(self, args=None):
"Expand macro, maybe with args"
global EXPANDED_MACRO
try:
self._validate_args(args)
except Exception as err:
print(f"\n\nError in macro {self.name} argument validation")
print(f"self.args: {self.args}")
print(f"incoming args: {args}\n\n")
raise err
expansion = self.expansion
EXPANDED_MACRO = True
if args:
args = [arg.strip() for arg in args]
if self.variadic:
# for some reason slicing this inline doesn't work
non_variadic_args = args[:len(self.args)-1]
variadic_args = args[len(non_variadic_args):]
for index, arg in enumerate(non_variadic_args):
expansion = re.sub(fr"\b{self.args[index]}\b", str(arg), expansion)
variadic_target = "__VA__ARGS__"
if len(self.args[-1]) > 3: # named variadic target, i.e. "args..."
variadic_target = self.args[-1][:-3]
expansion = re.sub(fr"{variadic_target}", ", ".join(variadic_args), expansion)
else:
for index, arg in enumerate(args):
expansion = re.sub(fr"\b{self.args[index]}\b", str(arg), expansion)
return expansion
[docs] def preprocess(self, lines):
if TRIGGER_INTERNAL_ERROR:
raise Exception
lines[-1] += "// " + self.__str__()
def __str__(self):
return f"Macro {self.name} with args {self.args} expanding to '{self.expansion}'"