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

Compiler Design Practical File PDF

The document provides an index of 8 practical assignments related to compilers. The first practical is to write a C program for implementation of a lexical analyzer. The second is to write a C program to detect tokens. The third and fourth practicals involve installing LEX and YACC tools. The remaining practicals involve writing programs using FLEX and analyzing grammar.

Uploaded by

Pankaj Yadav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
298 views

Compiler Design Practical File PDF

The document provides an index of 8 practical assignments related to compilers. The first practical is to write a C program for implementation of a lexical analyzer. The second is to write a C program to detect tokens. The third and fourth practicals involve installing LEX and YACC tools. The remaining practicals involve writing programs using FLEX and analyzing grammar.

Uploaded by

Pankaj Yadav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

INDEX

S.no. Practicals Signature


1. Write a C program for implementation of
Lexical Analyzer

2. Write a C program to detect token

3. Installation of LEX Tool


4. Installation of YACC Tool
5. Write a FLEX program to print “hi” as input
and “by” as output
6. Write a FLEX program for checking odd or
even number
7. Write a FLEX program to check operator
entered is relational operator or not
8. Write a C program to print first and follow
of given grammar
Program 1 :- Write a program for implementation of lexical analyzer

#include <stdio.h>
#include <string.h>
#include <ctype.h>
void main(){
int i, ic=0, m, cc=0, oc=0, j;
char b[30], operator[30], identifier[30], constant[30];
printf("Enter the string: ");
scanf("%[^\n]s",&b);
for(int i=0;i<strlen(b);i++){
if(isspace(b[i])){
continue;
}
else if(isalpha(b[i])){
identifier[ic] = b[i];
ic++;
}
else if(isdigit(b[i])){
m = (b[i]-'0');
i = i+1;
while(isdigit(b[i])){
m = m*10+(b[i]-'0');
i++;
}
i = i-1;
constant[cc] = m;
cc++;
}
else{
if(b[i]=='*'){
operator[oc] = '*';
oc++;
}
else if(b[i]=='+'){
operator[oc] = '+';
oc++;
}
else if(b[i]=='-'){
operator[oc] = '-';
oc++;
}
else if(b[i]=='='){
operator[oc] = '=';
oc++;
}
}
}
printf("Identifier: ");
for(int i=0;i<ic;i++){
printf("%c, ", identifier[i]);
}
printf("\n");
printf("operator: ");
for(int i=0;i<oc;i++){
printf("%c, ", operator[i]);
}
printf("\n");
printf("constant: ");
for(int i=0;i<cc;i++){
printf("%d, ", constant[i]);
}
}
Program 2 :- Write a C program to detect token

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

bool isDelimiter(char ch)


{
if (ch == ' ' || ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == ',' || ch == ';' || ch == '>' ||
ch == '<' || ch == '=' || ch == '(' || ch == ')' ||
ch == '[' || ch == ']' || ch == '{' || ch == '}')
return (true);
return (false);
}

bool isOperator(char ch)


{
if (ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == '>' || ch == '<' ||
ch == '=')
return (true);
return (false);
}

bool validIdentifier(char* str)


{
if (str[0] == '0' || str[0] == '1' || str[0] == '2' ||
str[0] == '3' || str[0] == '4' || str[0] == '5' ||
str[0] == '6' || str[0] == '7' || str[0] == '8' ||
str[0] == '9' || isDelimiter(str[0]) == true)
return (false);
return (true);
}

bool isKeyword(char* str)


{
if (!strcmp(str, "if") || !strcmp(str, "else") ||
!strcmp(str, "while") || !strcmp(str, "do") ||
!strcmp(str, "break") ||
!strcmp(str, "continue") || !strcmp(str, "int")
|| !strcmp(str, "double") || !strcmp(str, "float")
|| !strcmp(str, "return") || !strcmp(str, "char")
|| !strcmp(str, "case") || !strcmp(str, "char")
|| !strcmp(str, "sizeof") || !strcmp(str, "long")
|| !strcmp(str, "short") || !strcmp(str, "typedef")
|| !strcmp(str, "switch") || !strcmp(str, "unsigned")
|| !strcmp(str, "void") || !strcmp(str, "static")
|| !strcmp(str, "struct") || !strcmp(str, "goto"))
return (true);
return (false);
}

bool isInteger(char* str)


{
int i, len = strlen(str);

if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' || (str[i] == '-' && i > 0))
return (false);
}
return (true);
}

bool isRealNumber(char* str)


{
int i, len = strlen(str);
bool hasDecimal = false;

if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' && str[i] != '.' ||
(str[i] == '-' && i > 0))
return (false);
if (str[i] == '.')
hasDecimal = true;
}
return (hasDecimal);
}

char* subString(char* str, int left, int right)


{
int i;
char* subStr = (char*)malloc(
sizeof(char) * (right - left + 2));

for (i = left; i <= right; i++)


subStr[i - left] = str[i];
subStr[right - left + 1] = '\0';
return (subStr);
}

void parse(char* str)


{
int left = 0, right = 0;
int len = strlen(str);

while (right <= len && left <= right) {


if (isDelimiter(str[right]) == false)
right++;

if (isDelimiter(str[right]) == true && left == right) {


if (isOperator(str[right]) == true)
printf("'%c' IS AN OPERATOR\n", str[right]);

right++;
left = right;
}
else if (isDelimiter(str[right]) == true && left != right || (right == len
&& left != right)) {
char* subStr = subString(str, left, right - 1);

if (isKeyword(subStr) == true)
printf("'%s' IS A KEYWORD\n", subStr);

else if (isInteger(subStr) == true)


printf("'%s' IS AN INTEGER\n", subStr);

else if (isRealNumber(subStr) == true)


printf("'%s' IS A REAL NUMBER\n", subStr);

else if (validIdentifier(subStr) == true


&& isDelimiter(str[right - 1]) == false)
printf("'%s' IS A VALID IDENTIFIER\n", subStr);

else if (validIdentifier(subStr) == false


&& isDelimiter(str[right - 1]) == false)
printf("'%s' IS NOT A VALID IDENTIFIER\n", subStr);
left = right;
}
}
return;
}

int main()
{
char str[100] = " int a = b + 1c; ";
parse(str);
return (0);
}
Practical - 3

Aim :- Installation of LEX Tool

Lex is a lexical analyzer generator tool that is widely used in the field of
computer science to create scanner for computer programs. A scanner is a
program that reads the input character by character and produces a sequence
of tokens, which are the smallest syntactic units of a programming language.

Feature of LEX :-
● Lex is a tool that takes a file containing regular expressions and generates
a scanner program that can recognize these expressions in an input
stream. The input file is divided into two sections: the first section
contains declarations that define the tokens and other variables used by
the scanner, while the second section contains rules that specify how the
scanner should recognize the tokens.
● Lex uses regular expressions to describe the patterns that it should
match. A regular expression is a pattern that specifies a set of strings. For
example, the regular expression [a-zA-Z]+ matches one or more
consecutive letters of the alphabet, while the regular expression [0-9]+
matches one or more consecutive digits. The rules in the input file use
regular expressions to specify the patterns that the scanner should
recognize and the actions that should be taken when a pattern is
matched
● When a scanner is generated by Lex, it is typically written in C or another
programming languages. The generated scanner reads input from a file
or a stream, and when a pattern is matched, it calls a user-defined
function that performs some action based on the token that was
recognized.
History of LEX :-
● Lex was first developed in the late 1970s by Mike Lesk and Eric Schmidt
at Bell Laboratories. It was designed to be used in conjunction with the
YACC parser generator, which was also developed at Bell Labs. The
combination of Lex and Yacc was used to create the first version of the
Unix operating system.
● Lex was developed to address the problem of scanning input streams in
programming languages. Prior to the development of Lex, scanning was
typically done using ad-hoc methods that were difficult to maintain and
error-prone. Lex provides a way to generate a scanner automatically
from a high-level description of the token patterns.

Application of LEX :-
● Lex is used in many applications today, ranging from compiler and
interpreter to text processing utilities. In the area of compiler and
interpreter, Lex is often used in conjunction with Yacc to create complete
language processors for programming languages. In text processing, Lex
is used to recognize and tokenize input data, which can then be
processed by other tools.
● Lex is also used in the field of natural language processing to recognize
and tokenize input text. For example, Lex can be used to recognize
patterns in text that indicate the presence of certain named entities,
such as people, places, and organisations.

Conclusion :-
Lex is a powerful tool for creating scanners that can recognize complex patterns
in input data. Its use of regular expressions makes it easy to describe the
patterns that should be matched, and its ability to generate code in target
programming languages makes it highly flexible. Lex has a long history of use in
the development of programming languages and software tools.
Practical - 4

Aim :- Installation of YACC Tool

Yacc (Yet Another Compiler Compiler) is a powerful tool used in computer


science to generate parsers for programming languages. It was developed in
the early 1970s by stephen C. Johnson at Bells Labs as a part of the
development of the Unix operating system.

Features of YACC :-
● Yacc is a tool that takes as input a specification of the grammar of a
programming language and generates a parser that can recognize and
parse input conforming to that grammar. The input file is divided into
three sections: the first section contains declarations of variables and
other information used by the parser, the second section contains the
grammar rules, and the third section contains user-defined code that is
executed when a rule is matched.
● Yacc uses context-free grammar to describe the syntax of the language
being parsed. A context-free grammar consists of a set of productions,
each of which defines how a non-terminal symbol can be rewritten in
terms of other symbols. For example, a production might define how an
arithmetic expression can be rewritten in terms of operands and
operators.
● When a parser is generated by Yacc, it is typically written in C or another
programming language. The generated parser reads input from a file or a
stream, and when a grammar rule is matched, it calls a user-defined
function that performs some action based on the input that was
recognized.
History of YACC :-
● Yacc was developed in the early 1970s by Stephen C. Johnson at Bell
Labs, as part of the development of the Unix operating system. It was
designed to be used in conjunction with the Lex lexical analyzer
generator, which was also developed at Bell Labs.
● The development of Yacc was motivated by the need for a tool that could
automatically generate parsers for programming languages. Prior to the
development of Yacc, parsers were typically written by hand, which was
a time-consuming and error-prone process. Yacc provided a way to
generate parsers automatically from a high-level description of the
grammar of the language being parsed.

Application of YACC :-
● Yacc is used in many applications today, ranging from compilers and
interpreters to text processing utilities. In the area of compilers and
interpreters, Yacc is often used in conjunction with Lex to create
complete language processors for programming languages. In text
processing, Yacc is used to recognize and parse input data, which can
then be processed by other tools.
● Yacc is also used in the field of natural language processing to recognize
and parse input text. For example, Yacc can be used to recognize and
parse sentences in a natural language, such as English or French.

Conclusion :-
Yacc is a powerful tool for generating parsers for programming languages and
other formal languages. Its use of a context-free grammar makes it easy to
describe the syntax of the language being parsed, and its ability to generate
code in a target programming language makes it highly flexible.
Program 5 :- Write a FLEX program to print “hi” as input and “by” as
output

%{
#include <stdio.h>
%}

%%
"hi" {
printf("Reply: By");
}
.* {
printf("error");
}
%%

int main(){
printf("Enter the input: ");
yylex();
}

int yywrap()
{
return 1;
}
Program 6 :- Write a FLEX program for checking odd or even number

%{
#include <stdio.h>
int i;
%}

%%

[0-9]+ {
i = atoi(yytext);
if(i%2==0){
printf("Even");
}
else{
printf("Odd");
}
}
.* {
printf("Not a number");
}

%%

int yywrap() {
return 1;
}
int main () {
printf("Enter the input: ")
yylex();
return 0;
}
Program 7 :- Write a FLEX program to check operator entered is
relational operator or not

%{
#include <stdio.h>
%}

%%

">"||"<"||"<="||">="||"=="||"!=" {
printf("Relational Operator = %s", yytext);
}

.* {
printf("Wrong");
}

%%

int yywrap() {
return 1;
}

int main () {
printf("Enter the input: ");
yylex();
}
Program 8 :- Write a C program to print first and follow of given
grammar

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

void followfirst(char, int, int);


void follow(char c);

void findfirst(char, int, int);

int count, n = 0;

char calc_first[10][100];
char calc_follow[10][100];
int m = 0;

char production[10][10];
char f[10], first[10];
int k;
char ck;
int e;

int main(int argc, char** argv)


{
int jm = 0;
int km = 0;
int i, choice;
char c, ch;
count = 8;

strcpy(production[0], "X=TnS");
strcpy(production[1], "X=Rm");
strcpy(production[2], "T=q");
strcpy(production[3], "T=#");
strcpy(production[4], "S=p");
strcpy(production[5], "S=#");
strcpy(production[6], "R=om");
strcpy(production[7], "R=ST");

int kay;
char done[count];
int ptr = -1;

for (k = 0; k < count; k++) {


for (kay = 0; kay < 100; kay++) {
calc_first[k][kay] = '!';
}
}
int point1 = 0, point2, xxx;

for (k = 0; k < count; k++) {


c = production[k][0];
point2 = 0;
xxx = 0;
for (kay = 0; kay <= ptr; kay++)
if (c == done[kay])
xxx = 1;

if (xxx == 1)
continue;

findfirst(c, 0, 0);
ptr += 1;

done[ptr] = c;
printf("\n First(%c) = { ", c);
calc_first[point1][point2++] = c;

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


int lark = 0, chk = 0;

for (lark = 0; lark < point2; lark++) {

if (first[i] == calc_first[point1][lark]) {
chk = 1;
break;
}
}
if (chk == 0) {
printf("%c, ", first[i]);
calc_first[point1][point2++] = first[i];
}
}
printf("}\n");
jm = n;
point1++;
}
printf("\n");
printf("-----------------------------------------------"
"\n\n");
char donee[count];
ptr = -1;
for (k = 0; k < count; k++) {
for (kay = 0; kay < 100; kay++) {
calc_follow[k][kay] = '!';
}
}
point1 = 0;
int land = 0;
for (e = 0; e < count; e++) {
ck = production[e][0];
point2 = 0;
xxx = 0;

for (kay = 0; kay <= ptr; kay++)


if (ck == donee[kay])
xxx = 1;
if (xxx == 1)
continue;
land += 1;
follow(ck);
ptr += 1;
donee[ptr] = ck;
printf(" Follow(%c) = { ", ck);
calc_follow[point1][point2++] = ck;

for (i = 0 + km; i < m; i++) {


int lark = 0, chk = 0;
for (lark = 0; lark < point2; lark++) {
if (f[i] == calc_follow[point1][lark]) {
chk = 1;
break;
}
}
if (chk == 0) {
printf("%c, ", f[i]);
calc_follow[point1][point2++] = f[i];
}
}
printf(" }\n\n");
km = m;
point1++;
}
}

void follow(char c)
{
int i, j;

if (production[0][0] == c) {
f[m++] = '$';
}
for (i = 0; i < 10; i++) {
for (j = 2; j < 10; j++) {
if (production[i][j] == c) {
if (production[i][j + 1] != '\0') {
followfirst(production[i][j + 1], i,
(j + 2));
}

if (production[i][j + 1] == '\0'
&& c != production[i][0]) {
follow(production[i][0]);
}
}
}
}
}

void findfirst(char c, int q1, int q2)


{
int j;

if (!(isupper(c))) {
first[n++] = c;
}
for (j = 0; j < count; j++) {
if (production[j][0] == c) {
if (production[j][2] == '#') {
if (production[q1][q2] == '\0')
first[n++] = '#';
else if (production[q1][q2] != '\0'
&& (q1 != 0 || q2 != 0)) {
findfirst(production[q1][q2], q1,
(q2 + 1));
}
else
first[n++] = '#';
}
else if (!isupper(production[j][2])) {
first[n++] = production[j][2];
}
else {
findfirst(production[j][2], j, 3);
}
}
}
}

void followfirst(char c, int c1, int c2)


{
int k;
if (!(isupper(c)))
f[m++] = c;
else {
int i = 0, j = 1;
for (i = 0; i < count; i++) {
if (calc_first[i][0] == c)
break;
}

while (calc_first[i][j] != '!') {


if (calc_first[i][j] != '#') {
f[m++] = calc_first[i][j];
}
else {
if (production[c1][c2] == '\0') {
follow(production[c1][0]);
}
else {
followfirst(production[c1][c2], c1,
c2 + 1);
}
}
j++;
}
}
}

You might also like