• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Parser arytmetyczny

0 głosów
90 wizyt
pytanie zadane 17 lipca w Python, Django przez Jakub 0 Stary wyjadacz (13,240 p.)
zamknięte 17 lipca przez Jakub 0

Witam, niedawno zacząłem się uczyć pythona ( znam już C++ ). po raz pierwszy zabrałem się na jakiś prosty projekt w tym języku, jest nim Parser arytmetyczny, oto kod jaki napisałem:

drzewo wyrażeń ( działa ok ):

import Parser.exceptions as err


class Expression:
    def eval(self, memory):
        raise NotImplementedError


class Constant(Expression):
    def __init__(self, value):
        self.value = value

    def eval(self, memory):
        return self.value


class Variable(Expression):
    def __init__(self, name):
        self.name = name

    def eval(self, memory):
        if self.name in memory:
            return memory[self.name]
        else:
            raise err.BadASTVariableReferError(self.name)


class BinaryOperator(Expression):
    def __init__(self, operator, left_exp, right_exp):
        self.operator = operator
        self.left_exp = left_exp
        self.right_exp = right_exp

    def eval(self, memory):
        if self.operator == '+':
            return self.left_exp.eval(memory) + self.right_exp.eval(memory)
        elif self.operator == '-':
            return self.left_exp.eval(memory) - self.right_exp.eval(memory)
        elif self.operator == '*':
            return self.left_exp.eval(memory) * self.right_exp.eval(memory)
        elif self.operator == '/':
            return self.left_exp.eval(memory) / self.right_exp.eval(memory)
        elif self.operator == '%':
            return self.left_exp.eval(memory) % self.right_exp.eval(memory)
        elif self.operator == '^':
            return self.left_exp.eval(memory) ** self.right_exp.eval(memory)
        else:
            raise err.BadASTOperatorError(self.operator)

parser budujący drzewo wyrażeń ( mnóstwo problemów ):

import Parser.exceptions as err
import Parser.AST as stree


class Parser:
    def __init__(self, input_data):
        self.input_data = input_data
        self.input_data += '$'
        self.position = 0

    def skip_whitespace(self):
        while self.input_data[self.position].isspace():
            self.position += 1

    def look_ahead(self):
        self.skip_whitespace()
        return self.input_data[self.position]

    def parse_expression(self):
        e = self.parse_sum()
        if self.look_ahead() == '$':
            return e
        else:
            raise err.NotParsed()

    def parse_sum(self):
        e = self.parse_mult()
        c = self.look_ahead()
        while c == '+' or c == '-':
            self.position += 1
            e = stree.BinaryOperator(c, e, self.parse_mult())
        return e

    def parse_mult(self):
        e = self.parse_term()
        c = self.look_ahead()
        while c == '*' or c == '/' or c == '%' or c == '^':
            self.position += 1
            e = stree.BinaryOperator(c, e, self.parse_term())
            c = self.look_ahead()
        return e

    def parse_term(self):
        c = self.look_ahead()
        if c.isdigit():
            return self.parse_constant()
        elif c.isalpha():
            return self.parse_variable()
        elif c == '(':
            return self.parse_paren()
        else:
            raise err.NotParsed()

    def parse_constant(self):
        s = str()
        while self.input_data[self.position].isdigit() or self.input_data[self.position] == '.':
            s += self.input_data[self.position]
            self.position += 1
        try:
            v = float(s)
            return stree.Constant(v)
        except ValueError:
            raise err.NotParsed()

    def parse_variable(self):
        s = str()
        while self.input_data[self.position].isalpha():
            s += self.input_data[self.position]
            self.position += 1
        return stree.Variable(s)

    def parse_paren(self):
        self.position += 1
        e = self.parse_sum()
        if self.look_ahead() == ')':
            self.position += 1
            return e
        else:
            raise err.NotParsed()



oraz plik main.py:


import Parser.parser as prs

var = {
    'PI': 3.14
}

# input_data = str(input("Your expression: "))
parser = prs.Parser('10+10')
expression = parser.parse_expression()
# print(expression.eval(var))

Nie dałem tu wszystkich plików ( brakuje pliku z klasami wyjątków ) bo nie wiem czy jest sens dawać dały kod. Jeśli ktoś jednak chce uruchomić ten program to mogę zrobić repozytorium i dać linka...

oto lista błędów:

Traceback (most recent call last):
  File "C:/Users/komputer/first/main.py", line 10, in <module>
    expression = parser.parse_expression()
  File "C:\Users\komputer\first\Parser\parser.py", line 20, in parse_expression
    e = self.parse_sum()
  File "C:\Users\komputer\first\Parser\parser.py", line 31, in parse_sum
    e = stree.BinaryOperator(c, e, self.parse_mult())
  File "C:\Users\komputer\first\Parser\parser.py", line 35, in parse_mult
    e = self.parse_term()
  File "C:\Users\komputer\first\Parser\parser.py", line 44, in parse_term
    c = self.look_ahead()
  File "C:\Users\komputer\first\Parser\parser.py", line 16, in look_ahead
    self.skip_whitespace()
  File "C:\Users\komputer\first\Parser\parser.py", line 12, in skip_whitespace
    while self.input_data[self.position].isspace():
IndexError: string index out of range

mówiąc szczerze to nie wiem zupełnie o co w tych błędach chodzi poza ostatnim. Starałem się szukać informacji ale dalej nie wiem co zrobiłem źle...

bardzo dziękuje za pomoc i pozdrawiam :)

komentarz zamknięcia: problem rozwiązany

1 odpowiedź

+1 głos
odpowiedź 17 lipca przez DeBos123 Nałogowiec (35,670 p.)
wybrane 17 lipca przez Jakub 0
 
Najlepsza

Problem jest w tym, że w funkcji Parser.skip_whitespace zawsze wychodzisz poza tablicę. Dodaj:

self.position<len(input_data)

na początku warunku.

Moim zdaniem powinieneś usuwać wszystkie białe znaki na samym początku jeżeli i tak je pomijasz.

Twój błąd polega na tym samym co w tym kodzie:

a=' '
p=0
while a[p].isspace():
    p+=1
print p
  1. p=0
    sprawdzane jest w warunku czy a[0].isspace().
  2. p=1
    sprawdzane jest w warunku czy a[1].isspace(), czyli wyszedłeś poza zmienną.

Jeżeli dodałbyś:

p<len(a)

to wtedy pętla wykona się tylko raz, bo 0<1, ale 1<1 już nie. 

komentarz 17 lipca przez Jakub 0 Stary wyjadacz (13,240 p.)

Problem jest w tym, że w funkcji Parser.skip_whitespace zawsze wychodzisz poza tablicę

(...)

wój błąd polega na tym samym co w tym kodzie

(...)

Mogło by się to wydawać logiczne, tyle że ja dodałem na koniec wyrażenia tzw. "znak strażnik":

self.input_data += '$'

dla niego metoda isspace() da oczywiście wartość False, więc pętla while zostanie zerwana i dalsze sprawdzanie się nie odbędzie ( wyjście poza tablice nie powinno nastąpić ). Właśnie tego nie rozumiem...

komentarz 17 lipca przez DeBos123 Nałogowiec (35,670 p.)
Mógłbyś wrzucić to do repozytorium i dać link?
komentarz 17 lipca przez Jakub 0 Stary wyjadacz (13,240 p.)
komentarz 17 lipca przez Jakub 0 Stary wyjadacz (13,240 p.)
tak może być? Bo pierwszy raz wrzucałem coś na GitHub używając PyCharm
1
komentarz 17 lipca przez DeBos123 Nałogowiec (35,670 p.)
Tak może być. Napiszę jeżeli znajdę co jest przyczyną lub jakiś inny sposób na naprawienie tego.
komentarz 17 lipca przez Jakub 0 Stary wyjadacz (13,240 p.)
dzięki wielkie, bo ja wymiękam ;)
1
komentarz 17 lipca przez DeBos123 Nałogowiec (35,670 p.)

Przejrzałem twój kod i w skrócie:

  1. Wywołujesz funkcję Parser.parse_expression.
  2. Wywołujesz funkcję Parser.parse_sum.
  3. Ustawiasz zmienną c na +.
  4. Wykonujesz pętlę dopóki c jest równe + lub -.
  5. W pętli nie zmieniasz zmiennej c, więc pętla jest nieskończona i niezależnie od następnego znaku, zwiększasz pozycję, aż do 6, co wskazuje na jeden znak po $.
  6. Wykonujesz funkcję parse_mult, ona wykonuje look_ahead, które wykonuje skip_whitespace.
  7. skip_whitespace sprawdzasz czy znak pod 6 index'em jest białym znakiem, a string kończy się na index'ie 5, dlatego dostajesz błąd. 
komentarz 17 lipca przez Jakub 0 Stary wyjadacz (13,240 p.)
Faktycznie... dzięki :)

Podobne pytania

0 głosów
1 odpowiedź 64 wizyt
pytanie zadane 29 września 2018 w Python, Django przez Piotr Jasiński Bywalec (2,120 p.)
0 głosów
1 odpowiedź 45 wizyt
pytanie zadane 7 czerwca 2018 w C# i .NET przez Oskar Szkurłat Obywatel (1,170 p.)
0 głosów
1 odpowiedź 82 wizyt
pytanie zadane 24 marca 2018 w PHP, Symfony, Zend przez Kamil Jarzyna Użytkownik (940 p.)
Porady nie od parady
Odznacz odpowiedź zieloną fajką, jeśli uważasz, że jest ona najlepsza ze wszystkich i umożliwiła ci rozwiązanie problemu.Najlepsza odpowiedź

66,451 zapytań

113,207 odpowiedzi

239,680 komentarzy

46,704 pasjonatów

Przeglądających: 272
Pasjonatów: 11 Gości: 261

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...