0% found this document useful (0 votes)
3 views

compiler Design lab

The document outlines various programs related to compiler writing using LEX and YACC, including their functions and formats. It also includes several C++ programs that demonstrate checking string membership in grammar, removing left recursion, performing left factoring, stack operations, finding leading non-terminals, implementing shift-reduce parsing, and checking operator precedence in grammars. Each program is provided with code snippets and descriptions of their purpose.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

compiler Design lab

The document outlines various programs related to compiler writing using LEX and YACC, including their functions and formats. It also includes several C++ programs that demonstrate checking string membership in grammar, removing left recursion, performing left factoring, stack operations, finding leading non-terminals, implementing shift-reduce parsing, and checking operator precedence in grammars. Each program is provided with code snippets and descriptions of their purpose.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 15

Program 1

Practice of LEX/YACC of compiler writing.

LEX:-

Lex is a program that generates lexical analyzer. It is used with YACC parser generator.
The lexical analyzer is a program that transforms an input stream into a sequence of tokens.
It reads the input stream and produces the source code as output through implementing the lexical analyzer
in the C program.
The function of Lex is as follows:
Firstly lexical analyzer creates a program lex.1 in the Lex language. Then Lex compiler runs the lex.1
program and produces a C program lex.yy.c.
Finally C compiler runs the lex.yy.c program and produces an object program a.out.
a.out is lexical analyzer that transforms an input stream into a sequence of tokens.

Lex file
format
A Lex

program is separated into three sections by %% delimiters. The formal of Lex source is as follows:
{ definitions }
%%
{ rules }
%%
{ user subroutines }
Definitions include declarations of constant, variable and regular definitions.
Rules define the statement of form p1 {action1} p2 {action2}....pn {action}.
Where pi describes the regular expression and action1 describes the actions what action the lexical analyzer
should take when pattern pi matches a lexeme.
User subroutines are auxiliary procedures needed by the actions. The subroutine can be loaded with the
lexical analyzer and compiled separately.
YACC

YACC stands for Yet Another Compiler Compiler.


YACC provides a tool to produce a parser for a given grammar.
YACC is a program designed to compile a LALR (1) grammar.
It is used to produce the source code of the syntactic analyzer of the language produced by LALR (1)
grammar.
The input of YACC is the rule or grammar and the output is a C program.
These are some points about YACC:
Input: A CFG- file.y

Output: A parser y.tab.c (yacc)

The output file "file.output" contains the parsing tables.


The file "file.tab.h" contains declarations.
The parser called the yyparse ().
Parser expects to use a function called yylex () to get tokens.
The basic operational sequence is as follows:

This file contains the desired grammar in YACC format.

It shows the YACC program.

It is the c source program created by YACC.


C Compiler

Executable file that will parse grammar given in gram.Y


Program 2

Write a program to check whether a string belong to the grammar or not

#include <iostream>
#include <string>
using namespace std;
bool belongsToGrammar(string str, int index) {
if (index == str.length()) {
return true;
}
if (str[index] == '0' && str[str.length() - 1 - index] == '0') {
return belongsToGrammar(str, index + 1);
}
return false;
}
int main() {
string input;
cout << "Enter a binary string: ";
cin >> input;
if (belongsToGrammar(input, 0)) {
cout << "The string belongs to the grammar." << endl;
} else {
cout << "The string does not belong to the grammar." << endl;
}
return 0;
}

Output:-
Program 3

Write a program to check whether a string include Keyword or not.

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> keywords = {"if", "else", "while", "for", "int", "float", "return", "void"};
string input;
cout << "Enter a string: ";
getline(cin, input);
bool containsKeyword = false;
for (const string& keyword : keywords) {
if (input.find(keyword) != string::npos) {
containsKeyword = true;
break;
}
}
if (containsKeyword) {
cout << "The string contains at least one keyword." << endl;
} else {
cout << "The string does not contain any keywords." << endl;
}
return 0;
}

Output:-
Program 4

Write a program to remove left Recursion from a Grammar.

#include<iostream>
#include<string>
using namespace std;
int main()
{ string ip,op1,op2,temp;
int sizes[10] = {};
char c;
int n,j,l;
cout<<"Enter the Parent Non-Terminal : ";
cin>>c;
ip.push_back(c);
op1 += ip + "\'->";
ip += "->";
op2+=ip;
cout<<"Enter the number of productions : ";
cin>>n;
for(int i=0;i<n;i++)
{ cout<<"Enter Production "<<i+1<<" : ";
cin>>temp;
sizes[i] = temp.size();
ip+=temp;
if(i!=n-1)
ip += "|";
}
cout<<"Production Rule : "<<ip<<endl;
for(int i=0,k=3;i<n;i++)
{
if(ip[0] == ip[k])
{
cout<<"Production "<<i+1<<" has left recursion."<<endl;
if(ip[k] != '#')
{
for(l=k+1;l<k+sizes[i];l++)
op1.push_back(ip[l]);
k=l+1;
op1.push_back(ip[0]);
op1 += "\'|";
}
}
else
{
cout<<"Production "<<i+1<<" does not have left recursion."<<endl;
if(ip[k] != '#')
{
for(j=k;j<k+sizes[i];j++)
op2.push_back(ip[j]);
k=j+1;
op2.push_back(ip[0]);
op2 += "\'|";
}
else
{
op2.push_back(ip[0]);
op2 += "\'";
}}}
op1 += "#";
cout<<op2<<endl;
cout<<op1<<endl;
return 0;}

Output:-
Program 5

Write a program to perform Left Factoring on a Grammar


#include <iostream>
#include <string>
using namespace std;

int main() {
string gram, part1, part2, modifiedGram, newGram, tempGram;
int pos = 0;

cout << "Enter Production: A->";


getline(cin, gram);

for (size_t i = 0; i < gram.length() && gram[i] != '|'; i++) {


part1 += gram[i];
pos = i + 1;
}

for (size_t i = pos; i < gram.length(); i++) {


part2 += gram[i];
}

for (size_t i = 0; i < part1.length() && i < part2.length(); i++) {


if (part1[i] == part2[i]) {
modifiedGram += part1[i];
pos = i + 1;
} else {
break;
}
}

for (size_t i = pos; i < part1.length(); i++) {


newGram += part1[i];
}
newGram += '|';
for (size_t i = pos; i < part2.length(); i++) {
newGram += part2[i];
}

modifiedGram += 'X';

cout << "\nGrammar Without Left Factoring:\n";


cout << "A->" << modifiedGram << endl;
cout << "X->" << newGram << endl;

return 0;
}
Output:-
Program 6

Write a program to show all the operations of a stack.


#include <iostream>
using namespace std;
int stack[100], n=100, top=-1;
void push(int val) {
if(top>=n-1)
cout<<"Stack Overflow"<<endl;
else {
top++;
stack[top]=val;
}
}
void pop() {
if(top<=-1)
cout<<"Stack Underflow"<<endl;
else {
cout<<"The popped element is "<< stack[top] <<endl;
top--;
}
}
void display() {
if(top>=0) {
cout<<"Stack elements are:";
for(int i=top; i>=0; i--)
cout<<stack[i]<<" ";
cout<<endl;
} else
cout<<"Stack is empty";
}
int main() {
int ch, val;
cout<<"1) Push in stack"<<endl;
cout<<"2) Pop from stack"<<endl;
cout<<"3) Display stack"<<endl;
cout<<"4) Exit"<<endl;
do {
cout<<"Enter choice: "<<endl;
cin>>ch;
switch(ch) {
case 1: {
cout<<"Enter value to be pushed:"<<endl;
cin>>val;
push(val);
break;
}
case 2: {
pop();
break;
}
case 3: {
display();
break;
}
case 4: {
cout<<"Exit"<<endl;
break;
}
default: {
cout<<"Invalid Choice"<<endl;
}
}
}while(ch!=4);
return 0;
}

Output:-
Program 7

Write a program to find out the leading of the non-terminals in a grammar.


#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
int n;
cout << "Enter the number of productions: ";
cin >> n;
vector<string> productions(n);

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


cout << "Enter production " << i + 1 << ": ";
cin >> productions[i];
}

vector<string> leading(n);
for (int i = 0; i < n; i++) {
leading[i] = productions[i].substr(0, 1);
for (int j = 1; j < productions[i].size(); j++) {
if (productions[i][j] == '|') {
j++;
if (j < productions[i].size()) {
if (isupper(productions[i][j])) {
leading[i] += productions[i][j];
}
}
}
}
}

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


cout << "Leading(" << productions[i][0] << ") = {" << leading[i] << "}" << endl;
}

return 0;
}

Output:-
Program 8

Write a program to Implement Shift Reduce parsing for a String.


#include <iostream>
#include <string>
using namespace std;

string ip_sym, stack;


int ip_ptr = 0, st_ptr = 0, len;
string act;

void check();

int main() {
cout << "\n\t\tSHIFT REDUCE PARSER\n";
cout << "\nGRAMMAR\n";
cout << "E -> E+E\nE -> E/E\nE -> E*E\nE -> a/b\n";

cout << "Enter the input symbol: ";


cin >> ip_sym;

cout << "\nStack Implementation Table";


cout << "\nStack\tInput Symbol\tAction";

stack = "$";
act = "shift";
len = ip_sym.length();

while (ip_ptr < len) {


stack += ip_sym[ip_ptr];
ip_sym[ip_ptr] = ' ';
ip_ptr++;

cout << "\n$" << stack << "\t" << ip_sym << "$\t" << act;

act = "shift";
act += ip_sym[ip_ptr];
check();
st_ptr++;
}

st_ptr++;
check();

return 0;
}

void check() {
string temp2 = stack.substr(st_ptr, 1);
if (temp2 == "a" || temp2 == "b") {
stack[st_ptr] = 'E';
cout << "\n$" << stack << "\t" << ip_sym << "$\tE->" << temp2;
} else if (temp2 == "+" || temp2 == "*" || temp2 == "/") {
// Do nothing for these symbols
} else if (stack.substr(st_ptr) == "E+E" || stack.substr(st_ptr) == "E/E" || stack.substr(st_ptr) == "E*E") {
stack = "E";
st_ptr = 0;
cout << "\n$" << stack << "\t" << ip_sym << "$\tE->" << stack.substr(0, 3);
} else if (stack == "E" && ip_ptr == len) {
cout << "\n$" << stack << "\t" << ip_sym << "$\tACCEPT";
exit(0);
} else {
cout << stack << "\t" << ip_sym << "\treject";
exit(0);
}
}

Output:-
Program 10

Write a program to check whether a grammar is operator precedent.


#include <iostream>
#include <string>
#include <stack>

bool isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}

bool hasHigherPrecedence(char op1, char op2) {


if ((op1 == '+' || op1 == '-') && (op2 == '*' || op2 == '/'))
return false;
return true;
}

bool isOperatorPrecedent(const std::string& expression) {


std::stack<char> operators;

for (char c : expression) {


if (isOperator(c)) {
while (!operators.empty() && hasHigherPrecedence(operators.top(), c)) {
operators.pop();
}
operators.push(c);
}
}

return operators.empty();
}

int main() {
std::string expression = "a + b * c - d";

if (isOperatorPrecedent(expression)) {
std::cout << "The grammar is operator precedent." << std::endl;
} else {
std::cout << "The grammar is not operator precedent." << std::endl;
}

return 0;
}

Output:-

You might also like