0% found this document useful (0 votes)
15 views16 pages

Compiler Practls

The document outlines various practical exercises related to grammar transformations, automata theory, algorithms, and parsing techniques. It includes implementations for converting right linear grammar to left linear grammar, NDFA to DFA, Warshall's algorithm, precedence matrices, and parsing using precedence matrices. Additionally, it covers the computation of FIRST and FOLLOW sets, infix to postfix conversion, and the generation of three-address code.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views16 pages

Compiler Practls

The document outlines various practical exercises related to grammar transformations, automata theory, algorithms, and parsing techniques. It includes implementations for converting right linear grammar to left linear grammar, NDFA to DFA, Warshall's algorithm, precedence matrices, and parsing using precedence matrices. Additionally, it covers the computation of FIRST and FOLLOW sets, infix to postfix conversion, and the generation of three-address code.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

Practical 1

Aim: Right linear grammar to left linear grammar


import sys

class Grammar:

def main(self):

temp = [''] * 20

left = [''] * 20

tempn = [''] * 20

right = ''

count = 0

print("Enter The Right linear grammar (separated by '-'), e.g., S-aB")

print("Enter 'q' to Quit")

str_list = []

while True:

line = input()

if line == 'q':

break

str_list.append(line)

print("The Right linear grammar is:")

for rule in str_list:

print(rule)

print("Terminals are:")

try:

for rule in str_list:

for j in range(2, len(rule)):

if 'a' <= rule[j] <= 'z':

if not temp[0]:

temp[count] = rule[j]

else:

if rule[j] not in temp[:count+1]:

count += 1

temp[count] = rule[j]

except IndexError:

pass

print(" ".join([c for c in temp if c]))

print("\nNon-terminals are:")

count = 0

try:

for rule in str_list:

for j in range(2, len(rule)):

if 'A' <= rule[j] <= 'Z':

if not tempn[0]:

tempn[count] = rule[j]

else:

if rule[j] not in tempn[:count+1]:

count += 1

tempn[count] = rule[j]

except IndexError:

pass

print(" ".join([c for c in tempn if c]))


print("\nThe Left linear Grammar is:")

for rule in str_list:

cr = 0

if 'A' <= rule[0] <= 'Z' and 'A' <= rule[-1] <= 'Z':

if (len(rule) - 2) // 2 >= 1:

for j in range(2, len(rule)):

left[cr] = rule[j]

cr += 1

for k in range((len(rule) - 2) // 2):

right = left[k]

left[k] = left[(len(rule) - 2) - 1 - k]

left[(len(rule) - 2) - 1 - k] = right

print(f"{left[0]}'-{rule[0]}'", end='')

for k in range((len(rule) - 2) - 1, 0, -1):

print(left[k], end='')

print()

else:

print(f"{rule[-1]}'-{rule[0]}'")

else:

print(f"Z'-{rule[0]}'", end='')

for j in range(2, len(rule)):

print(rule[j], end='')

print()

if __name__ == "__main__":

grammar = Grammar()

grammar.main()

Practical 2

Aim: Conversion of NDFA to DFA


import pandas as pd

# Input NFA
nfa = {input(f"State {i + 1}: "): {input(f"Symbol {j + 1}: "): input(f"End state(s) for state {i + 1} through symbol {j + 1}:
").split()
for j in range(int(input("No of Transitions: ")))} for i in range(int(input("No of States: ")))}

print("\nNFA:", nfa, "\nNFA Table:")


print(pd.DataFrame(nfa).transpose())
# Input Final States of NFA
nfa_final = input("\nEnter Final State(s) of NFA: ").split()

# Convert NFA to DFA


dfa, new_states, paths = {}, [], list(nfa[next(iter(nfa))].keys())
initial = "".join(nfa[next(iter(nfa))][paths[0]])
dfa[initial] = {}; new_states.append(initial)

while new_states:
curr = new_states.pop(0)
dfa[curr] = {}
for path in paths:
state = "".join(sorted(set(sum((nfa[s][path] for s in curr if path in nfa[s]), []))))
if state:
dfa[curr][path] = state
if state not in dfa: new_states.append(state)

print("\nDFA:", dfa, "\nDFA Table:")


print(pd.DataFrame(dfa).transpose().fillna("-"))

# Determine DFA Final States


dfa_final = [s for s in dfa if any(f in s for f in nfa_final)]
print("\nFinal States of the DFA:", dfa_final)
Practical 3

Aim: Implementation of Warshall Algorithm and Kleen Closure

a)Warshall Algorithm
nv, INF = 4, 999
def floyd_warshall(G):
for k in range (nv):
for i in range (nv):
for j in range (nv):
G[i][j] = min(G[i][j], G[i][k] + G[k][j])
for row in G:
print( " " .join("INF" if x == INF else str(x) for x in row ))
G=[
[0,3,INF,5],
[2,0,INF,4],
[INF,1,0,4],
[INF,INF,2,0]
]

floyd_warshall(G)
b) Transitive closure

def transitive_closure(graph):
V = len(graph)
closure=[[0]* V for _ in range(V)]

for i in range(V):
for j in range(V):
closure[i][j] = graph[i][j]

for k in range(V):
for i in range(V):
for j in range(V):
closure[i][j] = closure[i][j] or (closure[i][k] and closure[k][j])
return closure

graph= [
[1, 1, 0, 1],
[0, 1, 1, 0],
[0, 0, 1, 1],
[0, 0, 0, 1]
]
result = transitive_closure(graph)
print("transitive closure:")
for row in result:
print(row)

Practical 4
Aim: Generating Simple Precedence Matrix

def topological_sort(precedence_matrix):
n = len(precedence_matrix)
in_degree = [sum(col) for col in zip(*precedence_matrix)]
graph = {i: [j for j, val in enumerate(row) if val] for i, row in enumerate(precedence_matrix)}

queue = deque(i for i, deg in enumerate(in_degree) if deg == 0)


linear_order = []

while queue:
node = queue.popleft()
linear_order.append(node)
for neighbor in graph[node]:
in_degree[neighbor] -= 1
if in_degree[neighbor] == 0:
queue.append(neighbor)

if len(linear_order) == n:
return linear_order
raise ValueError("Graph has a cycle or is not a DAG.")

# Example usage
precedence_matrix = np.array([
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[0, 0, 0, 0]
])

print("Topological order:", topological_sort(precedence_matrix))

Practical 5
Aim: Parsing using Simple Precedence Matrix
# Simple Precedence Parser in Python

# Define the grammar terminals and non-terminals


terminals = ['+','*','i','(',')','$']
non_terminals = ['E','T','F']

# Simple Precedence matrix


#+*i()$
matrix = [
['>','<','<','<','>','>'], # +
['>','>','<','<','>','>'], # *
['>','>','>','','','>'], # i
['<','<','<','<','=',''], # (
['>','>','','','>','>'], # )
['<','<','<','<','',''], # $
]

# Function to get the precedence relation from the matrix


def get_precedence(a,b):
if a in terminals and b in terminals:
i = terminals.index(a)
j = terminals.index(b)
return matrix[i][j]
return None

# Function to parse the input string


def parse(input_string):
stack = ['$']
i=0
input_string += '$'

print(f"Stack\tInput\tAction")
print(f"{''.join(stack)}\t{input_string[i:]}\t")

while i < len(input_string):


top = stack[-1]
current_input = input_string[i]

precedence = get_precedence(top, current_input)

if precedence == '<' or precedence == '=':


stack.append(current_input)
i += 1
action = "Shift"
elif precedence == '>':
while get_precedence(stack[-2], stack[-1]) != '<':
stack.pop()
stack.pop()
action = "Reduce"
elif precedence == '':
print(f"Error: No precedence relation between {top} and {current_input}.")
return False
else:
print(f"Error: unrecognized action.")
return False

print(f"{''.join(stack)}\t{input_string[i:]}\t{action}")

if stack == ['$'] and input_string[i] == '$':


print("Parsing Successful!")
return True

print("Parsing Failed!")
return False

# Example Usage
input_string = "i+i*i"
parse(input_string)
Practical 6

Aim: Linearizing Simple Precedence Matrix to Precedence Functions

import numpy as np

# Sample terminal symbols


symbols = ['a', 'b', 'c']

# Input precedence matrix


# '<': -1, '=': 0, '>': 1
precedence_matrix = np.array([
[0, -1, 1],
[1, 0, -1],
[-1, 1, 0]
])

def compute_precedence_function(matrix, symbols):


n = len(symbols)

# Initialize Precedence functions f and g


f = [0] * n
g = [0] * n

# Assign precedence functions based on the matrix


for i in range(n):
for j in range(n):
if matrix[i][j] == 1:
f[i] = max(f[i], g[j] + 1)
elif matrix[i][j] == -1:
g[i] = max(g[i], f[j] + 1)

return f, g

# Compute precedence functions


f, g = compute_precedence_function(precedence_matrix, symbols)

# Output the precedence functions for each symbol


print("Precedence Function f:", {symbols[i]: f[i] for i in range(len(symbols))})
print("Precedence Function g:", {symbols[i]: g[i] for i in range(len(symbols))})

Practical 7

Aim: Generating Operator Precedence Matrix

def create_precedence_matrix(operators):
precedence_rules = {
('+','+'): '.>', ('+','*'): '<.', ('+','('): '<.', ('+',')'): '.>',
('*','+'): '.>', ('*','*'): '.>', ('*','('): '<.', ('*',')'): '.<',
('(','+'): '<.', ('(','*'): '<.', ('(','('): '<.', (')','+'): '>.',
(')','*'): '>.', (')',')'): '.>'
}
return [[precedence_rules.get((op1, op2), '.') for op2 in operators] for op1 in operators]

def print_precedence_matrix(operators, matrix):


print("Precedence Matrix\n " + " ".join(operators))
for op, row in zip(operators, matrix): print(op, " ".join(row))

if __name__ == "__main__":
operators = ['+', '*', '(', ')']
print_precedence_matrix(operators, create_precedence_matrix(operators))
Practical 8
Aim: Program for computation of FIRST AND FOLLOW of non-terminals.

from collections import defaultdict

# Input grammar as a dictionary


grammar = {
'S': ['AB', 'BC'],
'A': ['a', 'ε'],
'B': ['b'],
}

# FIRST and FOLLOW sets stored as Dictionaries


first = defaultdict(set)
follow = defaultdict(set)

# Function to compute the FIRST set for a given symbol


def compute_first(symbol):
# If already computed, return the FIRST set
if symbol in first and first[symbol]:
return first[symbol]

# If the symbol is terminal (lowercase), add it to its FIRST set


if symbol.islower() or symbol == 'ε':
first[symbol].add(symbol)
return first[symbol]

# If the symbol is non-terminal, iterate over its productions


for prod in grammar.get(symbol, []):
if prod == 'ε':
first[symbol].add('ε')
else:
for char in prod:
first_set = compute_first(char)
first[symbol].update(first_set - {'ε'}) # Add FIRST without ε
if 'ε' not in first_set:
break # Stop if no ε, as we found a terminal
else:
# If we reached the end and encountered ε, add ε to FIRST set
first[symbol].add('ε')

return first[symbol]

# Function to compute the FOLLOW set for a given symbol


def compute_follow(symbol):
if follow[symbol]:
return follow[symbol]
if symbol == 'S':
follow[symbol].add('$') # Assuming $ is the end of input marker

for lhs, productions in grammar.items():


for production in productions:
if symbol in production:
for i in range(len(production)):
if production[i] == symbol:
if i + 1 < len(production):
next_symbol = production[i + 1]
first_next = compute_first(next_symbol)
follow[symbol].update(first_next - {'ε'})
if 'ε' in first_next:
follow[symbol].update(compute_follow(lhs))
else:
if lhs != symbol:
follow[symbol].update(compute_follow(lhs))

return follow[symbol]

# Compute FIRST sets for all non-terminals


for non_terminal in grammar.keys():
compute_first(non_terminal)

# Compute FOLLOW sets for all non-terminals


for non_terminal in grammar.keys():
compute_follow(non_terminal)

# Display the FIRST and FOLLOW sets


print("FIRST sets:")
for key, value in first.items():
print(f"{key}: {value}")

print("\nFOLLOW sets:")
for key, value in follow.items():
print(f"{key}: {value}")
Practical 9
Aim: Conversion of Infix to Postfix notation, Postfix to Infix notations

a) Infix to Postfix notation


def precedence(op): return {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}.get(op, 0)
def is_operand(char): return char.isalnum()

def infix_to_postfix(expression):
stack, output = [], []
for char in expression:
if is_operand(char): output.append(char)
elif char == '(': stack.append(char)
elif char == ')':
while stack[-1] != '(': output.append(stack.pop())
stack.pop()
else:
while stack and precedence(char) <= precedence(stack[-1]): output.append(stack.pop())
stack.append(char)
return ''.join(output + stack[::-1])

expression = "A+B*(C-D)"
print("Infix Expression:", expression)
print("Postfix Expression:", infix_to_postfix(expression))

b) Postfix to Infix notations


def precedence(op): return {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}.get(op, 0)
def is_operand(char): return char.isalnum()

def infix_to_postfix(expression):
stack, output = [], []
for char in expression:
if is_operand(char): output.append(char)
elif char == '(': stack.append(char)
elif char == ')':
while stack[-1] != '(': output.append(stack.pop())
stack.pop()
else:
while stack and precedence(char) <= precedence(stack[-1]): output.append(stack.pop())
stack.append(char)
return ''.join(output + stack[::-1])

expression = "A+B*(C-D)"
print("Infix Expression:", expression)
print("Postfix Expression:", infix_to_postfix(expression))
Practical 10
Aim: Generation of three address code and DAG for the given arithmetic expression

class ThreeAddressCode:
def __init__(self):
self.temp_count = 0
self.code = []

def new_temp(self):
self.temp_count += 1
return f't{self.temp_count}'

def generate_tac(self, expression):


postfix = self.infix_to_postfix(expression)
return self.postfix_to_tac(postfix)

def infix_to_postfix(self, expression):


precedence = {'+': 1, '-': 1, '*': 2, '/': 2}
output = []
stack = []
tokens = list(expression.replace(" ", ""))

for token in tokens:


if token.isalnum(): # Operand
output.append(token)
elif token == '(': # Left parenthesis
stack.append(token)
elif token == ')': # Right parenthesis
while stack and stack[-1] != '(':
output.append(stack.pop())
stack.pop() # Remove the '('
else: # Operator
while (stack and stack[-1] in precedence and
precedence[stack[-1]] >= precedence[token]):
output.append(stack.pop())
stack.append(token)

while stack: # Pop all the operators in the stack


output.append(stack.pop())

return output

def postfix_to_tac(self, postfix):


stack = []
for token in postfix:
if token.isalnum():
stack.append(token)
else:
arg2 = stack.pop()
arg1 = stack.pop()
temp = self.new_temp()
self.code.append(f'{temp} = {arg1} {token} {arg2}')
stack.append(temp)

return self.code

class DAGNode:
def __init__(self, value):
self.value = value
self.children = []
self.label = None

def __repr__(self):
return f"{self.value} (label: {self.label})"

class DAG:
def __init__(self):
self.nodes = []

def find_or_create_node(self, value):


for node in self.nodes:
if node.value == value:
return node

# Create a new node if not found


new_node = DAGNode(value)
self.nodes.append(new_node)
return new_node

def create_dag(self, expression):


postfix = self.infix_to_postfix(expression)
return self.build_dag_from_postfix(postfix)

def infix_to_postfix(self, expression):


precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '(': 0, ')': 0}
output = []
stack = []
tokens = list(expression.replace(" ", ""))

for token in tokens:


if token.isalnum():
output.append(token)
elif token == '(':
stack.append(token)
elif token == ')':
while stack and stack[-1] != '(':
output.append(stack.pop())
stack.pop()
else:
while (stack and stack[-1] in precedence and
precedence[stack[-1]] >= precedence[token]):
output.append(stack.pop())
stack.append(token)

while stack:
output.append(stack.pop())
return output

def build_dag_from_postfix(self, postfix):


stack = []

for token in postfix:


if token.isalnum():
node = self.find_or_create_node(token)
stack.append(node)
else:
arg2 = stack.pop()
arg1 = stack.pop()
node = self.find_or_create_node(f"{arg1.value} {token} {arg2.value}")
node.children.extend([arg1, arg2])
stack.append(node)

return stack[0]

def display(self, node, level=0):


if node:
print(' ' * (level * 4) + str(node))
for child in node.children:
self.display(child, level + 1)

# Example
expression = "(a + b) * (c + d)"

# Generate TAC
tac_generator = ThreeAddressCode()
tac = tac_generator.generate_tac(expression)
print("Three Address Code:")
for line in tac:
print(line)

# Generate DAG
dag = DAG()
root = dag.create_dag(expression)
print("\nDirected Acyclic Graph:")
dag.display(root)

You might also like