You are on page 1of 12

Name Srushti Manvendra Haryan

UID no. 2020300018

Experiment No. 4b

AIM: Program to To implement LL(1) parser in Java

Program 1

PROBLEM The problem is to develop a program that can parse a string using a given grammar and
STATEMENT : parsing table, and determine whether the string is accepted or rejected by the grammar.
The program must be able to accept the grammar and parsing table as inputs, and then
take a user-provided string as input for parsing. The program should then use the parsing
table to determine if the string can be generated by the grammar or not. The output of the
program should indicate whether the string is accepted or rejected by the grammar.

THEORY: LL(1) Parsing:


Here the 1st L represents that the scanning of the Input will be done from Left to Right
manner and the second L shows that in this parsing technique we are going to use Left
most Derivation Tree. And finally, the 1 represents the number of look-ahead, which
means how many symbols are you going to see when you want to make a decision.

Algorithm to construct LL(1) Parsing Table:

Step 1: First check for left recursion in the grammar, if there is left recursion in the
grammar remove that and go to step 2.

Step 2: Calculate First() and Follow() for all non-terminals.


First(): If there is a variable, and from that variable, if we try to drive all the strings then
the beginning Terminal Symbol is called the First.
Follow(): What is the Terminal Symbol which follows a variable in the process of
derivation.

Step 3: For each production A –> α. (A tends to alpha)


▪ Find First(α) and for each terminal in First(α), make entry A –> α in the table.
▪ If First(α) contains ε (epsilon) as terminal than, find the Follow(A) and for each
terminal in Follow(A), make entry A –> α in the table.
▪ If the First(α) contains ε and Follow(A) contains $ as terminal, then make entry A
–> α in the table for the $.
To construct the parsing table, we have two functions:

In the table, rows will contain the Non-Terminals and the column will contain the
Terminal Symbols. All the Null Productions of the Grammars will go under the Follow
elements and the remaining productions will lie under the elements of the First set.

PROGRAM: package EXP_5;

import java.util.*;

class Production {

String LHS;
List<String> RHSList;

Production() {
RHSList = new ArrayList<>();
}
}

class Table {

// Nonterminals -> (terminals -> productions)

HashMap<String, HashMap<String, Production>> table;

List<String> sb;

Stack<String> stack;

String startSymbol = "S";


Set<String> nonTerminals;
Set<String> Terminals;

Table() {
table = new HashMap<>();
stack = new Stack<>();

nonTerminals = new HashSet<>();


Terminals = new HashSet<>();

// Input window
///

//Input 1:
nonTerminals.add("S");
Terminals.add("(");
Terminals.add(")");
Terminals.add("$");

stack.push("$");

table.put("S", new HashMap<>());

Production prod1 = new Production();


prod1.LHS = "S";
prod1.RHSList = new ArrayList<>();
prod1.RHSList.add("(");
prod1.RHSList.add("S");
prod1.RHSList.add(")");

table.get("S").put("(", prod1);

Production prod2 = new Production();


prod2.LHS = "S";
prod2.RHSList = new ArrayList<>();
prod2.RHSList.add("^");

table.get("S").put(")", prod2);
table.get("S").put("$", prod2);

// Input 2:

// nonTerminals.add("S");
// Terminals.add("(");
// Terminals.add(")");
// Terminals.add("$");
// //dont consider epsilon

// stack.push("$");

// table.put("S", new HashMap<>());


// Production prod1 = new Production();
// prod1.LHS = "S";
// prod1.RHSList = new ArrayList<>();
// prod1.RHSList.add("(");
// prod1.RHSList.add("S");
// prod1.RHSList.add(")");

// table.get("S").put("(", prod1);

// Production prod2 = new Production();


// prod2.LHS = "S";
// prod2.RHSList = new ArrayList<>();
// prod2.RHSList.add("^");

// table.get("S").put(")", prod2);
// table.get("S").put("$", prod2);

/////
}

void displaySampleString(int idx){

// displays the sample string

System.out.print("[");
for(int i = 0; i <sb.size(); i++){

if(i==idx){
System.out.print("\u001B[35m"+sb.get(i)+"\u001B[0m ");

}else{
System.out.print("\u001B[0m"+sb.get(i)+"\u001B[0m ");

}
}
System.out.print("]\n");

void displayParsingTable() {

// displays the parsing table in the form of:


// (LHS, RHS) - > (corresponding production)

System.out.println("----------------------------------------------
------------------------------------");

for (String NT : table.keySet()) {

for (String terminal : table.get(NT).keySet()) {

System.out.print("["+NT+","+ terminal+"] : ");

// error wala block


if(table.get(NT).get(terminal)!=null){

List<String> list = new


ArrayList<>(table.get(NT).get(terminal).RHSList);

Iterator<String> itr = list.iterator();

System.out.print("{ "+NT+" -> ");


while (itr.hasNext()) {
System.out.print(itr.next() + " ");
}
System.out.print("}");
}else{
// the blanks lead to errors
System.out.print("Error");
}
System.out.print("\t\t");

System.out.println();

}
System.out.println("----------------------------------------------
------------------------------------");
}
void checkParsing() {

modifyString();

int index = 0;

stack.push(startSymbol); // push the start symbol in the stack, in


the beginning

while (!stack.peek().equals("$") && !sb.get(index).equals("$")) {

// left stores the stack top symbol


String left = stack.peek();

// stores the character to which the the pointer points at


that index
String right = sb.get(index);

System.out.print("Stack: ");
System.out.print("[");
Iterator<String> stkitr = stack.iterator();
while(stkitr.hasNext()){

System.out.print(stkitr.next()+" ");

}
System.out.print("]\n");
System.out.println("Stack TOP: \u001B[33m"+left+"\u001B[0m");
displaySampleString(index);
System.out.println("------------------------------------------
----------------------------------------");

// when the stack top symbol and the character on the pointer
is equal(same), pop the stack and increment the pointer
if (left.equals(right)) {
stack.pop();
index++;
continue;
}

Production currentProd = new Production();


// the corresponding production gets stored
currentProd = table.get(left).get(right);

// if there is no production that exists in that cell of the


table
if(currentProd==null){
break;
}

//RHS of a production gets stored in a list


List<String> rhsList = new ArrayList<>(currentProd.RHSList);

// if its not a null production


if (!rhsList.get(0).equals("^")) {

stack.pop();

// push the RHS of the production, in reverse order


for (int k = rhsList.size() - 1; k >= 0; k--) {
// System.out.println(rhsList.get(k));

stack.push(rhsList.get(k));
}
} else {
// if its a null production
stack.pop();
}

// if the stack top symbol is $ and the pointer on the sample


string also points at $, ACCEPT the string
if (stack.peek().equals("$") && sb.get(index).equals("$")) {
System.out.println("Stack TOP: \u001B[33m"+
stack.peek()+"\u001B[0m");
displaySampleString(index);
System.out.println("\u001B[32m Accepted \u001B[0m");
} else {
// REJECT the string in all other cases
System.out.println("\u001B[31m Rejected \u001B[0m");

}
}

void modifyString() {

sb = new ArrayList<>();
sb.add("(");
sb.add("(");
sb.add("(");
sb.add("(");
sb.add(")");
sb.add(")");
sb.add(")");
sb.add(")");
sb.add("$");

// sb.add("(");
// sb.add("(");
// sb.add("n");
// sb.add(")");
// sb.add("+");
// sb.add("i");
// sb.add(")");
// sb.add("$");

// sb.add("(");
// sb.add(")");
// sb.add("(");
// sb.add(")");
// sb.add("$");

public class ParsingTable {


public static void main(String[] args) {

Table obj = new Table();

// displays the parsing table


obj.displayParsingTable();

// checks if the string is acceptable or not


obj.checkParsing();
}
}

RESULT:

Output 1:

Accepted:
Rejected String:
Output 2:
CONCLUSION: In this experiment, I developed an LL(1) parser using Java. To create the parsing table, I
used nested hashmaps. The LL(1) parsing algorithm was implemented using a stack and
the parsing table. The program defines a user-provided string as input and parses it using
the LL(1) parsing algorithm. If the parsing is successful and the stack is empty by the
end of the input string, the program accepts the string. Otherwise, if the stack is not
empty or the input string has not been fully processed, the program rejects the string.

You might also like