Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 11

Assignment 3

Logic and Comparison Implementation Using Parser


Name: Dilsher Chiyay Salim Group.B

Email: Dilsher.18014064@stud.uoz.edu.krd

➢ University of Zakho.

➢ Faulty of Science.

➢ Computer Science Department.

➢ Third Stage / 5th Semester.

“Computation and Compiler”


“Logic and Comparison Implementation Using Parser”

Date:

Supervisor: Muhsin Atto. 2020/2021


1. Theory for BinOP:

In Lab 2, parser implementation we saw that the way we can describe a binary tree for
operations and numbers using “AST”, for example let’s say we have this expiration
“ 2+3∗5−1∗4 “ and we want to describe it in “AST” it would be like this
AST: Bin(-, Bin(+, Bin(*, 2, Bin(*, 3, 5)), Bin(*, 1,4) ).

1.1 Theory for BinComp:

In order to actually solve this, and for our parser to be able to compare numbers we
need to extend our “AST”, just like the following,

AST: BinComp(Comparison, Bin, Bin), where Bins are our left and right
expression

let’s say we have this expression that contain some comparison,” 3+5<7 +7 “ we need an
upgraded version for our “AST” so it can handle this, so our new “AST” will look like the
below one

AST: BinComp(¿, Bin(+, 3, 5), Bin(+, 7, 7)).

Its similar to our good old “AST” for operation and numbers(BinOP), but instant of
operation it now holds the comparison its self, and the left and right of the tree now
hold the old BinOP’s, determining that we are comparing those two expressions(BinOP).

1.2 Theory for BinLogic:

Again, if we want for our parser to hold Logics now, we have to extend our “AST” even
further, so we do the following.

AST: BinLogic(Logic, BinComp, BinComp) , where BinComps are our left and
right comparison that we have been apply it to our expression (BinOP).

let’s say we have this following asthmatic and comparison ,” 5+3<7 +7∧¿7 >9 , so our
new “AST” will look like the below one.

AST: BinLogic(&&, BinComp(¿, Bin(+, 5, 3), Bin(+, 7, 7)),


BinComp(¿, Bin(7), Bin(9))).

operation it now holds the Logics its self, and the left and right of the tree now hold
the BinComp, determining that we are testing Logics on those two BinComps
<, >, <=, , &&
+,>=,
*,
AND
OR ||
/- ==, != Comparison operator

2. Theory of precedence of arithmetic, comparison and


Logics:

Since we know the precedence of the mathematical operations which mean we have to
do the “parentheses” first then we have to do the “powers” then “multiplication and
division” then “addition and subtraction”, but what about the others comparison and
Logics is there a precedence for them? Will actually there is.

For Logical operation : we have to do the “AND (&&)” operation first then we do the
“OR (||)” next.

For comparison operation : since there will be only on comparison per each Logic so we
only compute what we have, in another word comparison operation does not have
precedence.

Check table 1 for more details.

Higher Precedence Asthmatics operator

Lower Precedence Logical operators

Table 1: precedence of arithmetic, comparison and Logics:

For example, let’s say we have this complex Procedure that contain multiple operation
exp < exp && exp == exp || exp != exp || exp >= exp && exp < exp

we start solving it by going from left to right “AND(&&)” first then “OR(||)”
((( exp < exp && exp == exp ) || exp != exp ) || ( exp >= exp && exp < exp))

And our AST will look like the following:

AST: BinLogic(||, BinLogic(||, BinLogic(&&, BinComp(<, exp, exp),


BinComp(==, exp, exp)), BinComp(!=, exp, exp)), BinLogic(&&,
BinComp(>=, exp, exp), BinComp(<, exp, exp)))

EXP: here mean it’s an AST of type BinOP


3. Implementation of the Task:
We now start by implementing the (BinLogic) and (BinComp), first we start by coding
their classes(objects), we add this code to our parser lab

class BinLogic:
def __init__(self, Logic, leftCompBin, rightCompBin):
self.Logic = Logic
self.leftCompBin = leftCompBin
self.rightCompBin = rightCompBin

The code above will hold our AST for Logics, and it has three perimeters, Logic will
hold our logical operation, leftCompBin and rightCompBin holds the AST for
Compression (defined later below).

class BinComp:
def __init__(self.comp, leftExpBin, rightExpBin):
self.comp = comp
self.leftExpBin = leftExpBin
self.rightExpBin = rightExpBin

The second above code will hold our AST for compression, and it has three perimeters,
Comp will hold our compression operation, leftExpBin and rightExpBin holds the AST of
BinOP or expression (have been defined earlier in Lab1, 2, and 3 of parser
implementation).

Next, we start by defining our function so that we could generate an AST the function
implementation will be exactly like the Expr(), term(), and factor() we will follow the
same prosses we add those two functions to the parser class

def Compare(self):
node = self.expr()
while str(self.current_token.value) in Operators.keys():
token = self.current_token
if str(token.value) in Operators.keys():
self.eat(token.type)
node = BinComp(token.type, node, self.expr())
return node

def Logic(self):
node = self.Compare()
while str(self.current_token.value) in Logic.keys():
token = self.current_token
if str(token.value) in Logic.keys():
self.eat(token.type)
node = BinLogic(token.type, node, self.Compare())
return node
Now after we create our classes and functions to generate the new upgraded version of
our “AST”, next step is that we want to calculate the result, and print out if the
following procedure is True or False, we do this by attacking the Interpreter class and
define new functions to calculate for us the result here are the functions we add.

The first function called “Visit_BinComp() ”

def visit_BinComp(self, node):


l = self.visit(node.leftExpBin)
r = self.visit(node.rightExpBin)

if node.comp in ("EQ","LE","GE"):
result = l-r
if not(result):
return True
if node.comp in ("EQ"):
return False

if node.comp in (“LT”,"LE"):
result = int(r/l)
if result:
return True
else:
return False

if node.comp in ("GT","GE"):
result = int(l/r)
if result:
return True
else:
return False

if node.comp in ("NE"):
result = l - r
if not(result):
return False
else:
return True

The first function Visit_BinComp() will calculate the comparison operation for us, and
return True or False Value.

Okay here we will assume that the computer doesn’t actually know what are the
comparison or logical operation are, so we define them from scratch, the code above
(Visit_BinComp()) function as you can see there is a lot of “if” statements we will
explain them one by one.
if node.comp in ("EQ","LE","GE"):
result = l-r
if not(result):
return True
if node.comp in ("EQ"):
return False

The first “if statement” from Visit_BinComp() function, checks if user want to know if
two expression are equal, in order to know this, we take those two expressions and
subtracted them with each other if the result of subtraction is zero mean they are
equal otherwise not, it also checks for example if the user want to see if they are ”GE”
or ”LE”, because there is a chance that those two expressions may be equal.

if node.comp in (“LT”,"LE"):
result = int(r/l)
if result:
return True
else:
return False

if node.comp in ("GT","GE"):
result = int(l/r)
if result:
return True
else:
return False

The next two “if statements” compare two expression to check which one of them is
greater or lesser, here we do some mathematics.

numerator
 Case 1: result= if numerator is greater than the denominator the
denominator
answer is always = result ≥ 1

numerator
 Case 2: result= if denominator is greater than the numerator the
denominator
answer always is = result ¿ 1 ( result = 0 ~ 0.9999999…… )

If the result is “Case 1” it means numerator is greater and vice versa.

if node.comp in ("NE"):
result = l - r
if not(result):
return False
else:
return True
The last “if statement” checks if they are not equal “NE”, its pretty straightforward
just like the equal “EQ” statement, but in reverse.

The next function we add to the Interpreter class, called: Visit_BinLogic().

def visit_BinLogic(self, node):


l = self.visit(node.leftCompBin)
r = self.visit(node.rightCompBin)

if node.Logic in ("AND"): # the first “if statement”


if l:
if r:
return True
else:
return False
else:
return False

if node.Logic in ("OR"): # the second “if statement”


if l:
return True
if r:
return True
else:
return False

Okay after we calculate our comparison operation, we return that result from
Visit_BinComp() function to Visit_BinLogic(), and here we check if any logical
operation has been done.

if node.Logic in ("AND"): # the first “if statement”


if l:
if r:
return True
else:
return False
else:
return False

The first “if” check if both left and right are True, if it is it return True but if one of
them is False, we return False, this what “AND” do everything must be True.

if node.Logic in ("OR"): # the second “if statement”


if l:
return True
if r:
return True
else:
return False
The entire pasar code.
import sys
from Scanner import *

class AST(object):
pass

class Bin(AST):
def __init__(self, left, op, right):
self.left = left
self.token = self.op = op
self.right = right

class BinComp:
def __init__(self,comp,leftExpBin,rightExpBin):
self.comp = comp
self.leftExpBin = leftExpBin
self.rightExpBin = rightExpBin

class BinLogic:
def __init__(self, Logic, leftCompBin, rightCompBin):
self.Logic = Logic
self.leftCompBin = leftCompBin
self.rightCompBin = rightCompBin

# Numbers (Lab 2)
class Num(AST):
def __init__(self, value):
self.value = value

class Parser(object):
def __init__(self, lexer):
self.lexer = lexer
self.current_token = self.lexer.get_next_token()

def error(self, message):


sys.exit('Invalid Syntax: ' + message)

def eat(self, token_type):


if self.current_token.type == token_type:
self.current_token = self.lexer.get_next_token()

else:
self.error("Expected Token: " + str(token_type) + " but " +
str(self.current_token.type) + " is given")

def expr(self):
node = self.term()
while self.current_token.type in ('PLUS', 'SUB'):
token = self.current_token
The second “if”
if check if one of
token.type == the lefts and right are True, if it is it return True
'PLUS':
self.eat('PLUS')
but if both of them are False, we return False, this what “OR” do one of them need
elif token.type == 'SUB':
to be True in order to return True.
self.eat('SUB')
node = Bin(left=node, op=token, right=self.term())
return node

def term(self):
node = self.factor()
while self.current_token.type in ('MUL', 'DIV'):
token = self.current_token
if token.type == 'MUL':
self.eat('MUL')
elif token.type == 'DIV':
self.eat('DIV')
node = Bin(left=node, op=token, right=self.factor())

return node

def factor(self):

token = self.current_token
if token.type == 'INTEGER':
self.eat('INTEGER')
return Num(token.value)
elif token.type == 'LPAREN':
self.eat('LPAREN')
node = self.expr()
self.eat('RPAREN')
return node

def Compare(self):
node = self.expr()
while str(self.current_token.value) in Operators.keys():
token = self.current_token
if str(token.value) in Operators.keys():
self.eat(token.type)
node = BinComp(token.type, node, self.expr())
return node

def Logic(self):
node = self.Compare()
while str(self.current_token.value) in Logic.keys():
token = self.current_token
if str(token.value) in Logic.keys():
self.eat(token.type)
node = BinLogic(token.type, node, self.Compare())
return node

def parse(self):
st = self.Logic()
if self.current_token.type != 'EOF':
self.error("Expected end of file")
return st

class NodeVisitor(object):
def visit(self, node):
method_name = 'visit_' + type(node).__name__
visitor = getattr(self, method_name, self.generic_visit)
return visitor(node)
def generic_visit(self, node):
raise Exception('No visit_{} method'.format(type(node).__name__) +
str(node))

class Interpreter(NodeVisitor):

def __init__(self, parser):


self.parser = parser

def visit_Bin(self, node):


result = ''
l = self.visit(node.left)
r = self.visit(node.right)
if node.op.type == 'SUB':
result = l - r
elif node.op.type == 'PLUS':
result = l + r
elif node.op.type == 'MUL':
result = l * r
elif node.op.type == 'DIV':
result = l / r

return result

def visit_BinComp(self, node):


l = self.visit(node.leftExpBin)
r = self.visit(node.rightExpBin)

if node.comp in ("EQ","LE","GE"):
result = l-r
if not(result):
return True
if node.comp in ("EQ"):
return False

if node.comp in ('LT',"LE"):
result = int(r/l)
if result:
return True
else:
return False

if node.comp in ("GT","GE"):
result = int(l/r)
if result:
return True
else:
return False

if node.comp in ("NE"):
result = l - r
if not(result):
return False
else:
return True

def visit_BinLogic(self,node):
l = self.visit(node.leftCompBin)
r = self.visit(node.rightCompBin)
if node.Logic in ("AND"):
if l:
if r:
return True
else:
return False
else:
return False

if node.Logic in ("OR"):
if l:
return True
if r:
return True
else:
return False

# Numbers
def visit_Num(self, node):
return node.value

def interpret(self):
tree = self.parser.parse()
result = self.visit(tree)
return result

def main():
p = open("SourceCode.txt", "r")
file = open("SourceCode.txt", "r")
lexer = Scanner(file.read())
parser = Parser(lexer)
interpreter = Interpreter(parser)
result = interpreter.interpret()
print(p.read())
print("Result: " + str(result))
file.close()

if __name__ == '__main__':
main()

You might also like