Jugando con pyparsing

Sep 16, 2011 No Comments by

Para un proyecto personal, estoy trabajando en un prototipo de pseudo-lenguaje like SQL, como primera instancia, estoy trabajando con pyparsing, para luego continuar en una segunda fase con algo más maduro con Lex y YACC.

Pyparsing, es una librería que permite realizar un parser de forma muy sencilla, cuenta con muchos ejemplos y una documentación decente..

El siguiente trozo de código es sencillo, vamos a tratar de parsear con pyparsing un string que contiene una serie de número naturales y operandos descritos en forma RPN (Notación Polaca Inversa).

La RPN (Notiación Polaca Inversa), no utiliza parentesis, si no, mantiene un orden de ingreso de datos, operando operando operador, ejemplo 4 4 +, que es igual a 8.

Definimos nuestro statement principal rpn_stmt con una grámatica descendente, luego nuestro operandos (enteros), operadores (+ – * /) y una expresión ( operando operando + operador ), finalmente nuestra statement principal (rpn_stmt) es un conjunto de una expresión o más expresiones.

Ahora, falta analizar los tokens que nos va a devolver nuestro parser, para lo cuál he creado una pequeña clase llamada RPNSimpleParser, ella toma cada token y realiza la siguiente tarea.

Mientras el token no sea un operador, agregamos el operando al stack (push, append), si el token es un operador, sacamos dos operandos (pop), realizamos la operación y guardamos el resultado en el stack.

#!/usr/bin/env python
# rpn_simple_parser.py ( is just one simple example)
# @author deerme.org

from pyparsing import *
ParserElement.enablePackrat()

# Language Definition
rpn_stmt = Forward()
expr = Forward().setName("expression")

integer = Regex(r"[+-]?\d+")
operating = ( integer )
operator = oneOf('+ - * /')

expr << (  operating + operating + operator  | operating + operator  )
# Main statement
rpn_stmt << (  expr + ZeroOrMore( expr  )  )

class RPNSimpleParser:
    def __init__(self,parser):
        self._parser = parser

    def execute(self,query):
        print "Query\t" + query
        tokens = self._parser.parseString( query )
        print "Tokens\t" + str( tokens )
        # We analyze the arrays of tokens
        stack = []
        for i in range( 0 , len(tokens) ):

            if ( tokens[i] == "+" or tokens[i] == "-" or tokens[i] == "/" or tokens[i] == "*" ):
                op2 = int(stack.pop())
                op1 = int(stack.pop())
                if ( tokens[i] == "+" ):
                    r = op1 + op2
                if ( tokens[i] == "-" ):
                    r = op1 - op2
                if ( tokens[i] == "/" ):
                    r = op1 / op2
                if ( tokens[i] == "*" ):
                    r = op1 * op2
                stack.append(r)
            else:
                stack.append( tokens[i] )
        if len(stack) > 0 :
            print stack.pop()

rpn = RPNSimpleParser( rpn_stmt )
rpn.execute("10 20 + 3 /")
rpn.execute("15 3 * 5 + 10 / 300 -")
Python

About the author

Ingeniero en Informática, Oracle Certified Master Java EE 6 Enterprise Architect, Oracle Certified Professional Java Programmer. Experto en distintas ramas de la computación y otras "yerbas" xD. Si te gusto este post, sígueme en @deerme_org, escríbeme a info AT deerme.org o contactame por linkedin.
No Responses to “Jugando con pyparsing”

Leave a Reply


nine - 6 =