Você está na página 1de 19

COMPILER CONSTRUCTION LAB BOOK - 153158

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;

char beta[50], alpha[50];


char temp1[50], temp2[50];

int j = 0, k = 0;
int q = 0, o = 0;

void direct(char temp2[])


{
i = 0;
int length = strlen(temp2);
cout << "\nlength= " << length;
char left = temp2[0];
cout << "\nleft= " << left;
j = 0, k = 0;

for (i = 2; i < length; i++){


if (temp2[i] == left){
int c = i + 1;
while (temp2[c] != '|' && temp2[c] != '\o'){
alpha[j] = temp2[c];
c++;
j++;

}
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(){

cout << "Enter the no.of productions: ";


int count;
cin >> count;
if (count>1){

cout << "\nEnter production 1:\n";


cin >> r.S;
cout << "\nEnter production 2:\n";
cin >> r.A;
cout << "---------------------------------\n";
cout << "\nEntered Production 1 is=\t" << r.S;
cout << "\nEntered Production 2 is=\t" << r.A;

int len1 = strlen(r.S);


int len2 = strlen(r.A);
cout << "\n---------------------------------\n";
cout << "\nlength1= " << len1 << "\tlength2= " << len2;

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";

r.temp2[r.q] = 'S'; r.q++;


r.temp2[r.q] = '='; r.q++;

for (int i = 2; i< len1; i++){


if (r.S[i] == r.left2){
r.flag3 = true;
int h = i + 1;

while (r.S[h] != '|' && r.S[h] != '\o'){


r.temp1[r.o] = r.S[h];
h++;
r.o++;
}
for (int p = 2; p < len2; p++){
while (r.A[p] != '|' && r.A[p] != '\o'){
r.temp2[r.q] = r.A[p];
r.q++;

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;

int length = strlen(r.temp2);


for (int i = 0; i <length; i++)
cout << r.temp2[i];
r.direct(r.temp2);
}
else{
cout << "\nEnter production:\n";
cin >> r.temp2;
cout << "---------------------------------\n";
cout << "\nEntered Production is=\t" << r.temp2;
r.direct(r.temp2);
}
return 0;
}

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];

Student std = new Student();

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

b) Recognize Regular Language a*b+ in C

#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();
}
}

b) Simple LL Parser (Predictive Parser) for syntax checking.

#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)

Precedence Operator Description Associativity


++ -- Suffix/postfix increment and decrement Left-to-right
() Function call
[] Array subscripting
1
. Structure and union member access
-> Structure and union member access through pointer
(type){list} Compound literal
++ -- Prefix increment and decrement Right-to-left
+- Unary plus and minus
!~ Logical NOT and bitwise NOT
(type) Type cast
2
* Indirection (dereference)
& Address-of
sizeof Size-of
_Alignof Alignment requirement
3 */% Multiplication, division, and remainder Left-to-right
4 +- Addition and subtraction
5 << >> Bitwise left shift and right shift
COMPILER CONSTRUCTION LAB BOOK - 153158

< <= For relational operators < and ≤ respectively


6
> >= For relational operators > and ≥ respectively
7 == != For relational = and ≠ respectively
8 & Bitwise AND
9 ^ Bitwise XOR (exclusive or)
10 | Bitwise OR (inclusive or)
11 && Logical AND
12 || Logical OR
13 ?: Ternary conditional Right-to-Left
= Simple assignment
+= -= Assignment by sum and difference
14 *= /= %= Assignment by product, quotient, and remainder
<<= >>= Assignment by bitwise left shift and right shift
&= ^= |= Assignment by bitwise AND, XOR, and OR
15 , Comma Left-to-right

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

Keywords, strings, integers floats symbols identifiers

#include <iostream>
#include <limits>
#include <cstring>
using namespace std;

void CharToStr(string str, string *strArray, int array_size)


{
for(int i=0; i<array_size; i++)
{
if(strArray[i] == "")
{
*(strArray + i) = str;
return;
}}}
bool DataType(string str)
{
string DATATYPES[] = {"int", "string", "float", "double", "short", "bool", "long"};
COMPILER CONSTRUCTION LAB BOOK - 153158

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


{
if(DATATYPES[i] == str)
{
return true;
}}
return false;}
bool StatementEnd(string str)
{
for(int i=0; i<str.length(); i++)
{
if(str[i] == ';')
{
return true;
}}
return false;}
int main()
{
string OPERATORS[] = {"+", "-", "*", "/"};
int array_size;
char *inputChar;
string *tokenArray;
string token;
cout << "Enter the size of Character array: ";
cin >> array_size;
cin.ignore (numeric_limits<streamsize>::max(), '\n');
inputChar = new char[array_size];
tokenArray = new string[array_size];
cout << "Input: ";
cin.getline(inputChar, array_size + 1);

// 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

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


cout << "{ ";
for(int i=0; i<array_size; i++)
{
if(*(tokenArray + i) != "")
{
cout << "\'"<<*(tokenArray + i) << "\', ";
}}
cout <<" }";
cout << "\n\nStatements" << endl;
cout << "-------------------------------------\n";
for(int i=0, j = 1; i<array_size; i++)
{
if(*(tokenArray + i) != "")
{
if(isDataType(*(tokenArray + i)))
{
cout << "DataType: \'"<<*(tokenArray + i) <<"\' ";
}
else
{
cout << "Indentifier: \'"<<*(tokenArray + i) <<"\' ";
}

// check statement end


if(StatementEnd(*(tokenArray + i)))
{
cout << "\n\n";}}}
return 0;
}

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.

Important methods of Parameter Passing


1. Pass by Value: This method uses in-mode semantics. Changes made to formal parameter do not
get transmitted back to the caller. Any modifications to the formal parameter variable inside the
called function or method affect only the separate storage location and will not be reflected in the
actual parameter in the calling environment. This method is also called as call by value.
// C program to illustrate
// call by value
#include <stdio.h>

void func(int a, int b)


{
a += b;
printf("In func, a = %d b = %d\n", a, b);
}
int main(void)
{
int x = 5, y = 7;

// 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>

void swapnum(int* i, int* j)


{
int temp = *i;
*i = *j;
*j = temp;
}

int main(void)
{
int a = 10, b = 20;

// passing parameters
swapnum(&a, &b);

printf("a is %d and b is %d\n", a, b);


return 0;
}
Output:
a is 20 and b is 10

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";
}}}

b) What is back patching, write functions of back patching?

Back patching: The syntax directed definition can be implemented in two or more passes (we have both
synthesized attributes and inherited attributes).

Build the tree first.

Walk the tree in the depth-first order.

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

Lab 10: Macros?

#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;

Lab 11: String to Hexadecimal then Hexadecimal to Binary

#include <stdio.h>
#include <string.h>

int main(void) {
char text[] = "I love Pakistan!";
int len = strlen(text);

char hex[100], string[50];

// Convert text to hex.


for (int i = 0, j = 0; i < len; ++i, j += 2)
sprintf(hex + j, "%02x", text[i] & 0xff);

printf("'%s' in hex is %s.\n", text, hex);

// Convert the hex back to a string.


len = strlen(hex);
for (int i = 0, j = 0; j < len; ++i, j += 2) {
int val[1];
COMPILER CONSTRUCTION LAB BOOK - 153158

sscanf(hex + j, "%2x", val);


string[i] = val[0];
string[i + 1] = '\0';
}

printf("%s as a string is '%s'.\n", hex, string);

return 0;
}

Hexadecimal to Binary:

#include <stdio.h>
#define MAX 1000

int main()
{
char binarynum[MAX], hexa[MAX];
long int i = 0;

printf("Enter the value for hexadecimal ");


scanf("%s", hexa);
printf("\n Equivalent binary value: ");
while (hexa[i])
{
switch (hexa[i])
{
case '0':
printf("0000"); break;
case '1':
printf("0001"); break;
case '2':
printf("0010"); break;
case '3':
printf("0011"); break;
case '4':
printf("0100"); break;
case '5':
printf("0101"); break;
case '6':
printf("0110"); break;
case '7':
printf("0111"); break;
case '8':
printf("1000"); break;
case '9':
printf("1001"); break;
case 'A':
printf("1010"); break;
case 'B':
printf("1011"); break;
case 'C':
COMPILER CONSTRUCTION LAB BOOK - 153158

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)

Você também pode gostar