Найти - Пользователи
Полная версия: парсер Страуструпа
Начало » Python для новичков » парсер Страуструпа
1 2
py.user.next
odnochlen
Ну и c in ‘0123456789’ стоило бы заменить на c in set('0123456789').
в смысле O(n) на O(1) ?
baslie
Не могу не похвастаться, что все заработало как надо. Еще интерфейс на Qt запилю, и тогда вообще будет сказка Спасибо вам огромное, дорогой py.user.next!
#! /usr/bin/env python
# ------loads from MATH module, you can change this list------
FUNCTIONS = ['sin', 'cos', 'tan', 'sqrt', 'log']
# ------------------------------------------------------------
#    Expression:
#        Term
#        Expression + Term
#        Expression - Term
#    Term:
#        Primary
#        Term * Primary
#        Term / Primary
#        Term % Primary
#    Primary:
#        Number
#        ( Expression )
#        function ( Expression )
#        - Primary
#        + Primary
#    Number:
#        floating-point-literal
class Buffer(list):
    def get(self):
        if self:
            return self.pop(0)
    def putback(self, val):
        self.insert(0, val)
def expression(buf):
    left = term(buf)
    t = buf.get()
    while True:
        if t == '+':
            left += term(buf)
            t = buf.get()
        elif t == '-':
            left -= term(buf)
            t = buf.get()
        else:
            buf.putback(t)
            return left
def term(buf):
    left = primary(buf)
    t = buf.get()
    while True:
        if t == '*':
            left *= primary(buf)
            t = buf.get()
        elif t == '/':
            d = primary(buf)
            if d == 0.:
                raise ValueError('divide by zero')
            left /= d
            t = buf.get()
        elif t == '%':
            d = primary(buf)
            if d == 0.:
                raise ValueError('divide by zero')
            left %= d
            t = buf.get()
        else:
            buf.putback(t)
            return left
import math
def primary(buf):
    t = buf.get()
    if isint(t):
        return int(t)
    elif isfloat(t):
        return float(t)
    elif t == '-':
        return - primary(buf)
    elif t == '+':
        return primary(buf)
    elif t == '(':
        d = expression(buf)
        t = buf.get()
        if t != ')':
            raise ValueError("')' expected")
        return d
    elif t in FUNCTIONS:
        return getattr(math, str(t))(primary(buf))
    else:
        raise ValueError('primary expected')
def isint(string):
    try:
        int(string)
        return True
    except ValueError:
        return False
def isfloat(string):
    try:
        float(string)
        return True
    except ValueError:
        return False
NUMBERS = '0123456789' 
PERIOD = '.'
SYMBOLS = '()+-*/%'
NUMBERS_WITH_PERIOD = PERIOD + NUMBERS
FUNCTIONS_str = ''.join(FUNCTIONS)
def p(s):
    res = []
    s = ''.join(s.split())
    state = 'normal'
    slen = len(s)
    eword = ''
    i = 0
    while i < slen:
        c = s[i]
        if state == 'normal':
            if c in NUMBERS_WITH_PERIOD:
                state = 'number'
                num = ''
                was_period = False
            elif c in SYMBOLS:
                state = 'symbol'
            elif c in FUNCTIONS_str:
                state = 'function'
                func = ''
            else:
                state = 'error'
            i -= 1
        elif state == 'number':
            if c in NUMBERS:
                num += c
            elif c == PERIOD:
                if was_period:
                    eword = c
                    state = 'error'
                    i -= 1
                else:
                    num += c
                    was_period = True
            if c not in NUMBERS_WITH_PERIOD:
                res.append(num)
                num = ''
                state = 'normal'
                i -= 1
            if i + 1 == slen:
                res.append(num)
        elif state == 'symbol':
            if c in SYMBOLS:
                res.append(c)
            else:
                state = 'normal'
                i -= 1
        elif state == 'function':
            if c in FUNCTIONS_str:
                func += c
            if c not in FUNCTIONS_str:
                if func in FUNCTIONS:
                    res.append(func)
                    state = 'normal'
                else:
                    eword = func
                    state = 'error'
                i -= 1
            if i + 1 == slen:
                if func in FUNCTIONS:
                    res.append(func)
                else:
                    eword = func
                    state = 'error'
                    i -= 1
        elif state == 'error':
            raise ValueError("wrong word '{}'".format(eword))
        i += 1
    return res
def calc(expr):
    return expression(Buffer(p(expr)))
if __name__ == "__main__":
    from time import time
    from math import *
    exprs = ['(3+2+1+9/2-98*5+7%2)-2+4/2+(((321)-43)-1)/2.',
             '-2-1',
             '(+2-1)/.100',
             '.311-2/4.5',
             '10%3',
             'sqrt(12)',
             'sqrt(4)-1+cos(33)',
             'log(20)']
    for e in exprs:
        t1 = time()
        e1 = eval(e)
        t1 -= time()
        t2 = time()
        e2 = calc(e)
        t2 -= time()
        print "eval({0}):\t{1}\t{2:10f}\ncalc({0}):\t{3}\t{4:10f}\n".format(e, e1, t1, e2, t2)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB