Logic-Formulae-Validator-dl.../readme.md
2019-06-01 19:01:50 +02:00

4.2 KiB

Uzycie

python program.py -f plik.txt, gdzie każda linia to nowa formuła

python program.py a&b>c|(a&!g)

+Opcjonalny przełącznik -g, który przełącza tryb sprawdzania na Regexp

Założenia:

  1. Algorytm sprawdzający poprawność nie musi parsować wyrażenia
  2. Można było po prostu napisać parser - gdy formuła nie będzie poprawna to gdzieś dostaniemy błąd - ciekawiej jest jednak wymyślić coś nowego samemu.

Co to jest poprawna formuła?

Dowolne wyrażenie KRZ, gdzie zmienną jest dowolny znak od a do z A znakiem specjalnym jest znak zawierający się w zbiorze { (, ), &, >, =, | }. Nawiasy muszą być poprawnie zamknięte

Algorytm

W osobnej tablicy o długości równej ilości znaków formuły zapisujemy głębkość (dalej nazywaną depth) danego znaku. Nim bardziej zagnieżdżone jest podwyrażenie, tym większa wartość głębkokości. Tak dla formuły a>b, tablica depth przyjmie wartości 0,0,0, ale dla a|(a&b)>(c|q) będzie to już 0,0,1,1,1,1,1,0,1,1,1,1,1. Widać zatem, że można tak znaleźć zagnieżdżone podformuły.

Algorytm szuka pierwszego znaku z wartością depth równą min(depth), który jest operatorem dwuargumentowym. Formuła jest dzielona na stronę prawą i lewą od operatora i proces jest powtarzany aż do momentu, kiedy nie będzie już żadnych formuł zagnieżdżonych tj. kiedy wszystkie wartości w tablicy depth, będą równe min(depth).

Występują przypadki skrajne, gdzie lewa bądź prawa część jest pusta - wtedy kończy się rekurencja na danej gałęzi.

Gdy spełniony jest wcześniej wspomniany warunek, uruchamiana jest inna procedura, która bada czy nie występują zabronione ciągi. Są one zapisane jak sztywny zbiór reguł. Algorytm iteruje przez każdy znak w formule, pamiętając swojego poprzednika.

Istnieje skończona ilość reguł, które określają formułę jako niepoprawną.

  1. Błędnie postawione nawiasy
  2. Negacja za zmienną bądź przed innym operatorem
  3. Dwa operatory obok siebie
  4. Dwie zmienne obok siebie
  5. Zmienna po lewej stronie nawiasu otwierającego lub po prawej zamykającego
  6. Operator dwuargumentowy bez wyrażeń po obu stronach

Przełącznik -g

Zadaniem było tylko sprawdzenie, czy formuła jest poprawnie zapisana. Jak zostało wcześniej wspomniane istnieje skończona ilość reguł które mówią że formuła jest niepoprawna.

Można więc przeszukiwać formułę w poszukiwaniu niepoprawnych ciągów. Do przeszukiwania tekstu w poszukiwaniu wzorców idealnie nadaje się dowolny silnik wyrażeń regularnych (ten z pythona nie miał opcji przeszukiwania rekursywnego, więc używamy programu grep z przełącznikiem -P żeby przełączyć się na silnik z Perla - jest to potrzebne przy sprawdzaniu, czy nawiasy są poprawnie zamknięte).

Dla każdej z powyższych reguł można sformułować odpowiednie wyrażenie, które znajdując (bądź nie) dopasowanie poinformuje nas czy formuła zawiera jakiś niedozwolony ciąg.

Taki sposób jest o wiele wolniejszy i mniej ciekawy niż poprzedni, ale też działa. Do tego, wyrażenia KRZ nie są regularne, więc używanie narzędzia zupełnie do tego nieprzeznaczonego wydało się nam ciekawe do zaprezentowania.

Opis struktury programu

class Formula reprezentuje formułę. Konstruktor przyjmuje string formula i obiekt interpretera. Interpreter to dowolny obiekt z metodą isValid(f:Formula)->bool.

AbstractInterpreter

Klasa pomocnicza, klasy abstrakcyjne nie istnieją w Pythonie, ale warto zrobić jakąś bazę.

SimpleInterpreter

Klasa definiująca interpreter, który sprawdza, czy formuła bez zagnieżdzeń jest poprawnie zapisana. Opiera się na sztywnym zbiorze reguł

ProperInterpreter

Klasa definiująca interpreter sprawdzający czy złożona formuła jest poprawna. Rozbija rekurencyjnie na mniejsze formuły aż do momentu, kiedy można je sprawdzić przez SimpleInterpreter

RegexInterpreter

Klasa definiująca interpreter, który swoje działanie opiera na wyrażeniach regularnych i programie grep. Działa tylko, gdy ten program jest zainstalowany (czyli głównie na linuksie).

Szuka niepoprawnych ciągów i sprawdza czy nawiasy są prawidłowo pozamykane.