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

6. Generate a YACC specification to recognize a valid arithmetic expression that uses operators +, – , *,/ and parenthesis.

Below is a YACC specification for recognizing valid arithmetic expressions that involve operators (+, -, *, /) and parentheses. I'll explain each line of the code afterward: ```yacc %{ #include <stdio.h> %} %token NUMBER %left '+' '-' %left '*' '/' %% expression: expression '+' expression            | expression '-' expression            | expression '*' expression            | expression '/' expression            | '(' expression ')'            | NUMBER            ; %% int yylex() {     // Code for tokenizing input and returning tokens } void yyerror(const char *s) {     fprintf(stderr, "Error: %s\n", s); } int main() {     yyparse();     return 0; } ``` Now, let's break down the YACC specification line by line: 1. `%{` ... `%}`: This is the C code section where y...

1, Design and implement a lexical analyzer using C language to recognize all valid tokens in the input program. The lexical analyzer should ignore redundant spaces, tabs and newlines. It should also ignore comments

#include <stdio.h> #include <ctype.h> int main() {     char c;     while ((c = getchar()) != EOF) {         if (isspace(c)) {             // Ignore whitespace, tabs, and newlines             continue;         }         if (c == '/') {             // Check for comments             char nextChar = getchar();             if (nextChar == '/') {                 while ((nextChar = getchar()) != '\n');         ...

17. Write a program to perform constant propagation.

Sure, I can provide you with a basic example of a constant propagation program along with explanations for each line. Please note that this example is simplified and might not cover all possible cases of constant propagation. ```c #include <stdio.h> #include <stdbool.h> // Structure to represent an assignment statement struct Assignment {     char variable;     int value;     bool isConstant; }; int main() {     // Example assignments (variable, value, isConstant)     struct Assignment assignments[] = {         {'a', 10, true},         {'b', 20, true},         {'c', 0, true},         {'d', 30, false},         {'e', 0, false}     };     int numAssignments = sizeof(assignments) / sizeof(assignments[0]);     // Perform constant propagation     for (int i = 0; i < numAssignments; i++) { ...