0% found this document useful (0 votes)
6 views49 pages

Compiler Lab3 22BPS1073

The document outlines the implementation of an LR(0) parser, detailing the steps to construct the LR(0) parse table and perform shift-reduce parsing on an input string. It includes an algorithm for inputting grammar, augmenting it, constructing LR(0) items, generating the parsing table, and parsing the input string. Additionally, the document provides source code in C++ that implements these functionalities.

Uploaded by

teeshtakparmar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views49 pages

Compiler Lab3 22BPS1073

The document outlines the implementation of an LR(0) parser, detailing the steps to construct the LR(0) parse table and perform shift-reduce parsing on an input string. It includes an algorithm for inputting grammar, augmenting it, constructing LR(0) items, generating the parsing table, and parsing the input string. Additionally, the document provides source code in C++ that implements these functionalities.

Uploaded by

teeshtakparmar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 49

Name: Teeshta Parmar

Registration Number: 22BPS1073

ASSESSMENT 3
EXPERIMENT 1:
Aim/Objective:

To implement an LR(0) parser that constructs the LR(0) parse table using state transitions and
performs shift-reduce parsing on a given input string.

Algorithm:

Step 1: Input the Grammar

1. Read the number of productions, terminals, and non-terminals.


2. Store the grammar rules in an appropriate data structure.

Step 2: Augment the Grammar

1. Introduce a new start symbol if required and add a production rule.


2. Add a dot (.) at the beginning of each production.

Step 3: Construct the Canonical Collection of LR(0) Items

1. Create the initial state I0 by applying the closure operation.


2. For each state, determine the goto state on terminals and non-terminals.
3. If a state is new, add it to the state list; otherwise, link it to an existing state.
4. Continue until no new states can be added.

Step 4: Generate the Parsing Table

1. Construct the shift actions based on state transitions.


2. Compute reduce actions using follow sets.
3. Identify the accept state.

Step 5: Parse an Input String

1. Initialize stacks for state and symbol tracking.


2. Read the input character-by-character and determine shift/reduce actions:
o Shift: Move to the next state and push the symbol.
o Reduce: Pop symbols based on the production rule and transition to the correct
state.
o Accept: If $ is encountered in the final state, the string is accepted.
3. If an invalid state is reached, reject the input.

Source Code:

#include<iostream>

#include<stack>

#include<string.h>

#include<stdlib.h>

#include<stdio.h>

using namespace std;

char terminals[100]={};int no_t;

char non_terminals[100]={};int no_nt; char

goto_table[100][100];

char reduce[20][20];

char follow[20][20];char fo_co[20][20];

char first[20][20];

stack<int> state_stack;

stack<char> symbol_stack;

struct state{
int prod_count;

char prod[100][100]={{}};

};

// Global variables to store the parser state

struct state init;

struct state temp;

struct state temp1;

int state_count = 1;

int no_re[100] = {-1}; // Increased size for safety

void add_dots(struct state *I){

for(int i=0;i<I->prod_count;i++){

for (int j=99;j>3;j--)

I->prod[i][j] = I->prod[i][j-1];

I->prod[i][3]='.';

void augument(struct state *S,struct state *I){

if(I->prod[0][0]=='S')

strcpy(S->prod[0],"Z->.S");

else{
strcpy(S->prod[0],"S->.");

S->prod[0][4]=I->prod[0][0];}

S->prod_count++;

void get_prods(struct state *I){

cout<<"Enter the number of productions:\n";

cin>>I->prod_count;

cout<<"Enter the number of non terminals:"<<endl;

cin>>no_nt;

cout<<"Enter the non terminals one by one:"<<endl;

for(int i=0;i<no_nt;i++)

cin>>non_terminals[i];

cout<<"Enter the number of terminals:"<<endl;

cin>>no_t;

cout<<"Enter the terminals (single lettered) one by one:"<<endl;

for(int i=0;i<no_t;i++)

cin>>terminals[i];

cout<<"Enter the productions one by one in form (S->ABc):\n";

for(int i=0;i<I->prod_count;i++){

cin>>I->prod[i];

}
bool is_non_terminal(char a){

if (a >= 'A' && a <= 'Z')

return true;

else

return false;

bool in_state(struct state *I,char *a){

for(int i=0;i<I->prod_count;i++){

if(!strcmp(I->prod[i],a))

return true;

return false;

char char_after_dot(char a[100]) {

for(int i = 0; i < strlen(a); i++) {

if(a[i] == '.') {

return a[i+1];

return '\0'; // Add default return value


}

char* move_dot(char b[100], int len) {

// Allocate memory dynamically

static char a[100]; // Changed to static to persist after function returns

memset(a, 0, sizeof(a)); // Clear the array

strcpy(a, b);

for(int i = 0; i < len; i++) {

if(a[i] == '.') {

swap(a[i], a[i+1]);

break;

return a;

bool same_state(struct state *I0,struct state *I){

if (I0->prod_count != I->prod_count)

return false;

for (int i=0; i<I0->prod_count; i++)

{
int flag = 0;

for (int j=0; j<I->prod_count; j++)

if (strcmp(I0->prod[i], I->prod[j]) == 0)

flag = 1;

if (flag == 0)

return false;

return true;

void closure(struct state *I,struct state *I0){

char a={};

for(int i=0;i<I0->prod_count;i++){

a=char_after_dot(I0->prod[i]);

if(is_non_terminal(a)){

for(int j=0;j<I->prod_count;j++){

if(I->prod[j][0]==a){

if(!in_state(I0,I->prod[j])){

strcpy(I0->prod[I0->prod_count],I->prod[j]);

I0->prod_count++;

}
}

void goto_state(struct state *I,struct state *S,char a){

int time=1;

for(int i=0;i<I->prod_count;i++){

if(char_after_dot(I->prod[i])==a){

if(time==1){

time++;

strcpy(S->prod[S->prod_count],move_dot(I->prod[i],strlen(I->prod[i])));

S->prod_count++;

void print_prods(struct state *I){

for(int i=0;i<I->prod_count;i++)

printf("%s\n",I->prod[i]);

cout<<endl;

}
bool in_array(char a[20],char b){

for(int i=0;i<strlen(a);i++)

if(a[i]==b)

return true;

return false;

char* chars_after_dots(struct state *I) {

static char a[20] = {}; // Changed to static

memset(a, 0, sizeof(a)); // Clear the array

for(int i = 0; i < I->prod_count; i++) { if(!

in_array(a, char_after_dot(I->prod[i]))) {

a[strlen(a)] = char_after_dot(I->prod[i]);

return a;

void cleanup_prods(struct state * I){

char a[100]={};

for(int i=0;i<I->prod_count;i++)

strcpy(I->prod[i],a);
I->prod_count=0;

int return_index(char a) {

for(int i = 0; i < no_t; i++)

if(terminals[i] == a)

return i;

for(int i = 0; i < no_nt; i++)

if(non_terminals[i] == a)

return no_t + i;

return -1; // Add default return value for when no match is found

void print_shift_table(int state_count){

cout<<endl<<"********Shift Actions*********"<<endl<<endl;

cout<<"\t";

for(int i=0;i<no_t;i++)

cout<<terminals[i]<<"\t";

for(int i=0;i<no_nt;i++)

cout<<non_terminals[i]<<"\t";

cout<<endl;

for(int i=0;i<state_count;i++){

int arr[no_nt+no_t]={-1};
for(int j=0;j<state_count;j++){

if(goto_table[i][j]!='~'){

arr[return_index(goto_table[i][j])]= j;

cout<<"I"<<i<<"\t";

for(int j=0;j<no_nt+no_t;j++){

if(i==1&&j==no_t-1)

cout<<"ACC"<<"\t";

if(arr[j]==-1||arr[j]==0)

cout<<"\t";

else{ if(j<no_t

cout<<"S"<<arr[j]<<"\t";

else

cout<<arr[j]<<"\t";

cout<<"\n";

int get_index(char c, char *a) {


for(int i = 0; i < strlen(a); i++)

if(a[i] == c)

return i;

return -1; // Add default return value

void add_dot_at_end(struct state* I){

for(int i=0;i<I->prod_count;i++){

strcat(I->prod[i],".");

void add_to_first(int n,char b){

for(int i=0;i<strlen(first[n]);i++)

if(first[n][i]==b)

return;

first[n][strlen(first[n])]=b;

void add_to_first(int m,int n){

for(int i=0;i<strlen(first[n]);i++){

int flag=0;

for(int j=0;j<strlen(first[m]);j++){
if(first[n][i]==first[m][j])

flag=1;

if(flag==0)

add_to_first(m,first[n][i]);

void add_to_follow(int n,char b){

for(int i=0;i<strlen(follow[n]);i++)

if(follow[n][i]==b)

return;

follow[n][strlen(follow[n])]=b;

void add_to_follow(int m,int n){

for(int i=0;i<strlen(follow[n]);i++){

int flag=0;

for(int j=0;j<strlen(follow[m]);j++){

if(follow[n][i]==follow[m][j])

flag=1;

if(flag==0)
add_to_follow(m,follow[n][i]);

void add_to_follow_first(int m,int n){

for(int i=0;i<strlen(first[n]);i++){

int flag=0;

for(int j=0;j<strlen(follow[m]);j++){

if(first[n][i]==follow[m][j])

flag=1;

if(flag==0) add_to_follow(m,first[n]

[i]);

void find_first(struct state *I){

for(int i=0;i<no_nt;i++){

for(int j=0;j<I->prod_count;j++){

if(I->prod[j][0]==non_terminals[i]){

if(!is_non_terminal(I->prod[j][3])){

add_to_first(i,I->prod[j][3]);

}
}

void find_follow(struct state *I){

for(int i=0;i<no_nt;i++){

for(int j=0;j<I->prod_count;j++){

for(int k=3;k<strlen(I->prod[j]);k++){

if(I->prod[j][k]==non_terminals[i]){

if(I->prod[j][k+1]!='\0'){

if(!is_non_terminal(I->prod[j][k+1])){

add_to_follow(i,I->prod[j][k+1]);

int get_index(int *arr,int n){

for(int i=0;i<no_t;i++){
if(arr[i]==n)

return i;

return -1;

void print_reduce_table(int state_count,int *no_re,struct state *temp1){

cout<<"**********Reduce actions**********"<<endl<<endl; cout<<"\

t";

int arr[temp1->prod_count][no_t]={-1};

for(int i=0;i<no_t;i++){

cout<<terminals[i]<<"\t";

cout<<endl;

for(int i=0;i<temp1->prod_count;i++){

int n=no_re[i];

for(int j=0;j<strlen(follow[return_index(temp1->prod[i][0])-no_t]);j++){

for(int k=0;k<no_t;k++){

if(follow[return_index(temp1->prod[i][0])-no_t][j]==terminals[k]) arr[i]

[k]=i+1;

cout<<"I"<<n<<"\t";
for(int j=0;j<no_t;j++){

if(arr[i][j]!=-1&&arr[i][j]!=0&&arr[i][j]<state_count)

cout<<"R"<<arr[i][j]<<"\t";

else

cout<<"\t";

cout<<endl;

void initialize_stacks() {

// Clear stacks

while (!state_stack.empty()) state_stack.pop();

while (!symbol_stack.empty()) symbol_stack.pop();

// Initialize with starting state and symbol

state_stack.push(0); // Start state

symbol_stack.push('$'); // Bottom marker

string get_action(int state, char input, int state_count, int* no_re, struct state* temp1) {

// Check for shift action

for(int j = 0; j < state_count; j++) {


if(goto_table[state][j] == input) {

return "S" + to_string(j);

// Check for reduce action

for(int i = 0; i < temp1->prod_count; i++) {

if(no_re[i] == state) {

for(int j = 0; j < strlen(follow[return_index(temp1->prod[i][0])-no_t]); j++) {

if(follow[return_index(temp1->prod[i][0])-no_t][j] == input) {

return "R" + to_string(i+1);

// Check for accept

if(state == 1 && input == '$') {

return "ACC";

return "ERR";

}
bool parse_input(string input, int state_count, int* no_re, struct state* temp1) {

initialize_stacks();

input += '$'; // Add end marker

int input_pos = 0;

cout << "\nParsing Input: " << input << "\n";

cout << "Stack\t\tInput\t\tAction\n";

cout << " \n";

while(true) {

// Print current configuration

string stack_content = "";

stack<int> temp_stack = state_stack;

while(!temp_stack.empty()) {

stack_content = to_string(temp_stack.top()) + stack_content;

temp_stack.pop();

cout << stack_content << "\t\t" << input.substr(input_pos) << "\t\t";

string action = get_action(state_stack.top(), input[input_pos], state_count, no_re, temp1);

cout << action << "\n";


if(action == "ERR") {

cout << "Error: Invalid input string!\n";

return false;

if(action == "ACC") {

cout << "Input string accepted!\n";

return true;

if(action[0] == 'S') { // Shift action

int next_state = stoi(action.substr(1));

state_stack.push(next_state);

symbol_stack.push(input[input_pos]);

input_pos++;

else if(action[0] == 'R') { // Reduce action

int prod_num = stoi(action.substr(1)) - 1;

string production = temp1->prod[prod_num];

// Count symbols on right side of production

int rhs_length = production.length() - 4; // Subtract left side and arrow


// Pop states and symbols

for(int i = 0; i < rhs_length; i++)

state_stack.pop();

symbol_stack.pop();

// Push the non-terminal

symbol_stack.push(production[0]);

// Get goto state

int current_state = state_stack.top();

int goto_state = -1;

for(int j = 0; j < state_count; j++) {

if(goto_table[current_state][j] == production[0]) {

goto_state = j;

break;

if(goto_state == -1) {

cout << "Error: Invalid goto state!\n";

return false;
}

state_stack.push(goto_state);

return false;

// Function to generate the parse table

void generate_parse_table() {

// Clear goto_table

for(int i=0;i<100;i++)

for(int j=0;j<100;j++)

goto_table[i][j]='~';

struct state I[50];

augument(&I[0],&init);

closure(&init,&I[0]); cout<<"\

nI0:\n"; print_prods(&I[0]);

char characters[20]={};
for(int i=0;i<state_count;i++){

char characters[20]={};

for(int z=0;z<I[i].prod_count;z++) if(!

in_array(characters,char_after_dot(I[i].prod[z])))

characters[strlen(characters)]=char_after_dot(I[i].prod[z]);

for(int j=0;j<strlen(characters);j++){

goto_state(&I[i],&I[state_count],characters[j]);

closure(&init,&I[state_count]);

int flag=0;

for(int k=0;k<state_count-1;k++){

if(same_state(&I[k],&I[state_count])){

cleanup_prods(&I[state_count]);flag=1;

cout<<"I"<<i<<" on reading the symbol "<<characters[j]<<" goes to I"<<k<<".\n";

goto_table[i][k]=characters[j];;

break;

if(flag==0){ state_count+

+;

cout<<"I"<<i<<" on reading the symbol "<<characters[j]<<" goes to I"<<state_count-


1<<":\n";
goto_table[i][state_count-1]=characters[j];

print_prods(&I[state_count-1]);

terminals[no_t]='$';no_t++;

add_dot_at_end(&temp1);

for(int i=0;i<state_count;i++){

for(int j=0;j<I[i].prod_count;j++)

for(int k=0;k<temp1.prod_count;k++)

if(in_state(&I[i],temp1.prod[k]))

no_re[k]=i;

find_first(&temp);

for(int l=0;l<no_nt;l++){

for(int i=0;i<temp.prod_count;i++){

if(is_non_terminal(temp.prod[i][3])){

add_to_first(return_index(temp.prod[i][0])-no_t,return_index(temp.prod[i][3])-no_t);

}}
find_follow(&temp);

add_to_follow(0,'$');

for(int l=0;l<no_nt;l++){

for(int i=0;i<temp.prod_count;i++){

for(int k=3;k<strlen(temp.prod[i]);k++){

if(temp.prod[i][k]==non_terminals[l]){

if(is_non_terminal(temp.prod[i][k+1])){

add_to_follow_first(l,return_index(temp.prod[i][k+1])-no_t);} if(temp.prod[i]

[k+1]=='\0')

add_to_follow(l,return_index(temp.prod[i][0])-no_t);

// Function to display the parse table

void display_parse_table() {

if (state_count <= 1) {

cout << "Parse table not generated yet. Please input productions first." << endl;

return;

}
print_shift_table(state_count);

cout << endl << endl;

print_reduce_table(state_count, no_re, &temp1);

// Function to parse an input string

void parse_string() {

if (state_count <= 1) {

cout << "Parse table not generated yet. Please input productions first." << endl;

return;

string test_input;

cout << "\nEnter the input string to parse: ";

cin >> test_input;

if(parse_input(test_input, state_count, no_re, &temp1)) {

cout << "Parsing completed successfully!\n";

} else {

cout << "Parsing failed!\n";

}
// Function to show the menu and get user choice

int showMenu() {

int choice;

cout << "\n========== LR PARSER MENU ==========\n";

cout << "1. Input Productions\n";

cout << "2. Display Parse Table\n";

cout << "3. Parse Input String\n";

cout << "4. Exit\n";

cout << "Enter your choice (1-4): ";

cin >> choice;

return choice;

int main() {

int choice;

bool exit = false;

bool initialized = false;

while (!exit) {

choice = showMenu();

switch (choice) {

case 1:
// Initialize or reinitialize the parser

state_count = 1;

memset(no_re, -1, sizeof(no_re));

// Get productions

get_prods(&init);

temp = init;

temp1 = temp;

add_dots(&init);

// Generate parse table

generate_parse_table();

initialized = true;

cout << "\nProductions successfully inputted and parse table generated.\n";

break;

case 2:

if (initialized) {

display_parse_table();

} else {

cout << "\nPlease input productions first (Option 1).\n";

}
break;

case 3:

if (initialized) {

parse_string();

} else {

cout << "\nPlease input productions first (Option 1).\n";

break;

case 4:

cout << "\nExiting the program. Goodbye!\n";

exit = true;

break;

default:

cout << "\nInvalid choice. Please enter a number between 1 and 4.\n";

return 0;

}
Conclusion:

The implemented LR(0) parser successfully constructs the parsing table and processes an input
string using shift-reduce parsing. It correctly determines whether a string belongs to the
language defined by the grammar, validating the working of the LR(0) parsing method.

Input and Output :


EXPERIMENT 2:
Aim/Objective:

To implement a CLR(1) parser that constructs the CLR(1) parse table using canonical LR(1) items
and performs shift-reduce parsing to validate input strings based on a given grammar.

Algorithm:

1. Input the Grammar


o Read the number of grammar productions.
o Store terminals and non-terminals separately.
o Augment the grammar by adding a new start symbol.
2. Compute FIRST Sets
o Determine the FIRST set for each symbol.
3. Compute Closure of an Item Set
o Generate initial items and expand using productions.
4. Compute GOTO Function
o Shift the dot past the next symbol to create new items.
5. Construct the Canonical LR(1) Collection
o Start with the augmented grammar closure and apply GOTO for all symbols.
6. Build the Parsing Table
o Add shift, reduce, accept, and goto actions based on items.
7. Parse an Input String
o Initialize stack and read input.
o Perform shift, reduce, or accept actions using the parse table.
o Reject if no valid action is found.

Source Code:

#include <iostream>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <algorithm>

#include <iomanip>
#include <stack>

using namespace std;

struct Production {

char left;

string right;

bool operator==(const Production& other) const {

return left == other.left && right == other.right;

};

struct Item {

Production prod;

int dot;

set<char> lookahead;

bool operator==(const Item& other) const {

return prod == other.prod && dot == other.dot && lookahead == other.lookahead;

}
bool operator<(const Item& other) const {

if (prod.left != other.prod.left) return prod.left < other.prod.left;

if (prod.right != other.prod.right) return prod.right < other.prod.right;

if (dot != other.dot) return dot < other.dot;

return lookahead < other.lookahead;

};

class CLRParser {

private:

vector<Production> grammar;

set<char> non_terminals;

set<char> terminals;

vector<set<Item>> canonical_collection;

map<pair<int, char>, int> goto_table;

map<pair<int, char>, pair<char, int>> action_table;

set<char> first(const string& s);

set<Item> closure(set<Item> I);

set<Item> go_to(const set<Item>& I, char X);

void build_canonical_collection();

void build_parsing_table();
public:

void input_grammar();

void generate_parse_table();

void print_parse_table();

bool parse_string(const string& input);

};

set<char> CLRParser::first(const string& s) {

set<char> result;

if (s.empty() || terminals.count(s[0])) {

result.insert(s.empty() ? '$' : s[0]);

} else {

for (auto& prod : grammar) {

if (prod.left == s[0]) {

auto f = first(prod.right);

result.insert(f.begin(), f.end());

return result;

}
set<Item> CLRParser::closure(set<Item> I) {

bool changed;

do {

changed = false;

set<Item> newItems;

for (const auto& item : I) {

if (item.dot < item.prod.right.length()) {

char B = item.prod.right[item.dot];

if (non_terminals.count(B)) {

string beta = item.prod.right.substr(item.dot + 1);

set<char> firstBeta;

if(beta.empty()){

firstBeta = item.lookahead;

else{

firstBeta = first(beta);

if(firstBeta.count('$'))

firstBeta.erase('$');

firstBeta.insert(item.lookahead.begin(), item.lookahead.end());

}
for (auto& prod : grammar) {

if (prod.left == B) {

Item newItem = {prod, 0, firstBeta};

if (I.count(newItem) == 0 && newItems.count(newItem) == 0) {

newItems.insert(newItem);

changed = true;

I.insert(newItems.begin(), newItems.end());

} while (changed);

return I;

set<Item> CLRParser::go_to(const set<Item>& I, char X) {

set<Item> J;

for (const auto& item : I) {

if (item.dot < item.prod.right.length() && item.prod.right[item.dot] == X) {

Item newItem = item;


newItem.dot++;

J.insert(newItem);

return closure(J);

void CLRParser::build_canonical_collection() {

grammar.insert(grammar.begin(), {'S', string(1, grammar[0].left)});

non_terminals.insert('S');

Production augmented_grammar = {'S', string(1, grammar[0].left)};

Item initial_item = {augmented_grammar, 0, {'$'}};

set<Item> initial_state = {initial_item};

set<Item> initial_closure = closure(initial_state);

canonical_collection.push_back(initial_closure);

bool changed = true;

while (changed) {

changed = false;

int num_states = canonical_collection.size();

for (int i = 0; i < num_states; ++i) {

for (char symbol : non_terminals) {


set<Item> goto_result = go_to(canonical_collection[i], symbol);

if (!goto_result.empty()) {

bool state_exists = false;

int state_index = -1;

for (int j = 0; j < canonical_collection.size(); ++j) {

if (canonical_collection[j] == goto_result) {

state_exists = true;

state_index = j;

break;

if (!state_exists) {

canonical_collection.push_back(goto_result);

state_index = canonical_collection.size() - 1;

changed = true;

goto_table[{i, symbol}] = state_index;

}
for (char symbol : terminals) {

set<Item> goto_result = go_to(canonical_collection[i], symbol);

if (!goto_result.empty()) {

bool state_exists = false;

int state_index = -1;

for (int j = 0; j < canonical_collection.size(); ++j) {

if (canonical_collection[j] == goto_result) {

state_exists = true;

state_index = j;

break;

if (!state_exists) {

canonical_collection.push_back(goto_result);

state_index = canonical_collection.size() - 1;

changed = true;

goto_table[{i, symbol}] = state_index;


}

void CLRParser::build_parsing_table() {

for (int i = 0; i < canonical_collection.size(); i++) {

for (const auto& item : canonical_collection[i]) {

if (item.dot == item.prod.right.length()) {

Production augmented_grammar = {'S', string(1, grammar[0].left)}; // Corrected


augmented grammar

if (item.prod.left == 'S' && item.prod.right == grammar[0].right &&


item.lookahead.count('$')) {

action_table[{i, '$'}] = {'a', 0};

} else {

for (char a : item.lookahead) {

int prod_index = 0;

for (int k = 1; k < grammar.size(); k++) {

if (grammar[k] == item.prod) {

prod_index = k;

break;

}
action_table[{i, a}] = {'r', prod_index};

} else {

char a = item.prod.right[item.dot];

if (terminals.count(a) && goto_table.count({i, a})) {

action_table[{i, a}] = {'s', goto_table[{i, a}]};

void CLRParser::input_grammar() {

int n;

cout << "Enter the number of productions: ";

cin >> n;

cin.ignore();

cout << "Enter the productions (format: A->aBc):" << endl;

for (int i = 0; i < n; i++) {

string line;

getline(cin, line);
size_t arrowPos = line.find("->");

if (arrowPos != string::npos) {

char left = line[0];

string right = line.substr(arrowPos + 2);

grammar.push_back({left, right});

non_terminals.insert(left);

for (char c : right) {

if (!isupper(c) && c != '\'') terminals.insert(c);

} else {

cout << "Invalid production format: " << line << endl;

terminals.insert('$');

void CLRParser::generate_parse_table() {

input_grammar();

build_canonical_collection();

build_parsing_table();

void CLRParser::print_parse_table() {
// Find all states and symbols

set<int> states;

set<char> action_symbols, goto_symbols;

for (const auto& entry : action_table) {

states.insert(entry.first.first);

if (!isupper(entry.first.second)) action_symbols.insert(entry.first.second);

for (const auto& entry : goto_table) {

states.insert(entry.first.first);

if (isupper(entry.first.second)) goto_symbols.insert(entry.first.second);

// Print table headers

cout << "State | Action Table | Goto Table\n";

cout << " | ";

for (char sym : action_symbols) cout << sym << " ";

cout << "| ";

for (char sym : goto_symbols) cout << sym << " ";

cout << "\n";

cout << string(6 + 4 * action_symbols.size() + 3 + 4 * goto_symbols.size(), '-') << "\n";

// Print table contents

for (int state : states) {


cout << setw(5) << state << " | ";

// Action Table

for (char sym : action_symbols) {

if (action_table.count({state, sym})) {

auto action = action_table[{state, sym}];

if (action.first == 's')

cout << "s" << setw(2) << action.second << " ";

else if (action.first == 'r')

cout << "r" << setw(2) << action.second << " ";

else

cout << "acc ";

} else {

cout << " ";

cout << "| ";

// Goto Table

for (char sym : goto_symbols) {

if (goto_table.count({state, sym})) {

cout << setw(3) << goto_table[{state, sym}] << " ";


} else {

cout << " ";

cout << "\n";

bool CLRParser::parse_string(const string& input) {

stack<int> state_stack;

state_stack.push(0);

int input_pos = 0;

cout << "Parsing Steps:\n";

cout << "Stack\t\t\tInput\t\t\tAction\n";

cout << "-----\t\t\t-----\t\t\t-----\n";

while (true) {

int current_state = state_stack.top();

char current_symbol = (input_pos < input.length()) ? input[input_pos] : '$';

// Print current stack and input

cout << "[";


stack<int> temp_stack = state_stack;

vector<int> stack_contents;

while (!temp_stack.empty()) {

stack_contents.push_back(temp_stack.top());

temp_stack.pop();

for (auto it = stack_contents.rbegin(); it != stack_contents.rend(); ++it) {

cout << *it << " ";

cout << "]\t\t\t" << input.substr(input_pos) << "$\t\t\t";

if (action_table.count({current_state, current_symbol})) {

auto action = action_table[{current_state, current_symbol}];

if (action.first == 's') {

cout << "Shift, push state " << action.second << "\n";

state_stack.push(action.second);

input_pos++;

} else if (action.first == 'r') {

int prod_index = action.second;

int pop_count = grammar[prod_index].right.length();

cout << "Reduce using production " << prod_index << ": "
<< grammar[prod_index].left << " -> " << grammar[prod_index].right << "\n";

for (int i = 0; i < pop_count; i++) {

state_stack.pop();

int goto_state = goto_table[{state_stack.top(), grammar[prod_index].left}];

state_stack.push(goto_state);

// Print Goto action

cout << "[";

temp_stack = state_stack;

stack_contents.clear();

while (!temp_stack.empty()) {

stack_contents.push_back(temp_stack.top());

temp_stack.pop();

for (auto it = stack_contents.rbegin(); it != stack_contents.rend(); ++it) {

cout << *it << " ";

cout << "]\t\t\t" << input.substr(input_pos) << "$\t\t\t";

cout << "Goto state " << goto_state << "\n";

} else if (action.first == 'a') {


cout << "Accept\n";

return true;

} else {

cout << "Error: No action defined for state " << current_state << " and symbol " <<
current_symbol << "\n";

return false;

int main() {

CLRParser parser;

parser.generate_parse_table();

parser.print_parse_table();

string input;

cout << "Enter a string to parse: ";

cin >> input;

if (parser.parse_string(input)) {
cout << "The input string is valid according to the grammar." << endl;

} else {

cout << "The input string is not valid according to the grammar." << endl;

Conclusion:

The implemented CLR(1) parser correctly constructs the parsing table and parses an input string
using shift-reduce parsing. It ensures accurate and conflict-free parsing decisions using
lookaheads.

Input and Output:

You might also like