{"id":2769,"library":"sly","title":"SLY - Sly Lex Yacc","description":"SLY is a 100% Python implementation of the lex and yacc tools, loosely based on the traditional compiler construction tools lex and yacc, implementing the LALR(1) parsing algorithm. It provides a bare-bones, yet fully capable, library for writing parsers in Python. The current version is 0.5. As of December 21, 2025, the project has been officially retired by its author, and no further maintenance is expected.","status":"abandoned","version":"0.5","language":"en","source_language":"en","source_url":"https://github.com/dabeaz/sly","tags":["lexer","parser","compiler","LALR(1)","language tools","abandoned"],"install":[{"cmd":"pip install sly","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"Lexer is used to break input text into tokens.","symbol":"Lexer","correct":"from sly import Lexer"},{"note":"Parser is used to recognize language syntax from a stream of tokens.","symbol":"Parser","correct":"from sly import Parser"}],"quickstart":{"code":"from sly import Lexer, Parser\n\nclass CalcLexer(Lexer):\n    tokens = { NUMBER, ID, PLUS, MINUS, TIMES, DIVIDE, ASSIGN, LPAREN, RPAREN }\n    literals = { '=', '+', '-', '*', '/', '(', ')' }\n\n    # String containing ignored characters\n    ignore = ' \\t'\n\n    # Regular expression rules for tokens\n    NUMBER = r'\\d+'\n    ID = r'[a-zA-Z_][a-zA-Z0-9_]*'\n\n    # Special rules for tokens\n    def NUMBER(self, t):\n        t.value = int(t.value)\n        return t\n\n    def ID(self, t):\n        t.value = str(t.value)\n        return t\n\n    def error(self, t):\n        print(f\"Illegal character '{t.value[0]}' at line {t.lineno}\")\n        self.index += 1\n\nclass CalcParser(Parser):\n    tokens = CalcLexer.tokens\n\n    precedence = (\n        ('left', PLUS, MINUS),\n        ('left', TIMES, DIVIDE)\n    )\n\n    def __init__(self):\n        self.names = { }\n\n    @_('ID ASSIGN expr')\n    def statement(self, p):\n        self.names[p.ID] = p.expr\n        return p.expr\n\n    @_('expr')\n    def statement(self, p):\n        return p.expr\n\n    @_('expr PLUS expr')\n    def expr(self, p):\n        return p.expr0 + p.expr1\n\n    @_('expr MINUS expr')\n    def expr(self, p):\n        return p.expr0 - p.expr1\n\n    @_('expr TIMES expr')\n    def expr(self, p):\n        return p.expr0 * p.expr1\n\n    @_('expr DIVIDE expr')\n    def expr(self, p):\n        return p.expr0 / p.expr1\n\n    @_('LPAREN expr RPAREN')\n    def expr(self, p):\n        return p.expr\n\n    @_('NUMBER')\n    def expr(self, p):\n        return p.NUMBER\n\n    @_('ID')\n    def expr(self, p):\n        try:\n            return self.names[p.ID]\n        except LookupError:\n            print(f\"Undefined name '{p.ID}'\")\n            return 0\n\n    def error(self, p):\n        if p:\n            print(f\"Syntax error at token {p.type}, value '{p.value}'\")\n        else:\n            print(\"Syntax error at EOF\")\n\nif __name__ == '__main__':\n    lexer = CalcLexer()\n    parser = CalcParser()\n    while True:\n        try:\n            text = input('calc > ')\n            if text.lower() == 'quit':\n                break\n            result = parser.parse(lexer.tokenize(text))\n            if result is not None: # Only print if there was a calculable result\n                print(result)\n        except EOFError:\n            break\n        except Exception as e:\n            print(f\"Error: {e}\")","lang":"python","description":"This quickstart demonstrates a simple calculator using SLY. It defines a lexer to tokenize input (numbers, IDs, operators) and a parser to build an abstract syntax tree and evaluate expressions, including variable assignments."},"warnings":[{"fix":"Migrate to an actively maintained parsing library (e.g., PLY, Lark) or fork SLY's source code if continued use is necessary.","message":"The SLY project was officially retired by its author on December 21, 2025. No further maintenance or development is expected. Users are advised to consider other parsing libraries or fork the project for continued use.","severity":"breaking","affected_versions":"All versions (from December 21, 2025, onwards)"},{"fix":"Rewrite PLY-based lexers and parsers to conform to SLY's API and conventions. Consult SLY's documentation for correct usage.","message":"SLY is a modernization of the PLY project, but code written for PLY is generally not compatible with SLY. Direct migration of PLY code to SLY without modifications will likely fail.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure your project uses Python 3.6 or a more recent version.","message":"SLY requires Python 3.6 or newer. It is not compatible with older Python versions.","severity":"gotcha","affected_versions":"<0.5 (older Python versions)"},{"fix":"Always define `tokens` as a set of all-capitalized token names. Carefully review regular expressions and ensure they match the intended input. Utilize the `error` method in the Lexer for debugging unmatched characters.","message":"Lexer classes *must* define a `tokens` set specifying all possible token type names. Token names should generally be in all-caps. Incorrectly defined tokens or regex patterns are a common source of parsing issues.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Refer to rule components using `p.symbolname` for unique symbols or `p.symbolnameN` (where N is a 0-indexed number) for repeated symbols. Consult the documentation for examples of `_()` decorator usage.","message":"When defining parser rules, the `_()` decorator is crucial. Accessing parts of a rule (e.g., `expr PLUS expr`) requires careful indexing (e.g., `p.expr0`, `p.expr1`) if a symbol appears multiple times in a rule's right-hand side, or by name (e.g., `p.NUMBER`) otherwise.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-10T00:00:00.000Z","next_check":"2026-07-09T00:00:00.000Z"}