# Python Pyparsing Module

The `pyparsing` module provides an alternative approach to creating and executing simple grammars, versus the traditional lex/yacc approach, or the use of regular expressions. It handles recursive grammars and complex parsing logic more elegantly than regex.

## Installation

```bash
pip install pyparsing
```

## Basic Usage

You define a grammar using Python objects, then use that grammar to parse strings.

```python
from pyparsing import Word, alphas

# Define grammar: a word composed of alphabetical characters
greet = Word(alphas) + "," + Word(alphas) + "!"

# Parse a string
hello = "Hello, World!"
print(greet.parseString(hello))
# Output: ['Hello', ',', 'World', '!']
```

## Common Elements

*   `Word`: Matches a word composed of specific characters.
*   `Literal`: Matches a specific string literal.
*   `OneOrMore`: Matches one or more occurrences.
*   `ZeroOrMore`: Matches zero or more occurrences.
*   `Optional`: Matches an optional element.
*   `Suppress`: Matches an element but suppresses it from the output.

```python
from pyparsing import Word, nums, Suppress

# Parse an IP address (e.g., 192.168.0.1)
octet = Word(nums)
dot = Suppress('.')
ip_addr = octet + dot + octet + dot + octet + dot + octet

print(ip_addr.parseString("192.168.0.1"))
# Output: ['192', '168', '0', '1'] (dots are suppressed)
```

## Parse Actions

You can attach functions to be called when a grammar element is matched. This is useful for type conversion.

```python
from pyparsing import Word, nums

def convert_to_int(tokens):
    return int(tokens[0])

integer = Word(nums).setParseAction(convert_to_int)
result = integer.parseString("123")
print(result[0]) # Output: 123 (as integer)
print(type(result[0])) # <class 'int'>
```

## Complex Grammars (Arithmetic)

Pyparsing handles operator precedence easily using `infixNotation`.

```python
from pyparsing import Word, nums, infixNotation, opAssoc

integer = Word(nums).setParseAction(lambda t: int(t[0]))
operand = integer

expr = infixNotation(operand, [
    ('*', 2, opAssoc.LEFT),
    ('/', 2, opAssoc.LEFT),
    ('+', 2, opAssoc.LEFT),
    ('-', 2, opAssoc.LEFT),
])

print(expr.parseString("2 + 3 * 4"))
# Output: [[2, '+', [3, '*', 4]]]
```

[[programming/python/python]]