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

question-closed Parser arytmetyczny

VPS Starter Arubacloud
0 głosów
197 wizyt
pytanie zadane 17 lipca 2019 w Python przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 17 lipca 2019 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 2019 przez DeBos123 Nałogowiec (44,950 p.)
wybrane 17 lipca 2019 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 2019 przez Jakub 0 Pasjonat (23,120 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 2019 przez DeBos123 Nałogowiec (44,950 p.)
Mógłbyś wrzucić to do repozytorium i dać link?
komentarz 17 lipca 2019 przez Jakub 0 Pasjonat (23,120 p.)
komentarz 17 lipca 2019 przez Jakub 0 Pasjonat (23,120 p.)
tak może być? Bo pierwszy raz wrzucałem coś na GitHub używając PyCharm
1
komentarz 17 lipca 2019 przez DeBos123 Nałogowiec (44,950 p.)
Tak może być. Napiszę jeżeli znajdę co jest przyczyną lub jakiś inny sposób na naprawienie tego.
komentarz 17 lipca 2019 przez Jakub 0 Pasjonat (23,120 p.)
dzięki wielkie, bo ja wymiękam ;)
1
komentarz 17 lipca 2019 przez DeBos123 Nałogowiec (44,950 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 2019 przez Jakub 0 Pasjonat (23,120 p.)
Faktycznie... dzięki :)

Podobne pytania

0 głosów
1 odpowiedź 196 wizyt
pytanie zadane 29 września 2018 w Python przez Piotr Jasiński Bywalec (2,120 p.)
0 głosów
2 odpowiedzi 304 wizyt
pytanie zadane 15 marca 2020 w PHP przez szaman219 Nowicjusz (140 p.)
0 głosów
1 odpowiedź 112 wizyt
pytanie zadane 7 czerwca 2018 w C# przez Oskar Szkurłat Bywalec (2,780 p.)

92,454 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...