Parsimonious

0.11.0 · active · verified Thu Apr 09

Parsimonious is a pure-Python library for creating parsers based on Parsing Expression Grammars (PEGs). It aims for speed and usability, allowing users to define grammars using a simplified EBNF notation. It is designed for applications requiring efficient parsing of structured text, such as configuration files or domain-specific languages. The current version is 0.11.0.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to define a simple arithmetic grammar, parse an input string, and then process the resulting parse tree using a `NodeVisitor` to evaluate the expression. This pattern of grammar definition followed by a visitor for tree manipulation is central to using Parsimonious effectively.

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor

# 1. Define your grammar
grammar = Grammar(
    """
    expression = term (("+" / "-") term)*
    term       = factor (("*" / "/") factor)*
    factor     = "(" expression ")" / number
    number     = ~"[0-9]+"
    """
)

# 2. Parse an input string
input_string = "(10 + 20) * 3"
try:
    tree = grammar.parse(input_string)
    print(f"Successfully parsed: {input_string}")
    # print(tree.prettily())

    # 3. (Optional) Process the parse tree using a NodeVisitor
    class CalculatorVisitor(NodeVisitor):
        def visit_number(self, node, visited_children):
            return int(node.text)

        def visit_factor(self, node, visited_children):
            if len(visited_children) == 3: # ( expression )
                _, expr, _ = visited_children
                return expr
            return visited_children[0] # number

        def visit_term(self, node, visited_children):
            result = visited_children[0]
            for i in range(1, len(visited_children), 2):
                op = visited_children[i][0].text # Access the operator node's text
                num = visited_children[i+1]
                if op == '*':
                    result *= num
                elif op == '/':
                    result /= num
            return result

        def visit_expression(self, node, visited_children):
            result = visited_children[0]
            for i in range(1, len(visited_children), 2):
                op = visited_children[i][0].text # Access the operator node's text
                num = visited_children[i+1]
                if op == '+':
                    result += num
                elif op == '-':
                    result -= num
            return result

        def generic_visit(self, node, visited_children):
            return visited_children or node

    calculator = CalculatorVisitor()
    result = calculator.visit(tree)
    print(f"Result: {result}")

except Exception as e:
    print(f"Error parsing: {e}")

view raw JSON →