Skip to content

Commit

Permalink
Fix: Fix alot of errors and bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
mahdidehghandev committed Dec 9, 2024
1 parent af7bc7a commit 9ee28e9
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 149 deletions.
155 changes: 69 additions & 86 deletions evaluate.py
Original file line number Diff line number Diff line change
@@ -1,179 +1,162 @@
import math

class Evaluate:

def __init__(self, postfix_expr,symbol_table):
class Evaluate:
def __init__(self, postfix_expr, symbol_table):
self.postfix_expr = postfix_expr
self.identifier_vals = {}
self.symbol_table = symbol_table

# @staticmethod
# def _reserved_ids():
# return ['div', 'mod', 'sin', 'cos', 'tan', 'cot', 'arcsin', 'arccos',
# 'arctan', 'arccot', 'log', 'sqrt', 'sqr', 'exp']


@staticmethod
def convert_to_num(entry):
try:
if entry in ["e","E"]:#! add another method
return 2.71
num = float(entry)
return int(num) if num.is_integer() else num
except ValueError:
raise Exception("ERROR: Invalid number format")

# @staticmethod
# def is_single_op(element):
# ops = ['sin', 'cos', 'tan', 'cot', 'arcsin', 'arccos',
# 'arctan', 'arccot', 'log', 'sqrt', 'sqr', 'exp', 'unary-']
# return element in ops

# @staticmethod
# def is_binary_op(element):
# ops = ['+', '-', 'mod', 'div', '*', '/', '^']
# return element in ops



@staticmethod
def _apply_binary_op(op, a, b):

if op == '+':
if op == "+":
return a + b
elif op == '-':
elif op == "-":
return a - b
elif op == '*':
elif op == "*":
return a * b
elif op == '/':
elif op == "/":
return a / b
elif op == '^':
return a ** b
elif op == 'mod':
if isinstance(b, float): #! check if there is a float number after the mod
elif op == "^":
return a**b
elif op == "mod":
if isinstance(b, float): #! check if there is a float number after the mod
raise Exception("Syntax error: 'mod' requires an integer operand")

return a % b
elif op == 'div':
elif op == "div":
return a // b
else:
raise Exception(f"Unknown binary operator: {op}")




@staticmethod
def _apply_single_op(op, a):
if op == 'unary-':
if op == "unary-":
return -a
elif op == 'sin':
elif op == "sin":
return math.sin(a)
elif op == 'cos':
elif op == "cos":
return math.cos(a)
elif op == 'tan':
elif op == "tan":
return math.tan(a)
elif op == 'cot':
elif op == "cot":
return 1 / math.tan(a)
elif op == 'arcsin':
elif op == "arcsin":
if -1 <= a <= 1:
return math.asin(a)
raise Exception("arcsin domain error")
elif op == 'arccos':
elif op == "arccos":
if -1 <= a <= 1:
return math.acos(a)
raise Exception("arccos domain error")
elif op == 'arctan':
elif op == "arctan":
return math.atan(a)
elif op == 'arccot':
elif op == "arccot":
return 1 / math.atan(a)
elif op == 'log':
elif op == "log":
if a > 0:
return math.log(a)
raise Exception("log domain error")
elif op == 'sqrt':
elif op == "sqrt":
if a >= 0:
return math.sqrt(a)
raise Exception("sqrt domain error")
elif op == 'sqr':
return a ** 2
elif op == 'exp':
elif op == "sqr":
return a**2
elif op == "exp":
return math.exp(a)
else:
raise Exception(f"Unknown unary operator: {op}")


def get_values(self):
for token in self.postfix_expr:
if token.type == "ID" and not self.symbol_table.is_reserved(token.value.lower()):
token_lower = token.value.lower()

if token_lower not in self.symbol_table.table and token_lower != 'e':
value = input(f"Enter the value for '{token.value}': ")
result = self.convert_to_num(value)
self.symbol_table.table[token_lower] = {"type" : "IDENTIFIER" , "value" :result , "is_reserved" : None}
elif token_lower == 'e':
value = 2.71
result = self.convert_to_num(value)
self.symbol_table.table[token_lower] = {"type" : "IDENTIFIER" , "value" :result, "is_reserved" : None}#! use another method

print(token)
if (token.type == "ID") and (
self.symbol_table.table[token.value.lower()]["type"] == "IDENTIFIER"
and self.symbol_table.table[token.value.lower()]["value"] is None
):
value = input(f"Enter the value for '{token.value}': ")
result = self.convert_to_num(value)
self.symbol_table.table[token.value.lower()]["value"] = result



def put_values(self, value):
for token in self.postfix_expr:
if token.type == "ID" and not self.symbol_table.is_reserved(token.value):#!why don't use token.value.lower()
token_lower = token.value.lower()
if (token.type == "ID") and not self.symbol_table.is_not_reserved(token.value.lower()) and not self.symbol_table.is_id_existence(token.value.lower()):
self.symbol_table.add_id(token.value.lower())
result = self.convert_to_num(value)
self.symbol_table.table[token.value.lower()]["value"] = result

if token_lower not in self.symbol_table.table and token_lower != 'e':
value = input(f"Enter the value for '{token.value}': ")
result = self.convert_to_num(value)
self.symbol_table.table[token_lower] = {"type" : "IDENTIFIER" , "value" :result, "is_reserved" : None}
elif token_lower == 'e':
value = 2.71
result = self.convert_to_num(value)
self.symbol_table.table[token_lower] = {"type" : "IDENTIFIER" , "value" :result, "is_reserved" : None}#! use another method


def is_number(self, entry):
entry = self.convert_to_num(entry)
if isinstance(entry, int):
return True

elif isinstance(entry, float):
return True

else:
return False
return False


def evaluate_expression(self):
operand_stack = []

for element in self.postfix_expr:
if element.type == "ID" and not self.symbol_table.is_reserved(element.value.lower()):
operand_stack.append(self.symbol_table.table[element.value.lower()]["value"])
if element.type == "ID" and self.symbol_table.is_id_existence:
operand_stack.append(
self.symbol_table.table[element.value.lower()]["value"]
)
elif self.symbol_table.is_binary_op(element.value.lower()):
if len(operand_stack) < 2:
raise Exception("Insufficient operands for binary operation.")
top_element = operand_stack.pop()
bottom_element = operand_stack.pop()
operand_stack.append(self._apply_binary_op(element.value.lower(), bottom_element, top_element))

operand_stack.append(
self._apply_binary_op(
element.value.lower(), bottom_element, top_element
)
)

elif self.symbol_table.is_single_op(element.value.lower()):
if len(operand_stack) < 1:
raise Exception("Insufficient operands for binary operation.")
top_element = operand_stack.pop()
operand_stack.append(self._apply_single_op(element.value.lower(), top_element))

operand_stack.append(
self._apply_single_op(element.value.lower(), top_element)
)

elif self.is_number(element.value):
operand_stack.append(self.convert_to_num(element.value))

else:
raise Exception(f"Invalid element: {element.value}")
if len(operand_stack) != 1:
raise Exception("Invalid postfix expression. Stack contains:", operand_stack)
raise Exception(
"Invalid postfix expression. Stack contains:", operand_stack
)
return operand_stack.pop()

def evaluate(self):
self.get_values()
return self.evaluate_expression()

def evaluate_with_value(self, value):
self.put_values(value)
return self.evaluate_expression()
return self.evaluate_expression()
88 changes: 38 additions & 50 deletions lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ def __init__(self, symbol_table,text):
self.line = 1
self.beginning = 0
self.forward = 0
# ! delete
# self.operators = ['+', '-', '*', '/', 'div', 'mod', '^', '(', ')']
self.tokens = []


Expand Down Expand Up @@ -193,29 +191,50 @@ def is_identifier(self):
state = 2
case 2:
lexeme = self.text[self.beginning:self.forward].lower()
if self.symbol_table.is_not_reserved(lexeme) and not self.symbol_table.is_id_existence(lexeme):
self.symbol_table.add_id(lexeme)
if self.symbol_table.is_function(lexeme):
# if self.symbol_table.is_not_reserved(lexeme) and not self.symbol_table.is_id_existence(lexeme):
# self.symbol_table.add_id(lexeme)
if self.symbol_table.is_operator(lexeme):
self.create_token("OPERATOR")
self.beginning = self.forward
return
elif self.symbol_table.is_function(lexeme):

# if lexeme in ['sin', 'cos', 'tan', 'cot', 'arcsin', 'arccos', 'arctan', 'arccot', 'log', 'sqrt', 'sqr', 'exp']:
self.create_token("FUNCTION")
self.beginning = self.forward
return
else:
self.create_token("ID")
self.beginning = self.forward
return
if not self.symbol_table.is_id_existence(lexeme) and not self.symbol_table.is_reserved(lexeme):
self.symbol_table.add_id(lexeme)
self.create_token("ID")
self.beginning = self.forward
return
else:
self.create_token("ID")
self.beginning = self.forward
return



if state == 1:
lexeme = self.text[self.beginning:self.forward].lower()
if not self.symbol_table.is_id_existence(lexeme):
self.symbol_table.add_id(lexeme)
if self.symbol_table.is_function(lexeme):
# if lexeme in ['sin', 'cos', 'tan', 'cot', 'arcsin', 'arccos', 'arctan', 'arccot', 'log', 'sqrt', 'sqr', 'exp']:
self.create_token("FUNCTION")
self.beginning = self.forward
else:
self.create_token("ID")
self.beginning = self.forward

lexeme = self.text[self.beginning:self.forward].lower()
if not self.symbol_table.is_id_existence(lexeme):
self.symbol_table.add_id(lexeme)
if self.symbol_table.is_function(lexeme):
self.create_token("FUNCTION")
self.beginning = self.forward
else:
if not self.symbol_table.is_id_existence(lexeme) and not self.symbol_table.is_reserved(lexeme):
self.symbol_table.add_id(lexeme)
self.create_token("ID")

self.beginning = self.forward

else:
self.create_token("ID")
self.beginning = self.forward


else:
self.error()
Expand All @@ -235,37 +254,6 @@ def is_operator(self):
self.error()


# def is_identifier(self):
# state = 0
# while self.forward < len(self.text):
# char = self.text[self.forward]
# match state:
# case 0:
# if char.isalpha() or char == '_':
# state = 1
# self.forward += 1
# case 1:
# if char.isalpha() or char == '_' or char.isdigit():
# state = 1
# self.forward += 1
# else:
# state = 2

# case 2:
# self.create_token("ID")
# self.beginning = self.forward
# return
# if state in {1}:
# self.create_token("ID")
# else:
# self.error()



# def is_operator(self):
# for op in self.operators:
# if self.text[self.forward:self.forward + len(op)] == op:
# self.forward += len(op)
# self.create_token("OPERATOR")
# self.beginning = self.forward
# return
# self.error()
Loading

0 comments on commit 9ee28e9

Please sign in to comment.