201 lines
6.9 KiB
Python
201 lines
6.9 KiB
Python
import sys
|
|
import subprocess
|
|
|
|
class AbstractInterpreter:
|
|
def __init__(self):
|
|
pass
|
|
def isValid(self,formula:str)->bool:
|
|
raise NotImplementedError
|
|
class SimpleInterpreter(AbstractInterpreter):
|
|
def __init__(self):
|
|
pass
|
|
def isValid(self,formula)->bool:
|
|
|
|
variables = {}
|
|
f=[]
|
|
def isBlacklisted(char):
|
|
return char in ['\n', '\t', ' ']
|
|
def isSign(char):
|
|
logic_signs = ['=', '>', '&', '|', '!', '(', ')']
|
|
return char in logic_signs
|
|
def isParentice(char):
|
|
return char in ('(', ')')
|
|
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
|
|
|
|
prev = formula.s[i-1] if i>0 else None #None, gdy jesteśmy na pierwszym znaku
|
|
if (char=='(' and isVariable(prev) and prev is not None): #a(b|c)
|
|
return False
|
|
if isSign(char):
|
|
if (not isNegation(char)):
|
|
if isSign(prev) and not isNegation(prev): # tylko negacje mogą się powtarzać po innym znaku
|
|
return False
|
|
else:
|
|
if isVariable(prev) and prev is not None: # obrona przed a!>b
|
|
return False
|
|
else:
|
|
#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
|
|
class RegexInterpreter(AbstractInterpreter):
|
|
def __init__(self):
|
|
#check if grep is available
|
|
import subprocess
|
|
# r=subprocess.run("grep")
|
|
|
|
def isValid(self,f)->bool:
|
|
|
|
formula = "({0})".format(f.s.replace("!", "\\!"))
|
|
|
|
make_reg = lambda formula,pattern: 'echo "{0}" | grep -P "{1}"'.format(formula,pattern)
|
|
def check_assertion(formula, pattern):
|
|
cmd = make_reg(formula,pattern)
|
|
print("EXECUTING... ",cmd)
|
|
result = subprocess.run([cmd], shell=True, stdout=subprocess.PIPE)
|
|
return len(result.stdout)>0
|
|
|
|
cmd =make_reg(formula,'^(\((?:[^()]++|(?1))*\))$')
|
|
print("EXECUTING... ",cmd)
|
|
|
|
result = subprocess.run([cmd], shell=True, stdout=subprocess.PIPE)
|
|
return None
|
|
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?
|
|
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:
|
|
print(e)
|
|
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
|
|
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))
|
|
|
|
#print(formula)
|
|
|
|
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:
|
|
# print(formula, " is simple")
|
|
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])
|
|
class Formula:
|
|
def __init__(self, formula_string:str, interpreter:AbstractInterpreter=None):
|
|
self.s = formula_string
|
|
self.__i = interpreter
|
|
|
|
def isValid(self, interpreter=None)->bool:
|
|
i = self.__i if interpreter is None else interpreter
|
|
return i.isValid(self)
|
|
|
|
if len(sys.argv) > 1 :
|
|
i = ProperInterpreter()
|
|
if '-g' in sys.argv:
|
|
i = RegexInterpreter()
|
|
print(sys.argv)
|
|
|
|
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:
|
|
print(Formula(l,i).isValid())
|
|
else:
|
|
print(Formula( sys.argv[1] if sys.argv[1] != '-g' else sys.argv[2],i).isValid())
|
|
|
|
else:
|
|
print("help?")
|
|
|
|
|