{"id":5716,"library":"rply","title":"RPly: Python Lex/Yacc Parser Generator","description":"RPly is a pure Python parser generator, offering a modern API and compatibility with RPython. It is a re-implementation of David Beazley's PLY library. RPly simplifies the process of building lexers (tokenizers) and parsers (syntax analyzers) for domain-specific languages or custom syntaxes. The current version is 0.7.8, and it has a relatively slow release cadence.","status":"active","version":"0.7.8","language":"en","source_language":"en","source_url":"https://github.com/alex/rply","tags":["parser-generator","lexer","yacc","ply","rpython"],"install":[{"cmd":"pip install rply","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"LexerGenerator","correct":"from rply import LexerGenerator"},{"symbol":"ParserGenerator","correct":"from rply import ParserGenerator"},{"note":"Required for RPython compatibility or when building AST nodes for the parser.","symbol":"BaseBox","correct":"from rply.token import BaseBox"},{"note":"Exception raised during lexing errors.","symbol":"LexingError","correct":"from rply.lexer import LexingError"},{"note":"Exception raised during parsing errors.","symbol":"ParsingError","correct":"from rply import ParsingError"}],"quickstart":{"code":"from rply import LexerGenerator, ParserGenerator, ParsingError\nfrom rply.token import BaseBox\n\n# 1. Define the Abstract Syntax Tree (AST) nodes\nclass Number(BaseBox):\n    def __init__(self, value):\n        self.value = value\n\n    def eval(self):\n        return self.value\n\nclass BinaryOp(BaseBox):\n    def __init__(self, left, right):\n        self.left = left\n        self.right = right\n\nclass Add(BinaryOp):\n    def eval(self):\n        return self.left.eval() + self.right.eval()\n\nclass Sub(BinaryOp):\n    def eval(self):\n        return self.left.eval() - self.right.eval()\n\nclass Mul(BinaryOp):\n    def eval(self):\n        return self.left.eval() * self.right.eval()\n\nclass Div(BinaryOp):\n    def eval(self):\n        return self.left.eval() / self.right.eval()\n\n# 2. Build the Lexer\nlg = LexerGenerator()\n\nlg.add('NUMBER', r'\\d+')\nlg.add('PLUS', r'\\+')\nlg.add('MINUS', r'-')\nlg.add('MUL', r'\\*')\nlg.add('DIV', r'/')\nlg.add('OPEN_PAREN', r'\\(')\nlg.add('CLOSE_PAREN', r'\\)')\n\nlg.ignore(r'\\s+')\n\nlexer = lg.build()\n\n# 3. Build the Parser\npg = ParserGenerator(\n    ['NUMBER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'OPEN_PAREN', 'CLOSE_PAREN'],\n    precedence=[('left', ['PLUS', 'MINUS']), ('left', ['MUL', 'DIV'])]\n)\n\n@pg.production('expression : NUMBER')\ndef expression_number(p):\n    return Number(int(p[0].getstr()))\n\n@pg.production('expression : OPEN_PAREN expression CLOSE_PAREN')\ndef expression_paren(p):\n    return p[1]\n\n@pg.production('expression : expression PLUS expression')\ndef expression_plus(p):\n    return Add(p[0], p[2])\n\n@pg.production('expression : expression MINUS expression')\ndef expression_minus(p):\n    return Sub(p[0], p[2])\n\n@pg.production('expression : expression MUL expression')\ndef expression_mul(p):\n    return Mul(p[0], p[2])\n\n@pg.production('expression : expression DIV expression')\ndef expression_div(p):\n    return Div(p[0], p[2])\n\n@pg.error\ndef error_handler(token):\n    raise ValueError(\"Ran into a %s where it wasn't expected\" % token.gettokentype())\n\nparser = pg.build()\n\n# 4. Use the Lexer and Parser\ntext = \"(10 + 5) * 2 / 3 - 1\"\ntokens = lexer.lex(text)\n\ntry:\n    result = parser.parse(tokens).eval()\n    print(f\"Result of '{text}': {result}\")\nexcept ParsingError as e:\n    print(f\"Parsing error at position {e.getsourcepos()}: {e}\")\nexcept ValueError as e:\n    print(f\"Error: {e}\")","lang":"python","description":"This quickstart demonstrates how to create a simple arithmetic expression parser using RPly. It covers defining tokens with `LexerGenerator`, creating an Abstract Syntax Tree (AST) using classes inheriting from `BaseBox`, and defining grammar rules and precedence with `ParserGenerator` to evaluate expressions."},"warnings":[{"fix":"Ensure all classes used as AST nodes in parser productions inherit from `rply.token.BaseBox`.","message":"When targeting RPython, AST nodes passed between parser productions *must* inherit from `rply.token.BaseBox`. This ensures type compatibility in the RPython type inference system. For pure Python usage, this inheritance is not strictly necessary but is good practice if RPython compatibility might be a future goal.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always raise an exception (e.g., `ValueError`, `ParsingError`, `LexingError`) within custom error handler functions.","message":"Custom error handlers provided to `ParserGenerator` or `LexerGenerator` must raise an exception to correctly signal a parsing or lexing error. If an error handler merely returns, the parser/lexer will attempt to continue, potentially leading to incorrect results or infinite loops.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Carefully define precedence rules using `precedence=[('associativity', ['TOKEN1', 'TOKEN2'])]` in the `ParserGenerator` constructor. Operators with higher precedence should appear later in the list.","message":"Omitting or incorrectly defining precedence rules in `ParserGenerator` can lead to ambiguous grammars and unexpected parse trees, especially with operators like multiplication/division and addition/subtraction.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}