0% found this document useful (0 votes)
6 views17 pages

_new Compiler Practls

The document contains multiple practical programming exercises focused on various topics in computer science, including grammar conversion, NDFA to DFA conversion, Warshall's algorithm, precedence parsing, and FIRST/FOLLOW sets computation. Each practical includes code snippets and explanations of the algorithms or methods being implemented. The exercises aim to provide hands-on experience with theoretical concepts in automata theory and parsing techniques.
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)
6 views17 pages

_new Compiler Practls

The document contains multiple practical programming exercises focused on various topics in computer science, including grammar conversion, NDFA to DFA conversion, Warshall's algorithm, precedence parsing, and FIRST/FOLLOW sets computation. Each practical includes code snippets and explanations of the algorithms or methods being implemented. The exercises aim to provide hands-on experience with theoretical concepts in automata theory and parsing techniques.
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/ 17

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

import numpy as np

from collections import deque

def topological_sort(precedence_matrix):
# Number of vertices

n = len(precedence_matrix)

# Compute in-degrees of each node

in_degree = [sum(col) for col in zip(*precedence_matrix)]

# Build adjacency list representation of the graph

graph = {i: [j for j, val in enumerate(precedence_matrix[i]) if val] for i in range(n)}

# Initialize a queue with all nodes having zero in-degree

queue = deque(i for i in range(n) if in_degree[i] == 0)

linear_order = []

# Process nodes in the queue

while queue:

node = queue.popleft()

linear_order.append(node)

# Decrement in-degree of neighboring nodes

for neighbor in graph[node]:

in_degree[neighbor] -= 1

if in_degree[neighbor] == 0:

queue.append(neighbor)

# Check if all nodes were processed


if len(linear_order) == n:

return linear_order

# If not, there is a cycle in the graph

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