|
import streamlit as st |
|
import numpy as np |
|
import pandas as pd |
|
|
|
|
|
def removeLeftRecursion(rulesDiction): |
|
store = {} |
|
for lhs in rulesDiction: |
|
alphaRules = [] |
|
betaRules = [] |
|
allrhs = rulesDiction[lhs] |
|
for subrhs in allrhs: |
|
if subrhs[0] == lhs: |
|
alphaRules.append(subrhs[1:]) |
|
else: |
|
betaRules.append(subrhs) |
|
if len(alphaRules) != 0: |
|
lhs_ = lhs + "'" |
|
while (lhs_ in rulesDiction.keys()) or (lhs_ in store.keys()): |
|
lhs_ += "'" |
|
for b in range(len(betaRules)): |
|
betaRules[b].append(lhs_) |
|
rulesDiction[lhs] = betaRules |
|
for a in range(len(alphaRules)): |
|
alphaRules[a].append(lhs_) |
|
alphaRules.append(['#']) |
|
store[lhs_] = alphaRules |
|
for left in store: |
|
rulesDiction[left] = store[left] |
|
return rulesDiction |
|
|
|
|
|
def LeftFactoring(rulesDiction): |
|
newDict = {} |
|
for lhs in rulesDiction: |
|
allrhs = rulesDiction[lhs] |
|
temp = dict() |
|
for subrhs in allrhs: |
|
if subrhs[0] not in temp.keys(): |
|
temp[subrhs[0]] = [subrhs] |
|
else: |
|
temp[subrhs[0]].append(subrhs) |
|
new_rule = [] |
|
tempo_dict = {} |
|
for term_key in temp: |
|
allStartingWithTermKey = temp[term_key] |
|
if len(allStartingWithTermKey) > 1: |
|
lhs_ = lhs + "'" |
|
while (lhs_ in rulesDiction.keys()) or (lhs_ in tempo_dict.keys()): |
|
lhs_ += "'" |
|
new_rule.append([term_key, lhs_]) |
|
ex_rules = [] |
|
for g in temp[term_key]: |
|
ex_rules.append(g[1:]) |
|
tempo_dict[lhs_] = ex_rules |
|
else: |
|
new_rule.append(allStartingWithTermKey[0]) |
|
newDict[lhs] = new_rule |
|
for key in tempo_dict: |
|
newDict[key] = tempo_dict[key] |
|
return newDict |
|
|
|
|
|
def first(symbol, grammar, first_sets): |
|
if symbol in first_sets: |
|
return first_sets[symbol] |
|
first_set = set() |
|
if symbol not in grammar: |
|
first_set.add(symbol) |
|
else: |
|
for rule in grammar[symbol]: |
|
if rule == ['#']: |
|
first_set.add('#') |
|
else: |
|
for s in rule: |
|
first_set |= first(s, grammar, first_sets) |
|
if '#' not in first(s, grammar, first_sets): |
|
break |
|
first_sets[symbol] = first_set |
|
return first_set |
|
|
|
|
|
def follow(symbol, grammar, start_symbol, follow_sets, first_sets): |
|
if symbol in follow_sets: |
|
return follow_sets[symbol] |
|
follow_set = set() |
|
if symbol == start_symbol: |
|
follow_set.add('$') |
|
for lhs in grammar: |
|
for rule in grammar[lhs]: |
|
for i, s in enumerate(rule): |
|
if s == symbol: |
|
if i + 1 < len(rule): |
|
follow_set |= first(rule[i + 1], grammar, first_sets) - {'#'} |
|
if i + 1 == len(rule) or '#' in first(rule[i + 1], grammar, first_sets): |
|
follow_set |= follow(lhs, grammar, start_symbol, follow_sets, first_sets) |
|
follow_sets[symbol] = follow_set |
|
return follow_set |
|
|
|
|
|
def computeAllFirsts(grammar): |
|
first_sets = {} |
|
for symbol in grammar: |
|
first(symbol, grammar, first_sets) |
|
return first_sets |
|
|
|
|
|
def computeAllFollows(grammar, start_symbol, first_sets): |
|
follow_sets = {} |
|
for symbol in grammar: |
|
follow(symbol, grammar, start_symbol, follow_sets, first_sets) |
|
return follow_sets |
|
|
|
|
|
def createParseTable(grammar, first_sets, follow_sets, terminals): |
|
parse_table = {} |
|
for lhs in grammar: |
|
for rule in grammar[lhs]: |
|
first_set = first(rule[0], grammar, first_sets) |
|
for terminal in first_set - {'#'}: |
|
if lhs not in parse_table: |
|
parse_table[lhs] = {} |
|
parse_table[lhs][terminal] = rule |
|
if '#' in first_set: |
|
for terminal in follow_sets[lhs]: |
|
if lhs not in parse_table: |
|
parse_table[lhs] = {} |
|
parse_table[lhs][terminal] = rule |
|
return parse_table |
|
|
|
|
|
def validateStringUsingStackBuffer(parse_table, grammar_is_LL, terminals, input_string, term_userdef, start_symbol): |
|
stack = [start_symbol] |
|
input_string = input_string + ['$'] |
|
idx = 0 |
|
while stack: |
|
top = stack[-1] |
|
if top == input_string[idx]: |
|
stack.pop() |
|
idx += 1 |
|
elif top in parse_table and input_string[idx] in parse_table[top]: |
|
rule = parse_table[top][input_string[idx]] |
|
stack.pop() |
|
if rule != ['#']: |
|
stack.extend(reversed(rule)) |
|
else: |
|
return "String is not valid." |
|
if idx == len(input_string): |
|
return "String is valid." |
|
return "String is not valid." |
|
|
|
|
|
def main(): |
|
st.title("Grammar Analyzer") |
|
st.markdown("This app performs grammar analysis, including left recursion removal, left factoring, FIRST/FOLLOW set calculations, and LL(1) parsing.") |
|
|
|
|
|
st.sidebar.header("Input Parameters") |
|
start_symbol = st.text_input("Start Symbol (Non-terminal):", "S") |
|
num_rules = st.number_input("Number of Grammar Rules:", min_value=1, value=4) |
|
|
|
|
|
grammar_rules = [] |
|
for i in range(num_rules): |
|
rule = st.text_input(f"Rule {i + 1}:", f"S -> A k O") |
|
grammar_rules.append(rule) |
|
|
|
non_terminals = st.text_input("Non-Terminals (comma-separated):", "S, A, B, C") |
|
terminals = st.text_input("Terminals (comma-separated):", "a, b, c, d, k, r, O") |
|
|
|
|
|
if st.button("Analyze"): |
|
|
|
non_terminals_list = [nt.strip() for nt in non_terminals.split(",")] |
|
terminals_list = [t.strip() for t in terminals.split(",")] |
|
|
|
|
|
grammar_dict = {} |
|
for rule in grammar_rules: |
|
lhs, rhs = rule.split("->") |
|
rhs_options = rhs.split("|") |
|
grammar_dict[lhs.strip()] = [option.strip().split() for option in rhs_options] |
|
|
|
|
|
grammar_dict = removeLeftRecursion(grammar_dict) |
|
|
|
|
|
grammar_dict = LeftFactoring(grammar_dict) |
|
|
|
|
|
first_sets = computeAllFirsts(grammar_dict) |
|
follow_sets = computeAllFollows(grammar_dict, start_symbol, first_sets) |
|
|
|
|
|
parse_table = createParseTable(grammar_dict, first_sets, follow_sets, terminals_list) |
|
|
|
|
|
st.subheader("Parsing Table") |
|
st.write(parse_table) |
|
|
|
|
|
input_string = st.text_input("Enter string to validate:", "a c") |
|
validation_result = validateStringUsingStackBuffer(parse_table, True, terminals_list, input_string.split(), terminals_list, start_symbol) |
|
st.write(validation_result) |
|
|
|
if __name__ == "__main__": |
|
main() |
|
|