File size: 7,577 Bytes
4290b1a
2dbf53a
 
4290b1a
2dbf53a
4290b1a
 
 
 
 
 
 
 
 
 
 
 
 
2fb8011
4290b1a
 
 
 
 
 
 
 
 
 
 
 
2dbf53a
4290b1a
 
 
 
2dbf53a
4290b1a
2dbf53a
4290b1a
 
 
 
 
 
2dbf53a
 
4290b1a
2fb8011
4290b1a
 
 
 
 
 
 
2dbf53a
4290b1a
 
 
 
 
2dbf53a
 
 
 
 
 
 
 
 
 
 
4290b1a
2dbf53a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4290b1a
2dbf53a
 
 
 
2fb8011
2dbf53a
2fb8011
2dbf53a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2fb8011
2dbf53a
 
 
 
 
 
2fb8011
2dbf53a
 
2fb8011
2dbf53a
 
2fb8011
2dbf53a
 
 
2fb8011
2dbf53a
 
 
 
 
 
2fb8011
2dbf53a
 
 
 
2fb8011
2dbf53a
2fb8011
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import streamlit as st
import numpy as np
import pandas as pd

# Function to remove left recursion
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

# Function for Left Factoring
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

# Function to compute the FIRST set
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

# Function to compute the FOLLOW 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

# Function to compute all FIRST sets
def computeAllFirsts(grammar):
    first_sets = {}
    for symbol in grammar:
        first(symbol, grammar, first_sets)
    return first_sets

# Function to compute all FOLLOW 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

# Function to create the LL(1) parsing table
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

# Function to validate a string using the LL(1) parsing 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."

# Main Streamlit App
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.")

    # Input Section
    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)
    
    # Input rules dynamically based on the number of rules
    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")

    # Process the inputs
    if st.button("Analyze"):
        # Parse the non-terminals and terminals
        non_terminals_list = [nt.strip() for nt in non_terminals.split(",")]
        terminals_list = [t.strip() for t in terminals.split(",")]
        
        # Parse the grammar rules
        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]

        # Remove left recursion
        grammar_dict = removeLeftRecursion(grammar_dict)

        # Apply left factoring
        grammar_dict = LeftFactoring(grammar_dict)

        # Compute FIRST and FOLLOW sets
        first_sets = computeAllFirsts(grammar_dict)
        follow_sets = computeAllFollows(grammar_dict, start_symbol, first_sets)

        # Generate parsing table
        parse_table = createParseTable(grammar_dict, first_sets, follow_sets, terminals_list)

        # Display the parsing table
        st.subheader("Parsing Table")
        st.write(parse_table)

        # Validate the input string using the parsing 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()