2024-04-25 16:47:45 +00:00
|
|
|
from fol.node import Node
|
2024-04-24 12:40:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Parser:
|
|
|
|
def __init__(self, lexer):
|
|
|
|
self.lexer = lexer
|
|
|
|
|
|
|
|
def consume(self, name):
|
|
|
|
tok = self.lexer.peek()
|
|
|
|
|
|
|
|
if tok and tok.is_a(name):
|
|
|
|
self.lexer.next()
|
|
|
|
return tok
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
def ensure(self, name):
|
|
|
|
tok = self.consume(name)
|
|
|
|
|
|
|
|
if tok is None:
|
|
|
|
raise Exception(f'invalid {name}')
|
|
|
|
|
|
|
|
if tok and not tok.is_a(name):
|
|
|
|
raise Exception(f'expected {name}, got {tok.name}')
|
|
|
|
|
|
|
|
return tok
|
|
|
|
|
|
|
|
def parse(self):
|
|
|
|
return self.parse_f()
|
|
|
|
|
|
|
|
def parse_f(self):
|
|
|
|
return self.parse_exists()
|
|
|
|
|
|
|
|
def parse_exists(self):
|
|
|
|
if self.consume('EXISTS'):
|
|
|
|
tok_var = self.ensure('VAR')
|
|
|
|
rhs = self.parse_forall()
|
|
|
|
node = Node('EXISTS')
|
|
|
|
node.add_child(Node('VAR', tok_var.value))
|
|
|
|
node.add_child(rhs)
|
|
|
|
return node
|
|
|
|
|
|
|
|
return self.parse_forall()
|
|
|
|
|
|
|
|
def parse_forall(self):
|
|
|
|
if self.consume('FORALL'):
|
|
|
|
tok_var = self.ensure('VAR')
|
|
|
|
rhs = self.parse_imp()
|
|
|
|
node = Node('FORALL')
|
|
|
|
node.add_child(Node('VAR', tok_var.value))
|
|
|
|
node.add_child(rhs)
|
|
|
|
return node
|
|
|
|
|
|
|
|
return self.parse_imp()
|
|
|
|
|
|
|
|
def parse_imp(self):
|
|
|
|
lhs = self.parse_or()
|
|
|
|
|
|
|
|
if self.consume('IMP'):
|
|
|
|
rhs = self.parse_or()
|
|
|
|
node = Node('IMP')
|
|
|
|
node.add_child(lhs)
|
|
|
|
node.add_child(rhs)
|
|
|
|
lhs = node
|
|
|
|
|
|
|
|
return lhs
|
|
|
|
|
|
|
|
def parse_or(self):
|
|
|
|
lhs = self.parse_and()
|
|
|
|
|
|
|
|
while self.consume('OR'):
|
|
|
|
rhs = self.parse_and()
|
|
|
|
node = Node('OR')
|
|
|
|
node.add_child(lhs)
|
|
|
|
node.add_child(rhs)
|
|
|
|
lhs = node
|
|
|
|
|
|
|
|
return lhs
|
|
|
|
|
|
|
|
def parse_and(self):
|
|
|
|
lhs = self.parse_not()
|
|
|
|
|
|
|
|
while self.consume('AND'):
|
|
|
|
rhs = self.parse_not()
|
|
|
|
node = Node('AND')
|
|
|
|
node.add_child(lhs)
|
|
|
|
node.add_child(rhs)
|
|
|
|
lhs = node
|
|
|
|
|
|
|
|
return lhs
|
|
|
|
|
|
|
|
def parse_not(self):
|
|
|
|
if self.consume('NOT'):
|
|
|
|
node = Node('NOT')
|
2024-04-25 16:47:45 +00:00
|
|
|
node.add_child(self.parse_group())
|
2024-04-24 12:40:43 +00:00
|
|
|
return node
|
|
|
|
|
|
|
|
return self.parse_group()
|
|
|
|
|
|
|
|
def parse_group(self):
|
|
|
|
if self.consume('OPAR'):
|
|
|
|
node = self.parse_f()
|
|
|
|
self.ensure('CPAR')
|
|
|
|
return node
|
|
|
|
return self.parse_pred()
|
|
|
|
|
|
|
|
def parse_pred(self):
|
|
|
|
tok = self.ensure('PRED')
|
|
|
|
self.ensure('OPAR')
|
|
|
|
|
|
|
|
node = Node('PRED', tok.value)
|
|
|
|
node.add_child(self.parse_term())
|
|
|
|
|
|
|
|
while self.consume('COMMA'):
|
|
|
|
node.add_child(self.parse_term())
|
|
|
|
|
|
|
|
self.ensure('CPAR')
|
|
|
|
return node
|
|
|
|
|
|
|
|
def parse_term(self):
|
|
|
|
maybe_var = self.lexer.peek(0)
|
|
|
|
maybe_opar = self.lexer.peek(1)
|
|
|
|
|
|
|
|
if maybe_var and maybe_opar and maybe_var.is_a('VAR') \
|
|
|
|
and maybe_opar.is_a('OPAR'):
|
|
|
|
return self.parse_function()
|
|
|
|
|
|
|
|
tok = self.lexer.next()
|
|
|
|
if tok is None:
|
|
|
|
raise Exception('unexpected end')
|
|
|
|
|
|
|
|
if tok.name in ['VAR', 'CONST']:
|
|
|
|
return Node(tok.name, tok.value)
|
|
|
|
|
|
|
|
raise Exception(f'unknown term {tok.value}')
|
|
|
|
|
|
|
|
def parse_function(self):
|
|
|
|
tok = self.ensure('VAR')
|
|
|
|
self.ensure('OPAR')
|
|
|
|
|
|
|
|
node = Node('FUN', tok.value)
|
|
|
|
node.add_child(self.parse_term())
|
|
|
|
|
|
|
|
while self.consume('COMMA'):
|
|
|
|
node.add_child(self.parse_term())
|
|
|
|
|
|
|
|
self.ensure('CPAR')
|
|
|
|
return node
|