{"name":"PLY: A Legacy Python Lex-Yacc Parser Generator (Project Abandoned)","description":"PLY (Python Lex-Yacc) is a zero-dependency Python implementation of the traditional lex and yacc parsing tools, designed for building compilers, ASTs, and protocol decoders. Created by David Beazley, it offers a robust LALR(1) parsing algorithm compatible with modern Python versions. However, it's important to note that the project has been officially abandoned by its author, with no further maintenance expected.","github":"https://github.com/dabeaz/ply","url":"https://osrepos.com/repo/dabeaz-ply","source":"osrepos.com","sourceDescription":"This repository profile is provided by osrepos.com, an open source repository discovery platform.","repositoryProfile":"https://osrepos.com/repo/dabeaz-ply","generatedFor":"open source discovery and AI-assisted research","markdown":"https://osrepos.com/repo/dabeaz-ply.md","json":"https://osrepos.com/repo/dabeaz-ply.json","topics":["Python","Lexer","Parser","Yacc","Compiler","AST","Programming Tools"],"keywords":["Python","Lexer","Parser","Yacc","Compiler","AST","Programming Tools"],"stars":null,"summary":"PLY (Python Lex-Yacc) is a zero-dependency Python implementation of the traditional lex and yacc parsing tools, designed for building compilers, ASTs, and protocol decoders. Created by David Beazley, it offers a robust LALR(1) parsing algorithm compatible with modern Python versions. However, it's important to note that the project has been officially abandoned by its author, with no further maintenance expected.","content":"## Introduction\n\nPLY (Python Lex-Yacc) is a venerable, zero-dependency Python implementation of the classic lex and yacc parsing tools. Authored by David Beazley, PLY was originally developed in 2001 to support an Introduction to Compilers course at the University of Chicago. It utilizes the same LALR(1) parsing algorithm as yacc and provides core features for building Abstract Syntax Trees (ASTs), simple one-pass compilers, and protocol decoders.\n\n**Important Notice:** As of December 21, 2025, the PLY project has been officially abandoned by its author after 25 years. No further maintenance is expected. While modern, high-quality parsing libraries are now available, users can continue to use PLY by copying it directly into their projects, or explore writing a hand-rolled recursive descent parser as a challenge.\n\n## Installation\n\nPLY is not distributed or installed via a package manager. To use PLY, you need to copy its two core files, `lex.py` and `yacc.py`, which are contained within a `ply` package directory. Simply copy this `ply` directory into your project and import `lex` and `yacc` from it. Alternatively, you can install these files into your Python environment using `make install`.\n\npython\nfrom .ply import lex\nfrom .ply import yacc\n\n\nPLY has no third-party dependencies, is very small, and rarely changes, making it flexible for integration into various projects. It requires Python 3.6 or greater. For older Python versions, historical releases are available.\n\n## Examples\n\nPLY's primary application is in writing parsers for programming languages. The following example demonstrates how to use PLY to parse simple arithmetic expressions and construct an Abstract Syntax Tree (AST):\n\npython\n# -----------------------------------------------------------------------------\n# example.py\n#\n# Example of using PLY To parse the following simple grammar.\n#\n#   expression : term PLUS term\n#              | term MINUS term\n#              | term\n#\n#   term       : factor TIMES factor\n#              | factor DIVIDE factor\n#              | factor\n#\n#   factor     : NUMBER\n#              | NAME\n#              | PLUS factor\n#              | MINUS factor\n#              | LPAREN expression RPAREN\n#\n# -----------------------------------------------------------------------------\n\nfrom ply.lex import lex\nfrom ply.yacc import yacc\n\n# --- Tokenizer\n\n# All tokens must be named in advance.\ntokens = ( 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'LPAREN', 'RPAREN',\n           'NAME', 'NUMBER' )\n\n# Ignored characters\nt_ignore = ' \\t'\n\n# Token matching rules are written as regexs\nt_PLUS = r'\\+'\nt_MINUS = r'-'\nt_TIMES = r'\\*'\nt_DIVIDE = r'/'\nt_LPAREN = r'\\('\nt_RPAREN = r'\\)'\nt_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'\n\n# A function can be used if there is an associated action.\n# Write the matching regex in the docstring.\ndef t_NUMBER(t):\n    r'\\d+'\n    t.value = int(t.value)\n    return t\n\n# Ignored token with an action associated with it\ndef t_ignore_newline(t):\n    r'\\n+'\n    t.lexer.lineno += t.value.count('\\n')\n\n# Error handler for illegal characters\ndef t_error(t):\n    print(f'Illegal character {t.value[0]!r}')\n    t.lexer.skip(1)\n\n# Build the lexer object\nlexer = lex()\n    \n# --- Parser\n\n# Write functions for each grammar rule which is\n# specified in the docstring.\ndef p_expression(p):\n    '''\n    expression : term PLUS term\n               | term MINUS term\n    '''\n    # p is a sequence that represents rule contents.\n    #\n    # expression : term PLUS term\n    #   p[0]     : p[1] p[2] p[3]\n    # \n    p[0] = ('binop', p[2], p[1], p[3])\n\ndef p_expression_term(p):\n    '''\n    expression : term\n    '''\n    p[0] = p[1]\n\ndef p_term(p):\n    '''\n    term : factor TIMES factor\n         | factor DIVIDE factor\n    '''\n    p[0] = ('binop', p[2], p[1], p[3])\n\ndef p_term_factor(p):\n    '''\n    term : factor\n    '''\n    p[0] = p[1]\n\ndef p_factor_number(p):\n    '''\n    factor : NUMBER\n    '''\n    p[0] = ('number', p[1])\n\ndef p_factor_name(p):\n    '''\n    factor : NAME\n    '''\n    p[0] = ('name', p[1])\n\ndef p_factor_unary(p):\n    '''\n    factor : PLUS factor\n           | MINUS factor\n    '''\n    p[0] = ('unary', p[1], p[2])\n\ndef p_factor_grouped(p):\n    '''\n    factor : LPAREN expression RPAREN\n    '''\n    p[0] = ('grouped', p[2])\n\ndef p_error(p):\n    print(f'Syntax error at {p.value!r}')\n\n# Build the parser\nparser = yacc()\n\n# Parse an expression\nast = parser.parse('2 * 3 + 4 * (5 - x)')\nprint(ast)\n\n\n## Why Use PLY?\n\nDespite its abandoned status, PLY holds value for several reasons. Its zero-dependency nature and small codebase make it highly portable and easy to integrate without introducing complex dependency chains. For those learning about compiler design and parsing, PLY offers a straightforward, direct implementation of traditional lex/yacc principles, making it an excellent educational tool.\n\nThe author explicitly suggests that users copy PLY into their projects, emphasizing its stability and minimal change over time. This approach gives developers full control over their parsing library. Furthermore, PLY is free software, allowing users to copy and modify it to create more powerful or specialized parsing tools, provided the original copyright notice is retained. For a more modern API and active development, the related [SLY project](https://github.com/dabeaz/sly){:target=\"_blank\" rel=\"noopener noreferrer\"} is recommended.\n\n## Links\n\n*   **GitHub Repository:** [https://github.com/dabeaz/ply](https://github.com/dabeaz/ply){:target=\"_blank\" rel=\"noopener noreferrer\"}\n*   **Author's Website:** [https://www.dabeaz.com](https://www.dabeaz.com){:target=\"_blank\" rel=\"noopener noreferrer\"}\n*   **Related SLY Project:** [https://github.com/dabeaz/sly](https://github.com/dabeaz/sly){:target=\"_blank\" rel=\"noopener noreferrer\"}\n*   **Compiler Course:** [https://www.dabeaz.com/compiler.html](https://www.dabeaz.com/compiler.html){:target=\"_blank\" rel=\"noopener noreferrer\"}\n*   **Historical Releases:** [https://github.com/dabeaz/archive/tree/main/ply](https://github.com/dabeaz/archive/tree/main/ply){:target=\"_blank\" rel=\"noopener noreferrer\"}\n*   **Test Suite (Download):** [https://github.com/dabeaz/ply/raw/master/ply-tests.tar.gz](https://github.com/dabeaz/ply/raw/master/ply-tests.tar.gz){:target=\"_blank\" rel=\"noopener noreferrer\"}","metrics":{"detailViews":0,"githubClicks":0},"dates":{"published":null,"modified":"2026-07-30T19:19:41.000Z"}}