Logic-Formulae-Validator-dl.../program.py

216 lines
7.4 KiB
Python
Raw Normal View History

2019-05-25 18:22:08 +02:00
import sys
2019-05-30 19:54:46 +02:00
import subprocess
2019-05-30 20:12:34 +02:00
2019-05-25 18:22:08 +02:00
class AbstractInterpreter:
def __init__(self):
pass
2019-05-31 19:25:20 +02:00
def isValid(self,formula)->bool:
2019-05-25 18:22:08 +02:00
raise NotImplementedError
class SimpleInterpreter(AbstractInterpreter):
def __init__(self):
pass
def isValid(self,formula)->bool:
2019-05-30 19:54:46 +02:00
2019-05-25 18:22:08 +02:00
variables = {}
f=[]
def isBlacklisted(char):
return char in ['\n', '\t', ' ']
def isSign(char):
logic_signs = ['=', '>', '&', '|', '!', '(', ')']
return char in logic_signs
2019-05-30 19:54:46 +02:00
def isParentice(char):
2019-05-30 20:36:52 +02:00
return char in ['(', ')']
2019-05-25 18:22:08 +02:00
def isVariable(char):
return not isSign(char)
def isNegation(char):
return char == '!'
#print(vars(formula))
for i,char in enumerate(formula.s):
if isBlacklisted(char): return False
2019-05-30 19:54:46 +02:00
2019-05-25 18:22:08 +02:00
prev = formula.s[i-1] if i>0 else None #None, gdy jesteśmy na pierwszym znaku
2019-05-30 19:54:46 +02:00
if (char=='(' and isVariable(prev) and prev is not None): #a(b|c)
2019-05-30 20:53:08 +02:00
2019-05-30 19:54:46 +02:00
return False
2019-05-30 20:36:52 +02:00
if (prev is None):
if not (isVariable(char) or isParentice(char) or isNegation(char)):
2019-05-31 19:25:20 +02:00
2019-05-30 20:53:08 +02:00
return False
if isSign(char) and prev is not None:
2019-05-25 18:22:08 +02:00
if (not isNegation(char)):
2019-05-30 20:53:08 +02:00
2019-05-25 18:22:08 +02:00
if isSign(prev) and not isNegation(prev): # tylko negacje mogą się powtarzać po innym znaku
return False
2019-05-30 20:36:52 +02:00
if isNegation(prev):
2019-05-30 20:53:08 +02:00
2019-05-30 20:36:52 +02:00
if not (isNegation(char) or isParentice(char)):
2019-05-30 20:53:08 +02:00
return False
if isNegation(char):
if isVariable(prev): #a!
return False
2019-05-31 19:25:20 +02:00
elif not isSign(char) and prev is not None:
2019-05-25 18:22:08 +02:00
#if current char is a variable
if isVariable(prev) and prev is not None: #Obrona abc>d
print("previous is also a variable");
return False
return True
2019-05-27 12:44:23 +02:00
class RegexInterpreter(AbstractInterpreter):
def __init__(self):
#check if grep is available
import subprocess
2019-05-30 19:54:46 +02:00
# r=subprocess.run("grep")
2019-05-27 12:44:23 +02:00
2019-05-30 19:54:46 +02:00
def isValid(self,f)->bool:
2019-05-27 12:44:23 +02:00
2019-05-30 19:58:02 +02:00
formula = "({0})".format(f.s.replace("!", "\\!"))
2019-05-30 19:54:46 +02:00
2019-05-27 12:44:23 +02:00
make_reg = lambda formula,pattern: 'echo "{0}" | grep -P "{1}"'.format(formula,pattern)
def check_assertion(formula, pattern):
2019-05-30 19:54:46 +02:00
cmd = make_reg(formula,pattern)
2019-05-30 20:11:35 +02:00
#print("EXECUTING... ",cmd)
2019-05-30 19:54:46 +02:00
result = subprocess.run([cmd], shell=True, stdout=subprocess.PIPE)
2019-05-30 20:11:35 +02:00
return not len(result.stdout)>0
2019-05-30 19:54:46 +02:00
cmd =make_reg(formula,'^(\((?:[^()]++|(?1))*\))$')
2019-05-30 20:11:35 +02:00
#print("EXECUTING... ",cmd)
2019-05-30 19:54:46 +02:00
result = subprocess.run([cmd], shell=True, stdout=subprocess.PIPE)
2019-05-30 20:11:35 +02:00
2019-05-27 12:44:23 +02:00
isValid = len(result.stdout)>0
if not isValid: return False
#assertions
assertions = ['(?:[>|&|\|=][\(\)]*){2,}','\((?:[>|&|\|=][\(\)]*)','[a-z]{2,}','\((?:[>|&|\|=|!])?\)']
for assertion in assertions:
if not check_assertion(formula,assertion):
return False
return True
# (?:[>|&|\|=][\(\)]*){2,} - czy powtarzają się jakieś operatory obok siebie?
# echo "formuła" | grep -P "regex" - to jeżeli coś zwróci to znaczy, że mamy dopasowanie
#najpierw sprawdzamy, czy parentices są ok
#^(\((?:[^()]++|(?1))*\))$ - powinno zwrócić cały nasz string
#potem sprawdzamy czy dopasuje cokolwiek co może być nie tak
# \((?:[>|&|\|=][\(\)]*) - (>b)
# [a-z]{2,} - czy powtarzają się jakieś lierki obok siebie?
# \((?:[>|&|\|=|!])?\) - czy istnieją puste nawiasy, bądź nawiasy z samym operatorem?
2019-05-30 19:54:46 +02:00
class ProperInterpreter(AbstractInterpreter):
class Expression:
def __init__(self,operator,left,right):
self.right=right
self.left = left
self.operator = operator
def __init__(self):
pass
def isValid(self,formula)->bool:
try:
self.parse(formula.s)
except Exception as e:
2019-05-31 19:25:20 +02:00
#print(e)
2019-05-30 19:54:46 +02:00
return False
else:
return True
def check_simple_formula(self,simple_formula:str)->bool:
#używamy SimpleInterpretera
n = SimpleInterpreter()
return Formula(simple_formula,n).isValid()
def parse(self,formula:str):
#przypisywanie głębi do każdego znaku
if len(formula)==0:
# print("Empty subformula")
return None
2019-05-30 20:36:52 +02:00
if (formula=='!'): raise Exception("Negacja źle postawiona")
2019-05-30 19:54:46 +02:00
x=[0 for u in formula]
current_depth=0
for i,char in enumerate(formula):
if current_depth<0:
break
if char == '(':
current_depth+=1
x[i] = current_depth
elif char == ')':
x[i] = current_depth
current_depth-=1
else:
x[i] = current_depth
if current_depth!=0:
raise Exception("Nawiasy źle umieszczone w podformule: {0}".format(formula))
2019-05-31 19:25:20 +02:00
#print(formula)
2019-05-30 19:54:46 +02:00
min_depth = min(x)
slice_point = 0
#czy formuła jest prosta?
is_simple = True
for i in x:
if i != x[0]:
is_simple=False;
break
#Szukanie najbardziej znaczącego spójnika
for i,char in enumerate(formula):
if char in ('>', '&', '|', '=') and x[i] == min_depth:
slice_point = i
break
if is_simple:
2019-05-30 20:36:52 +02:00
#print(formula, " is simple")
2019-05-30 19:54:46 +02:00
if not self.check_simple_formula(formula):
raise Exception("Błąd na poziomie formuły bez zagnieżdzeń: {0}".format(formula))
return False
else:
s=0
e=len(formula)
if min_depth>0:
# print("There are useless parentices... Deleting")
s=1
e=-1
# print("Slice point: ", slice_point)
# print("min depth: ", min_depth)
if (s==slice_point):
#print("Nie ma spójnika - formuła jest jednak prosta")
if not self.check_simple_formula(formula):
raise Exception("Błąd na poziomie formuły bez zagnieżdzeń: {0}".format(formula))
return False
self.parse(formula[s:slice_point])
self.parse(formula[slice_point+1:e])
2019-05-25 18:22:08 +02:00
class Formula:
2019-05-30 19:54:46 +02:00
def __init__(self, formula_string:str, interpreter:AbstractInterpreter=None):
2019-05-25 18:22:08 +02:00
self.s = formula_string
self.__i = interpreter
2019-05-30 19:54:46 +02:00
def isValid(self, interpreter=None)->bool:
i = self.__i if interpreter is None else interpreter
return i.isValid(self)
2019-05-30 20:36:52 +02:00
sim = SimpleInterpreter()
2019-05-30 19:54:46 +02:00
if len(sys.argv) > 1 :
i = ProperInterpreter()
if '-g' in sys.argv:
i = RegexInterpreter()
2019-05-30 20:11:35 +02:00
#print(sys.argv)
2019-05-25 18:22:08 +02:00
2019-05-30 19:54:46 +02:00
if '-f' in sys.argv:
#open from file
print("opening from file")
g = open(sys.argv[sys.argv.index('-f')+1], 'r')
u = g.readlines()
for l in u:
2019-05-31 19:25:20 +02:00
print(Formula(l.replace("\n",'').replace("\r",''),i).isValid())
2019-05-30 19:54:46 +02:00
else:
2019-05-30 20:36:52 +02:00
print(
Formula(sys.argv[1] if sys.argv[1] != '-g' else sys.argv[2],i).isValid()
)
2019-05-30 19:54:46 +02:00
else:
print("help?")
2019-05-25 18:22:08 +02:00