From 503fae9e186f54e8390c029713145f649f678900 Mon Sep 17 00:00:00 2001 From: David Beazley Date: Sun, 18 Nov 2018 06:42:22 -0600 Subject: [PATCH] Various usability improvements --- CHANGES | 21 +++++++++++++++++++++ sly/yacc.py | 19 ++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 18e4d93..b6f34ce 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,26 @@ Version 0.4 ----------- +11/18/2018 Various usability fixes observed from last compilers course. + + - Errors encountered during grammar construction are now + reported as part of the raised GrammarError exception + instead of via logging. This places them in the same + visual position as normal Python errors (at the end + of the traceback) + + - Repeated warning messages about unused tokens have + been consolidated in a single warning message to make + the output less verbose. + + - Grammar attributes (e.g., p.TOKEN) used during parsing + are now read-only. + + - The error about "infinite recursion" is only checked + if there are no undefined grammar symbols. Sometimes + you'd get this message and be confused when the only + mistake was a bad token name or similar. + + 9/8/2018 Fixed Issue #14. YaccProduction index property causes AttributeError if index is 0 diff --git a/sly/yacc.py b/sly/yacc.py index 000653c..7fe91e2 100644 --- a/sly/yacc.py +++ b/sly/yacc.py @@ -152,10 +152,10 @@ class YaccProduction: raise AttributeError(f'No symbol {name}. Must be one of {nameset}.') def __setattr__(self, name, value): - if name[0:1] == '_' or name not in self._namemap: + if name[:1] == '_': super().__setattr__(name, value) else: - self._slice[self._namemap[name]].value = value + raise AttributeError(f"Can't reassign the value of attribute {name!r}") # ----------------------------------------------------------------------------- # === Grammar Representation === @@ -1719,9 +1719,10 @@ class Parser(metaclass=ParserMeta): for u in unreachable: cls.log.warning('Symbol %r is unreachable', u) - infinite = grammar.infinite_cycles() - for inf in infinite: - errors += 'Infinite recursion detected for symbol %r\n' % inf + if len(undefined_symbols) == 0: + infinite = grammar.infinite_cycles() + for inf in infinite: + errors += 'Infinite recursion detected for symbol %r\n' % inf unused_prec = grammar.unused_precedence() for term, assoc in unused_prec: @@ -1806,11 +1807,11 @@ class Parser(metaclass=ParserMeta): if token: lineno = getattr(token, 'lineno', 0) if lineno: - sys.stderr.write(f'yacc: Syntax error at line {lineno}, token={token.type}\n') + sys.stderr.write(f'sly: Syntax error at line {lineno}, token={token.type}\n') else: - sys.stderr.write(f'yacc: Syntax error, token={token.type}') + sys.stderr.write(f'sly: Syntax error, token={token.type}') else: - sys.stderr.write('yacc: Parse error in input. EOF\n') + sys.stderr.write('sly: Parse error in input. EOF\n') def errok(self): ''' @@ -1995,4 +1996,4 @@ class Parser(metaclass=ParserMeta): continue # Call an error function here - raise RuntimeError('yacc: internal parser error!!!\n') + raise RuntimeError('sly: internal parser error!!!\n')