import copy import streamlit as st stateMap = {} diction = {} start_symbol = "" rules = [] statesDict={} stateCount = 0 separatedRulesList = [] def grammarAugmentation(rules, nonterm_userdef, start_symbol): newRules = [] newChar = start_symbol + "'" while (newChar in nonterm_userdef): newChar += "'" newRules.append([newChar, ['.', start_symbol]]) for rule in rules: k = rule.split("->") lhs = k[0].strip() rhs = k[1].strip() multirhs = rhs.split('|') for rhs1 in multirhs: rhs1 = rhs1.strip().split() rhs1.insert(0, '.') newRules.append([lhs, rhs1]) return newRules def findClosure(input_state, dotSymbol): global separatedRulesList closureSet = [] if isinstance(input_state, int): for rule in separatedRulesList: if rule[0] == dotSymbol: closureSet.append(rule) else: closureSet = input_state prevLen = -1 while prevLen != len(closureSet): prevLen = len(closureSet) tempClosureSet = [] for rule in closureSet: indexOfDot = rule[1].index('.') if rule[1][-1] != '.': dotPointsHere = rule[1][indexOfDot + 1] for in_rule in separatedRulesList: if dotPointsHere == in_rule[0] and in_rule not in tempClosureSet: tempClosureSet.append(in_rule) for rule in tempClosureSet: if rule not in closureSet: closureSet.append(rule) return closureSet def compute_GOTO(state): global statesDict, stateCount generateStatesFor = [] for rule in statesDict[state]: if rule[1][-1] != '.': indexOfDot = rule[1].index('.') dotPointsHere = rule[1][indexOfDot + 1] if dotPointsHere not in generateStatesFor: generateStatesFor.append(dotPointsHere) if len(generateStatesFor) != 0: for symbol in generateStatesFor: GOTO(state, symbol) return def GOTO(state, charNextToDot): global statesDict, stateCount, stateMap newState = [] for rule in statesDict[state]: indexOfDot = rule[1].index('.') if rule[1][-1] != '.': if rule[1][indexOfDot + 1] == charNextToDot: shiftedRule = copy.deepcopy(rule) shiftedRule[1][indexOfDot] = shiftedRule[1][indexOfDot + 1] shiftedRule[1][indexOfDot + 1] = '.' newState.append(shiftedRule) addClosureRules = [] for rule in newState: indexDot = rule[1].index('.') if rule[1][-1] != '.': closureRes = findClosure(newState, rule[1][indexDot + 1]) for rule in closureRes: if rule not in addClosureRules and rule not in newState: addClosureRules.append(rule) for rule in addClosureRules: newState.append(rule) stateExists = -1 for state_num in statesDict: if statesDict[state_num] == newState: stateExists = state_num break if stateExists == -1: stateCount += 1 statesDict[stateCount] = newState stateMap[(state, charNextToDot)] = stateCount else: stateMap[(state, charNextToDot)] = stateExists return def generateStates(I0): global statesDict, stateCount statesDict[0] = I0 stateCount = 0 prev_len = -1 called_GOTO_on = [] while (len(statesDict) != prev_len): prev_len = len(statesDict) keys = list(statesDict.keys()) for key in keys: if key not in called_GOTO_on: called_GOTO_on.append(key) compute_GOTO(key) return def first(rule): global rules, term_userdef, diction, firsts if len(rule) != 0 and rule[0] in term_userdef: return [rule[0]] if len(rule) != 0 and rule[0] == '#': return ['#'] if len(rule) != 0: fres = [] rhs_rules = diction[rule[0]] for itr in rhs_rules: indivRes = first(itr) if '#' in indivRes: indivRes.remove('#') if len(rule) > 1: indivRes += first(rule[1:]) else: indivRes.append('#') fres.extend(indivRes) return list(set(fres)) return [] def follow(nt): global start_symbol, diction, firsts, follows solset = set() if nt == start_symbol: solset.add('$') for curNT in diction: rhs = diction[curNT] for subrule in rhs: if nt in subrule: while nt in subrule: index_nt = subrule.index(nt) subrule = subrule[index_nt + 1:] if subrule: res = first(subrule) if '#' in res: res.remove('#') solset.update(res) solset.update(follow(curNT)) else: solset.update(res) else: if nt != curNT: solset.update(follow(curNT)) return list(solset) def createParseTable(statesDict, stateMap, T, NT): global separatedRulesList, diction parse_table = {i: {} for i in range(len(statesDict))} for (state, symbol) in stateMap: if symbol in T: parse_table[state][symbol] = f'S{stateMap[(state, symbol)]}' elif symbol in NT: parse_table[state][symbol] = str(stateMap[(state, symbol)]) for state in statesDict: for item in statesDict[state]: if item[1][-1] == '.': prod = f"{item[0]} -> {' '.join(item[1][:-1])}" if prod == f"{separatedRulesList[0][0]} -> {separatedRulesList[0][1][1]}": parse_table[state]['$'] = 'ACC' else: rule_index = next( (i for i, rule in enumerate(separatedRulesList) if rule == item), None ) if rule_index is None: print(f"Warning: Rule for item {item} not found in separatedRulesList.") continue for symbol in T + ['$']: if symbol not in parse_table[state]: parse_table[state][symbol] = f'R{rule_index}' return parse_table def main(): st.title("SLR(1) Parser Generator") st.header("Grammar Input") rules = st.text_area("Enter the grammar rules (one per line):", "E -> E + T | T\nT -> T * F | F\nF -> ( E ) | id") rules = rules.split('\n') nonterm_userdef = st.text_input("Enter the non-terminal symbols (separated by space):", "E T F") nonterm_userdef = nonterm_userdef.split() term_userdef = st.text_input("Enter the terminal symbols (separated by space):", "id + * ( )") term_userdef = term_userdef.split() start_symbol = st.text_input("Enter the start symbol:", "E") if st.button("Generate SLR(1) Parser"): st.subheader("Original Grammar Input:") for rule in rules: st.write(rule) st.subheader("Grammar after Augmentation:") global separatedRulesList separatedRulesList = grammarAugmentation(rules, nonterm_userdef, start_symbol) for rule in separatedRulesList: st.write(f"{rule[0]} -> {' '.join(rule[1])}") start_symbol = separatedRulesList[0][0] st.subheader("Calculated Closure: I0") I0 = findClosure(0, start_symbol) st.write("I0:") for rule in I0: st.write(f"{rule[0]} -> {' '.join(rule[1])}") generateStates(I0) st.subheader("Generated States:") for state, rules in statesDict.items(): st.write(f"I{state}:") for rule in rules: st.write(f" {rule[0]} -> {' '.join(rule[1])}") st.write("") st.subheader("SLR(1) Parsing Table") table = createParseTable(statesDict, stateMap, term_userdef, nonterm_userdef) cols = ['State'] + term_userdef + ['$'] + nonterm_userdef table_data = [] for state in range(len(statesDict)): row = [f'I{state}'] for symbol in term_userdef + ['$'] + nonterm_userdef: row.append(table[state].get(symbol, '')) table_data.append(row) st.table([cols] + table_data) compact_table = "State`" + '`'.join(term_userdef + ['$'] + nonterm_userdef) + '`' for state in range(len(statesDict)): compact_table += f"I{state}" for symbol in term_userdef + ['$'] + nonterm_userdef: compact_table += table[state].get(symbol, '') st.subheader("Follow Sets") follow_sets = {} for nt in nonterm_userdef: follow_set = follow(nt) follow_sets[nt] = follow_set st.write(f"Follow({nt}): {{ {' , '.join(follow_set)} }}") compact_follow = "Non-Terminal`Follow Set\n" for nt, follow_set in follow_sets.items(): compact_follow += f"{nt}`{{ {' , '.join(follow_set)} }}\n" st.text_area("Compact Follow Sets Representation:", value=compact_follow, height=300) if __name__ == "__main__": main()