Compiler Lab3 22BPS1073
Compiler Lab3 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:
Source Code:
#include<iostream>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
goto_table[100][100];
char reduce[20][20];
char first[20][20];
stack<int> state_stack;
stack<char> symbol_stack;
struct state{
int prod_count;
char prod[100][100]={{}};
};
int state_count = 1;
for(int i=0;i<I->prod_count;i++){
I->prod[i][j] = I->prod[i][j-1];
I->prod[i][3]='.';
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++;
cin>>I->prod_count;
cin>>no_nt;
for(int i=0;i<no_nt;i++)
cin>>non_terminals[i];
cin>>no_t;
for(int i=0;i<no_t;i++)
cin>>terminals[i];
for(int i=0;i<I->prod_count;i++){
cin>>I->prod[i];
}
bool is_non_terminal(char a){
return true;
else
return false;
for(int i=0;i<I->prod_count;i++){
if(!strcmp(I->prod[i],a))
return true;
return false;
if(a[i] == '.') {
return a[i+1];
strcpy(a, b);
if(a[i] == '.') {
swap(a[i], a[i+1]);
break;
return a;
if (I0->prod_count != I->prod_count)
return false;
{
int flag = 0;
if (strcmp(I0->prod[i], I->prod[j]) == 0)
flag = 1;
if (flag == 0)
return false;
return true;
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++;
}
}
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++;
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;
in_array(a, char_after_dot(I->prod[i]))) {
a[strlen(a)] = char_after_dot(I->prod[i]);
return a;
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) {
if(terminals[i] == a)
return i;
if(non_terminals[i] == a)
return no_t + i;
return -1; // Add default return value for when no match is found
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";
if(a[i] == c)
return i;
for(int i=0;i<I->prod_count;i++){
strcat(I->prod[i],".");
for(int i=0;i<strlen(first[n]);i++)
if(first[n][i]==b)
return;
first[n][strlen(first[n])]=b;
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]);
for(int i=0;i<strlen(follow[n]);i++)
if(follow[n][i]==b)
return;
follow[n][strlen(follow[n])]=b;
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]);
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]);
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]);
}
}
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]);
for(int i=0;i<no_t;i++){
if(arr[i]==n)
return i;
return -1;
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
string get_action(int state, char input, int state_count, int* no_re, struct state* temp1) {
if(no_re[i] == state) {
if(follow[return_index(temp1->prod[i][0])-no_t][j] == input) {
return "ACC";
return "ERR";
}
bool parse_input(string input, int state_count, int* no_re, struct state* temp1) {
initialize_stacks();
int input_pos = 0;
while(true) {
while(!temp_stack.empty()) {
temp_stack.pop();
return false;
if(action == "ACC") {
return true;
state_stack.push(next_state);
symbol_stack.push(input[input_pos]);
input_pos++;
state_stack.pop();
symbol_stack.pop();
symbol_stack.push(production[0]);
if(goto_table[current_state][j] == production[0]) {
goto_state = j;
break;
if(goto_state == -1) {
return false;
}
state_stack.push(goto_state);
return false;
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]='~';
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]={};
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;
goto_table[i][k]=characters[j];;
break;
if(flag==0){ state_count+
+;
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);
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);
void parse_string() {
if (state_count <= 1) {
cout << "Parse table not generated yet. Please input productions first." << endl;
return;
string test_input;
} else {
}
// Function to show the menu and get user choice
int showMenu() {
int choice;
return choice;
int main() {
int choice;
while (!exit) {
choice = showMenu();
switch (choice) {
case 1:
// Initialize or reinitialize the parser
state_count = 1;
// Get productions
get_prods(&init);
temp = init;
temp1 = temp;
add_dots(&init);
generate_parse_table();
initialized = true;
break;
case 2:
if (initialized) {
display_parse_table();
} else {
}
break;
case 3:
if (initialized) {
parse_string();
} else {
break;
case 4:
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.
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:
Source Code:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <algorithm>
#include <iomanip>
#include <stack>
struct Production {
char left;
string right;
};
struct Item {
Production prod;
int dot;
set<char> lookahead;
}
bool operator<(const Item& other) const {
};
class CLRParser {
private:
vector<Production> grammar;
set<char> non_terminals;
set<char> terminals;
vector<set<Item>> canonical_collection;
void build_canonical_collection();
void build_parsing_table();
public:
void input_grammar();
void generate_parse_table();
void print_parse_table();
};
set<char> result;
if (s.empty() || terminals.count(s[0])) {
} else {
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;
char B = item.prod.right[item.dot];
if (non_terminals.count(B)) {
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) {
newItems.insert(newItem);
changed = true;
I.insert(newItems.begin(), newItems.end());
} while (changed);
return I;
set<Item> J;
J.insert(newItem);
return closure(J);
void CLRParser::build_canonical_collection() {
non_terminals.insert('S');
canonical_collection.push_back(initial_closure);
while (changed) {
changed = false;
if (!goto_result.empty()) {
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;
}
for (char symbol : terminals) {
if (!goto_result.empty()) {
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;
void CLRParser::build_parsing_table() {
if (item.dot == item.prod.right.length()) {
} else {
int prod_index = 0;
if (grammar[k] == item.prod) {
prod_index = k;
break;
}
action_table[{i, a}] = {'r', prod_index};
} else {
char a = item.prod.right[item.dot];
void CLRParser::input_grammar() {
int n;
cin >> n;
cin.ignore();
string line;
getline(cin, line);
size_t arrowPos = line.find("->");
if (arrowPos != string::npos) {
grammar.push_back({left, right});
non_terminals.insert(left);
} 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;
states.insert(entry.first.first);
if (!isupper(entry.first.second)) action_symbols.insert(entry.first.second);
states.insert(entry.first.first);
if (isupper(entry.first.second)) goto_symbols.insert(entry.first.second);
for (char sym : action_symbols) cout << sym << " ";
for (char sym : goto_symbols) cout << sym << " ";
// Action Table
if (action_table.count({state, sym})) {
if (action.first == 's')
cout << "s" << setw(2) << action.second << " ";
cout << "r" << setw(2) << action.second << " ";
else
} else {
// Goto Table
if (goto_table.count({state, sym})) {
stack<int> state_stack;
state_stack.push(0);
int input_pos = 0;
while (true) {
vector<int> stack_contents;
while (!temp_stack.empty()) {
stack_contents.push_back(temp_stack.top());
temp_stack.pop();
if (action_table.count({current_state, current_symbol})) {
if (action.first == 's') {
cout << "Shift, push state " << action.second << "\n";
state_stack.push(action.second);
input_pos++;
cout << "Reduce using production " << prod_index << ": "
<< grammar[prod_index].left << " -> " << grammar[prod_index].right << "\n";
state_stack.pop();
state_stack.push(goto_state);
temp_stack = state_stack;
stack_contents.clear();
while (!temp_stack.empty()) {
stack_contents.push_back(temp_stack.top());
temp_stack.pop();
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;
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.