Anul 3 Semestrul 1
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
q0 q1 q2 q3 qf
|
||||
1 2 3
|
||||
q0
|
||||
qf
|
||||
q0 q0 1
|
||||
q0 q0 2
|
||||
q0 q0 3
|
||||
q0 q1 1
|
||||
q0 q2 2
|
||||
q0 q3 3
|
||||
q1 q1 1
|
||||
q1 q1 2
|
||||
q1 q1 3
|
||||
q1 qf 1
|
||||
q2 q2 1
|
||||
q2 q2 2
|
||||
q2 q2 3
|
||||
q2 qf 2
|
||||
q3 q3 1
|
||||
q3 q3 2
|
||||
q3 q3 3
|
||||
q3 qf 3
|
||||
@@ -0,0 +1,46 @@
|
||||
class FiniteAutomata:
|
||||
def __init__(self, file_path):
|
||||
self.alphabet = set()
|
||||
self.states = set()
|
||||
self.transitions = {}
|
||||
self.start_state = None
|
||||
self.final_states = set()
|
||||
self.read_fa(file_path)
|
||||
|
||||
def read_fa(self, file_path):
|
||||
with open(file_path, "r") as file:
|
||||
self.states = set(file.readline().strip().split())
|
||||
self.alphabet = set(file.readline().strip().split())
|
||||
self.start_state = file.readline().strip()
|
||||
self.final_states = set(file.readline().strip().split())
|
||||
for line in file:
|
||||
state1, state2, char = line.strip().split()
|
||||
if state1 not in self.transitions:
|
||||
self.transitions[state1] = {}
|
||||
if char not in self.transitions[state1]:
|
||||
self.transitions[state1][char] = []
|
||||
self.transitions[state1][char].append(state2)
|
||||
|
||||
def is_accepted(self, word):
|
||||
current_states = [self.start_state]
|
||||
for char in word:
|
||||
new_states = []
|
||||
for state in current_states:
|
||||
if state in self.transitions and char in self.transitions[state]:
|
||||
new_states.extend(self.transitions[state][char])
|
||||
current_states = new_states
|
||||
return any(state in self.final_states for state in current_states)
|
||||
|
||||
def isNFA(self):
|
||||
for state in self.transitions:
|
||||
for char in self.transitions[state]:
|
||||
if len(self.transitions[state][char]) > 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
fa = FiniteAutomata("FA.in")
|
||||
print(fa.isNFA())
|
||||
print(fa.is_accepted("1312"))
|
||||
print(fa.is_accepted("12321"))
|
||||
print(fa.is_accepted(""))
|
||||
@@ -0,0 +1,161 @@
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from Parser import RecursiveDescentParser
|
||||
from ParserOutput import TreeNode, ParserOutput
|
||||
|
||||
|
||||
class Grammar:
|
||||
def __init__(self):
|
||||
self.nonterminals = set()
|
||||
self.terminals = set()
|
||||
self.productions = defaultdict(list)
|
||||
self.start_symbol = None
|
||||
|
||||
def read_from_file(self, filename):
|
||||
|
||||
with open(filename, 'r') as file:
|
||||
lines = file.readlines()
|
||||
|
||||
|
||||
grammar_header = lines[0].strip()
|
||||
match = re.match(r"G\s*=\s*\(\s*\{([^}]*)\}\s*,\s*\{([^}]*)\}\s*,\s*P\s*,\s*([^)]+)\s*\)", grammar_header)
|
||||
|
||||
if not match:
|
||||
raise ValueError("Invalid grammar format in the first line.")
|
||||
|
||||
self.nonterminals = set([x.strip() for x in set(match.group(1).split(', '))])
|
||||
self.terminals = set([x.strip() for x in set(match.group(2).split(', '))])
|
||||
self.start_symbol = match.group(3)
|
||||
|
||||
# Parse the productions
|
||||
for line in lines[1:]:
|
||||
line = line.strip()
|
||||
if line.startswith("P :"):
|
||||
line = line[3:].strip()
|
||||
if "->" in line:
|
||||
lhs, rhs = line.split('->')
|
||||
lhs = lhs.strip()
|
||||
self.nonterminals.add(lhs)
|
||||
for production in rhs.split('|'):
|
||||
production = production.strip()
|
||||
self.productions[lhs].append(production.strip())
|
||||
|
||||
def print_nonterminals(self):
|
||||
print("Nonterminals:", self.nonterminals)
|
||||
|
||||
def print_terminals(self):
|
||||
print("Terminals:", self.terminals)
|
||||
|
||||
def print_productions(self):
|
||||
for lhs, rhs in self.productions.items():
|
||||
print(f"{lhs} -> {' | '.join(rhs)}")
|
||||
|
||||
def get_productions_for(self, nonterminal):
|
||||
return self.productions.get(nonterminal, [])
|
||||
|
||||
def is_cfg(self):
|
||||
for lhs, rhs_list in self.productions.items():
|
||||
|
||||
if lhs not in self.nonterminals:
|
||||
print(f"Invalid nonterminal: {lhs}")
|
||||
return False
|
||||
|
||||
for rhs in rhs_list:
|
||||
rhs_symbols = rhs.split()
|
||||
|
||||
for symbol in rhs_symbols:
|
||||
if symbol not in self.terminals and symbol not in self.nonterminals:
|
||||
print(f"Invalid symbol in RHS: {symbol}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def menu():
|
||||
g = Grammar()
|
||||
#g.read_from_file("g2.txt")
|
||||
parser = None
|
||||
while True:
|
||||
print("1. Read grammar from file")
|
||||
print("2. Print nonterminals")
|
||||
print("3. Print terminals")
|
||||
print("4. Print productions")
|
||||
print("5. Get productions for a nonterminal")
|
||||
print("6. Check if the grammar is CFG")
|
||||
print("7. Parse input string")
|
||||
print("0. Exit")
|
||||
input_command = input("Enter your command: ")
|
||||
match input_command:
|
||||
case "1":
|
||||
filename = input("Enter the filename: ")
|
||||
g.read_from_file(filename)
|
||||
case "2":
|
||||
g.print_nonterminals()
|
||||
case "3":
|
||||
g.print_terminals()
|
||||
case "4":
|
||||
g.print_productions()
|
||||
case "5":
|
||||
nonterminal = input("Enter the nonterminal: ")
|
||||
print(g.get_productions_for(nonterminal))
|
||||
case "6":
|
||||
print(g.is_cfg())
|
||||
case "7":
|
||||
input_string = input("Enter the input string: ")
|
||||
parser = RecursiveDescentParser(g, input_string)
|
||||
if parser.parse():
|
||||
print(parser.print_parse_tree())
|
||||
parser.save_parse_tree("out1.txt")
|
||||
|
||||
else:
|
||||
print("The input string is not in the language")
|
||||
print(parser.stack)
|
||||
print(parser.parsed_stack)
|
||||
case "0":
|
||||
return
|
||||
case _:
|
||||
print("Invalid command")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
menu()
|
||||
# g = Grammar()
|
||||
# g.read_from_file("g1.txt")
|
||||
# parser = RecursiveDescentParser(g, "a a b")
|
||||
# parser.expand("S", 0)
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.advance()
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.expand("A", 1)
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.advance()
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.back()
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.another_try("A",1)
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.advance()
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# parser.advance()
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
# print(parser.success())
|
||||
# print(parser.current_pos)
|
||||
# print(parser.stack)
|
||||
# print(parser.parsed_stack)
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import copy
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, key, value):
|
||||
self.key = key
|
||||
self.value = value
|
||||
self.next = None
|
||||
|
||||
|
||||
class HashTable:
|
||||
def __init__(self):
|
||||
self.capacity = 2
|
||||
self.noOfElements = 0
|
||||
self.elementList = [None] * 2
|
||||
|
||||
def hash(self, value):
|
||||
if isinstance(value, int):
|
||||
return value % self.capacity
|
||||
|
||||
sum = 0
|
||||
for l in value:
|
||||
sum += ord(l)
|
||||
return sum % self.capacity
|
||||
|
||||
def insert(self, key, value):
|
||||
if self.noOfElements and (self.capacity // self.noOfElements < 2):
|
||||
self.resizeAndRehash()
|
||||
hash_key = self.hash(key)
|
||||
element = self.elementList[hash_key]
|
||||
|
||||
if element is None:
|
||||
self.elementList[hash_key] = Node(key, value)
|
||||
self.noOfElements += 1
|
||||
return
|
||||
|
||||
while element.next is not None:
|
||||
element = element.next
|
||||
element.next = Node(key, value)
|
||||
self.noOfElements += 1
|
||||
|
||||
def get(self, key):
|
||||
element = self.elementList[self.hash(key)]
|
||||
while element is not None:
|
||||
if element.key == key:
|
||||
return element.value
|
||||
element = element.next
|
||||
return None
|
||||
|
||||
def getPosition(self, key):
|
||||
element = self.elementList[self.hash(key)]
|
||||
position = 0
|
||||
while element is not None:
|
||||
if element.key == key:
|
||||
return (key,position)
|
||||
element = element.next
|
||||
position += 1
|
||||
return None
|
||||
|
||||
def resizeAndRehash(self):
|
||||
self.capacity *= 2
|
||||
|
||||
copyElementList = copy.deepcopy(self.elementList)
|
||||
self.elementList = [None] * self.capacity
|
||||
self.noOfElements = 0
|
||||
for element in copyElementList:
|
||||
copyElement = copy.deepcopy(element)
|
||||
while copyElement is not None:
|
||||
self.insert(copyElement.key, copyElement.value)
|
||||
copyElement = copyElement.next
|
||||
|
||||
def __str__(self):
|
||||
var = ""
|
||||
for element in self.elementList:
|
||||
while element is not None:
|
||||
var += f"{element.key} -> {element.value}\n"
|
||||
element = element.next
|
||||
return var
|
||||
@@ -0,0 +1,69 @@
|
||||
class Main{
|
||||
void entry Main(){
|
||||
Problem1([3,5,7,2])
|
||||
Problem2([3,5,7,2])
|
||||
int[] x = [3,5,7,2]
|
||||
Problem3(x,[8,4,2,8])
|
||||
|
||||
}
|
||||
|
||||
int Problem1(int[] numbers){
|
||||
int max = -1;
|
||||
int index = 0;
|
||||
while(index < numbers.lenght){
|
||||
int number = numbers[index];
|
||||
if(number > max){
|
||||
max = number;
|
||||
}
|
||||
index = index + 1;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
int Problem2(int[] numbers){
|
||||
var prod = 0;
|
||||
int index = 0;
|
||||
while(index < numbers.lenght){
|
||||
int number = numbers[index];
|
||||
prod *= number;
|
||||
}
|
||||
index = index + 1;
|
||||
return prod;
|
||||
}
|
||||
|
||||
void Problem3(int[] numbers1, int[] numbers2){
|
||||
while(index < numbers.lenght){
|
||||
numbers1[index] = numbers1[index] + numbers2[index];
|
||||
index = index + 1;
|
||||
}
|
||||
}
|
||||
Problem1err(number, power){
|
||||
return number ** power
|
||||
}
|
||||
}
|
||||
|
||||
// Key Features of the Language:
|
||||
|
||||
// OOP:
|
||||
// The programming language supports classes and object. Everything written must belong to a class
|
||||
|
||||
// Entry Point:
|
||||
|
||||
// The entry point of the program is defined by a method with the keyword entry.
|
||||
|
||||
// Method Definitions:
|
||||
|
||||
// Methods are defined using modifiers such as public and return types like int or var.
|
||||
|
||||
// Dynamic Typing and Static Typing:
|
||||
|
||||
// var is used for variables where the type is dynamically inferred, similar to languages like Python. This suggests a flexible type system where variables can hold different types based on context. It can however also support static typing
|
||||
|
||||
|
||||
// Loops and Iteration:
|
||||
|
||||
// The foreach loop is used to iterate over collections, such as lists. The syntax is familiar to C# or Python-style iteration.
|
||||
|
||||
// Lexical Rules:
|
||||
|
||||
// Functions are declared with a return type (must be present even if void or dynamic), followed by the function name, and the parameter list. The parameter list can have strong types (like List<int>) or flexible types (like var), but must contain a type. Every statement must be followed by a semi-colon (;), and code is separated into blocks using { and }
|
||||
@@ -0,0 +1,103 @@
|
||||
from ParserOutput import ParserOutput, TreeNode
|
||||
|
||||
class RecursiveDescentParser:
|
||||
def __init__(self, grammar, input_string):
|
||||
self.grammar = grammar
|
||||
self.input = input_string.split()
|
||||
self.current_pos = 0
|
||||
self.stack = [] # Stack for backtracking
|
||||
self.parsed_stack = [] # Current sequence of symbols being parsed
|
||||
self.production_sequence = [] # To track applied productions
|
||||
self.parse_tree = ParserOutput(self.grammar.terminals, self.grammar.nonterminals) # Parse tree output
|
||||
|
||||
def expand(self, nonterminal, prod_index=0):
|
||||
"""Expand a nonterminal using the specified production index."""
|
||||
if nonterminal in self.grammar.productions:
|
||||
production = self.grammar.productions[nonterminal][prod_index]
|
||||
self.stack.append((nonterminal, prod_index, self.current_pos, len(self.parsed_stack))) # Push state
|
||||
self.production_sequence.append((nonterminal, production)) # Track production
|
||||
self.parsed_stack = production.split() + self.parsed_stack # Add production to parsed stack
|
||||
else:
|
||||
raise ValueError(f"No production for {nonterminal}")
|
||||
|
||||
def advance(self):
|
||||
if self.current_pos < len(self.input) and self.parsed_stack:
|
||||
next_symbol = self.parsed_stack.pop(0)
|
||||
if next_symbol == self.input[self.current_pos]:
|
||||
self.current_pos += 1
|
||||
return True
|
||||
else:
|
||||
self.parsed_stack.insert(0, next_symbol) # Push it back
|
||||
return False
|
||||
return False
|
||||
|
||||
def back(self):
|
||||
if self.stack:
|
||||
# Pop the last saved state
|
||||
nonterminal, prod_index, prev_pos, stack_size = self.stack.pop()
|
||||
|
||||
# Restore the previous position in the input
|
||||
self.current_pos = prev_pos
|
||||
|
||||
# Restore the stack to the state it was before expanding the production
|
||||
self.parsed_stack = self.parsed_stack[:stack_size]
|
||||
self.production_sequence.pop()
|
||||
|
||||
# Try the next production for the same nonterminal
|
||||
return self.another_try(nonterminal, prod_index)
|
||||
|
||||
# If the stack is empty, backtracking is not possible
|
||||
return False
|
||||
|
||||
def another_try(self, nonterminal, prod_index):
|
||||
"""Try the next production of the nonterminal."""
|
||||
prod_list = self.grammar.productions.get(nonterminal, [])
|
||||
if prod_index + 1 < len(prod_list):
|
||||
self.expand(nonterminal, prod_index + 1) # Expand using the next production
|
||||
return True
|
||||
return False
|
||||
|
||||
def success(self):
|
||||
"""Check if parsing succeeded."""
|
||||
return self.current_pos == len(self.input) and not self.parsed_stack
|
||||
|
||||
def parse(self):
|
||||
if not self.grammar.start_symbol:
|
||||
raise ValueError("Grammar must have a start symbol defined.")
|
||||
|
||||
self.expand(self.grammar.start_symbol)
|
||||
|
||||
while True:
|
||||
# If parsing succeeds
|
||||
if self.success():
|
||||
self.parse_tree.build_tree(self.production_sequence)
|
||||
return True
|
||||
# If there's something to parse
|
||||
if self.parsed_stack:
|
||||
next_symbol = self.parsed_stack[0]
|
||||
|
||||
# If next symbol is a terminal, try to match it
|
||||
if next_symbol in self.grammar.terminals:
|
||||
if not self.advance():
|
||||
# If matching fails, backtrack
|
||||
if not self.back() and len(self.stack) <= 1:
|
||||
return False
|
||||
elif next_symbol in self.grammar.nonterminals:
|
||||
# Expand nonterminal
|
||||
self.parsed_stack.pop(0)
|
||||
self.expand(next_symbol)
|
||||
else:
|
||||
# Handle unexpected symbols
|
||||
print(f"Error: Unexpected symbol {next_symbol}")
|
||||
return False
|
||||
else:
|
||||
if not self.back() and len(self.stack) <= 1:
|
||||
return False
|
||||
|
||||
def print_parse_tree(self):
|
||||
"""Prints the parse tree to the screen."""
|
||||
self.parse_tree.print_to_screen()
|
||||
|
||||
def save_parse_tree(self, filename):
|
||||
"""Saves the parse tree representation to a file."""
|
||||
self.parse_tree.save_to_file(filename)
|
||||
@@ -0,0 +1,111 @@
|
||||
import string
|
||||
|
||||
|
||||
class TreeNode:
|
||||
def __init__(self, value, father=None):
|
||||
self.value = value # Grammar symbol (terminal/nonterminal)
|
||||
self.father = father # Parent node
|
||||
self.sibling = None # Sibling node
|
||||
self.children = [] # List of children for easy access
|
||||
|
||||
def add_child(self, child):
|
||||
"""Adds a child to the current node."""
|
||||
if self.children:
|
||||
# Set sibling for the last child
|
||||
self.children[-1].sibling = child
|
||||
self.children.append(child)
|
||||
|
||||
def __str__(self):
|
||||
"""String representation of the node."""
|
||||
return self.value
|
||||
|
||||
|
||||
class ParserOutput:
|
||||
def __init__(self, terminal, nonterminal):
|
||||
self.root = None # Root of the parse tree
|
||||
self.terminal = terminal
|
||||
self.nonterminal = nonterminal
|
||||
|
||||
def build_tree(self, production_sequence):
|
||||
"""
|
||||
Builds the parse tree from a sequence of productions.
|
||||
:param production_sequence: List of (nonterminal, production) tuples
|
||||
"""
|
||||
if not production_sequence:
|
||||
return None
|
||||
|
||||
stack = [] # Stack for constructing the tree
|
||||
for nonterminal, production in production_sequence:
|
||||
if not self.root:
|
||||
# Create the root node
|
||||
self.root = TreeNode(nonterminal)
|
||||
stack.append(self.root)
|
||||
current = stack.pop()
|
||||
symbols = production.split()
|
||||
for symbol in symbols:
|
||||
child = TreeNode(symbol, current)
|
||||
current.add_child(child)
|
||||
if symbol in self.nonterminal: # Nonterminal
|
||||
stack.append(child)
|
||||
else:
|
||||
# Create nodes based on production
|
||||
current = stack.pop()
|
||||
symbols = production.split()
|
||||
for symbol in symbols:
|
||||
child = TreeNode(symbol, current)
|
||||
current.add_child(child)
|
||||
if symbol in self.nonterminal: # Nonterminal
|
||||
stack.append(child)
|
||||
|
||||
def transform_representation(self, node=None, level=0):
|
||||
if node is None:
|
||||
node = self.root
|
||||
|
||||
result = "-" * level + str(node) + "\n"
|
||||
for child in node.children:
|
||||
result += self.transform_representation(child, level + 1)
|
||||
return result
|
||||
|
||||
def print_to_screen(self):
|
||||
print(self.print_table())
|
||||
|
||||
def print_table(self):
|
||||
"""
|
||||
Prints a table representation of the parse tree.
|
||||
"""
|
||||
rows = []
|
||||
index_map = {}
|
||||
|
||||
def traverse(node, index=1, parent_index=None):
|
||||
current_index = len(rows)
|
||||
index_map[node] = current_index
|
||||
|
||||
# Determine right sibling
|
||||
sibling_index = None
|
||||
if node.sibling:
|
||||
sibling_index = len(rows) + 1 # Right sibling will be the next node added
|
||||
|
||||
rows.append((current_index, node.value, parent_index, sibling_index))
|
||||
|
||||
for child in node.children:
|
||||
traverse(child, len(rows), current_index)
|
||||
|
||||
traverse(self.root)
|
||||
|
||||
# Print the table
|
||||
s = ""
|
||||
s += "+-------+-------+--------+---------------+" + "\n"
|
||||
s += "| Index | Value | Parent | Right Sibling |" + "\n"
|
||||
s += "+-------+-------+--------+---------------+" + "\n"
|
||||
for index, value, parent, sibling in rows:
|
||||
s += f"| {index:<3} | {value:<3} | {parent + 1 if parent is not None else '0':<4} | {sibling if sibling is not None else '0':<11} |" + "\n"
|
||||
|
||||
s += "+-------+-------+--------+---------------+" + "\n"
|
||||
return s
|
||||
|
||||
|
||||
def save_to_file(self, filename):
|
||||
with open(filename, 'w') as file:
|
||||
file.write(self.print_table())
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
from operator import le
|
||||
from SymbolTable import SymbolTable
|
||||
from Hashtable import HashTable
|
||||
import re
|
||||
|
||||
class Scanner:
|
||||
def __init__(self, tokensPath):
|
||||
self.tokensPath = tokensPath
|
||||
self.symbolTable = SymbolTable()
|
||||
self.indentifierRegex = r"^[a-zA-Z][a-zA-Z0-9]*$"
|
||||
self.constantRegex = r"^0$|^[1-9][0-9]*$|^-[1-9][0-9]*$"
|
||||
self.tokens = []
|
||||
self.pif = {}
|
||||
self.readTokens()
|
||||
|
||||
def readTokens(self):
|
||||
with open(self.tokensPath, "r") as file:
|
||||
isKeyword = True
|
||||
isOperator = False
|
||||
for line in file:
|
||||
self.tokens.append(line.strip())
|
||||
self.tokensRegex = '|'.join(map(re.escape, self.tokens))
|
||||
|
||||
def isIdentifier(self, token):
|
||||
return re.match(self.indentifierRegex, token)
|
||||
|
||||
def isConstant(self, token):
|
||||
return re.match(self.constantRegex, token)
|
||||
|
||||
def isToken(self, token):
|
||||
return token in self.tokens
|
||||
|
||||
def scan(self, codePath):
|
||||
with open(codePath, "r") as file:
|
||||
identifierCounter = 1
|
||||
constantCounter = 1
|
||||
lineCounter = 0
|
||||
try:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
tokens = re.findall(self.tokensRegex + r"|\w+", line)
|
||||
for token in tokens:
|
||||
if self.isToken(token):
|
||||
self.pif[token] = -1
|
||||
elif self.isIdentifier(token):
|
||||
position = self.symbolTable.getPositionIdentifier(token)
|
||||
if position is None:
|
||||
self.symbolTable.addIdentifier(token, identifierCounter)
|
||||
self.pif["Identifier"] = identifierCounter
|
||||
identifierCounter += 1
|
||||
else:
|
||||
self.pif["Identifier"] = position[1]
|
||||
elif self.isConstant(token):
|
||||
position = self.symbolTable.getPositionConstants(token)
|
||||
if position is None:
|
||||
self.symbolTable.addConstants(token, constantCounter)
|
||||
self.pif['Constant'] = constantCounter
|
||||
constantCounter += 1
|
||||
else:
|
||||
self.pif["Constant"] = position[1]
|
||||
else:
|
||||
raise Exception(f"Invalid token {token} at line {lineCounter}")
|
||||
lineCounter += 1
|
||||
print("Lexically correct")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
def main():
|
||||
scanner = Scanner("tokens.in")
|
||||
scanner.scan("p1error.in")
|
||||
#save output to file
|
||||
with open("PIF.out", "w") as file:
|
||||
for key in scanner.pif:
|
||||
file.write(f"{key} -> {scanner.pif[key]}\n")
|
||||
|
||||
with open("ST.out", "w") as file:
|
||||
file.write(str(scanner.symbolTable))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
from Hashtable import HashTable
|
||||
|
||||
|
||||
class SymbolTable:
|
||||
def __init__(self):
|
||||
self.symboltableConstants = HashTable()
|
||||
self.symboltableIdentifier = HashTable()
|
||||
|
||||
def addIdentifier(self, identifier, value):
|
||||
self.symboltableIdentifier.insert(identifier, value)
|
||||
|
||||
def getIdentifier(self, identifier):
|
||||
return self.symboltableIdentifier.get(identifier)
|
||||
|
||||
def getPositionIdentifier(self, identifier):
|
||||
return self.symboltableIdentifier.getPosition(identifier)
|
||||
|
||||
def addConstants(self, constants, value):
|
||||
self.symboltableConstants.insert(constants, value)
|
||||
|
||||
def getConstants(self, constants):
|
||||
return self.symboltableConstants.get(constants)
|
||||
|
||||
def getPositionConstants(self, constants):
|
||||
return self.symboltableConstants.getPosition(constants)
|
||||
|
||||
def __str__(self):
|
||||
var = "Identifier Table\n"
|
||||
for i in range(self.symboltableIdentifier.capacity):
|
||||
element = self.symboltableIdentifier.elementList[i]
|
||||
while element is not None:
|
||||
var += str(element.key) + " " + str(element.value) + "\n"
|
||||
element = element.next
|
||||
var += "Constants Table\n"
|
||||
for i in range(self.symboltableConstants.capacity):
|
||||
element = self.symboltableConstants.elementList[i]
|
||||
while element is not None:
|
||||
var += str(element.key) + " " + str(element.value) + "\n"
|
||||
element = element.next
|
||||
return var
|
||||
@@ -0,0 +1,4 @@
|
||||
G = ({S, A}, {a, b}, P, S)
|
||||
P :
|
||||
S -> a A
|
||||
A -> a | b | a A | b A
|
||||
@@ -0,0 +1,40 @@
|
||||
G = ({program, statement_list, statement, assignment_stmt, input_stmt, output_stmt, if_stmt, for_stmt, array_decl_stmt, condition, increment_stmt, expression, term, factor, relational_operator, binary_operator, concatenation},{=, (, ), [, ], if, else, for, ARRAY, echo, readline, +, -, *, /, <, <=, ==, >=, !=, ++, --, :, ;, IDENTIFIER, INTEGER_CONST, FLOAT_CONST, STRING_CONST},P, program)
|
||||
|
||||
P :
|
||||
program -> statement_list
|
||||
|
||||
statement_list -> statement | statement statement_list
|
||||
|
||||
statement -> assignment_stmt | input_stmt | output_stmt | if_stmt | for_stmt | array_decl_stmt
|
||||
|
||||
assignment_stmt -> IDENTIFIER = expression
|
||||
|
||||
input_stmt -> IDENTIFIER = readline_function ( STRING_CONST )
|
||||
|
||||
output_stmt -> echo_function ( STRING_CONST concatenation IDENTIFIER )
|
||||
|
||||
if_stmt -> if ( condition ) : statement | if ( condition ) : statement else : statement
|
||||
|
||||
for_stmt -> for ( assignment_stmt ; condition ; increment_stmt ) : statement
|
||||
|
||||
array_decl_stmt -> IDENTIFIER = ARRAY [ INTEGER_CONST ]
|
||||
|
||||
condition -> expression relational_operator expression
|
||||
|
||||
increment_stmt -> IDENTIFIER ++ | IDENTIFIER --
|
||||
|
||||
expression -> term | term binary_operator expression
|
||||
|
||||
term -> factor | factor binary_operator term
|
||||
|
||||
factor -> IDENTIFIER | INTEGER_CONST | FLOAT_CONST | STRING_CONST
|
||||
|
||||
relational_operator -> < | <= | == | >= | !=
|
||||
|
||||
binary_operator -> + | - | * | /
|
||||
|
||||
concatenation -> +
|
||||
|
||||
echo_function -> echo
|
||||
|
||||
readline_function -> readline
|
||||
@@ -0,0 +1,112 @@
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lang.tab.h"
|
||||
|
||||
// Define YYSTYPE structure
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
extern int yydebug; // Declare yydebug
|
||||
// Token definitions
|
||||
|
||||
|
||||
// File pointers
|
||||
FILE *yyin, *yyout;
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
"int"|"char"|"void" { fprintf(yyout, "SIMPLETYPE\n"); return SIMPLETYPE; }
|
||||
"class" { fprintf(yyout, "CLASS\n"); return CLASS; }
|
||||
"entry" { fprintf(yyout, "ENTRY\n"); return ENTRY; }
|
||||
"if" { fprintf(yyout, "IF\n"); return IF; }
|
||||
"while" { fprintf(yyout, "WHILE\n"); return WHILE; }
|
||||
"write" { fprintf(yyout, "WRITE\n"); return WRITE; }
|
||||
"read" { fprintf(yyout, "READ\n"); return READ; }
|
||||
"return" { fprintf(yyout, "RETURN\n"); return RETURN; }
|
||||
"{" { fprintf(yyout, "LBRACE\n"); return LBRACE; }
|
||||
"}" { fprintf(yyout, "RBRACE\n"); return RBRACE; }
|
||||
"(" { fprintf(yyout, "LPAREN\n"); return LPAREN; }
|
||||
")" { fprintf(yyout, "RPAREN\n"); return RPAREN; }
|
||||
"[" { fprintf(yyout, "LBRACKET\n"); return LBRACKET; }
|
||||
"]" { fprintf(yyout, "RBRACKET\n"); return RBRACKET; }
|
||||
"+" { fprintf(yyout, "PLUS\n"); return PLUS; }
|
||||
"-" { fprintf(yyout, "MINUS\n"); return MINUS; }
|
||||
"*" { fprintf(yyout, "MULT\n"); return MULT; }
|
||||
"/" { fprintf(yyout, "DIV\n"); return DIV; }
|
||||
"=" { fprintf(yyout, "ASSIGN\n"); return ASSIGN; }
|
||||
"==" { fprintf(yyout, "EQ\n"); return EQ; }
|
||||
"<" { fprintf(yyout, "LT\n"); return LT; }
|
||||
"<=" { fprintf(yyout, "LE\n"); return LE; }
|
||||
">" { fprintf(yyout, "GT\n"); return GT; }
|
||||
">=" { fprintf(yyout, "GE\n"); return GE; }
|
||||
";" { fprintf(yyout, "SEMICOLON\n"); return SEMICOLON; }
|
||||
"." { fprintf(yyout, "DOT\n"); return DOT; }
|
||||
"," { fprintf(yyout, "COMMA\n"); return COMMA; }
|
||||
[0-9]+ { yylval.intval = atoi(yytext); fprintf(yyout, "CONSTANTEXP %d\n", yylval.intval); return CONSTANTEXP; }
|
||||
[a-zA-Z_][a-zA-Z0-9_]* { yylval.strval = strdup(yytext); fprintf(yyout, "IDENTIFIER %s\n", yylval.strval); return IDENTIFIER; }
|
||||
[ \t\n]+ { /* Ignore spaces and tabs */ }
|
||||
\r\n { /* Increment line count if needed */ }
|
||||
. { fprintf(yyout, "Unknown character: %s\n", yytext); }
|
||||
|
||||
%%
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
// Open input and output files
|
||||
yyin = fopen(argv[1], "r");
|
||||
if (!yyin) {
|
||||
perror("Failed to open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
yyout = fopen(argv[2], "w");
|
||||
if (!yyout) {
|
||||
perror("Failed to open output file");
|
||||
fclose(yyin);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int token;
|
||||
while ((token = yylex()) != 0) {
|
||||
// Process tokens
|
||||
}
|
||||
fclose(yyin);
|
||||
fclose(yyout);
|
||||
yyin = fopen(argv[1], "r");
|
||||
if (!yyin) {
|
||||
perror("Failed to open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
yyout = stdout;
|
||||
if (!yyout) {
|
||||
perror("Failed to open output file");
|
||||
fclose(yyin);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Close files
|
||||
// printf("%d\n", yylex());
|
||||
// printf("%d\n", yylex());
|
||||
// printf("%d\n", yylex());
|
||||
// printf("%d\n", yylex());
|
||||
|
||||
yydebug = 1;
|
||||
if (yyparse() == 0) {
|
||||
printf("Parsing successful\n");
|
||||
} else {
|
||||
printf("Parsing failed\n");
|
||||
}
|
||||
fclose(yyin);
|
||||
fclose(yyout);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_YY_LANG_TAB_H_INCLUDED
|
||||
# define YY_YY_LANG_TAB_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 1
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
YYEMPTY = -2,
|
||||
YYEOF = 0, /* "end of file" */
|
||||
YYerror = 256, /* error */
|
||||
YYUNDEF = 257, /* "invalid token" */
|
||||
SIMPLETYPE = 258, /* SIMPLETYPE */
|
||||
CLASS = 259, /* CLASS */
|
||||
ENTRY = 260, /* ENTRY */
|
||||
IF = 261, /* IF */
|
||||
WHILE = 262, /* WHILE */
|
||||
WRITE = 263, /* WRITE */
|
||||
READ = 264, /* READ */
|
||||
RETURN = 265, /* RETURN */
|
||||
IDENTIFIER = 266, /* IDENTIFIER */
|
||||
CONSTANTEXP = 267, /* CONSTANTEXP */
|
||||
LBRACE = 268, /* LBRACE */
|
||||
RBRACE = 269, /* RBRACE */
|
||||
LPAREN = 270, /* LPAREN */
|
||||
RPAREN = 271, /* RPAREN */
|
||||
LBRACKET = 272, /* LBRACKET */
|
||||
RBRACKET = 273, /* RBRACKET */
|
||||
ASSIGN = 274, /* ASSIGN */
|
||||
EQ = 275, /* EQ */
|
||||
LT = 276, /* LT */
|
||||
LE = 277, /* LE */
|
||||
GT = 278, /* GT */
|
||||
GE = 279, /* GE */
|
||||
SEMICOLON = 280, /* SEMICOLON */
|
||||
DOT = 281, /* DOT */
|
||||
PLUS = 282, /* PLUS */
|
||||
MINUS = 283, /* MINUS */
|
||||
MULT = 284, /* MULT */
|
||||
DIV = 285, /* DIV */
|
||||
COMMA = 286 /* COMMA */
|
||||
};
|
||||
typedef enum yytokentype yytoken_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
typedef struct {
|
||||
int intval;
|
||||
char *strval;
|
||||
} YYSTYPE;
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
|
||||
int yyparse (void);
|
||||
|
||||
|
||||
#endif /* !YY_YY_LANG_TAB_H_INCLUDED */
|
||||
@@ -0,0 +1,153 @@
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void yyerror(const char *s);
|
||||
|
||||
typedef struct ASTNode {
|
||||
char *type;
|
||||
char *value;
|
||||
struct ASTNode *left;
|
||||
struct ASTNode *right;
|
||||
} ASTNode;
|
||||
|
||||
|
||||
|
||||
ASTNode *createNode(const char *type, const char *value, ASTNode *left, ASTNode *right);
|
||||
%}
|
||||
|
||||
%token SIMPLETYPE CLASS ENTRY IF WHILE WRITE READ RETURN
|
||||
%token IDENTIFIER
|
||||
%token CONSTANTEXP
|
||||
%token LBRACE RBRACE LPAREN RPAREN LBRACKET RBRACKET ASSIGN EQ LT LE GT GE SEMICOLON DOT PLUS MINUS MULT DIV
|
||||
%token COMMA
|
||||
|
||||
%start program
|
||||
|
||||
%left PLUS MINUS
|
||||
%left MULT DIV
|
||||
%left LT LE GT GE EQ
|
||||
|
||||
%%
|
||||
|
||||
program:
|
||||
CLASS IDENTIFIER LBRACE entry_declaration class_body RBRACE
|
||||
;
|
||||
|
||||
|
||||
class_body:
|
||||
%empty
|
||||
| atrib_declaration class_body
|
||||
| method_declaration class_body
|
||||
;
|
||||
atrib_declaration:
|
||||
SIMPLETYPE IDENTIFIER SEMICOLON
|
||||
| SIMPLETYPE IDENTIFIER ASSIGN CONSTANTEXP SEMICOLON
|
||||
;
|
||||
|
||||
method_declaration:
|
||||
SIMPLETYPE IDENTIFIER LPAREN method_params RPAREN LBRACE method_body RBRACE
|
||||
;
|
||||
|
||||
method_params:
|
||||
%empty
|
||||
| SIMPLETYPE IDENTIFIER
|
||||
| SIMPLETYPE IDENTIFIER COMMA method_params
|
||||
;
|
||||
|
||||
method_body:
|
||||
%empty
|
||||
| statement_list
|
||||
;
|
||||
|
||||
statement_list:
|
||||
%empty
|
||||
| statement statement_list
|
||||
;
|
||||
|
||||
statement:
|
||||
atrib_statement
|
||||
| if_statement
|
||||
| while_statement
|
||||
| write_statement
|
||||
| read_statement
|
||||
| return_statement
|
||||
;
|
||||
|
||||
atrib_statement:
|
||||
IDENTIFIER ASSIGN expression SEMICOLON
|
||||
;
|
||||
|
||||
if_statement:
|
||||
IF LPAREN expression RPAREN LBRACE statement_list RBRACE
|
||||
;
|
||||
|
||||
while_statement:
|
||||
WHILE LPAREN expression RPAREN LBRACE statement_list RBRACE
|
||||
;
|
||||
|
||||
write_statement:
|
||||
WRITE LPAREN expression RPAREN SEMICOLON
|
||||
;
|
||||
|
||||
read_statement:
|
||||
READ LPAREN IDENTIFIER RPAREN SEMICOLON
|
||||
;
|
||||
|
||||
return_statement:
|
||||
RETURN expression SEMICOLON
|
||||
;
|
||||
|
||||
expression:
|
||||
CONSTANTEXP
|
||||
| expression PLUS expression
|
||||
| expression MINUS expression
|
||||
| expression MULT expression
|
||||
| expression DIV expression
|
||||
| expression EQ expression
|
||||
| expression LT expression
|
||||
| expression LE expression
|
||||
| expression GT expression
|
||||
| expression GE expression
|
||||
| LPAREN expression RPAREN
|
||||
| IDENTIFIER
|
||||
| IDENTIFIER LBRACKET expression RBRACKET
|
||||
| LBRACKET array_list RBRACKET
|
||||
| class_method_call
|
||||
| class_expression
|
||||
;
|
||||
|
||||
class_expression:
|
||||
IDENTIFIER
|
||||
| IDENTIFIER DOT class_expression
|
||||
;
|
||||
|
||||
class_method_call:
|
||||
class_expression LPAREN array_list RPAREN
|
||||
|
||||
array_list:
|
||||
%empty
|
||||
| expression
|
||||
| expression COMMA array_list
|
||||
;
|
||||
|
||||
entry_declaration:
|
||||
SIMPLETYPE ENTRY IDENTIFIER LPAREN RPAREN LBRACE statement_list RBRACE
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(const char *s) {
|
||||
fprintf(stderr, "Error: %s\n", s);
|
||||
}
|
||||
|
||||
ASTNode *createNode(const char *type, const char *value, ASTNode *left, ASTNode *right) {
|
||||
ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));
|
||||
node->type = strdup(type);
|
||||
node->value = value ? strdup(value) : NULL;
|
||||
node->left = left;
|
||||
node->right = right;
|
||||
return node;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
#test the symbol table
|
||||
from SymbolTable import SymbolTable
|
||||
|
||||
def main():
|
||||
symbol_table = SymbolTable()
|
||||
symbol_table.addIdentifier("a", 0)
|
||||
symbol_table.addIdentifier("ba", 1)
|
||||
symbol_table.addIdentifier("ab", 2)
|
||||
print(symbol_table.getIdentifier("a"))
|
||||
print(symbol_table.getIdentifier("ba"))
|
||||
print(symbol_table.getIdentifier("ab"))
|
||||
print(symbol_table.getPositionIdentifier("a"))
|
||||
print(symbol_table.getPositionIdentifier("ba"))
|
||||
print(symbol_table.getPositionIdentifier("ab"))
|
||||
print(symbol_table.getIdentifier("d"))
|
||||
print(symbol_table.getPositionIdentifier("d"))
|
||||
symbol_table.addIdentifier("d", 4)
|
||||
print(symbol_table.getIdentifier("d"))
|
||||
print(symbol_table.getPositionIdentifier("d"))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,16 @@
|
||||
CLASS
|
||||
IDENTIFIER Main
|
||||
LBRACE
|
||||
SIMPLETYPE
|
||||
ENTRY
|
||||
IDENTIFIER Main
|
||||
LPAREN
|
||||
RPAREN
|
||||
LBRACE
|
||||
WRITE
|
||||
LPAREN
|
||||
CONSTANTEXP 1
|
||||
RPAREN
|
||||
SEMICOLON
|
||||
RBRACE
|
||||
RBRACE
|
||||
@@ -0,0 +1,5 @@
|
||||
class Main{
|
||||
void entry Main(){
|
||||
write(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Main{
|
||||
|
||||
Problem1err(number, power){
|
||||
return 01 ** power
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
class Main{
|
||||
void entry Main(){
|
||||
Problem2([3,5,7,2])
|
||||
}
|
||||
|
||||
int Problem2(int[] numbers){
|
||||
var prod = 0;
|
||||
int index = 0;
|
||||
while(index < numbers.lenght){
|
||||
int number = numbers[index];
|
||||
prod *= number;
|
||||
}
|
||||
index = index + 1;
|
||||
return prod;
|
||||
}
|
||||
|
||||
void Problem3(int[] numbers1, int[] numbers2){
|
||||
while(index < numbers.lenght){
|
||||
numbers1[index] = numbers1[index] + numbers2[index];
|
||||
index = index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class Main{
|
||||
void entry Main(){
|
||||
int[] x = [3,5,7,2]
|
||||
Problem3(x,[8,4,2,8])
|
||||
|
||||
}
|
||||
void Problem3(int[] numbers1, int[] numbers2){
|
||||
while(index < numbers.lenght){
|
||||
numbers1[index] = numbers1[index] + numbers2[index];
|
||||
index = index + 1;
|
||||
}
|
||||
}
|
||||
Problem1err(number, power){
|
||||
return number ** power
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
class
|
||||
@@ -0,0 +1,32 @@
|
||||
+
|
||||
-
|
||||
*
|
||||
/
|
||||
[
|
||||
|
||||
{
|
||||
}
|
||||
(
|
||||
)
|
||||
;
|
||||
]
|
||||
=
|
||||
<
|
||||
>
|
||||
<=
|
||||
>=
|
||||
==
|
||||
;
|
||||
,
|
||||
.
|
||||
int
|
||||
char
|
||||
class
|
||||
if
|
||||
while
|
||||
read
|
||||
write
|
||||
entry
|
||||
return
|
||||
null
|
||||
void
|
||||
Reference in New Issue
Block a user