From e2f65bae1d9c2a0e99f4db442548421fd4be9a5b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 14 Dec 2024 18:15:50 +0100 Subject: [PATCH 1/5] refact: refactorize typing --- src/zxbpp/prepro/builtinmacro.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zxbpp/prepro/builtinmacro.py b/src/zxbpp/prepro/builtinmacro.py index b6a44ccbd..d823292aa 100644 --- a/src/zxbpp/prepro/builtinmacro.py +++ b/src/zxbpp/prepro/builtinmacro.py @@ -1,7 +1,6 @@ from collections.abc import Callable -from src.zxbpp import prepro - +from src.zxbpp.prepro import DefinesTable from .id_ import ID from .macrocall import MacroCall @@ -16,5 +15,5 @@ def __init__(self, macro_name: str, func: Callable[[MacroCall | None], str]): super().__init__(fname="", lineno=0, id_=macro_name) self.func = func - def __call__(self, symbolTable: prepro.DefinesTable | None = None, macro: MacroCall | None = None) -> str: + def __call__(self, symbolTable: DefinesTable | None = None, macro: MacroCall | None = None) -> str: return self.func(macro) From 63c9050dd0cf55546bbf3859e3942a45292c96a7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 14 Dec 2024 20:05:36 +0100 Subject: [PATCH 2/5] fix: fixes parsetab generation --- pyproject.toml | 12 + src/parsetab/tabs.dbm.bak | 8 +- src/parsetab/tabs.dbm.dat | Bin 1201302 -> 1201315 bytes src/parsetab/tabs.dbm.dir | 8 +- src/ply/__init__.py | 2 +- src/ply/lex.py | 303 +++++----- src/ply/yacc.py | 978 +++++++++++++++---------------- src/zxbpp/prepro/builtinmacro.py | 1 + 8 files changed, 629 insertions(+), 683 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2d8e72a44..2f2ee8fb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,10 +98,22 @@ disable_error_code = [ "union-attr", "var-annotated", ] +exclude = [ + 'src/ply/.*\.py$' +] + +[[tool.mypy.overrides]] +module = [ + "src.ply.*", +] +follow_imports = "skip" [tool.ruff] line-length = 120 target-version = "py310" +exclude = [ + "src/ply" # PLY, external 3rd party tool +] [tool.ruff.lint] select = [ diff --git a/src/parsetab/tabs.dbm.bak b/src/parsetab/tabs.dbm.bak index 3e0498e8d..342fa703c 100644 --- a/src/parsetab/tabs.dbm.bak +++ b/src/parsetab/tabs.dbm.bak @@ -1,4 +1,4 @@ -'zxbpp', (0, 66990) -'asmparse', (67072, 233944) -'zxnext_asmparse', (301056, 259009) -'zxbparser', (560128, 641174) +'zxbpp', (0, 67003) +'asmparse', (67072, 233956) +'zxnext_asmparse', (301056, 259034) +'zxbparser', (560128, 641187) diff --git a/src/parsetab/tabs.dbm.dat b/src/parsetab/tabs.dbm.dat index cdb15cc1291892b76ef82302f4e690b76b91271b..e65a05f9af9389e0b7cb40ba04d7940f297bdb41 100644 GIT binary patch delta 14170 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 Kv$K^u{eJ*FYfIz+ delta 14164 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 BA(8+9 diff --git a/src/parsetab/tabs.dbm.dir b/src/parsetab/tabs.dbm.dir index 3e0498e8d..342fa703c 100644 --- a/src/parsetab/tabs.dbm.dir +++ b/src/parsetab/tabs.dbm.dir @@ -1,4 +1,4 @@ -'zxbpp', (0, 66990) -'asmparse', (67072, 233944) -'zxnext_asmparse', (301056, 259009) -'zxbparser', (560128, 641174) +'zxbpp', (0, 67003) +'asmparse', (67072, 233956) +'zxnext_asmparse', (301056, 259034) +'zxbparser', (560128, 641187) diff --git a/src/ply/__init__.py b/src/ply/__init__.py index 863ef5423..45f28c5b5 100644 --- a/src/ply/__init__.py +++ b/src/ply/__init__.py @@ -2,4 +2,4 @@ # Author: David Beazley (dave@dabeaz.com) # https://github.com/dabeaz/ply -__version__ = "2022.10.27" +__version__ = '2022.10.27' diff --git a/src/ply/lex.py b/src/ply/lex.py index 42fe7102f..de011fe13 100644 --- a/src/ply/lex.py +++ b/src/ply/lex.py @@ -33,18 +33,18 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- -import copy -import inspect import re import sys import types +import copy +import os +import inspect # This tuple contains acceptable string types StringTypes = (str, bytes) # This regular expression is used to match valid token names -_is_identifier = re.compile(r"^[a-zA-Z0-9_]+$") - +_is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') # Exception thrown when invalid token encountered and no default error # handler is defined. @@ -53,34 +53,30 @@ def __init__(self, message, s): self.args = (message,) self.text = s - # Token class. This class is used to represent the tokens produced. -class LexToken: +class LexToken(object): def __repr__(self): - return f"LexToken({self.type},{self.value!r},{self.lineno},{self.lexpos})" - + return f'LexToken({self.type},{self.value!r},{self.lineno},{self.lexpos})' # This object is a stand-in for a logging object created by the # logging module. - -class PlyLogger: +class PlyLogger(object): def __init__(self, f): self.f = f def critical(self, msg, *args, **kwargs): - self.f.write((msg % args) + "\n") + self.f.write((msg % args) + '\n') def warning(self, msg, *args, **kwargs): - self.f.write("WARNING: " + (msg % args) + "\n") + self.f.write('WARNING: ' + (msg % args) + '\n') def error(self, msg, *args, **kwargs): - self.f.write("ERROR: " + (msg % args) + "\n") + self.f.write('ERROR: ' + (msg % args) + '\n') info = critical debug = critical - # ----------------------------------------------------------------------------- # === Lexing Engine === # @@ -95,34 +91,33 @@ def error(self, msg, *args, **kwargs): # lexpos - Current position in the input string # ----------------------------------------------------------------------------- - class Lexer: def __init__(self): - self.lexre = None # Master regular expression. This is a list of - # tuples (re, findex) where re is a compiled - # regular expression and findex is a list - # mapping regex group numbers to rules - self.lexretext = None # Current regular expression strings - self.lexstatere = {} # Dictionary mapping lexer states to master regexs - self.lexstateretext = {} # Dictionary mapping lexer states to regex strings - self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names - self.lexstate = "INITIAL" # Current lexer state - self.lexstatestack = [] # Stack of lexer states - self.lexstateinfo = None # State information - self.lexstateignore = {} # Dictionary of ignored characters for each state - self.lexstateerrorf = {} # Dictionary of error functions for each state - self.lexstateeoff = {} # Dictionary of eof functions for each state - self.lexreflags = 0 # Optional re compile flags - self.lexdata: str = "" # Actual input data (as a string) - self.lexpos = 0 # Current position in input text - self.lexlen = 0 # Length of the input text - self.lexerrorf = None # Error rule (if any) - self.lexeoff = None # EOF rule (if any) - self.lextokens = None # List of valid tokens - self.lexignore = "" # Ignored characters - self.lexliterals = "" # Literal characters that can be passed through - self.lexmodule = None # Module - self.lineno = 1 # Current line number + self.lexre = None # Master regular expression. This is a list of + # tuples (re, findex) where re is a compiled + # regular expression and findex is a list + # mapping regex group numbers to rules + self.lexretext = None # Current regular expression strings + self.lexstatere = {} # Dictionary mapping lexer states to master regexs + self.lexstateretext = {} # Dictionary mapping lexer states to regex strings + self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names + self.lexstate = 'INITIAL' # Current lexer state + self.lexstatestack = [] # Stack of lexer states + self.lexstateinfo = None # State information + self.lexstateignore = {} # Dictionary of ignored characters for each state + self.lexstateerrorf = {} # Dictionary of error functions for each state + self.lexstateeoff = {} # Dictionary of eof functions for each state + self.lexreflags = 0 # Optional re compile flags + self.lexdata = None # Actual input data (as a string) + self.lexpos = 0 # Current position in input text + self.lexlen = 0 # Length of the input text + self.lexerrorf = None # Error rule (if any) + self.lexeoff = None # EOF rule (if any) + self.lextokens = None # List of valid tokens + self.lexignore = '' # Ignored characters + self.lexliterals = '' # Literal characters that can be passed through + self.lexmodule = None # Module + self.lineno = 1 # Current line number def clone(self, object=None): c = copy.copy(self) @@ -164,10 +159,10 @@ def input(self, s): # ------------------------------------------------------------ def begin(self, state): if state not in self.lexstatere: - raise ValueError(f"Undefined state {state!r}") + raise ValueError(f'Undefined state {state!r}') self.lexre = self.lexstatere[state] self.lexretext = self.lexstateretext[state] - self.lexignore = self.lexstateignore.get(state, "") + self.lexignore = self.lexstateignore.get(state, '') self.lexerrorf = self.lexstateerrorf.get(state, None) self.lexeoff = self.lexstateeoff.get(state, None) self.lexstate = state @@ -206,10 +201,10 @@ def skip(self, n): # ------------------------------------------------------------ def token(self): # Make local copies of frequently referenced attributes - lexpos = self.lexpos - lexlen = self.lexlen + lexpos = self.lexpos + lexlen = self.lexlen lexignore = self.lexignore - lexdata = self.lexdata + lexdata = self.lexdata while lexpos < lexlen: # This code provides some short-circuit code for whitespace, tabs, and other ignored characters @@ -237,14 +232,15 @@ def token(self): if tok.type: self.lexpos = m.end() return tok - lexpos = m.end() - break + else: + lexpos = m.end() + break lexpos = m.end() # If token is processed by a function, call it - tok.lexer = self # Set additional attributes useful in token rules + tok.lexer = self # Set additional attributes useful in token rules self.lexmatch = m self.lexpos = lexpos newtok = func(tok) @@ -253,8 +249,8 @@ def token(self): # Every function must return a token, if nothing, we just move to next token if not newtok: - lexpos = self.lexpos # This is here in case user has updated lexpos. - lexignore = self.lexignore # This is here in case there was a state change + lexpos = self.lexpos # This is here in case user has updated lexpos. + lexignore = self.lexignore # This is here in case there was a state change break return newtok else: @@ -273,26 +269,28 @@ def token(self): tok = LexToken() tok.value = self.lexdata[lexpos:] tok.lineno = self.lineno - tok.type = "error" + tok.type = 'error' tok.lexer = self tok.lexpos = lexpos self.lexpos = lexpos newtok = self.lexerrorf(tok) if lexpos == self.lexpos: # Error method didn't change text position at all. This is an error. - raise LexError(f"Scanning error. Illegal character {lexdata[lexpos]!r}", lexdata[lexpos:]) + raise LexError(f"Scanning error. Illegal character {lexdata[lexpos]!r}", + lexdata[lexpos:]) lexpos = self.lexpos if not newtok: continue return newtok self.lexpos = lexpos - raise LexError(f"Illegal character {lexdata[lexpos]!r} at index {lexpos}", lexdata[lexpos:]) + raise LexError(f"Illegal character {lexdata[lexpos]!r} at index {lexpos}", + lexdata[lexpos:]) if self.lexeoff: tok = LexToken() - tok.type = "eof" - tok.value = "" + tok.type = 'eof' + tok.value = '' tok.lineno = self.lineno tok.lexpos = lexpos tok.lexer = self @@ -302,7 +300,7 @@ def token(self): self.lexpos = lexpos + 1 if self.lexdata is None: - raise RuntimeError("No input string given with input()") + raise RuntimeError('No input string given with input()') return None # Iterator interface @@ -315,7 +313,6 @@ def __next__(self): raise StopIteration return t - # ----------------------------------------------------------------------------- # ==== Lex Builder === # @@ -323,7 +320,6 @@ def __next__(self): # and build a Lexer object from it. # ----------------------------------------------------------------------------- - # ----------------------------------------------------------------------------- # _get_regex(func) # @@ -331,8 +327,7 @@ def __next__(self): # or as a .regex attribute attached by the @TOKEN decorator. # ----------------------------------------------------------------------------- def _get_regex(func): - return getattr(func, "regex", func.__doc__) - + return getattr(func, 'regex', func.__doc__) # ----------------------------------------------------------------------------- # get_caller_module_dict() @@ -343,8 +338,7 @@ def _get_regex(func): # ----------------------------------------------------------------------------- def get_caller_module_dict(levels): f = sys._getframe(levels) - return {**f.f_globals, **f.f_locals} - + return { **f.f_globals, **f.f_locals } # ----------------------------------------------------------------------------- # _form_master_re() @@ -356,7 +350,7 @@ def get_caller_module_dict(levels): def _form_master_re(relist, reflags, ldict, toknames): if not relist: return [], [], [] - regex = "|".join(relist) + regex = '|'.join(relist) try: lexre = re.compile(regex, reflags) @@ -371,7 +365,7 @@ def _form_master_re(relist, reflags, ldict, toknames): lexindexnames[i] = f elif handle is not None: lexindexnames[i] = f - if f.find("ignore_") > 0: + if f.find('ignore_') > 0: lexindexfunc[i] = (None, None) else: lexindexfunc[i] = (None, toknames[f]) @@ -381,8 +375,7 @@ def _form_master_re(relist, reflags, ldict, toknames): m = (len(relist) // 2) + 1 llist, lre, lnames = _form_master_re(relist[:m], reflags, ldict, toknames) rlist, rre, rnames = _form_master_re(relist[m:], reflags, ldict, toknames) - return (llist + rlist), (lre + rre), (lnames + rnames) - + return (llist+rlist), (lre+rre), (lnames+rnames) # ----------------------------------------------------------------------------- # def _statetoken(s,names) @@ -393,20 +386,20 @@ def _form_master_re(relist, reflags, ldict, toknames): # calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') # ----------------------------------------------------------------------------- def _statetoken(s, names): - parts = s.split("_") + parts = s.split('_') for i, part in enumerate(parts[1:], 1): - if part not in names and part != "ANY": + if part not in names and part != 'ANY': break if i > 1: states = tuple(parts[1:i]) else: - states = ("INITIAL",) + states = ('INITIAL',) - if "ANY" in states: + if 'ANY' in states: states = tuple(names) - tokenname = "_".join(parts[i:]) + tokenname = '_'.join(parts[i:]) return (states, tokenname) @@ -416,16 +409,16 @@ def _statetoken(s, names): # This class represents information needed to build a lexer as extracted from a # user's input file. # ----------------------------------------------------------------------------- -class LexerReflect: +class LexerReflect(object): def __init__(self, ldict, log=None, reflags=0): - self.ldict = ldict + self.ldict = ldict self.error_func = None - self.tokens = [] - self.reflags = reflags - self.stateinfo = {"INITIAL": "inclusive"} - self.modules = set() - self.error = False - self.log = PlyLogger(sys.stderr) if log is None else log + self.tokens = [] + self.reflags = reflags + self.stateinfo = {'INITIAL': 'inclusive'} + self.modules = set() + self.error = False + self.log = PlyLogger(sys.stderr) if log is None else log # Get all of the basic information def get_all(self): @@ -443,19 +436,19 @@ def validate_all(self): # Get the tokens map def get_tokens(self): - tokens = self.ldict.get("tokens", None) + tokens = self.ldict.get('tokens', None) if not tokens: - self.log.error("No token list is defined") + self.log.error('No token list is defined') self.error = True return if not isinstance(tokens, (list, tuple)): - self.log.error("tokens must be a list or tuple") + self.log.error('tokens must be a list or tuple') self.error = True return if not tokens: - self.log.error("tokens is empty") + self.log.error('tokens is empty') self.error = True return @@ -474,43 +467,41 @@ def validate_tokens(self): # Get the literals specifier def get_literals(self): - self.literals = self.ldict.get("literals", "") + self.literals = self.ldict.get('literals', '') if not self.literals: - self.literals = "" + self.literals = '' # Validate literals def validate_literals(self): try: for c in self.literals: if not isinstance(c, StringTypes) or len(c) > 1: - self.log.error(f"Invalid literal {c!r}. Must be a single character") + self.log.error(f'Invalid literal {c!r}. Must be a single character') self.error = True except TypeError: - self.log.error("Invalid literals specification. literals must be a sequence of characters") + self.log.error('Invalid literals specification. literals must be a sequence of characters') self.error = True def get_states(self): - self.states = self.ldict.get("states", None) + self.states = self.ldict.get('states', None) # Build statemap if self.states: if not isinstance(self.states, (tuple, list)): - self.log.error("states must be defined as a tuple or list") + self.log.error('states must be defined as a tuple or list') self.error = True else: for s in self.states: if not isinstance(s, tuple) or len(s) != 2: - self.log.error( - "Invalid state specifier %r. Must be a tuple (statename,'exclusive|inclusive')", s - ) + self.log.error("Invalid state specifier %r. Must be a tuple (statename,'exclusive|inclusive')", s) self.error = True continue name, statetype = s if not isinstance(name, StringTypes): - self.log.error("State name %r must be a string", name) + self.log.error('State name %r must be a string', name) self.error = True continue - if not (statetype == "inclusive" or statetype == "exclusive"): + if not (statetype == 'inclusive' or statetype == 'exclusive'): self.log.error("State type for state %r must be 'inclusive' or 'exclusive'", name) self.error = True continue @@ -518,28 +509,28 @@ def get_states(self): self.log.error("State %r already defined", name) self.error = True continue - self.stateinfo[str(name)] = statetype + self.stateinfo[name] = statetype # Get all of the symbols with a t_ prefix and sort them into various # categories (functions, strings, error functions, and ignore characters) def get_rules(self): - tsymbols = [f for f in self.ldict if f[:2] == "t_"] + tsymbols = [f for f in self.ldict if f[:2] == 't_'] # Now build up a list of functions and a list of strings - self.toknames = {} # Mapping of symbols to token names - self.funcsym = {} # Symbols defined as functions - self.strsym = {} # Symbols defined as strings - self.ignore = {} # Ignore strings by state - self.errorf = {} # Error functions by state - self.eoff = {} # EOF functions by state + self.toknames = {} # Mapping of symbols to token names + self.funcsym = {} # Symbols defined as functions + self.strsym = {} # Symbols defined as strings + self.ignore = {} # Ignore strings by state + self.errorf = {} # Error functions by state + self.eoff = {} # EOF functions by state for s in self.stateinfo: self.funcsym[s] = [] self.strsym[s] = [] if len(tsymbols) == 0: - self.log.error("No rules of the form t_rulename are defined") + self.log.error('No rules of the form t_rulename are defined') self.error = True return @@ -548,14 +539,14 @@ def get_rules(self): states, tokname = _statetoken(f, self.stateinfo) self.toknames[f] = tokname - if hasattr(t, "__call__"): - if tokname == "error": + if hasattr(t, '__call__'): + if tokname == 'error': for s in states: self.errorf[s] = t - elif tokname == "eof": + elif tokname == 'eof': for s in states: self.eoff[s] = t - elif tokname == "ignore": + elif tokname == 'ignore': line = t.__code__.co_firstlineno file = t.__code__.co_filename self.log.error("%s:%d: Rule %r must be defined as a string", file, line, t.__name__) @@ -564,20 +555,20 @@ def get_rules(self): for s in states: self.funcsym[s].append((f, t)) elif isinstance(t, StringTypes): - if tokname == "ignore": + if tokname == 'ignore': for s in states: self.ignore[s] = t - if "\\" in t: + if '\\' in t: self.log.warning("%s contains a literal backslash '\\'", f) - elif tokname == "error": + elif tokname == 'error': self.log.error("Rule %r must be defined as a function", f) self.error = True else: for s in states: self.strsym[s].append((f, t)) else: - self.log.error("%s not defined as a function or string", f) + self.log.error('%s not defined as a function or string', f) self.error = True # Sort the functions by line number @@ -621,39 +612,37 @@ def validate_rules(self): continue try: - c = re.compile("(?P<%s>%s)" % (fname, _get_regex(f)), self.reflags) - if c.match(""): - self.log.error( - "%s:%d: Regular expression for rule %r matches empty string", file, line, f.__name__ - ) + c = re.compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags) + if c.match(''): + self.log.error("%s:%d: Regular expression for rule %r matches empty string", file, line, f.__name__) self.error = True except re.error as e: self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file, line, f.__name__, e) - if "#" in _get_regex(f): + if '#' in _get_regex(f): self.log.error("%s:%d. Make sure '#' in rule %r is escaped with '\\#'", file, line, f.__name__) self.error = True # Validate all rules defined by strings for name, r in self.strsym[state]: tokname = self.toknames[name] - if tokname == "error": + if tokname == 'error': self.log.error("Rule %r must be defined as a function", name) self.error = True continue - if tokname not in self.tokens and tokname.find("ignore_") < 0: + if tokname not in self.tokens and tokname.find('ignore_') < 0: self.log.error("Rule %r defined for an unspecified token %s", name, tokname) self.error = True continue try: - c = re.compile("(?P<%s>%s)" % (name, r), self.reflags) - if c.match(""): + c = re.compile('(?P<%s>%s)' % (name, r), self.reflags) + if (c.match('')): self.log.error("Regular expression for rule %r matches empty string", name) self.error = True except re.error as e: self.log.error("Invalid regular expression for rule %r. %s", name, e) - if "#" in r: + if '#' in r: self.log.error("Make sure '#' in rule %r is escaped with '\\#'", name) self.error = True @@ -700,8 +689,8 @@ def validate_module(self, module): except IOError: return - fre = re.compile(r"\s*def\s+(t_[a-zA-Z_0-9]*)\(") - sre = re.compile(r"\s*(t_[a-zA-Z_0-9]*)\s*=") + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') counthash = {} linen += 1 @@ -716,23 +705,22 @@ def validate_module(self, module): counthash[name] = linen else: filename = inspect.getsourcefile(module) - self.log.error( - "%s:%d: Rule %s redefined. Previously defined on line %d", filename, linen, name, prev - ) + self.log.error('%s:%d: Rule %s redefined. Previously defined on line %d', filename, linen, name, prev) self.error = True linen += 1 - # ----------------------------------------------------------------------------- # lex(module) # # Build all of the regular expression rules from definitions in the supplied module # ----------------------------------------------------------------------------- -def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debuglog=None, errorlog=None): +def lex(*, module=None, object=None, debug=False, + reflags=int(re.VERBOSE), debuglog=None, errorlog=None): + global lexer ldict = None - stateinfo = {"INITIAL": "inclusive"} + stateinfo = {'INITIAL': 'inclusive'} lexobj = Lexer() global token, input @@ -752,8 +740,8 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug _items = [(k, getattr(module, k)) for k in dir(module)] ldict = dict(_items) # If no __file__ attribute is available, try to obtain it from the __module__ instead - if "__file__" not in ldict: - ldict["__file__"] = sys.modules[ldict["__module__"]].__file__ + if '__file__' not in ldict: + ldict['__file__'] = sys.modules[ldict['__module__']].__file__ else: ldict = get_caller_module_dict(2) @@ -765,9 +753,9 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug # Dump some basic debugging information if debug: - debuglog.info("lex: tokens = %r", linfo.tokens) - debuglog.info("lex: literals = %r", linfo.literals) - debuglog.info("lex: states = %r", linfo.stateinfo) + debuglog.info('lex: tokens = %r', linfo.tokens) + debuglog.info('lex: literals = %r', linfo.literals) + debuglog.info('lex: states = %r', linfo.stateinfo) # Build a dictionary of valid token names lexobj.lextokens = set() @@ -792,13 +780,13 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug # Add rules defined by functions first for fname, f in linfo.funcsym[state]: - regex_list.append("(?P<%s>%s)" % (fname, _get_regex(f))) + regex_list.append('(?P<%s>%s)' % (fname, _get_regex(f))) if debug: debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", fname, _get_regex(f), state) # Now add all of the simple rules for name, r in linfo.strsym[state]: - regex_list.append("(?P<%s>%s)" % (name, r)) + regex_list.append('(?P<%s>%s)' % (name, r)) if debug: debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", name, r, state) @@ -807,7 +795,7 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug # Build the master regular expressions if debug: - debuglog.info("lex: ==== MASTER REGEXS FOLLOW ====") + debuglog.info('lex: ==== MASTER REGEXS FOLLOW ====') for state in regexs: lexre, re_text, re_names = _form_master_re(regexs[state], reflags, ldict, linfo.toknames) @@ -820,42 +808,42 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug # For inclusive states, we need to add the regular expressions from the INITIAL state for state, stype in stateinfo.items(): - if state != "INITIAL" and stype == "inclusive": - lexobj.lexstatere[state].extend(lexobj.lexstatere["INITIAL"]) - lexobj.lexstateretext[state].extend(lexobj.lexstateretext["INITIAL"]) - lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames["INITIAL"]) + if state != 'INITIAL' and stype == 'inclusive': + lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) + lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) + lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) lexobj.lexstateinfo = stateinfo - lexobj.lexre = lexobj.lexstatere["INITIAL"] - lexobj.lexretext = lexobj.lexstateretext["INITIAL"] + lexobj.lexre = lexobj.lexstatere['INITIAL'] + lexobj.lexretext = lexobj.lexstateretext['INITIAL'] lexobj.lexreflags = reflags # Set up ignore variables lexobj.lexstateignore = linfo.ignore - lexobj.lexignore = lexobj.lexstateignore.get("INITIAL", "") + lexobj.lexignore = lexobj.lexstateignore.get('INITIAL', '') # Set up error functions lexobj.lexstateerrorf = linfo.errorf - lexobj.lexerrorf = linfo.errorf.get("INITIAL", None) + lexobj.lexerrorf = linfo.errorf.get('INITIAL', None) if not lexobj.lexerrorf: - errorlog.warning("No t_error rule is defined") + errorlog.warning('No t_error rule is defined') # Set up eof functions lexobj.lexstateeoff = linfo.eoff - lexobj.lexeoff = linfo.eoff.get("INITIAL", None) + lexobj.lexeoff = linfo.eoff.get('INITIAL', None) # Check state information for ignore and error rules for s, stype in stateinfo.items(): - if stype == "exclusive": + if stype == 'exclusive': if s not in linfo.errorf: errorlog.warning("No error rule is defined for exclusive state %r", s) if s not in linfo.ignore and lexobj.lexignore: errorlog.warning("No ignore rule is defined for exclusive state %r", s) - elif stype == "inclusive": + elif stype == 'inclusive': if s not in linfo.errorf: - linfo.errorf[s] = linfo.errorf.get("INITIAL", None) + linfo.errorf[s] = linfo.errorf.get('INITIAL', None) if s not in linfo.ignore: - linfo.ignore[s] = linfo.ignore.get("INITIAL", "") + linfo.ignore[s] = linfo.ignore.get('INITIAL', '') # Create global versions of the token() and input() functions token = lexobj.token @@ -864,14 +852,12 @@ def lex(*, module=None, object=None, debug=False, reflags=int(re.VERBOSE), debug return lexobj - # ----------------------------------------------------------------------------- # runmain() # # This runs the lexer as a main program # ----------------------------------------------------------------------------- - def runmain(lexer=None, data=None): if not data: try: @@ -879,7 +865,7 @@ def runmain(lexer=None, data=None): with open(filename) as f: data = f.read() except IndexError: - sys.stdout.write("Reading from standard input (type EOF to end):\n") + sys.stdout.write('Reading from standard input (type EOF to end):\n') data = sys.stdin.read() if lexer: @@ -896,8 +882,7 @@ def runmain(lexer=None, data=None): tok = _token() if not tok: break - sys.stdout.write(f"({tok.type},{tok.value!r},{tok.lineno},{tok.lexpos})\n") - + sys.stdout.write(f'({tok.type},{tok.value!r},{tok.lineno},{tok.lexpos})\n') # ----------------------------------------------------------------------------- # @TOKEN(regex) @@ -906,13 +891,11 @@ def runmain(lexer=None, data=None): # when its docstring might need to be set in an alternative way # ----------------------------------------------------------------------------- - def TOKEN(r): def set_regex(f): - if hasattr(r, "__call__"): + if hasattr(r, '__call__'): f.regex = _get_regex(r) else: f.regex = r return f - return set_regex diff --git a/src/ply/yacc.py b/src/ply/yacc.py index ece139b59..652879624 100644 --- a/src/ply/yacc.py +++ b/src/ply/yacc.py @@ -61,23 +61,23 @@ # own risk! # ---------------------------------------------------------------------------- -import inspect import re -import sys import types +import sys +import inspect -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # === User configurable parameters === # # Change these to modify the default behavior of yacc (if you wish) -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- -yaccdebug = False # Debugging mode. If set, yacc generates a -# a 'parser.out' file in the current directory +yaccdebug = False # Debugging mode. If set, yacc generates a + # a 'parser.out' file in the current directory -debug_file = "parser.out" # Default name of the debugging file -error_count = 3 # Number of symbols that must be shifted to leave recovery mode -resultlimit = 40 # Size limit of results when running in debug mode. +debug_file = 'parser.out' # Default name of the debugging file +error_count = 3 # Number of symbols that must be shifted to leave recovery mode +resultlimit = 40 # Size limit of results when running in debug mode. MAXINT = sys.maxsize @@ -87,67 +87,62 @@ # information, they can create their own logging object and pass # it into PLY. - -class PlyLogger: +class PlyLogger(object): def __init__(self, f): self.f = f def debug(self, msg, *args, **kwargs): - self.f.write((msg % args) + "\n") + self.f.write((msg % args) + '\n') info = debug def warning(self, msg, *args, **kwargs): - self.f.write("WARNING: " + (msg % args) + "\n") + self.f.write('WARNING: ' + (msg % args) + '\n') def error(self, msg, *args, **kwargs): - self.f.write("ERROR: " + (msg % args) + "\n") + self.f.write('ERROR: ' + (msg % args) + '\n') critical = debug - # Null logger is used when no output is generated. Does nothing. -class NullLogger: +class NullLogger(object): def __getattribute__(self, name): return self def __call__(self, *args, **kwargs): return self - # Exception raised for yacc-related errors class YaccError(Exception): pass - # Format the result message that the parser produces when running in debug mode. def format_result(r): repr_str = repr(r) - if "\n" in repr_str: + if '\n' in repr_str: repr_str = repr(repr_str) if len(repr_str) > resultlimit: - repr_str = repr_str[:resultlimit] + " ..." - result = "<%s @ 0x%x> (%s)" % (type(r).__name__, id(r), repr_str) + repr_str = repr_str[:resultlimit] + ' ...' + result = '<%s @ 0x%x> (%s)' % (type(r).__name__, id(r), repr_str) return result - # Format stack entries when the parser is running in debug mode def format_stack_entry(r): repr_str = repr(r) - if "\n" in repr_str: + if '\n' in repr_str: repr_str = repr(repr_str) if len(repr_str) < 16: return repr_str - return "<%s @ 0x%x>" % (type(r).__name__, id(r)) - + else: + return '<%s @ 0x%x>' % (type(r).__name__, id(r)) -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # === LR Parsing Engine === # # The following classes are used for the LR parser itself. These are not # used during table construction and are independent of the actual LR # table generation algorithm -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # This class is used to hold non-terminal grammar symbols during parsing. # It normally has the following attributes set: @@ -158,7 +153,6 @@ def format_stack_entry(r): # .lexpos = Starting lex position # .endlexpos = Ending lex position (optional, set automatically) - class YaccSymbol: def __str__(self): return self.type @@ -166,7 +160,6 @@ def __str__(self): def __repr__(self): return str(self) - # This class is a wrapper around the objects actually passed to each # grammar rule. Index lookup and assignment actually assign the # .value attribute of the underlying YaccSymbol object. @@ -176,7 +169,6 @@ def __repr__(self): # for a symbol. The lexspan() method returns a tuple (lexpos,endlexpos) # representing the range of positional information for a symbol. - class YaccProduction: def __init__(self, s, stack=None): self.slice = s @@ -187,9 +179,10 @@ def __init__(self, s, stack=None): def __getitem__(self, n): if isinstance(n, slice): return [s.value for s in self.slice[n]] - if n >= 0: + elif n >= 0: return self.slice[n].value - return self.stack[n].value + else: + return self.stack[n].value def __setitem__(self, n, v): self.slice[n].value = v @@ -201,38 +194,36 @@ def __len__(self): return len(self.slice) def lineno(self, n): - return getattr(self.slice[n], "lineno", 0) + return getattr(self.slice[n], 'lineno', 0) def set_lineno(self, n, lineno): self.slice[n].lineno = lineno def linespan(self, n): - startline = getattr(self.slice[n], "lineno", 0) - endline = getattr(self.slice[n], "endlineno", startline) + startline = getattr(self.slice[n], 'lineno', 0) + endline = getattr(self.slice[n], 'endlineno', startline) return startline, endline def lexpos(self, n): - return getattr(self.slice[n], "lexpos", 0) + return getattr(self.slice[n], 'lexpos', 0) def set_lexpos(self, n, lexpos): self.slice[n].lexpos = lexpos def lexspan(self, n): - startpos = getattr(self.slice[n], "lexpos", 0) - endpos = getattr(self.slice[n], "endlexpos", startpos) + startpos = getattr(self.slice[n], 'lexpos', 0) + endpos = getattr(self.slice[n], 'endlexpos', startpos) return startpos, endpos def error(self): raise SyntaxError - # ----------------------------------------------------------------------------- # == LRParser == # # The LR Parsing engine. # ----------------------------------------------------------------------------- - class LRParser: def __init__(self, lrtab, errorf): self.productions = lrtab.lr_productions @@ -249,7 +240,7 @@ def restart(self): del self.statestack[:] del self.symstack[:] sym = YaccSymbol() - sym.type = "$end" + sym.type = '$end' self.symstack.append(sym) self.statestack.append(0) @@ -284,22 +275,21 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): if isinstance(debug, int) and debug: debug = PlyLogger(sys.stderr) - lookahead = None # Current lookahead symbol - lookaheadstack = [] # Stack of lookahead symbols - actions = self.action # Local reference to action table (to avoid lookup on self.) - goto = self.goto # Local reference to goto table (to avoid lookup on self.) - prod = self.productions # Local reference to production list (to avoid lookup on self.) - defaulted_states = self.defaulted_states # Local reference to defaulted states - pslice = YaccProduction(None) # Production object passed to grammar rules - errorcount = 0 # Used during error recovery + lookahead = None # Current lookahead symbol + lookaheadstack = [] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + defaulted_states = self.defaulted_states # Local reference to defaulted states + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery if debug: - debug.info("PLY: PARSE DEBUG START") + debug.info('PLY: PARSE DEBUG START') # If no lexer was given, we will try to use the lex module if not lexer: from . import lex - lexer = lex.lexer # Set up the lexer and parser objects on pslice @@ -314,16 +304,16 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): get_token = self.token = lexer.token # Set up the state and symbol stacks - statestack = self.statestack = [] # Stack of parsing states - symstack = self.symstack = [] # Stack of grammar symbols - pslice.stack = symstack # Put in the production - errtoken = None # Err token + statestack = self.statestack = [] # Stack of parsing states + symstack = self.symstack = [] # Stack of grammar symbols + pslice.stack = symstack # Put in the production + errtoken = None # Err token # The start state is assumed to be (0,$end) statestack.append(0) sym = YaccSymbol() - sym.type = "$end" + sym.type = '$end' symstack.append(sym) state = 0 while True: @@ -332,17 +322,17 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # the next token off of the lookaheadstack or from the lexer if debug: - debug.debug("State : %s", state) + debug.debug('State : %s', state) if state not in defaulted_states: if not lookahead: if not lookaheadstack: - lookahead = get_token() # Get the next token + lookahead = get_token() # Get the next token else: lookahead = lookaheadstack.pop() if not lookahead: lookahead = YaccSymbol() - lookahead.type = "$end" + lookahead.type = '$end' # Check the action table ltype = lookahead.type @@ -350,12 +340,11 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): else: t = defaulted_states[state] if debug: - debug.debug("Defaulted state %s: Reduce using %d", state, -t) + debug.debug('Defaulted state %s: Reduce using %d', state, -t) if debug: - debug.debug( - "Stack : %s", ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip() - ) + debug.debug('Stack : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) if t is not None: if t > 0: @@ -364,7 +353,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): state = t if debug: - debug.debug("Action : Shift and goto state %s", t) + debug.debug('Action : Shift and goto state %s', t) symstack.append(lookahead) lookahead = None @@ -378,31 +367,24 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # reduce a symbol on the stack, emit a production p = prod[-t] pname = p.name - plen = p.len + plen = p.len # Get production function sym = YaccSymbol() - sym.type = pname # Production name + sym.type = pname # Production name sym.value = None if debug: if plen: - debug.info( - "Action : Reduce rule [%s] with %s and goto state %d", - p.str, - "[" + ",".join([format_stack_entry(_v.value) for _v in symstack[-plen:]]) + "]", - goto[statestack[-1 - plen]][pname], - ) + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, + '['+','.join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+']', + goto[statestack[-1-plen]][pname]) else: - debug.info( - "Action : Reduce rule [%s] with %s and goto state %d", - p.str, - [], - goto[statestack[-1]][pname], - ) + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, [], + goto[statestack[-1]][pname]) if plen: - targ = symstack[-plen - 1 :] + targ = symstack[-plen-1:] targ[0] = sym if tracking: @@ -410,8 +392,8 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): sym.lineno = t1.lineno sym.lexpos = t1.lexpos t1 = targ[-1] - sym.endlineno = getattr(t1, "endlineno", t1.lineno) - sym.endlexpos = getattr(t1, "endlexpos", t1.lexpos) + sym.endlineno = getattr(t1, 'endlineno', t1.lineno) + sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos) # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated @@ -427,18 +409,18 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): p.callable(pslice) del statestack[-plen:] if debug: - debug.info("Result : %s", format_result(pslice[0])) + debug.info('Result : %s', format_result(pslice[0])) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) # Save the current lookahead token - symstack.extend(targ[1:-1]) # Put the production slice back on the stack - statestack.pop() # Pop back one state (before the reduce) + lookaheadstack.append(lookahead) # Save the current lookahead token + symstack.extend(targ[1:-1]) # Put the production slice back on the stack + statestack.pop() # Pop back one state (before the reduce) state = statestack[-1] - sym.type = "error" - sym.value = "error" + sym.type = 'error' + sym.value = 'error' lookahead = sym errorcount = error_count self.errorok = False @@ -446,6 +428,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): continue else: + if tracking: sym.lineno = lexer.lineno sym.lexpos = lexer.lexpos @@ -464,17 +447,17 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): self.state = state p.callable(pslice) if debug: - debug.info("Result : %s", format_result(pslice[0])) + debug.info('Result : %s', format_result(pslice[0])) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) # Save the current lookahead token - statestack.pop() # Pop back one state (before the reduce) + lookaheadstack.append(lookahead) # Save the current lookahead token + statestack.pop() # Pop back one state (before the reduce) state = statestack[-1] - sym.type = "error" - sym.value = "error" + sym.type = 'error' + sym.value = 'error' lookahead = sym errorcount = error_count self.errorok = False @@ -483,20 +466,19 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): if t == 0: n = symstack[-1] - result = getattr(n, "value", None) + result = getattr(n, 'value', None) if debug: - debug.info("Done : Returning %s", format_result(result)) - debug.info("PLY: PARSE DEBUG END") + debug.info('Done : Returning %s', format_result(result)) + debug.info('PLY: PARSE DEBUG END') return result if t is None: + if debug: - debug.error( - "Error : %s", - ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip(), - ) + debug.error('Error : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) # We have some kind of parsing error here. To handle # this, we are going to push the current token onto @@ -512,10 +494,10 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): errorcount = error_count self.errorok = False errtoken = lookahead - if errtoken.type == "$end": - errtoken = None # End of file! + if errtoken.type == '$end': + errtoken = None # End of file! if self.errorfunc: - if errtoken and not hasattr(errtoken, "lexer"): + if errtoken and not hasattr(errtoken, 'lexer'): errtoken.lexer = lexer self.state = state tok = self.errorfunc(errtoken) @@ -528,17 +510,17 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): continue else: if errtoken: - if hasattr(errtoken, "lineno"): + if hasattr(errtoken, 'lineno'): lineno = lookahead.lineno else: lineno = 0 if lineno: - sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) + sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type)) else: - sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) + sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type) else: - sys.stderr.write("yacc: Parse error in input. EOF\n") - return None + sys.stderr.write('yacc: Parse error in input. EOF\n') + return else: errorcount = error_count @@ -547,7 +529,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # entire parse has been rolled back and we're completely hosed. The token is # discarded and we just keep going. - if len(statestack) <= 1 and lookahead.type != "$end": + if len(statestack) <= 1 and lookahead.type != '$end': lookahead = None errtoken = None state = 0 @@ -559,28 +541,28 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # at the end of the file. nuke the top entry and generate an error token # Start nuking entries on the stack - if lookahead.type == "$end": + if lookahead.type == '$end': # Whoa. We're really hosed here. Bail out - return None + return - if lookahead.type != "error": + if lookahead.type != 'error': sym = symstack[-1] - if sym.type == "error": + if sym.type == 'error': # Hmmm. Error is on top of stack, we'll just nuke input # symbol and continue if tracking: - sym.endlineno = getattr(lookahead, "lineno", sym.lineno) - sym.endlexpos = getattr(lookahead, "lexpos", sym.lexpos) + sym.endlineno = getattr(lookahead, 'lineno', sym.lineno) + sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos) lookahead = None continue # Create the error symbol for the first time and make it the new lookahead symbol t = YaccSymbol() - t.type = "error" + t.type = 'error' - if hasattr(lookahead, "lineno"): + if hasattr(lookahead, 'lineno'): t.lineno = t.endlineno = lookahead.lineno - if hasattr(lookahead, "lexpos"): + if hasattr(lookahead, 'lexpos'): t.lexpos = t.endlexpos = lookahead.lexpos t.value = lookahead lookaheadstack.append(lookahead) @@ -596,8 +578,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): continue # If we'r here, something really bad happened - raise RuntimeError("yacc: internal parser error!!!\n") - + raise RuntimeError('yacc: internal parser error!!!\n') # ----------------------------------------------------------------------------- # === Grammar Representation === @@ -607,7 +588,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # ----------------------------------------------------------------------------- # regex matching identifiers -_is_identifier = re.compile(r"^[a-zA-Z0-9_-]+$") +_is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') # ----------------------------------------------------------------------------- # class Production: @@ -633,23 +614,21 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): # usyms - Set of unique symbols found in the production # ----------------------------------------------------------------------------- - -class Production: +class Production(object): reduced = 0 - - def __init__(self, number, name, prod, precedence=("right", 0), func=None, file="", line=0): - self.name = name - self.prod = tuple(prod) - self.number = number - self.func = func + def __init__(self, number, name, prod, precedence=('right', 0), func=None, file='', line=0): + self.name = name + self.prod = tuple(prod) + self.number = number + self.func = func self.callable = None - self.file = file - self.line = line - self.prec = precedence + self.file = file + self.line = line + self.prec = precedence # Internal settings used during table construction - self.len = len(self.prod) # Length of the production + self.len = len(self.prod) # Length of the production # Create a list of unique production symbols used in the production self.usyms = [] @@ -663,15 +642,15 @@ def __init__(self, number, name, prod, precedence=("right", 0), func=None, file= # Create a string representation if self.prod: - self.str = "%s -> %s" % (self.name, " ".join(self.prod)) + self.str = '%s -> %s' % (self.name, ' '.join(self.prod)) else: - self.str = "%s -> " % self.name + self.str = '%s -> ' % self.name def __str__(self): return self.str def __repr__(self): - return "Production(" + str(self) + ")" + return 'Production(' + str(self) + ')' def __len__(self): return len(self.prod) @@ -689,11 +668,11 @@ def lr_item(self, n): p = LRItem(self, n) # Precompute the list of productions immediately following. try: - p.lr_after = self.Prodnames[p.prod[n + 1]] + p.lr_after = self.Prodnames[p.prod[n+1]] except (IndexError, KeyError): p.lr_after = [] try: - p.lr_before = p.prod[n - 1] + p.lr_before = p.prod[n-1] except IndexError: p.lr_before = None return p @@ -703,7 +682,6 @@ def bind(self, pdict): if self.func: self.callable = pdict[self.func] - # ----------------------------------------------------------------------------- # class LRItem # @@ -728,29 +706,27 @@ def bind(self, pdict): # lr_before - Grammar symbol immediately before # ----------------------------------------------------------------------------- - -class LRItem: +class LRItem(object): def __init__(self, p, n): - self.name = p.name - self.prod = list(p.prod) - self.number = p.number - self.lr_index = n + self.name = p.name + self.prod = list(p.prod) + self.number = p.number + self.lr_index = n self.lookaheads = {} - self.prod.insert(n, ".") - self.prod = tuple(self.prod) - self.len = len(self.prod) - self.usyms = p.usyms + self.prod.insert(n, '.') + self.prod = tuple(self.prod) + self.len = len(self.prod) + self.usyms = p.usyms def __str__(self): if self.prod: - s = "%s -> %s" % (self.name, " ".join(self.prod)) + s = '%s -> %s' % (self.name, ' '.join(self.prod)) else: - s = "%s -> " % self.name + s = '%s -> ' % self.name return s def __repr__(self): - return "LRItem(" + str(self) + ")" - + return 'LRItem(' + str(self) + ')' # ----------------------------------------------------------------------------- # rightmost_terminal() @@ -765,7 +741,6 @@ def rightmost_terminal(symbols, terminals): i -= 1 return None - # ----------------------------------------------------------------------------- # === GRAMMAR CLASS === # @@ -774,46 +749,45 @@ def rightmost_terminal(symbols, terminals): # This data is used for critical parts of the table generation process later. # ----------------------------------------------------------------------------- - class GrammarError(YaccError): pass - -class Grammar: +class Grammar(object): def __init__(self, terminals): - self.Productions = [None] # A list of all of the productions. The first - # entry is always reserved for the purpose of - # building an augmented grammar + self.Productions = [None] # A list of all of the productions. The first + # entry is always reserved for the purpose of + # building an augmented grammar - self.Prodnames = {} # A dictionary mapping the names of nonterminals to a list of all - # productions of that nonterminal. + self.Prodnames = {} # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. - self.Prodmap = {} # A dictionary that is only used to detect duplicate - # productions. + self.Prodmap = {} # A dictionary that is only used to detect duplicate + # productions. - self.Terminals = {} # A dictionary mapping the names of terminal symbols to a - # list of the rules where they are used. + self.Terminals = {} # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. for term in terminals: self.Terminals[term] = [] - self.Terminals["error"] = [] + self.Terminals['error'] = [] - self.Nonterminals = {} # A dictionary mapping names of nonterminals to a list - # of rule numbers where they are used. + self.Nonterminals = {} # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. - self.First = {} # A dictionary of precomputed FIRST(x) symbols + self.First = {} # A dictionary of precomputed FIRST(x) symbols - self.Follow = {} # A dictionary of precomputed FOLLOW(x) symbols + self.Follow = {} # A dictionary of precomputed FOLLOW(x) symbols - self.Precedence = {} # Precedence rules for each terminal. Contains tuples of the - # form ('right',level) or ('nonassoc', level) or ('left',level) + self.Precedence = {} # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) - self.UsedPrecedence = set() # Precedence rules that were actually used by the grammer. - # This is only used to provide error checking and to generate - # a warning about unused precedence rules. + self.UsedPrecedence = set() # Precedence rules that were actually used by the grammer. + # This is only used to provide error checking and to generate + # a warning about unused precedence rules. + + self.Start = None # Starting symbol for the grammar - self.Start = None # Starting symbol for the grammar def __len__(self): return len(self.Productions) @@ -830,10 +804,10 @@ def __getitem__(self, index): # ----------------------------------------------------------------------------- def set_precedence(self, term, assoc, level): - assert self.Productions == [None], "Must call set_precedence() before add_production()" + assert self.Productions == [None], 'Must call set_precedence() before add_production()' if term in self.Precedence: - raise GrammarError("Precedence already specified for terminal %r" % term) - if assoc not in ["left", "right", "nonassoc"]: + raise GrammarError('Precedence already specified for terminal %r' % term) + if assoc not in ['left', 'right', 'nonassoc']: raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'") self.Precedence[term] = (assoc, level) @@ -854,62 +828,60 @@ def set_precedence(self, term, assoc, level): # are valid and that %prec is used correctly. # ----------------------------------------------------------------------------- - def add_production(self, prodname, syms, func=None, file="", line=0): + def add_production(self, prodname, syms, func=None, file='', line=0): + if prodname in self.Terminals: - raise GrammarError("%s:%d: Illegal rule name %r. Already defined as a token" % (file, line, prodname)) - if prodname == "error": - raise GrammarError("%s:%d: Illegal rule name %r. error is a reserved word" % (file, line, prodname)) + raise GrammarError('%s:%d: Illegal rule name %r. Already defined as a token' % (file, line, prodname)) + if prodname == 'error': + raise GrammarError('%s:%d: Illegal rule name %r. error is a reserved word' % (file, line, prodname)) if not _is_identifier.match(prodname): - raise GrammarError("%s:%d: Illegal rule name %r" % (file, line, prodname)) + raise GrammarError('%s:%d: Illegal rule name %r' % (file, line, prodname)) # Look for literal tokens for n, s in enumerate(syms): if s[0] in "'\"": try: c = eval(s) - if len(c) > 1: - raise GrammarError( - "%s:%d: Literal token %s in rule %r may only be a single character" - % (file, line, s, prodname) - ) + if (len(c) > 1): + raise GrammarError('%s:%d: Literal token %s in rule %r may only be a single character' % + (file, line, s, prodname)) if c not in self.Terminals: self.Terminals[c] = [] syms[n] = c continue except SyntaxError: pass - if not _is_identifier.match(s) and s != "%prec": - raise GrammarError("%s:%d: Illegal name %r in rule %r" % (file, line, s, prodname)) + if not _is_identifier.match(s) and s != '%prec': + raise GrammarError('%s:%d: Illegal name %r in rule %r' % (file, line, s, prodname)) # Determine the precedence level - if "%prec" in syms: - if syms[-1] == "%prec": - raise GrammarError("%s:%d: Syntax error. Nothing follows %%prec" % (file, line)) - if syms[-2] != "%prec": - raise GrammarError( - "%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule" % (file, line) - ) + if '%prec' in syms: + if syms[-1] == '%prec': + raise GrammarError('%s:%d: Syntax error. Nothing follows %%prec' % (file, line)) + if syms[-2] != '%prec': + raise GrammarError('%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule' % + (file, line)) precname = syms[-1] prodprec = self.Precedence.get(precname) if not prodprec: - raise GrammarError("%s:%d: Nothing known about the precedence of %r" % (file, line, precname)) - self.UsedPrecedence.add(precname) - del syms[-2:] # Drop %prec from the rule + raise GrammarError('%s:%d: Nothing known about the precedence of %r' % (file, line, precname)) + else: + self.UsedPrecedence.add(precname) + del syms[-2:] # Drop %prec from the rule else: # If no %prec, precedence is determined by the rightmost terminal symbol precname = rightmost_terminal(syms, self.Terminals) - prodprec = self.Precedence.get(precname, ("right", 0)) + prodprec = self.Precedence.get(precname, ('right', 0)) # See if the rule is already in the rulemap - map = "%s -> %s" % (prodname, syms) + map = '%s -> %s' % (prodname, syms) if map in self.Prodmap: m = self.Prodmap[map] - raise GrammarError( - "%s:%d: Duplicate rule %s. " % (file, line, m) + "Previous definition at %s:%d" % (m.file, m.line) - ) + raise GrammarError('%s:%d: Duplicate rule %s. ' % (file, line, m) + + 'Previous definition at %s:%d' % (m.file, m.line)) # From this point on, everything is valid. Create a new Production instance - pnumber = len(self.Productions) + pnumber = len(self.Productions) if prodname not in self.Nonterminals: self.Nonterminals[prodname] = [] @@ -944,7 +916,7 @@ def set_start(self, start=None): if not start: start = self.Productions[1].name if start not in self.Nonterminals: - raise GrammarError("start symbol %s undefined" % start) + raise GrammarError('start symbol %s undefined' % start) self.Productions[0] = Production(0, "S'", [start]) self.Nonterminals[start].append(0) self.Start = start @@ -957,6 +929,7 @@ def set_start(self, start=None): # ----------------------------------------------------------------------------- def find_unreachable(self): + # Mark all symbols that are reachable from a symbol s def mark_reachable_from(s): if s in reachable: @@ -985,7 +958,7 @@ def infinite_cycles(self): for t in self.Terminals: terminates[t] = True - terminates["$end"] = True + terminates['$end'] = True # Nonterminals: @@ -996,7 +969,7 @@ def infinite_cycles(self): # Then propagate termination until no change: while True: some_change = False - for n, pl in self.Prodnames.items(): + for (n, pl) in self.Prodnames.items(): # Nonterminal n terminates iff any of its productions terminates. for p in pl: # Production p terminates iff all of its rhs symbols terminate. @@ -1024,9 +997,9 @@ def infinite_cycles(self): break infinite = [] - for s, term in terminates.items(): + for (s, term) in terminates.items(): if not term: - if s not in self.Prodnames and s not in self.Terminals and s != "error": + if s not in self.Prodnames and s not in self.Terminals and s != 'error': # s is used-but-not-defined, and we've already warned of that, # so it would be overkill to say that it's also non-terminating. pass @@ -1049,7 +1022,7 @@ def undefined_symbols(self): continue for s in p.prod: - if s not in self.Prodnames and s not in self.Terminals and s != "error": + if s not in self.Prodnames and s not in self.Terminals and s != 'error': result.append((s, p)) return result @@ -1062,7 +1035,7 @@ def undefined_symbols(self): def unused_terminals(self): unused_tok = [] for s, v in self.Terminals.items(): - if s != "error" and not v: + if s != 'error' and not v: unused_tok.append(s) return unused_tok @@ -1108,6 +1081,7 @@ def unused_precedence(self): # Afterward (e.g., when called from compute_follow()), it will be complete. # ------------------------------------------------------------------------- def _first(self, beta): + # We are computing First(x1,x2,x3,...,xn) result = [] for x in beta: @@ -1115,7 +1089,7 @@ def _first(self, beta): # Add all the non- symbols of First[x] to the result. for f in self.First[x]: - if f == "": + if f == '': x_produces_empty = True else: if f not in result: @@ -1132,7 +1106,7 @@ def _first(self, beta): # There was no 'break' from the loop, # so x_produces_empty was true for all x in beta, # so beta produces empty as well. - result.append("") + result.append('') return result @@ -1149,7 +1123,7 @@ def compute_first(self): for t in self.Terminals: self.First[t] = [t] - self.First["$end"] = ["$end"] + self.First['$end'] = ['$end'] # Nonterminals: @@ -1194,7 +1168,7 @@ def compute_follow(self, start=None): if not start: start = self.Productions[1].name - self.Follow[start] = ["$end"] + self.Follow[start] = ['$end'] while True: didadd = False @@ -1203,15 +1177,15 @@ def compute_follow(self, start=None): for i, B in enumerate(p.prod): if B in self.Nonterminals: # Okay. We got a non-terminal in a production - fst = self._first(p.prod[i + 1 :]) + fst = self._first(p.prod[i+1:]) hasempty = False for f in fst: - if f != "" and f not in self.Follow[B]: + if f != '' and f not in self.Follow[B]: self.Follow[B].append(f) didadd = True - if f == "": + if f == '': hasempty = True - if hasempty or i == (len(p.prod) - 1): + if hasempty or i == (len(p.prod)-1): # Add elements of follow(a) to follow(b) for f in self.Follow[p.name]: if f not in self.Follow[B]: @@ -1221,6 +1195,7 @@ def compute_follow(self, start=None): break return self.Follow + # ----------------------------------------------------------------------------- # build_lritems() # @@ -1248,11 +1223,11 @@ def build_lritems(self): lri = LRItem(p, i) # Precompute the list of productions immediately following try: - lri.lr_after = self.Prodnames[lri.prod[i + 1]] + lri.lr_after = self.Prodnames[lri.prod[i+1]] except (IndexError, KeyError): lri.lr_after = [] try: - lri.lr_before = lri.prod[i - 1] + lri.lr_before = lri.prod[i-1] except IndexError: lri.lr_before = None @@ -1264,7 +1239,6 @@ def build_lritems(self): i += 1 p.lr_items = lr_items - # ----------------------------------------------------------------------------- # === LR Generator === # @@ -1289,7 +1263,6 @@ def build_lritems(self): # FP - Set-valued function # ------------------------------------------------------------------------------ - def digraph(X, R, FP): N = {} for x in X: @@ -1301,14 +1274,13 @@ def digraph(X, R, FP): traverse(x, N, stack, F, X, R, FP) return F - def traverse(x, N, stack, F, X, R, FP): stack.append(x) d = len(stack) N[x] = d - F[x] = FP(x) # F(X) <- F'(x) + F[x] = FP(x) # F(X) <- F'(x) - rel = R(x) # Get y's related to x + rel = R(x) # Get y's related to x for y in rel: if N[y] == 0: traverse(y, N, stack, F, X, R, FP) @@ -1325,7 +1297,6 @@ def traverse(x, N, stack, F, X, R, FP): F[stack[-1]] = F[x] element = stack.pop() - class LALRError(YaccError): pass @@ -1337,7 +1308,6 @@ class LALRError(YaccError): # public methods. # ----------------------------------------------------------------------------- - class LRTable: def __init__(self, grammar, log=None): self.grammar = grammar @@ -1348,21 +1318,21 @@ def __init__(self, grammar, log=None): self.log = log # Internal attributes - self.lr_action = {} # Action table - self.lr_goto = {} # Goto table - self.lr_productions = grammar.Productions # Copy of grammar Production array - self.lr_goto_cache = {} # Cache of computed gotos - self.lr0_cidhash = {} # Cache of closures + self.lr_action = {} # Action table + self.lr_goto = {} # Goto table + self.lr_productions = grammar.Productions # Copy of grammar Production array + self.lr_goto_cache = {} # Cache of computed gotos + self.lr0_cidhash = {} # Cache of closures - self._add_count = 0 # Internal counter used to detect cycles + self._add_count = 0 # Internal counter used to detect cycles # Diagnostic information filled in by the table generator - self.sr_conflict = 0 - self.rr_conflict = 0 - self.conflicts = [] # List of conflicts + self.sr_conflict = 0 + self.rr_conflict = 0 + self.conflicts = [] # List of conflicts - self.sr_conflicts = [] - self.rr_conflicts = [] + self.sr_conflicts = [] + self.rr_conflicts = [] # Build the tables self.grammar.build_lritems() @@ -1387,7 +1357,7 @@ def lr0_closure(self, I): didadd = False for j in J: for x in j.lr_after: - if getattr(x, "lr0_added", 0) == self._add_count: + if getattr(x, 'lr0_added', 0) == self._add_count: continue # Add B --> .G to J J.append(x.lr_next) @@ -1427,13 +1397,13 @@ def lr0_goto(self, I, x): s[id(n)] = s1 gs.append(n) s = s1 - g = s.get("$end") + g = s.get('$end') if not g: if gs: g = self.lr0_closure(gs) - s["$end"] = g + s['$end'] = g else: - s["$end"] = gs + s['$end'] = gs self.lr_goto_cache[(id(I), x)] = g return g @@ -1528,7 +1498,7 @@ def find_nonterminal_transitions(self, C): for stateno, state in enumerate(C): for p in state: if p.lr_index < p.len - 1: - t = (stateno, p.prod[p.lr_index + 1]) + t = (stateno, p.prod[p.lr_index+1]) if t[1] in self.grammar.Nonterminals: if t not in trans: trans.append(t) @@ -1550,14 +1520,14 @@ def dr_relation(self, C, trans, nullable): g = self.lr0_goto(C[state], N) for p in g: if p.lr_index < p.len - 1: - a = p.prod[p.lr_index + 1] + a = p.prod[p.lr_index+1] if a in self.grammar.Terminals: if a not in terms: terms.append(a) # This extra bit is to handle the start state if state == 0 and N == self.grammar.Productions[0].prod[0]: - terms.append("$end") + terms.append('$end') return terms @@ -1611,8 +1581,8 @@ def reads_relation(self, C, trans, empty): # ----------------------------------------------------------------------------- def compute_lookback_includes(self, C, trans, nullable): - lookdict = {} # Dictionary of lookback relations - includedict = {} # Dictionary of include relations + lookdict = {} # Dictionary of lookback relations + includedict = {} # Dictionary of include relations # Make a dictionary of non-terminal transitions dtrans = {} @@ -1645,7 +1615,7 @@ def compute_lookback_includes(self, C, trans, nullable): li = lr_index + 1 while li < p.len: if p.prod[li] in self.grammar.Terminals: - break # No forget it + break # No forget it if p.prod[li] not in nullable: break li = li + 1 @@ -1653,8 +1623,8 @@ def compute_lookback_includes(self, C, trans, nullable): # Appears to be a relation between (j,t) and (state,N) includes.append((j, t)) - g = self.lr0_goto(C[j], t) # Go to next set - j = self.lr0_cidhash.get(id(g), -1) # Go to next state + g = self.lr0_goto(C[j], t) # Go to next set + j = self.lr0_cidhash.get(id(g), -1) # Go to next state # When we get here, j is the final state, now we have to locate the production for r in C[j]: @@ -1665,7 +1635,7 @@ def compute_lookback_includes(self, C, trans, nullable): i = 0 # This look is comparing a production ". A B C" with "A B C ." while i < r.lr_index: - if r.prod[i] != p.prod[i + 1]: + if r.prod[i] != p.prod[i+1]: break i = i + 1 else: @@ -1692,7 +1662,7 @@ def compute_lookback_includes(self, C, trans, nullable): def compute_read_sets(self, C, ntrans, nullable): FP = lambda x: self.dr_relation(C, x, nullable) - R = lambda x: self.reads_relation(C, x, nullable) + R = lambda x: self.reads_relation(C, x, nullable) F = digraph(ntrans, R, FP) return F @@ -1714,7 +1684,7 @@ def compute_read_sets(self, C, ntrans, nullable): def compute_follow_sets(self, ntrans, readsets, inclsets): FP = lambda x: readsets[x] - R = lambda x: inclsets.get(x, []) + R = lambda x: inclsets.get(x, []) F = digraph(ntrans, R, FP) return F @@ -1774,12 +1744,12 @@ def add_lalr_lookaheads(self, C): # ----------------------------------------------------------------------------- def lr_parse_table(self): Productions = self.grammar.Productions - Precedence = self.grammar.Precedence - goto = self.lr_goto # Goto array - action = self.lr_action # Action array - log = self.log # Logger for output + Precedence = self.grammar.Precedence + goto = self.lr_goto # Goto array + action = self.lr_action # Action array + log = self.log # Logger for output - actionp = {} # Action production array (temporary) + actionp = {} # Action production array (temporary) # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items # This determines the number of states @@ -1791,151 +1761,147 @@ def lr_parse_table(self): st = 0 for I in C: # Loop over each production in I - actlist = [] # List of actions - st_action = {} + actlist = [] # List of actions + st_action = {} st_actionp = {} - st_goto = {} - log.info("") - log.info("state %d", st) - log.info("") + st_goto = {} + log.info('') + log.info('state %d', st) + log.info('') for p in I: - log.info(" (%d) %s", p.number, p) - log.info("") + log.info(' (%d) %s', p.number, p) + log.info('') for p in I: - if p.len == p.lr_index + 1: - if p.name == "S'": - # Start symbol. Accept! - st_action["$end"] = 0 - st_actionp["$end"] = p - else: - # We are at the end of a production. Reduce! - laheads = p.lookaheads[st] - for a in laheads: - actlist.append((a, p, "reduce using rule %d (%s)" % (p.number, p))) - r = st_action.get(a) - if r is not None: - # Whoa. Have a shift/reduce or reduce/reduce conflict - if r > 0: - # Need to decide on shift or reduce here - # By default we favor shifting. Need to add - # some precedence rules here. - - # Shift precedence comes from the token - sprec, slevel = Precedence.get(a, ("right", 0)) - - # Reduce precedence comes from rule being reduced (p) - rprec, rlevel = Productions[p.number].prec - - if (slevel < rlevel) or ((slevel == rlevel) and (rprec == "left")): - # We really need to reduce here. - st_action[a] = -p.number - st_actionp[a] = p - if not slevel and not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as reduce", a) - self.sr_conflicts.append((st, a, "reduce")) - Productions[p.number].reduced += 1 - elif (slevel == rlevel) and (rprec == "nonassoc"): - st_action[a] = None - else: - # Hmmm. Guess we'll keep the shift - if not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as shift", a) - self.sr_conflicts.append((st, a, "shift")) - elif r < 0: - # Reduce/reduce conflict. In this case, we favor the rule - # that was defined first in the grammar file - oldp = Productions[-r] - pp = Productions[p.number] - if oldp.line > pp.line: - st_action[a] = -p.number - st_actionp[a] = p - chosenp, rejectp = pp, oldp - Productions[p.number].reduced += 1 - Productions[oldp.number].reduced -= 1 + if p.len == p.lr_index + 1: + if p.name == "S'": + # Start symbol. Accept! + st_action['$end'] = 0 + st_actionp['$end'] = p + else: + # We are at the end of a production. Reduce! + laheads = p.lookaheads[st] + for a in laheads: + actlist.append((a, p, 'reduce using rule %d (%s)' % (p.number, p))) + r = st_action.get(a) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from rule being reduced (p) + rprec, rlevel = Productions[p.number].prec + + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + st_action[a] = -p.number + st_actionp[a] = p + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + Productions[p.number].reduced += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the shift + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + st_action[a] = -p.number + st_actionp[a] = p + chosenp, rejectp = pp, oldp + Productions[p.number].reduced += 1 + Productions[oldp.number].reduced -= 1 + else: + chosenp, rejectp = oldp, pp + self.rr_conflicts.append((st, chosenp, rejectp)) + log.info(' ! reduce/reduce conflict for %s resolved using rule %d (%s)', + a, st_actionp[a].number, st_actionp[a]) else: - chosenp, rejectp = oldp, pp - self.rr_conflicts.append((st, chosenp, rejectp)) - log.info( - " ! reduce/reduce conflict for %s resolved using rule %d (%s)", - a, - st_actionp[a].number, - st_actionp[a], - ) + raise LALRError('Unknown conflict in state %d' % st) else: - raise LALRError("Unknown conflict in state %d" % st) - else: - st_action[a] = -p.number - st_actionp[a] = p - Productions[p.number].reduced += 1 - else: - i = p.lr_index - a = p.prod[i + 1] # Get symbol right after the "." - if a in self.grammar.Terminals: - g = self.lr0_goto(I, a) - j = self.lr0_cidhash.get(id(g), -1) - if j >= 0: - # We are in a shift state - actlist.append((a, p, "shift and go to state %d" % j)) - r = st_action.get(a) - if r is not None: - # Whoa have a shift/reduce or shift/shift conflict - if r > 0: - if r != j: - raise LALRError("Shift/shift conflict in state %d" % st) - elif r < 0: - # Do a precedence check. - # - if precedence of reduce rule is higher, we reduce. - # - if precedence of reduce is same and left assoc, we reduce. - # - otherwise we shift - - # Shift precedence comes from the token - sprec, slevel = Precedence.get(a, ("right", 0)) - - # Reduce precedence comes from the rule that could have been reduced - rprec, rlevel = Productions[st_actionp[a].number].prec - - if (slevel > rlevel) or ((slevel == rlevel) and (rprec == "right")): - # We decide to shift here... highest precedence to shift - Productions[st_actionp[a].number].reduced -= 1 - st_action[a] = j - st_actionp[a] = p - if not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as shift", a) - self.sr_conflicts.append((st, a, "shift")) - elif (slevel == rlevel) and (rprec == "nonassoc"): - st_action[a] = None - else: - # Hmmm. Guess we'll keep the reduce - if not slevel and not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as reduce", a) - self.sr_conflicts.append((st, a, "reduce")) + st_action[a] = -p.number + st_actionp[a] = p + Productions[p.number].reduced += 1 + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if a in self.grammar.Terminals: + g = self.lr0_goto(I, a) + j = self.lr0_cidhash.get(id(g), -1) + if j >= 0: + # We are in a shift state + actlist.append((a, p, 'shift and go to state %d' % j)) + r = st_action.get(a) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + raise LALRError('Shift/shift conflict in state %d' % st) + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from the rule that could have been reduced + rprec, rlevel = Productions[st_actionp[a].number].prec + + if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): + # We decide to shift here... highest precedence to shift + Productions[st_actionp[a].number].reduced -= 1 + st_action[a] = j + st_actionp[a] = p + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + else: + raise LALRError('Unknown conflict in state %d' % st) else: - raise LALRError("Unknown conflict in state %d" % st) - else: - st_action[a] = j - st_actionp[a] = p + st_action[a] = j + st_actionp[a] = p # Print the actions associated with each terminal _actprint = {} for a, p, m in actlist: if a in st_action: if p is st_actionp[a]: - log.info(" %-15s %s", a, m) + log.info(' %-15s %s', a, m) _actprint[(a, m)] = 1 - log.info("") + log.info('') # Print the actions that were not used. (debugging) not_used = 0 for a, p, m in actlist: if a in st_action: if p is not st_actionp[a]: if not (a, m) in _actprint: - log.debug(" ! %-15s [ %s ]", a, m) + log.debug(' ! %-15s [ %s ]', a, m) not_used = 1 _actprint[(a, m)] = 1 if not_used: - log.debug("") + log.debug('') # Construct the goto table for this state @@ -1949,14 +1915,13 @@ def lr_parse_table(self): j = self.lr0_cidhash.get(id(g), -1) if j >= 0: st_goto[n] = j - log.info(" %-30s shift and go to state %d", n, j) + log.info(' %-30s shift and go to state %d', n, j) action[st] = st_action actionp[st] = st_actionp goto[st] = st_goto st += 1 - # ----------------------------------------------------------------------------- # === INTROSPECTION === # @@ -1972,7 +1937,6 @@ def lr_parse_table(self): # associated with the yacc() call if none was provided. # ----------------------------------------------------------------------------- - def get_caller_module_dict(levels): f = sys._getframe(levels) ldict = f.f_globals.copy() @@ -1980,7 +1944,6 @@ def get_caller_module_dict(levels): ldict.update(f.f_locals) return ldict - # ----------------------------------------------------------------------------- # parse_grammar() # @@ -1998,7 +1961,7 @@ def parse_grammar(doc, file, line): if not p: continue try: - if p[0] == "|": + if p[0] == '|': # This is a continuation of a previous rule if not lastp: raise SyntaxError("%s:%d: Misplaced '|'" % (file, dline)) @@ -2007,20 +1970,19 @@ def parse_grammar(doc, file, line): else: prodname = p[0] lastp = prodname - syms = p[2:] + syms = p[2:] assign = p[1] - if assign != ":" and assign != "::=": + if assign != ':' and assign != '::=': raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file, dline)) grammar.append((file, dline, prodname, syms)) except SyntaxError: raise except Exception: - raise SyntaxError("%s:%d: Syntax error in rule %r" % (file, dline, ps.strip())) + raise SyntaxError('%s:%d: Syntax error in rule %r' % (file, dline, ps.strip())) return grammar - # ----------------------------------------------------------------------------- # ParserReflect() # @@ -2028,15 +1990,15 @@ def parse_grammar(doc, file, line): # start symbol, error function, tokens, precedence list, action functions, # etc. # ----------------------------------------------------------------------------- -class ParserReflect: +class ParserReflect(object): def __init__(self, pdict, log=None): - self.pdict = pdict - self.start = None + self.pdict = pdict + self.start = None self.error_func = None - self.tokens = None - self.modules = set() - self.grammar = [] - self.error = False + self.tokens = None + self.modules = set() + self.grammar = [] + self.error = False if log is None: self.log = PlyLogger(sys.stderr) @@ -2068,15 +2030,15 @@ def signature(self): if self.start: parts.append(self.start) if self.prec: - parts.append("".join(["".join(p) for p in self.prec])) + parts.append(''.join([''.join(p) for p in self.prec])) if self.tokens: - parts.append(" ".join(self.tokens)) + parts.append(' '.join(self.tokens)) for f in self.pfuncs: if f[3]: parts.append(f[3]) except (TypeError, ValueError): pass - return "".join(parts) + return ''.join(parts) # ----------------------------------------------------------------------------- # validate_modules() @@ -2091,7 +2053,7 @@ def signature(self): def validate_modules(self): # Match def p_funcname( - fre = re.compile(r"\s*def\s+(p_[a-zA-Z_0-9]*)\(") + fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') for module in self.modules: try: @@ -2110,13 +2072,12 @@ def validate_modules(self): counthash[name] = linen else: filename = inspect.getsourcefile(module) - self.log.warning( - "%s:%d: Function %s redefined. Previously defined on line %d", filename, linen, name, prev - ) + self.log.warning('%s:%d: Function %s redefined. Previously defined on line %d', + filename, linen, name, prev) # Get the start symbol def get_start(self): - self.start = self.pdict.get("start") + self.start = self.pdict.get('start') # Validate the start symbol def validate_start(self): @@ -2126,7 +2087,7 @@ def validate_start(self): # Look for error handler def get_error_func(self): - self.error_func = self.pdict.get("p_error") + self.error_func = self.pdict.get('p_error') # Validate the error function def validate_error_func(self): @@ -2147,24 +2108,24 @@ def validate_error_func(self): argcount = self.error_func.__code__.co_argcount - ismethod if argcount != 1: - self.log.error("%s:%d: p_error() requires 1 argument", efile, eline) + self.log.error('%s:%d: p_error() requires 1 argument', efile, eline) self.error = True # Get the tokens map def get_tokens(self): - tokens = self.pdict.get("tokens") + tokens = self.pdict.get('tokens') if not tokens: - self.log.error("No token list is defined") + self.log.error('No token list is defined') self.error = True return if not isinstance(tokens, (list, tuple)): - self.log.error("tokens must be a list or tuple") + self.log.error('tokens must be a list or tuple') self.error = True return if not tokens: - self.log.error("tokens is empty") + self.log.error('tokens is empty') self.error = True return @@ -2173,7 +2134,7 @@ def get_tokens(self): # Validate the tokens def validate_tokens(self): # Validate the tokens. - if "error" in self.tokens: + if 'error' in self.tokens: self.log.error("Illegal token name 'error'. Is a reserved word") self.error = True return @@ -2181,59 +2142,63 @@ def validate_tokens(self): terminals = set() for n in self.tokens: if n in terminals: - self.log.warning("Token %r multiply defined", n) + self.log.warning('Token %r multiply defined', n) terminals.add(n) # Get the precedence map (if any) def get_precedence(self): - self.prec = self.pdict.get("precedence") + self.prec = self.pdict.get('precedence') # Validate and parse the precedence map def validate_precedence(self): preclist = [] if self.prec: if not isinstance(self.prec, (list, tuple)): - self.log.error("precedence must be a list or tuple") + self.log.error('precedence must be a list or tuple') self.error = True return for level, p in enumerate(self.prec): if not isinstance(p, (list, tuple)): - self.log.error("Bad precedence table") + self.log.error('Bad precedence table') self.error = True return if len(p) < 2: - self.log.error("Malformed precedence entry %s. Must be (assoc, term, ..., term)", p) + self.log.error('Malformed precedence entry %s. Must be (assoc, term, ..., term)', p) self.error = True return assoc = p[0] if not isinstance(assoc, str): - self.log.error("precedence associativity must be a string") + self.log.error('precedence associativity must be a string') self.error = True return for term in p[1:]: if not isinstance(term, str): - self.log.error("precedence items must be strings") + self.log.error('precedence items must be strings') self.error = True return - preclist.append((term, assoc, level + 1)) + preclist.append((term, assoc, level+1)) self.preclist = preclist # Get all p_functions from the grammar def get_pfunctions(self): p_functions = [] for name, item in self.pdict.items(): - if not name.startswith("p_") or name == "p_error": + if not name.startswith('p_') or name == 'p_error': continue if isinstance(item, (types.FunctionType, types.MethodType)): - line = getattr(item, "co_firstlineno", item.__code__.co_firstlineno) + line = getattr(item, 'co_firstlineno', item.__code__.co_firstlineno) module = inspect.getmodule(item) p_functions.append((line, module, name, item.__doc__)) # Sort all of the actions by line number; make sure to stringify # modules to make them sortable, since `line` may not uniquely sort all # p functions - p_functions.sort(key=lambda p_function: (p_function[0], str(p_function[1]), p_function[2], p_function[3])) + p_functions.sort(key=lambda p_function: ( + p_function[0], + str(p_function[1]), + p_function[2], + p_function[3])) self.pfuncs = p_functions # Validate all of the p_functions @@ -2241,7 +2206,7 @@ def validate_pfunctions(self): grammar = [] # Check for non-empty symbols if len(self.pfuncs) == 0: - self.log.error("no rules of the form p_rulename are defined") + self.log.error('no rules of the form p_rulename are defined') self.error = True return @@ -2253,15 +2218,14 @@ def validate_pfunctions(self): else: reqargs = 1 if func.__code__.co_argcount > reqargs: - self.log.error("%s:%d: Rule %r has too many arguments", file, line, func.__name__) + self.log.error('%s:%d: Rule %r has too many arguments', file, line, func.__name__) self.error = True elif func.__code__.co_argcount < reqargs: - self.log.error("%s:%d: Rule %r requires an argument", file, line, func.__name__) + self.log.error('%s:%d: Rule %r requires an argument', file, line, func.__name__) self.error = True elif not func.__doc__: - self.log.warning( - "%s:%d: No documentation string specified in function %r (ignored)", file, line, func.__name__ - ) + self.log.warning('%s:%d: No documentation string specified in function %r (ignored)', + file, line, func.__name__) else: try: parsed_g = parse_grammar(doc, file, line) @@ -2279,49 +2243,35 @@ def validate_pfunctions(self): # or functions that look like they might be grammar rules. for n, v in self.pdict.items(): - if n.startswith("p_") and isinstance(v, (types.FunctionType, types.MethodType)): + if n.startswith('p_') and isinstance(v, (types.FunctionType, types.MethodType)): continue - if n.startswith("t_"): + if n.startswith('t_'): continue - if n.startswith("p_") and n != "p_error": - self.log.warning("%r not defined as a function", n) - if (isinstance(v, types.FunctionType) and v.__code__.co_argcount == 1) or ( - isinstance(v, types.MethodType) and v.__func__.__code__.co_argcount == 2 - ): + if n.startswith('p_') and n != 'p_error': + self.log.warning('%r not defined as a function', n) + if ((isinstance(v, types.FunctionType) and v.__code__.co_argcount == 1) or + (isinstance(v, types.MethodType) and v.__func__.__code__.co_argcount == 2)): if v.__doc__: try: - doc = v.__doc__.split(" ") - if doc.get(1, "") == ":": - self.log.warning( - "%s:%d: Possible grammar rule %r defined without p_ prefix", - v.__code__.co_filename, - v.__code__.co_firstlineno, - n, - ) + doc = v.__doc__.split(' ') + if doc[1] == ':': + self.log.warning('%s:%d: Possible grammar rule %r defined without p_ prefix', + v.__code__.co_filename, v.__code__.co_firstlineno, n) except IndexError: pass self.grammar = grammar - # ----------------------------------------------------------------------------- # yacc(module) # # Build a parser # ----------------------------------------------------------------------------- +def yacc(*, debug=yaccdebug, module=None, start=None, + check_recursion=True, optimize=False, debugfile=debug_file, + debuglog=None, errorlog=None): -def yacc( - *, - debug=yaccdebug, - module=None, - start=None, - check_recursion=True, - optimize=False, - debugfile=debug_file, - debuglog=None, - errorlog=None, -): # Reference to the parsing method of the last built parser global parse @@ -2334,45 +2284,45 @@ def yacc( pdict = dict(_items) # If no __file__ or __package__ attributes are available, try to obtain them # from the __module__ instead - if "__file__" not in pdict: - pdict["__file__"] = sys.modules[pdict["__module__"]].__file__ - if "__package__" not in pdict and "__module__" in pdict: - if hasattr(sys.modules[pdict["__module__"]], "__package__"): - pdict["__package__"] = sys.modules[pdict["__module__"]].__package__ + if '__file__' not in pdict: + pdict['__file__'] = sys.modules[pdict['__module__']].__file__ + if '__package__' not in pdict and '__module__' in pdict: + if hasattr(sys.modules[pdict['__module__']], '__package__'): + pdict['__package__'] = sys.modules[pdict['__module__']].__package__ else: pdict = get_caller_module_dict(2) # Set start symbol if it's specified directly using an argument if start is not None: - pdict["start"] = start + pdict['start'] = start # Collect parser information from the dictionary pinfo = ParserReflect(pdict, log=errorlog) pinfo.get_all() if pinfo.error: - raise YaccError("Unable to build parser") + raise YaccError('Unable to build parser') if debuglog is None: if debug: try: - debuglog = PlyLogger(open(debugfile, "w")) + debuglog = PlyLogger(open(debugfile, 'w')) except IOError as e: errorlog.warning("Couldn't open %r. %s" % (debugfile, e)) debuglog = NullLogger() else: debuglog = NullLogger() - debuglog.info("Created by PLY (http://www.dabeaz.com/ply)") + debuglog.info('Created by PLY (http://www.dabeaz.com/ply)') errors = False # Validate the parser information if pinfo.validate_all(): - raise YaccError("Unable to build parser") + raise YaccError('Unable to build parser') if not pinfo.error_func: - errorlog.warning("no p_error() function is defined") + errorlog.warning('no p_error() function is defined') # Create a grammar object grammar = Grammar(pinfo.tokens) @@ -2382,7 +2332,7 @@ def yacc( try: grammar.set_precedence(term, assoc, level) except GrammarError as e: - errorlog.warning("%s", e) + errorlog.warning('%s', e) # Add productions to the grammar for funcname, gram in pinfo.grammar: @@ -2390,7 +2340,7 @@ def yacc( try: grammar.add_production(prodname, syms, funcname, file, line) except GrammarError as e: - errorlog.error("%s", e) + errorlog.error('%s', e) errors = True # Set the grammar start symbols @@ -2404,81 +2354,81 @@ def yacc( errors = True if errors: - raise YaccError("Unable to build parser") + raise YaccError('Unable to build parser') # Verify the grammar structure undefined_symbols = grammar.undefined_symbols() for sym, prod in undefined_symbols: - errorlog.error("%s:%d: Symbol %r used, but not defined as a token or a rule", prod.file, prod.line, sym) + errorlog.error('%s:%d: Symbol %r used, but not defined as a token or a rule', prod.file, prod.line, sym) errors = True unused_terminals = grammar.unused_terminals() if unused_terminals: - debuglog.info("") - debuglog.info("Unused terminals:") - debuglog.info("") + debuglog.info('') + debuglog.info('Unused terminals:') + debuglog.info('') for term in unused_terminals: - errorlog.warning("Token %r defined, but not used", term) - debuglog.info(" %s", term) + errorlog.warning('Token %r defined, but not used', term) + debuglog.info(' %s', term) # Print out all productions to the debug log if debug: - debuglog.info("") - debuglog.info("Grammar") - debuglog.info("") + debuglog.info('') + debuglog.info('Grammar') + debuglog.info('') for n, p in enumerate(grammar.Productions): - debuglog.info("Rule %-5d %s", n, p) + debuglog.info('Rule %-5d %s', n, p) # Find unused non-terminals unused_rules = grammar.unused_rules() for prod in unused_rules: - errorlog.warning("%s:%d: Rule %r defined, but not used", prod.file, prod.line, prod.name) + errorlog.warning('%s:%d: Rule %r defined, but not used', prod.file, prod.line, prod.name) if len(unused_terminals) == 1: - errorlog.warning("There is 1 unused token") + errorlog.warning('There is 1 unused token') if len(unused_terminals) > 1: - errorlog.warning("There are %d unused tokens", len(unused_terminals)) + errorlog.warning('There are %d unused tokens', len(unused_terminals)) if len(unused_rules) == 1: - errorlog.warning("There is 1 unused rule") + errorlog.warning('There is 1 unused rule') if len(unused_rules) > 1: - errorlog.warning("There are %d unused rules", len(unused_rules)) + errorlog.warning('There are %d unused rules', len(unused_rules)) if debug: - debuglog.info("") - debuglog.info("Terminals, with rules where they appear") - debuglog.info("") + debuglog.info('') + debuglog.info('Terminals, with rules where they appear') + debuglog.info('') terms = list(grammar.Terminals) terms.sort() for term in terms: - debuglog.info("%-20s : %s", term, " ".join([str(s) for s in grammar.Terminals[term]])) + debuglog.info('%-20s : %s', term, ' '.join([str(s) for s in grammar.Terminals[term]])) - debuglog.info("") - debuglog.info("Nonterminals, with rules where they appear") - debuglog.info("") + debuglog.info('') + debuglog.info('Nonterminals, with rules where they appear') + debuglog.info('') nonterms = list(grammar.Nonterminals) nonterms.sort() for nonterm in nonterms: - debuglog.info("%-20s : %s", nonterm, " ".join([str(s) for s in grammar.Nonterminals[nonterm]])) - debuglog.info("") + debuglog.info('%-20s : %s', nonterm, ' '.join([str(s) for s in grammar.Nonterminals[nonterm]])) + debuglog.info('') if check_recursion: unreachable = grammar.find_unreachable() for u in unreachable: - errorlog.warning("Symbol %r is unreachable", u) + errorlog.warning('Symbol %r is unreachable', u) infinite = grammar.infinite_cycles() for inf in infinite: - errorlog.error("Infinite recursion detected for symbol %r", inf) + errorlog.error('Infinite recursion detected for symbol %r', inf) errors = True unused_prec = grammar.unused_precedence() for term, assoc in unused_prec: - errorlog.error("Precedence rule %r defined for unknown symbol %r", assoc, term) + errorlog.error('Precedence rule %r defined for unknown symbol %r', assoc, term) errors = True if errors: - raise YaccError("Unable to build parser") + raise YaccError('Unable to build parser') # Run the LRTable on the grammar lr = LRTable(grammar, debuglog) @@ -2488,40 +2438,40 @@ def yacc( # Report shift/reduce and reduce/reduce conflicts if num_sr == 1: - errorlog.warning("1 shift/reduce conflict") + errorlog.warning('1 shift/reduce conflict') elif num_sr > 1: - errorlog.warning("%d shift/reduce conflicts", num_sr) + errorlog.warning('%d shift/reduce conflicts', num_sr) num_rr = len(lr.rr_conflicts) if num_rr == 1: - errorlog.warning("1 reduce/reduce conflict") + errorlog.warning('1 reduce/reduce conflict') elif num_rr > 1: - errorlog.warning("%d reduce/reduce conflicts", num_rr) + errorlog.warning('%d reduce/reduce conflicts', num_rr) # Write out conflicts to the output file if debug and (lr.sr_conflicts or lr.rr_conflicts): - debuglog.warning("") - debuglog.warning("Conflicts:") - debuglog.warning("") + debuglog.warning('') + debuglog.warning('Conflicts:') + debuglog.warning('') for state, tok, resolution in lr.sr_conflicts: - debuglog.warning("shift/reduce conflict for %s in state %d resolved as %s", tok, state, resolution) + debuglog.warning('shift/reduce conflict for %s in state %d resolved as %s', tok, state, resolution) already_reported = set() for state, rule, rejected in lr.rr_conflicts: if (state, id(rule), id(rejected)) in already_reported: continue - debuglog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) - debuglog.warning("rejected rule (%s) in state %d", rejected, state) - errorlog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) - errorlog.warning("rejected rule (%s) in state %d", rejected, state) + debuglog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + debuglog.warning('rejected rule (%s) in state %d', rejected, state) + errorlog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + errorlog.warning('rejected rule (%s) in state %d', rejected, state) already_reported.add((state, id(rule), id(rejected))) warned_never = [] for state, rule, rejected in lr.rr_conflicts: if not rejected.reduced and (rejected not in warned_never): - debuglog.warning("Rule (%s) is never reduced", rejected) - errorlog.warning("Rule (%s) is never reduced", rejected) + debuglog.warning('Rule (%s) is never reduced', rejected) + errorlog.warning('Rule (%s) is never reduced', rejected) warned_never.append(rejected) # Build the parser diff --git a/src/zxbpp/prepro/builtinmacro.py b/src/zxbpp/prepro/builtinmacro.py index d823292aa..5afb641cc 100644 --- a/src/zxbpp/prepro/builtinmacro.py +++ b/src/zxbpp/prepro/builtinmacro.py @@ -1,6 +1,7 @@ from collections.abc import Callable from src.zxbpp.prepro import DefinesTable + from .id_ import ID from .macrocall import MacroCall From da9757ceec57abd90bc565efe8711652a1493b1c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 14 Dec 2024 20:47:32 +0100 Subject: [PATCH 3/5] test: add test to check parsetab building --- tests/zxbc/__init__.py | 0 tests/zxbc/test_build_parsetab.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/zxbc/__init__.py create mode 100644 tests/zxbc/test_build_parsetab.py diff --git a/tests/zxbc/__init__.py b/tests/zxbc/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/zxbc/test_build_parsetab.py b/tests/zxbc/test_build_parsetab.py new file mode 100644 index 000000000..775b7e209 --- /dev/null +++ b/tests/zxbc/test_build_parsetab.py @@ -0,0 +1,19 @@ +from unittest import mock + +from src.ply.yacc import LRParser + + +class TestBuildParsetab: + @mock.patch("src.api.utils.load_object", return_value=None) + @mock.patch("src.api.utils.save_object", lambda key, obj: obj) + def test_build_parsetab(self, mock_load_object): + from src.zxbc import zxbparser + + parser = zxbparser.parser + assert isinstance(parser, LRParser), "Could not generate an rparser" + + def test_loads_parsetab(self): + from src.zxbc import zxbparser + + parser = zxbparser.parser + assert isinstance(parser, LRParser), "Could not load an rparser" From 0a5ae81957c2aea8665f6c6a4448756017313fc4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 15 Dec 2024 11:26:23 +0100 Subject: [PATCH 4/5] fix: crash on PRINT (a = a) --- src/arch/z80/visitor/translator.py | 1 + src/arch/z80/visitor/translator_inst_visitor.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arch/z80/visitor/translator.py b/src/arch/z80/visitor/translator.py index 86f735e72..db2c1caea 100644 --- a/src/arch/z80/visitor/translator.py +++ b/src/arch/z80/visitor/translator.py @@ -794,6 +794,7 @@ def visit_PRINT(self, node): self.ic_fparam(i.type_, i.t) label = { + "bool": RuntimeLabel.PRINTU8, "i8": RuntimeLabel.PRINTI8, "u8": RuntimeLabel.PRINTU8, "i16": RuntimeLabel.PRINTI16, diff --git a/src/arch/z80/visitor/translator_inst_visitor.py b/src/arch/z80/visitor/translator_inst_visitor.py index 04c100e11..adaa870a3 100644 --- a/src/arch/z80/visitor/translator_inst_visitor.py +++ b/src/arch/z80/visitor/translator_inst_visitor.py @@ -106,7 +106,7 @@ def ic_exchg(self) -> None: self.emit("exchg") def ic_fparam(self, type_: TYPE | symbols.BASICTYPE, t) -> None: - self.emit("fparam" + self.TSUFFIX(type_), t) + self.emit(f"fparam{self._no_bool(type_)}", t) def ic_fpload(self, type_: TYPE | symbols.BASICTYPE, t, offset) -> None: self.emit("fpload" + self.TSUFFIX(type_), t, offset) From 51435d5bb338c9852a9c8698798f9a2d0431417b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 15 Dec 2024 11:35:11 +0100 Subject: [PATCH 5/5] refact: simplify typing --- .../z80/visitor/translator_inst_visitor.py | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/arch/z80/visitor/translator_inst_visitor.py b/src/arch/z80/visitor/translator_inst_visitor.py index adaa870a3..d0a0d0ab4 100644 --- a/src/arch/z80/visitor/translator_inst_visitor.py +++ b/src/arch/z80/visitor/translator_inst_visitor.py @@ -4,7 +4,7 @@ from src.arch.z80.backend import Backend from src.arch.z80.backend.common import BOOL_t, F16_t, F_t, I8_t, I16_t, I32_t, STR_t, U8_t, U16_t, U32_t from src.ast import NodeVisitor -from src.symbols import sym as symbols +from src.symbols import sym class TranslatorInstVisitor(NodeVisitor): @@ -18,8 +18,8 @@ def emit(self, *args: str) -> None: self.backend.MEMORY.append(quad) @staticmethod - def TSUFFIX(type_: TYPE | symbols.TYPEREF | symbols.BASICTYPE) -> str: - assert isinstance(type_, symbols.TYPE) or TYPE.is_valid(type_) + def TSUFFIX(type_: TYPE | sym.TYPEREF | sym.BASICTYPE) -> str: + assert isinstance(type_, sym.TYPE) or TYPE.is_valid(type_) _TSUFFIX = { TYPE.byte: I8_t, @@ -34,48 +34,48 @@ def TSUFFIX(type_: TYPE | symbols.TYPEREF | symbols.BASICTYPE) -> str: TYPE.boolean: BOOL_t, } - if isinstance(type_, symbols.TYPEREF): + if isinstance(type_, sym.TYPEREF): type_ = type_.final - assert isinstance(type_, symbols.BASICTYPE) + assert isinstance(type_, sym.BASICTYPE) - if isinstance(type_, symbols.BASICTYPE): + if isinstance(type_, sym.BASICTYPE): return _TSUFFIX[type_.type_] return _TSUFFIX[type_] @classmethod - def _no_bool(cls, type_: TYPE | symbols.TYPEREF | symbols.BASICTYPE) -> str: + def _no_bool(cls, type_: TYPE | sym.TYPEREF | sym.BASICTYPE) -> str: """Returns the corresponding type suffix except for bool which maps to U8_t""" return cls.TSUFFIX(type_) if cls.TSUFFIX(type_) != BOOL_t else U8_t def ic_aaddr(self, t1, t2) -> None: self.emit("aaddr", t1, t2) - def ic_abs(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_abs(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit("abs" + self.TSUFFIX(type_), t1, t2) - def ic_add(self, type_: TYPE | symbols.BASICTYPE, t1, t2, t3) -> None: + def ic_add(self, type_: TYPE | sym.BASICTYPE, t1, t2, t3) -> None: self.emit("add" + self.TSUFFIX(type_), t1, t2, t3) - def ic_aload(self, type_: TYPE | symbols.BASICTYPE, t1, mangle: str) -> None: + def ic_aload(self, type_: TYPE | sym.BASICTYPE, t1, mangle: str) -> None: self.emit("aload" + self.TSUFFIX(type_), t1, mangle) - def ic_and(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_and(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit(f"and{self._no_bool(type_)}", t, t1, t2) - def ic_astore(self, type_: TYPE | symbols.BASICTYPE, addr: str, t) -> None: + def ic_astore(self, type_: TYPE | sym.BASICTYPE, addr: str, t) -> None: self.emit("astore" + self.TSUFFIX(type_), addr, t) - def ic_band(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_band(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("band" + self.TSUFFIX(type_), t, t1, t2) - def ic_bnot(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_bnot(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit("bnot" + self.TSUFFIX(type_), t1, t2) - def ic_bor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_bor(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("bor" + self.TSUFFIX(type_), t, t1, t2) - def ic_bxor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_bxor(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("bxor" + self.TSUFFIX(type_), t, t1, t2) def ic_call(self, label: str, num: int) -> None: @@ -84,13 +84,13 @@ def ic_call(self, label: str, num: int) -> None: def ic_cast(self, t1, type1, type2, t2) -> None: self.emit("cast", t1, self.TSUFFIX(type1), self.TSUFFIX(type2), t2) - def ic_data(self, type_: TYPE | symbols.BASICTYPE, data: list) -> None: + def ic_data(self, type_: TYPE | sym.BASICTYPE, data: list) -> None: self.emit("data", self.TSUFFIX(type_), data) def ic_deflabel(self, label: str, t) -> None: self.emit("deflabel", label, t) - def ic_div(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_div(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("div" + self.TSUFFIX(type_), t, t1, t2) def ic_end(self, t) -> None: @@ -99,22 +99,22 @@ def ic_end(self, t) -> None: def ic_enter(self, arg) -> None: self.emit("enter", arg) - def ic_eq(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_eq(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("eq" + self.TSUFFIX(type_), t, t1, t2) def ic_exchg(self) -> None: self.emit("exchg") - def ic_fparam(self, type_: TYPE | symbols.BASICTYPE, t) -> None: + def ic_fparam(self, type_: TYPE | sym.BASICTYPE, t) -> None: self.emit(f"fparam{self._no_bool(type_)}", t) - def ic_fpload(self, type_: TYPE | symbols.BASICTYPE, t, offset) -> None: + def ic_fpload(self, type_: TYPE | sym.BASICTYPE, t, offset) -> None: self.emit("fpload" + self.TSUFFIX(type_), t, offset) - def ic_ge(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_ge(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("ge" + self.TSUFFIX(type_), t, t1, t2) - def ic_gt(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_gt(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("gt" + self.TSUFFIX(type_), t, t1, t2) def ic_in(self, t) -> None: @@ -123,16 +123,16 @@ def ic_in(self, t) -> None: def ic_inline(self, asm_code: str) -> None: self.emit("inline", asm_code) - def ic_jgezero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + def ic_jgezero(self, type_: TYPE | sym.BASICTYPE, t, label: str) -> None: self.emit(f"jgezero{self._no_bool(type_)}", t, label) - def ic_jnzero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + def ic_jnzero(self, type_: TYPE | sym.BASICTYPE, t, label: str) -> None: self.emit(f"jnzero{self._no_bool(type_)}", t, label) def ic_jump(self, label: str) -> None: self.emit("jump", label) - def ic_jzero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + def ic_jzero(self, type_: TYPE | sym.BASICTYPE, t, label: str) -> None: self.emit(f"jzero{self._no_bool(type_)}", t, label) def ic_label(self, label: str) -> None: @@ -141,7 +141,7 @@ def ic_label(self, label: str) -> None: def ic_larrd(self, offset, arg1, size, arg2, bound_ptrs) -> None: self.emit("larrd", offset, arg1, size, arg2, bound_ptrs) - def ic_le(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_le(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("le" + self.TSUFFIX(type_), t, t1, t2) def ic_leave(self, convention: str) -> None: @@ -150,43 +150,43 @@ def ic_leave(self, convention: str) -> None: def ic_lenstr(self, t1, t2) -> None: self.emit("lenstr", t1, t2) - def ic_load(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_load(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit("load" + self.TSUFFIX(type_), t1, t2) - def ic_lt(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_lt(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("lt" + self.TSUFFIX(type_), t, t1, t2) def ic_lvard(self, offset, default_value: list) -> None: self.emit("lvard", offset, default_value) - def ic_lvarx(self, type_: TYPE | symbols.BASICTYPE, offset, default_value: list) -> None: + def ic_lvarx(self, type_: TYPE | sym.BASICTYPE, offset, default_value: list) -> None: self.emit("lvarx", offset, self.TSUFFIX(type_), default_value) def ic_memcopy(self, t1, t2, t3) -> None: self.emit("memcopy", t1, t2, t3) - def ic_mod(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_mod(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("mod" + self.TSUFFIX(type_), t, t1, t2) - def ic_mul(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_mul(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("mul" + self.TSUFFIX(type_), t, t1, t2) - def ic_ne(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_ne(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("ne" + self.TSUFFIX(type_), t, t1, t2) - def ic_neg(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_neg(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit("neg" + self.TSUFFIX(type_), t1, t2) def ic_nop(self) -> None: self.emit("nop") - def ic_not(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_not(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit(f"not{self._no_bool(type_)}", t1, t2) - def ic_or(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_or(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit(f"or{self._no_bool(type_)}", t, t1, t2) - def ic_org(self, type_: TYPE | symbols.BASICTYPE) -> None: + def ic_org(self, type_: TYPE | sym.BASICTYPE) -> None: self.emit("org" + self.TSUFFIX(type_)) def ic_out(self, t1, t2) -> None: @@ -198,40 +198,40 @@ def ic_paaddr(self, t1, t2) -> None: def ic_paddr(self, t1, t2) -> None: self.emit("paddr", t1, t2) - def ic_paload(self, type_: TYPE | symbols.BASICTYPE, t, offset: int) -> None: + def ic_paload(self, type_: TYPE | sym.BASICTYPE, t, offset: int) -> None: self.emit("paload" + self.TSUFFIX(type_), t, offset) - def ic_param(self, type_: TYPE | symbols.BASICTYPE, t) -> None: + def ic_param(self, type_: TYPE | sym.BASICTYPE, t) -> None: self.emit("param" + self.TSUFFIX(type_), t) - def ic_pastore(self, type_: TYPE | symbols.BASICTYPE, offset, t) -> None: + def ic_pastore(self, type_: TYPE | sym.BASICTYPE, offset, t) -> None: self.emit("pastore" + self.TSUFFIX(type_), offset, t) - def ic_pload(self, type_: TYPE | symbols.BASICTYPE, t1, offset) -> None: + def ic_pload(self, type_: TYPE | sym.BASICTYPE, t1, offset) -> None: self.emit("pload" + self.TSUFFIX(type_), t1, offset) - def ic_pow(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_pow(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("pow" + self.TSUFFIX(type_), t, t1, t2) - def ic_pstore(self, type_: TYPE | symbols.BASICTYPE, offset, t) -> None: + def ic_pstore(self, type_: TYPE | sym.BASICTYPE, offset, t) -> None: self.emit("pstore" + self.TSUFFIX(type_), offset, t) - def ic_ret(self, type_: TYPE | symbols.BASICTYPE, t, addr) -> None: + def ic_ret(self, type_: TYPE | sym.BASICTYPE, t, addr) -> None: self.emit("ret" + self.TSUFFIX(type_), t, addr) def ic_return(self, addr) -> None: self.emit("ret", addr) - def ic_shl(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_shl(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("shl" + self.TSUFFIX(type_), t, t1, t2) - def ic_shr(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_shr(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("shr" + self.TSUFFIX(type_), t, t1, t2) - def ic_store(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + def ic_store(self, type_: TYPE | sym.BASICTYPE, t1, t2) -> None: self.emit("store" + self.TSUFFIX(type_), t1, t2) - def ic_sub(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_sub(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("sub" + self.TSUFFIX(type_), t, t1, t2) def ic_var(self, name: str, size_) -> None: @@ -240,8 +240,8 @@ def ic_var(self, name: str, size_) -> None: def ic_vard(self, name: str, data: list) -> None: self.emit("vard", name, data) - def ic_varx(self, name: str, type_: TYPE | symbols.BASICTYPE, default_value: list) -> None: + def ic_varx(self, name: str, type_: TYPE | sym.BASICTYPE, default_value: list) -> None: self.emit("varx", name, self.TSUFFIX(type_), default_value) - def ic_xor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + def ic_xor(self, type_: TYPE | sym.BASICTYPE, t, t1, t2) -> None: self.emit("xor" + self.TSUFFIX(type_), t, t1, t2)