Pranav Compiler Design Lab File
Pranav Compiler Design Lab File
LAB MANUAL
Subject code :- ACTDCTOC001P
SUBJECT NAME :- COMPILER DESIGN LAB
SEMESTER: VI SEM III YEAR
Session: - Dec - may 2023
2.
WAP to identify keyword and store them in symbol
table.
3.
Develop a lexical analyzer to recognize a few patterns.
4.
WAP to design three address code.
5.
WAP to develop an operator precedence parser.
6.
Develop a recursive descent parser.
7.
Write a program for generating for various intermediate
code forms Polish notation.
8.
Write a program to simulate Heap storage allocation
strategy.
9.
Given any intermediate code form, implement code
optimization techniques.
Experiment 1
WAP to identify keywords.
Every Keyword exists in lower case letters like auto, break, case, const,
continue, int etc.
do if static while
Example
#include <stdio.h>
#include <string.h>
int main() {
char keyword[32][10]={
"auto","double","int","struct","break","else","long",
"switch","case","enum","register","typedef","char",
"extern","return","union","const","float","short",
"unsigned","continue","for","signed","void","default",
"goto","sizeof","voltile","do","if","static","while"
};
char str[]="which";
int flag=0,i;
if(strcmp(str,keyword[i])==0) {
flag=1;
if(flag==1)
printf("%s is a keyword",str);
else
Output:
which is a keyword
Experiment 2
WAP to identify keyword and store them in symbol table.
Certainly! Below is a C program that reads a C source code file, identifies keywords, and
stores them in a symbol table:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct {
char keyword[20];
int frequency;
} KeywordEntry;
char *keywords[] = {"auto", "break", "case", "char", "const", "continue", "default", "do",
int i;
if (strcmp(str, keywords[i]) == 0) {
return 1;
}
}
return 0;
int main() {
FILE *fp;
int numKeywords = 0;
scanf("%s", filename);
fp = fopen(filename, "r");
if (fp == NULL) {
return 1;
// Read words from the file and check if they are keywords
word[i] = tolower(word[i]);
}
// Remove punctuations
if (ispunct(word[len - 1])) {
word[len - 1] = '\0';
if (isKeyword(word)) {
int found = 0;
if (strcmp(symbolTable[i].keyword, word) == 0) {
symbolTable[i].frequency++;
found = 1;
break;
if (!found) {
strcpy(symbolTable[numKeywords].keyword, word);
symbolTable[numKeywords].frequency = 1;
numKeywords++;
printf("Symbol Table:\n");
printf("Keyword\t\tFrequency\n");
return 0;
```
This program reads a C source code file provided by the user, identifies the keywords present
in the file, and stores them in a symbol table along with their frequencies. It then prints out
the symbol table at the end. Please note that this program assumes that the source code file
provided by the user is syntactically correct.
Experiment 3
Develop a lexical analyzer to recognize a few patterns.
PROGRAM CODE:
#include<string.h>
#include<ctype.h>
#include<stdio.h>
#include<stdlib.h>
if(strcmp("for",str)==0||strcmp("while",str)==0||strcmp("do",str)==0||strcmp("int",str)==0||str
cmp("float",str)==0||strcmp("char",str)==0||strcmp("double",str)==0||strcmp("printf",str)==0||
strcmp("switch",str)==0||strcmp("case",str)==0)
printf("\n%s is a keyword",str);
else
printf("\n%s is an identifier",str);
void main()
FILE *f1,*f2,*f3;
char c,str[10],st1[10];
int num[100],lineno=0,tokenvalue=0,i=0,j=0,k=0;
f1=fopen("input","r");
f2=fopen("identifier","w");
f3=fopen("specialchar","w");
while((c=getc(f1))!=EOF)
{
if(isdigit(c))
tokenvalue=c-'0';
c=getc(f1);
while(isdigit(c))
tokenvalue*=10+c-'0';
c=getc(f1);
num[i++]=tokenvalue;
ungetc(c,f1);
else
if(isalpha(c))
putc(c,f2);
c=getc(f1);
while(isdigit(c)||isalpha(c)||c=='_'||c=='$')
putc(c,f2);
c=getc(f1);
putc(' ',f2);
ungetc(c,f1);
else
if(c==' '||c=='\t')
printf(" ");
else
if(c=='\n')
lineno++;
else
putc(c,f3);
fclose(f2);
fclose(f3);
fclose(f1);
for(j=0;j<i;j++)
printf("\t%d",num[j]);
printf("\n");
f2=fopen("identifier","r");
k=0;
while((c=getc(f2))!=EOF)
if(c!=' ')
str[k++]=c;
else
str[k]='\0';
keyword(str);
k=0;
fclose(f2);
f3=fopen("specialchar","r");
while((c=getc(f3))!=EOF)
printf("\t%c",c);
printf("\n");
fclose(f3);
OUTPUT:
Experiment 4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
} ThreeAddressCode;
// Initialize variables
ThreeAddressCode* code =
(ThreeAddressCode*)malloc(sizeof(ThreeAddressCode));
int i = 0, j = 0;
while (expr[i] != '+' && expr[i] != '-' && expr[i] != '*' && expr[i] != '/') {
arg1[j++] = expr[i++];
arg1[j] = '\0';
j = 0;
op[0] = expr[i++];
op[1] = '\0';
arg2[j++] = expr[i++];
arg2[j] = '\0';
strcpy(result, "t1");
strcpy(code->op, op);
strcpy(code->arg1, arg1);
strcpy(code->arg2, arg2);
strcpy(code->result, result);
return code;
}
int main() {
char expr[100];
scanf("%s", expr);
printf("\nThree-Address Code:\n");
free(code);
return 0;
This program prompts the user to enter a simple arithmetic expression containing
addition, subtraction, multiplication, or division. It then generates the corresponding
three-address code and prints it out. For example, if the user enters "a + b", the
program will output "t1 = a + b", where "t1" is the result variable. Similarly, if the user
enters "x * y", the output will be "t1 = x * y".
Experiment 5
Below is the source code for C Program to input values into an array and display them which is
successfully compiled and run on Windows System to produce desired output as shown below :
Operator precedence & associativity are listed in the following table and this table is summarized
in decreasing Order of priority i.e topmost operator has highest priority and bottommost operator
has Lowest Priority.
++ – Prefix increment/decrement
* Dereference
* / % Multiplication/division/modulus left-to-right
+ – Addition/subtraction left-to-right
|| Logical OR left-to-right
= Assignment
+= -= Addition/subtraction assignment
*= /= Multiplication/division assignment
right-to-left
%= &= Modulus/bitwise AND assignment
SOURCE CODE : :
#include <stdio.h>
int main() {
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * c / d; // ( 30 * 15 ) / 5
printf("Value of (a + b) * c / d is : %d\n", e );
e = ((a + b) * c) / d; // (30 * 15 ) / 5
printf("Value of ((a + b) * c) / d is : %d\n" , e );
e = a + (b * c) / d; // 20 + (150/5)
printf("Value of a + (b * c) / d is : %d\n" , e );
return 0;
}
OUTPUT : :
Value of (a + b) * c / d is : 90
Value of ((a + b) * c) / d is : 90
Value of (a + b) * (c / d) is : 90
Value of a + (b * c) / d is : 50
Experiment 6
Backtracking:
Example
E+T|T T E'
T*F|F + T E' | e
( E ) | id F T'
* F T' | e
( E ) | id
1. **Here e is Epsilon
Now, we are going to create a separate program for each variable in the recursive
descent parser.
Program:
1. #include <stdio.h>
2. #include <string.h>
3.
4. #define SUCCESS 1
5. #define FAILED 0
6.
7. int E(), Edash(), T(), Tdash(), F();
8.
9. const char *cursor;
10. char string[64];
11.
12. int main()
13. {
14. puts("Enter the string");
15. // scanf("%s", string);
16. sscanf("i+(i+i)*i", "%s", string);
17. cursor = string;
18. puts("");
19. puts("Input Action");
20. puts("--------------------------------");
21.
22. if (E() && *cursor == '\0') {
23. puts("--------------------------------");
24. puts("String is successfully parsed");
25. return 0;
26. } else {
27. puts("--------------------------------");
28. puts("Error in parsing String");
29. return 1;
30. }
31. }
32.
33. int E()
34. {
35. printf("%-16s E -> T E'\n", cursor);
36. if (T()) {
37. if (Edash())
38. return SUCCESS;
39. else
40. return FAILED;
41. } else
42. return FAILED;
43. }
44.
45. int Edash()
46. {
47. if (*cursor == '+') {
48. printf("%-16s E' -> + T E'\n", cursor);
49. cursor++;
50. if (T()) {
51. if (Edash())
52. return SUCCESS;
53. else
54. return FAILED;
55. } else
56. return FAILED;
57. } else {
58. printf("%-16s E' -> $\n", cursor);
59. return SUCCESS;
60. }
61. }
62.
63. int T()
64. {
65. printf("%-16s T -> F T'\n", cursor);
66. if (F()) {
67. if (Tdash())
68. return SUCCESS;
69. else
70. return FAILED;
71. } else
72. return FAILED;
73. }
74.
75. int Tdash()
76. {
77. if (*cursor == '*') {
78. printf("%-16s T' -> * F T'\n", cursor);
79. cursor++;
80. if (F()) {
81. if (Tdash())
82. return SUCCESS;
83. else
84. return FAILED;
85. } else
86. return FAILED;
87. } else {
88. printf("%-16s T' -> $\n", cursor);
89. return SUCCESS;
90. }
91. }
92.
93. int F()
94. {
95. if (*cursor == '(') {
96. printf("%-16s F -> ( E )\n", cursor);
97. cursor++;
98. if (E()) {
99. if (*cursor == ')') {
100. cursor++;
101. return SUCCESS;
102. } else
103. return FAILED;
104. } else
105. return FAILED;
106. } else if (*cursor == 'i') {
107. cursor++;
108. printf("%-16s F ->i\n", cursor);
109. return SUCCESS;
110. } else
111. return FAILED;
112. }
Output:
Input Action
--------------------------------
i+(i+i)*i E -> T E'
i+(i+i)*i T -> F T'
+(i+i)*i F ->i
+(i+i)*i T' -> $
+(i+i)*i E' -> + T E'
(i+i)*i T -> F T'
(i+i)*i F -> ( E )
i+i)*i E -> T E'
i+i)*i T -> F T'
+i)*i F ->i
+i)*i T' -> $
+i)*i E' -> + T E'
i)*i T -> F T'
)*i F ->i
)*i T' -> $
)*i E' -> $
*i T' -> * F T'
F ->i
T' -> $
E' -> $
--------------------------------
String is successfully parsed
Experiment 7
Write a program for generating for various intermediate code forms Polish notation.
Certainly! Here's a C program that generates Polish notation (also known as prefix notation) for
arithmetic expressions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Append any remaining operators from the stack to the prefix expression
while (operatorTop >= 0) {
prefix[prefixIndex++] = operatorStack[operatorTop--];
}
int main() {
char infix[100];
char prefix[100];
return 0;
}
OUTPUT:
This program prompts the user to enter an infix expression and then converts it to Polish notation (prefix
notation). It supports addition, subtraction, multiplication, and division operators, as well as parentheses
for grouping. The resulting prefix notation is then printed to the console.
Experiment 8
Heap Allocation
The heap
The heap is a region of memory used for dynamic memory allocation, allowing
for the allocation and deallocation of memory at runtime. Unlike the stack,
memory allocated on the heap persists until explicitly freed
by the programmer. The heap provides flexibility for managing large data
structures, arrays, and dynamic memory requirements.
This program simulates heap storage allocation using a first-fit strategy. It initializes the heap with a
single memory block representing the entire heap size. Memory allocation is performed using the
`allocate` function, which searches for the first free memory block that can accommodate the requested
size. Memory deallocation is performed using the `deallocate` function, which marks the memory block
as free and coalesces adjacent free memory blocks. The state of the heap is printed before and after
memory allocation and deallocation to visualize the changes.
Experiment 9
Optimizing intermediate code involves transforming it to improve efficiency without changing its
behavior. There are various optimization techniques, and the choice depends on the specific
characteristics of the code. Below, I'll provide a simple example of code optimization using constant
folding:
```
1. t1 = 5 + 3
2. t2 = t1 * 2
3. t3 = t2 - 10
4. t4 = t3 / 4
```
We can optimize this code by performing constant folding, which involves evaluating constant
expressions at compile-time rather than at runtime. In this case, we can evaluate the constant expressions
and replace them with their results:
```
1. t1 = 8
2. t2 = t1 * 2
3. t3 = t2 - 10
4. t4 = t3 / 4
```
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
// Sample intermediate code
IntermediateCode code[] = {
{"t1", '+', "5", "3"},
{"t2", '*', "t1", "2"},
{"t3", '-', "t2", "10"},
{"t4", '/', "t3", "4"}
};
int numInstructions = sizeof(code) / sizeof(code[0]);
return 0;
}
```
This program takes an array of intermediate code instructions as input, performs constant folding
optimization, and prints the optimized intermediate code. In this example, constant expressions like "5 +
3" are evaluated at compile-time, resulting in optimized code.