Skip to main content

16. Construct a Shift Reduce Parser for a given language.


Constructing a Shift-Reduce Parser involves implementing a parsing algorithm that shifts tokens onto a stack and then reduces them using production rules. Since a full implementation can be quite extensive, I'll provide you with a basic example in Python and explain each line of code. Note that this example will use a simple grammar for illustration purposes.


**Example Grammar**:

```

E -> E + T | T

T -> T * F | F

F -> ( E ) | id

```


**Python Shift-Reduce Parser Example**:


```python

# Input string to be parsed

input_string = "id + id * id"


# Define grammar rules as a dictionary

grammar = {

    "E": [["E", "+", "T"], ["T"]],

    "T": [["T", "*", "F"], ["F"]],

    "F": [["(", "E", ")"], ["id"]]

}


# Define terminals and non-terminals

terminals = set(["+", "*", "(", ")", "id"])

non_terminals = set(["E", "T", "F"])


# Initialize the stack and add the starting symbol

stack = ["$"]  # $ is the end-marker

stack.append("E")


# Initialize the input pointer

input_ptr = 0


# Parsing algorithm

while len(stack) > 0:

    top = stack[-1]

    current_token = input_string[input_ptr]


    if top in terminals:

        if top == current_token:

            stack.pop()

            input_ptr += 1

        else:

            print("Error: Unexpected token")

            break

    elif top in non_terminals:

        if current_token in terminals:

            production_found = False

            for production in grammar[top]:

                if production[0] == current_token:

                    stack.pop()

                    for symbol in reversed(production[1:]):

                        if symbol != "ε":  # ε is epsilon, representing an empty string

                            stack.append(symbol)

                    production_found = True

                    break

            if not production_found:

                print("Error: No production found")

                break

        else:

            print("Error: Unexpected token")

            break

    else:

        print("Error: Invalid symbol")

        break


if len(stack) == 0 and input_ptr == len(input_string):

    print("Parsing successful")

else:

    print("Parsing failed")

```


**Explanation**:


1. We start by defining the input string and the grammar rules.

2. Terminals and non-terminals are defined separately.

3. The stack is initialized with the end-marker `$` and the starting symbol `E`.

4. We start parsing using a loop that continues until the stack is empty.

5. For each iteration, we check the top of the stack and the current input token.

6. If the top is a terminal, we compare it with the current token. If they match, we pop the stack and advance the input pointer.

7. If the top is a non-terminal and the current token is a terminal, we find a production that matches and replace the non-terminal with the right-hand side of the production.

8. If the top is a non-terminal and the current token is not a terminal, we report an error.

9. If the top is not a terminal or a non-terminal, we report an error.

10. After the loop, we check if both the stack is empty and the input pointer has reached the end of the input string to determine parsing success or failure.


Please note that this is a simplified example. Real-world parsers would involve error handling, precedence rules, and more complex grammars.


Comments

Popular posts from this blog

12. Write a program to convert NFA to DFA.

Converting a Non-Deterministic Finite Automaton (NFA) to a Deterministic Finite Automaton (DFA) involves creating a new DFA where each state corresponds to a set of NFA states reachable under certain conditions. Below is a simple Python program to perform this conversion. I'll explain each line of code: ```python from collections import defaultdict def epsilon_closure(states, transitions, epsilon):     closure = set(states)     stack = list(states)          while stack:         state = stack.pop()         for next_state in transitions[state].get(epsilon, []):             if next_state not in closure:                 closure.add(next_state)                 stack.append(next_state)          return closure def nfa_to_dfa(nfa_states, nfa_transitions, alphabet, start_state, n...