Escolar Documentos
Profissional Documentos
Cultura Documentos
Q1:
a) Program to check if grammar is Left-Recursive, if it is then remove left-recursion so
parser can use it.
b) How compiler will handle these errors?
#include<iostream>
#include<string.h>
using namespace std;
class rec{
public:
char S[10], A[10];
char left1, left2;
int i = 0;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
int j = 0, k = 0;
int q = 0, o = 0;
}
alpha[j] = '|';
j++;
i = c;
COMPILER CONSTRUCTION LAB BOOK - 153158
alpha[j] = '\o';
flag1 = true;
}
else if (temp2[i] != left){
int z = i;
while (temp2[z] != '|' && temp2[z] != '\o'){
beta[k] = temp2[z];
z++;
k++;
}
beta[k] = '|';
k++;
i = z;
beta[k] = '\o';
flag2 = true;
}
}
cout << "\n----------\n";
if (flag1 == true){
cout << "\nalpha= ";
for (i = 0; alpha[i] != '\o'; i++)
cout << alpha[i] << " ";
}
if (flag2 == true){
cout << "\nbeta= ";
for (i = 0; beta[i] != '\o'; i++)
cout << beta[i] << " ";
}
cout << "\n----------form\n";
cout << "A= ";
for (i = 0; beta[i] != '\o'; i++){
if (beta[i] != '|')
cout << beta[i];
else
cout << " A'|";
}
cout << "\n-----------\n";
cout << "A'= ";
for (i = 0; alpha[i] != '\o'; i++){
while (alpha[i] != '|'){
cout << alpha[i]; i++;
}
cout << " A'|";
}
cout << "^";
cout << endl;
}
COMPILER CONSTRUCTION LAB BOOK - 153158
} r;
int main(){
r.S[len1] = '\o';
r.A[len2] = '\o';
r.left1 = r.S[0];
r.left2 = r.A[0];
cout << "\nleft1= " << r.left1 << "\nleft2= " << r.left2;
cout << "\n---------------------------------\n";
p++;
COMPILER CONSTRUCTION LAB BOOK - 153158
}
for (int g = 0; g<(strlen(r.temp1)); g++){
r.temp2[r.q] = r.temp1[g];
r.q++;
}
r.temp2[r.q] = '|';
r.q++;
}
i = h;
}
else if (r.S[i] != r.left2){
r.temp2[r.q] = r.S[i];
r.q++;
}
}
r.temp2[r.q] = '\o';
cout << endl;
1)
Error 1:
Int scope_one;
{
Int scope_one;
{
Int scope_one;
}
}
Ans: There is an issue with the global scope. I can be resolved by defining the scope.
2)
Error 2:
Int arr[10];
COMPILER CONSTRUCTION LAB BOOK - 153158
arr[15] = “”;
Ans: Invalid conversion from constant char to int. We have to change the commas to the {} brackets.
3) Do Compilers allocate storage for statements, in which storage area, these statements will be
stored and calc space required to allocate?
Int var;
Int arr[10];
Ans: Student was not declared in this scope. We have to declare it first. The memory allocation work as
the followings:
COMPILER CONSTRUCTION LAB BOOK - 153158
Q2:
a) Count words, chars, and spaces in flex
%{
int ch=0, bl=0, ln=0, wr=0;
%}
%%
[\n] {ln++;wr++;}
[\t] {bl++;wr++;}
[" "] {bl++;wr++;}
[^\n\t] {ch++;}
%%
int main()
{
FILE *fp;
char file[10];
printf("Enter the filename: ");
scanf("%s", file);
stdin=fp;
yylex();
printf("Character=%d\nBlank=%d\nLines=%d\nWords=%d", ch, bl, ln, wr);
return 0;
}
Enter the filename: input
Character=16
Blank=2
Lines=1
Word=3
#include<iostream>
#include <string>
using namespace std;
int main() {
while (1)
{
char input[20];
int inc = 1, buffer=0, d=0;
cin >> input;
if(input[0]=='a')
{
while (inc<20)
{
if (input[inc]=='a'&& buffer!=0)
{
d++;
}
COMPILER CONSTRUCTION LAB BOOK - 153158
else if (c[inc]=='b')
{
buffer++;
}
inc++;
}
}
else if (input[0]=='b')
{
buffer++;
while (inc<20)
{
if (input[inc] == 'a')
{
d++;
}
inc++;
}
}
if (d == 0 && buffer >= 1 )
{
cout << " Recognized" << endl;
}
if (d > 0 || buffer==0)
{
cout << " Not Recognized" << endl;
}
}
return 0;
}
Q3:
a) For Calculator, Recognition of Numbers, Operators, Parenthesis (flex/tex tool)
%{
#include <stdio.h>
%}
%%
[0-9][0-9]* {return printf("Number ");}
"+"|"-"|"*"|"/" {return printf("Operator ");}
"(" {return printf("Start Parenthesis ");}
")" {return printf("End Parenthesis ");}
%%
int yywrap()
{
COMPILER CONSTRUCTION LAB BOOK - 153158
return 1;
}
int main()
{
printf("\nEnter an expression: ");
while(1)
{
yylex();
}
}
#include <iostream>
using namespace std;
int main()
{
cout << "LL Parser for" <<endl<<"A --> +AA "<<endl<<"A --> -AA"<<endl<<"A -->
0|1|2|3|4|5|6|7|8|9" << endl << endl << endl;
while (1)
{
char a[ ] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
cout << "Enter EXPRESSION = ";
cin >> a;
int i = 0, s = 0, n = 0,e=0;
if (a[0] == '+' || a[0] == '-')
{
s++;
i++;
while (a[i] != 'x')
{
if (a[i] == '-' || a[i] == '+')
{
s++;
}
if (a[i] == '0' || a[i] == '1' || a[i] == '2' || a[i] == '3' || a[i] == '4' || a[i] == '5' || a[i] == '6' || a[i] == '7'
|| a[i] == '8' || a[i] == '9')
{
n++;
}
i++;
}
i--;
i--;
if (a[i] != '0'&&a[i] != '1'&&a[i] != '2'&&a[i] != '3'&&a[i] != '4'&&a[i] != '5'&&a[i] != '6'&&a[i] !=
'7'&&a[i] != '8'&&a[i] != '9')
{
e++;
COMPILER CONSTRUCTION LAB BOOK - 153158
}
i--;
if (a[i] != '0'&&a[i] != '1'&&a[i] != '2'&&a[i] != '3'&&a[i] != '4'&&a[i] != '5'&&a[i] != '6'&&a[i] !=
'7'&&a[i] != '8'&&a[i] != '9')
{
e++;
}
}
if (n - s == 1 && e == 0)
{
cout << "acepted" << endl;
}
else
{
cout << "rejected" << endl;
}
}
return 0;
}
Q4:
Operator Precedence Evaluation in C (Compiler Perspective)
Q6:
Simple LL Parser for syntax checking. Take any simple grammar for this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
while(1)
{
int i,a=0,t=0;
char input[20];
printf("\nEnter a string: ");
scanf("%s", input);
for(i=0; i<10; i++)
{ switch(input[i])
{
case '-':
case '+':
if(a > 0)
{t++;}
a++;
break;
case '0':
case '1':
case '2':
COMPILER CONSTRUCTION LAB BOOK - 153158
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
t++;
break;
}
if(t == 2)
{
t = 0;
a--;
}}
if(((a >= 0 && t !=1) || (a == 1 && t ==1)) && input[19]!='+' && input[19]!='-')
{
printf("\nAccept! a %d, t %d", a, t);
}
else
{
printf("\nReject! a %d, t %d", a, t);
}}
return 0;
}
Q7:
Get User Input in Char array and tokenize them according to their role
#include <iostream>
#include <limits>
#include <cstring>
using namespace std;
// Tokenization
for(int i=0 ; i<array_size; i++)
{
if (inputChar[i] != NULL)
{
char single_char = inputChars[i];
if(single_char == ' ' || single_char == ';')
{
CharToStr(token, tokenArray, array_size);
token = "";
}
else
{
token += single_char;
}}}
// Print Tokens
cout << "\nTokens" << endl;
COMPILER CONSTRUCTION LAB BOOK - 153158
Q8:
What are the ways to pass parameters in functions? How compiler handle them?
There are different ways in which parameter data can be passed into and out of methods and functions.
Let us assume that a function B() is called from another function A(). In this case A is called the “caller
function” and B is called the “called function or callee function”. Also, the arguments which A sends
to B are called actual arguments and the parameters of B are called formal arguments.
COMPILER CONSTRUCTION LAB BOOK - 153158
Terminology
Formal Parameter: A variable and its type as they appear in the prototype of the function or
method.
Actual Parameter: The variable or expression corresponding to a formal parameter that appears
in the function or method call in the calling environment.
Modes:
IN: Passes info from caller to calle.
OUT: Callee writes values in caller.
IN/OUT: Caller tells callee value of variable, which may be updated by callee.
// Passing parameters
func(x, y);
printf("In main, x = %d y = %d\n", x, y);
return 0;
}
Output:
In func, a = 12 b = 7
In main, x = 5 y = 7
Shortcomings:
Inefficiency in storage allocation
For objects and arrays, the copy semantics are costly
Pass by reference (aliasing): This technique uses in/out-mode semantics. Changes made to formal
parameter do get transmitted back to the caller through parameter passing. Any changes to the formal
parameter are reflected in the actual parameter in the calling environment as formal parameter receives
a reference (or pointer) to the actual data. This method is also called as <em>call by reference. This
method is efficient in both time and space.
COMPILER CONSTRUCTION LAB BOOK - 153158
// C program to illustrate
// call by reference
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
// passing parameters
swapnum(&a, &b);
C and C++ both support call by value as well as call by reference whereas Java doesn’t support call by
reference.
Shortcomings:
Many potential scenarios can occur
Programs are difficult to understand sometimes
Q9:
a) Write algorithm to Simulate DFA
#include <iostream>
using namespace std;
int main()
{
string str;
while(1)
{
cout << "Enter the string: ";
bool accept = false;
getline(cin, str);
for (int i=0; i<str.size(); i++)
{
COMPILER CONSTRUCTION LAB BOOK - 153158
if(i==0)
{
if(str[i]== 'a')
{
accept = true;
continue;
}}
if(accept == true)
{
if(str[i]== 'b')
{
accept = true;
continue;
}
else
{
accept = false;
continue;
}}}
if(accept == true)
{
cout<< "Accepted\n";
}
else
{
cout<< "Rejected\n";
}}}
Back patching: The syntax directed definition can be implemented in two or more passes (we have both
synthesized attributes and inherited attributes).
The main difficulty with code generation in one pass is that we may not know the target of a branch
when we generate code for flow of control statements
Back patching is the technique to get around this problem. Generate branch instructions with empty
targets when the target is known, fill in the label of the branch instructions (back patching).
c) Suggest suitable approach for computing hash functions, and where hash fucntions can
be used in compiler?
COMPILER CONSTRUCTION LAB BOOK - 153158
#include <stdio.h>
#define SumOf(x,y) (x)+(y)
void main() {
int arg1=1, arg2=7;
printf("\narg1=%i,arg2=%i",arg1,arg2);
printf("\nSumOf(arg1,arg2)=%i",SumOf(arg1,arg2));
printf("\n2*SumOf(arg1,arg2)=%i",2*SumOf(arg1,arg2));
}
a = b * c + b * d;
_t1 = b * c;
_t2 = b * d;
_t3 = _t1 + _t2;
a = _t3;
if (a < b + c)
a = a - c;
c = b * c;
_t1 = b + c;
_t2 = a < _t1;
If Z _t2 Goto _L0;
_t3 = a - c;
a = _t3;
_L0: _t4 = b * c;
c = _t4;
#include <stdio.h>
#include <string.h>
int main(void) {
char text[] = "I love Pakistan!";
int len = strlen(text);
return 0;
}
Hexadecimal to Binary:
#include <stdio.h>
#define MAX 1000
int main()
{
char binarynum[MAX], hexa[MAX];
long int i = 0;
printf("1100"); break;
case 'D':
printf("1101"); break;
case 'E':
printf("1110"); break;
case 'F':
printf("1111"); break;
case 'a':
printf("1010"); break;
case 'b':
printf("1011"); break;
case 'c':
printf("1100"); break;
case 'd':
printf("1101"); break;
case 'e':
printf("1110"); break;
case 'f':
printf("1111"); break;
default:
printf("\n Invalid hexa digit %c ", hexa[i]);
return 0;
}
i++;
}
return 0;
}
Question#2:
1. Widening.
2. Widening.
3. Narrowing.
4. Narrowing, it gives garbage value.
5. Type casting (Widening).
Q5:
a) Compiler needs to record the variables and functions in a program, for this write module (C++ or
any feasible) that maintain a table of variables, functions
As
ID identifier Type/Return type MemAddr
1 sum int 1001
2 calcAverage Double 1002
(hint: Linear, Hash Tables, Search Tree)