Top Banner
INDEX S.No. Program Date Signature 1 Practice of LEX/YACC of compiler writing. 2 Write a program to implement stack opeartions using array. 3 Write a program to show all the operations of a stack using Link list. 4 Write a program to find whether string is a keyword or not. 5 Write a program is to find out whether a given string is an Identifier or not. 6 Write a program to find whether the string is constant or not. 7 Write a program to check whether string belongs to a grammar or not. 8 Write a program to find the FIRST of a variable. 9 Write a program to compute FOLLOW of non- terminals. 10 Write a program to find the Trailing Terminals in the String.
35

Compiler Design File

Jul 16, 2015

Download

Engineering

Archita Misra
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Compiler Design File

INDEX

S.No. Program Date Signature

1 Practice of LEX/YACC of compiler writing.

2 Write a program to implement stack opeartionsusing array.

3 Write a program to show all the operations of astack using Link list.

4 Write a program to find whether string is akeyword or not.

5 Write a program is to find out whether a givenstring is an Identifier or not.

6 Write a program to find whether the string isconstant or not.

7 Write a program to check whether string belongsto a grammar or not.

8 Write a program to find the FIRST of a variable.

9 Write a program to compute FOLLOW of non-terminals.

10 Write a program to find the Trailing Terminalsin the String.

Page 2: Compiler Design File

Program 1: Practice of LEX/YACC of compiler writing

Lex Theory

The first phase in a compiler reads the input source and converts strings in thesource to tokens. Using regular expressions, we can specify patterns to lex thatallow it to scan and match strings in the input. Each pattern in lex has an associatedaction. Typically an action returns a token, representing the matched string, forsubsequent use by the parser. To begin with, however, we will simply print thematched string rather than return a token value. We may scan for identifiers usingthe regular expression.

letter(letter|digit)*

This pattern matches a string of characters that begins with a single letter, and isfollowed by zero or more letters or digits. This example nicely illustratesoperations allowed in regular expressions:

repetition, expressed by the “*” operator

alternation, expressed by the “|” operator

concatenation

Any regular expression expressions may be expressed as a finite state automaton(FSA). We can represent an FSA using states, and transitions between states. Thereis one start state, and one or more final or accepting states.

Figure 1: Finite State Automaton

In Figure1, state 0 is the start state, and state 2 is the accepting state. As charactersare read, we make a transition from one state to another. When the first letter isread, we transition to state 1. We remain in state 1 as more letters or digits are read.

Page 3: Compiler Design File

When we read a character other than a letter or digit, we transition to state 2, theaccepting state. Any FSA may be expressed as a computer program. For example,our 3-state machine is easily programmed:

start : goto state0

state0: read c

if c = letter goto state1

goto state0

state1: read c

if c = letter goto state1

if c = digit goto state1

goto state2

state2: accept string

This is the technique used by lex. Regular expressions are translated by lex to acomputer program that mimics an FSA. Using the next input character, and currentstate, the next state is easily determined by indexing into a computer-generatedstate table.

Now we can easily understand some of lex’s limitations. For example, lex cannotbe used to recognize nested structures such as parentheses. Nested structures arehandled by incorporating a stack. Whenever we encounter a “(”, we push it on thestack. When a “)” is encountered, we match it with the top of the stack, and pop thestack. Lex, however, only has states and transitions between states. Since it has nostack, it is not well suited for parsing nested structures. Yacc augments an FSAwith a stack, and can process constructs such as parentheses with ease. Theimportant thing is to use the right tool for the job. Lex is good at pattern matching.Yacc is appropriate for more challenging tasks.

Page 4: Compiler Design File

Yacc Theory

Grammars for yacc are described using a variant of Backus Naur Form (BNF).This technique was pioneered by John Backus and Peter Naur, and used to describeALGOL60. A BNF grammar can be used to express context-free languages. Mostconstructs in modern programming languages can be represented in BNF. Forexample, the grammar for an expression that multiplies and adds numbers is

1 E -> E + E

2 E -> E * E

3 E -> id

Three productions have been specified. Terms that appear on the left-hand side(lhs) of a production, such as E (expression) are non-terminals. Terms such as id(identifier) are terminals (tokens returned by lex) and only appear on the right-handside (rhs) of a production. This grammar specifies that an expression may be thesum of two expressions, the product of two expressions, or an identifier. We canuse this grammar to generate expressions:

E -> E * E (r2)

-> E * z (r3)

-> E + E * z (r1)

-> E + y * z (r3)

-> x + y * z (r3)

At each step we expanded a term, replacing the lhs of a production with thecorresponding rhs. The numbers on the right indicate which rule applied. To parsean expression, we actually need to do the reverse operation. Instead of starting witha single nonterminal (start symbol) and generating an expression from a grammar,we need to reduce an expression to a single nonterminal. This is known as bottom-up or shift-reduce parsing, and uses a stack for storing terms. Here is the samederivation, but in reverse order:

Page 5: Compiler Design File

1 . x + y * z shift

2 x . + y * z reduce(r3)

3 E . + y * z shift

4 E + . y * z shift

5 E + y . * z reduce(r3)

6 E + E . * z shift

7 E + E * . z shift

8 E + E * z . reduce(r3)

9 E + E * E . reduce(r2) emit multiply

10 E + E . reduce(r1) emit add

11 E . accept

Terms to the left of the dot are on the stack, while remaining input is to the right ofthe dot. We start by shifting tokens onto the stack. When the top of the stackmatches the rhs of a production, we replace the matched tokens on the stack withthe lhs of the production. Conceptually, the matched tokens of the rhs are poppedoff the stack, and the lhs of the production is pushed on the stack. The matchedtokens are known as a handle, and we are reducing the handle to the lhs of theproduction. This process continues until we have shifted all input to the stack, andonly the starting nonterminal remains on the stack. In step 1 we shift the x to thestack. Step 2 applies rule r3 to the stack, changing x to E. We continue shifting andreducing, until a single nonterminal, the start symbol, remains in the stack. In step9, when we reduce rule r2, we emit the multiply instruction. Similarly, the addinstruction is emitted in step 10. Thus, multiply has a higher precedence thanaddition.

Consider, however, the shift at step 6. Instead of shifting, we could have reduced,applying rule r1. This would result in addition having a higher precedence thanmultiplication. This is known as a shift-reduce conflict. Our grammar is ambguous,

Page 6: Compiler Design File

as there is more than one possible derivation that will yield the expression. In thiscase, operator precedence is affected. As another example, associativity in the rule

E -> E + E

is ambiguous, for we may recurse on the left or the right. To remedy the situation,we could rewrite the grammar, or supply yacc with directives that indicate whichoperator has precedence. The latter method is simpler, and will be demonstrated inthe practice section.

The following grammar has a reduce-reduce conflict. With an id on the stack, wemay reduce to T, or reduce to E.

E -> T

E -> id

T -> id

Yacc takes a default action when there is a conflict. For shift-reduce conflicts, yaccwill shift. For reduce-reduce conflicts, it will use the first rule in the listing. It alsoissues a warning message whenever a conflict exists. The warnings may besuppressed by making the grammar unambiguous. Several methods for removingambiguity will be presented in subsequent sections.

Page 7: Compiler Design File

Program 2: - Write a program to implement stack operations using anarray.

#define MAX 4 //you can take any number to limit your stack size

#include<stdio.h>

#include<conio.h>

int stack[MAX];

int top;

void push(int token)

{

char a;

do

{

if(top==MAX-1)

{

printf("Stack full");

return;

}

printf("\nEnter the token to be inserted:");

scanf("%d",&token);

top=top+1;

stack[top]=token;

printf("do you want to continue insertion Y/N");

a=getch();

Page 8: Compiler Design File

}

while(a=='y');

}

int pop()

{

int t;

if(top==-1)

{

printf("Stack empty");

return -1;

}

t=stack[top];

top=top-1;

return t;

}

void show()

{

int i;

printf("\nThe Stack elements are:");

for(i=0;i<=top;i++)

{

printf("%d",stack[i]);

}

Page 9: Compiler Design File

}

int main()

{

char ch , a='y';

int choice, token;

top=-1;

printf("1.Insert");

printf("\n2.Delete");

printf("\n3.show or display");

do

{

printf("\nEnter your choice for the operation: ");

scanf("%d",&choice);

switch(choice)

{

case 1:

{

push(token);

show();

break;

}

case 2:

{

Page 10: Compiler Design File

token=pop();

printf("\nThe token deleted is %d",token);

show();

break;

}

case 3:

{

show();

break;

}

default:printf("Wrong choice");

break;

}

printf("\nDo you want to continue(y/n):");

ch=getch();

}

while(ch=='y'||ch=='Y');

getch();

}

Page 11: Compiler Design File

Output:-

Page 12: Compiler Design File

Program 3: - Write a program to implement stack operations using array

#include <stdio.h>

#include <stdlib.h>

struct Node

{

int Data;

struct Node *next;

}*top;

void popStack()

{

struct Node *temp, *var=top;

if(var==top)

{

top = top->next;

free(var);

}

else

printf("\nStack Empty");

}

void push(int value)

{

struct Node *temp;

temp=(struct Node *)malloc(sizeof(struct Node));

Page 13: Compiler Design File

temp->Data=value;

if (top == NULL)

{

top=temp;

top->next=NULL;

}

else

{

temp->next=top;

top=temp;

}

}

void display()

{

struct Node *var=top;

if(var!=NULL)

{

printf("\nElements are as:\n");

while(var!=NULL)

{

printf("\t%d\n",var->Data);

var=var->next;

}

Page 14: Compiler Design File

printf("\n");

}

else

printf("\nStack is Empty");

}

int main(int argc, char *argv[])

{

int i=0;

top=NULL;

printf(" \n1. Push to stack");

printf(" \n2. Pop from Stack");

printf(" \n3. Display data of Stack");

printf(" \n4. Exit\n");

while(1)

{

printf(" \nChoose Option: ");

scanf("%d",&i);

switch(i)

{

case 1:

{

int value;

printf("\nEnter a valueber to push into Stack: ");

Page 15: Compiler Design File

scanf("%d",&value);

push(value);

display();

break;

}

case 2:

{

popStack();

display();

break;

}

case 3:

{

display();

break;

}

case 4:

{

struct Node *temp;

while(top!=NULL)

{

temp = top->next;

free(top);

Page 16: Compiler Design File

top=temp;

}

exit(0);

}

default:

{

printf("\nwrong choice for operation");

}

}

}

}

Output:

Page 17: Compiler Design File

Program 4:- Program to find whether string is a keyword or not.

#include<stdio.h>

#include<conio.h>

#include<string.h>

void main()

{

int i,flag=0,m;

char s[5][10]={"if","else","goto","continue","return"},st[10];

clrscr();

printf("\n enter the string :");

gets(st);

for(i=0;i<5;i++)

{

m=strcmp(st,s[i]);

if(m==0)

flag=1;

}

if(flag==0)

printf("\n it is not a keyword");

else

printf("\n it is a keyword");

getch();

}

Page 18: Compiler Design File

Output:

Page 19: Compiler Design File

Program 5:- Write a program is to find out whether a given string is aIdentifier or not.

#include<stdio.h>

#include<conio.h>

#include<string.h>

#include<ctype.h>

void main()

{

int i=0,flag=0;

char string[10];

clrscr();

printf("Enter a string :");

gets(string);

/*----Checking the 1st character*----*/

if((string[0]=='_')||(isalpha(string[0])!=0))

{

/*---Checking rest of the characters*---*/

for(i=1;string[i]!='\0';i++)

if((isalnum(string[i])==0)&&(string[i]!='_'))

flag=1;

}

else

flag=1;

Page 20: Compiler Design File

if( flag==0)

printf("\n%s is an identifier ",string);

else

printf("\n%s is not an identifier ",string);

getch();

}

Output:

Page 21: Compiler Design File

Program no.6 :- Program to find whether the string is constant or not.

#include<stdio.h>

#include<conio.h>

#include<ctype.h>

#include<string.h>

void main()

{

char str[10];

int len,a;

clrscr();

printf("\n Input a string :");

gets(str);

len=strlen(str);

a=0;

while(a<len)

{

if(isdigit(str[a]))

{

a++;

}

else

{

printf(" It is not a Constant");

Page 22: Compiler Design File

break;

}

}

if(a==len)

{

printf(" It is a Constant");

}

getch();

}

Output:

Page 23: Compiler Design File

Program 7: Write a program to check whether string belongs to a grammaror not.

#include<stdio.h>

#include<conio.h>

#include<string.h>

void main()

{

clrscr();

int i,j,k=0;

char x,y,z;

char S[10],A[10],B[10],C[10];

printf("\t Enter String S->");

gets(S);

for(i=0;i<=strlen(S)-1;i=i+1)

{

x=S[i];

z=S[i+1];

if(x>='a' && x<='z')

{

printf("\n \n \t First(S)-> %c",x);

break;

}

else

Page 24: Compiler Design File

{

printf("\n \n \t Enter String for %c-> ",x);

label1:

gets(C);

for(j=0;j<=strlen(C)-1;j++)

{

y=C[j];

if(y>='a' && y<='z')

goto label;

else

{

printf("\n\t Enter String For %c-> ",y);

goto label1;

}

}

}

}

label:

printf("\n\tFirst(S)->%c%c",y,z);

getch();

}

Page 25: Compiler Design File

Output:

Page 26: Compiler Design File

Program 8: Write a program to find the FIRST of a variable.

#include<stdio.h>

#include<conio.h>

#include<string.h>

void main()

{

clrscr();

int i,j,k=0;

char x,y,z;

char S[10],A[10],B[10],C[10];

printf("\t Enter String S->");

gets(S);

for(i=0;i<=strlen(S)-1;i=i+1)

{

x=S[i];

z=S[i+1];

if(x>='a' && x<='z')

{

printf("\n \n \t First(S)-> %c",x);

break;

}

else

Page 27: Compiler Design File

{

printf("\n \n \t Enter String for %c-> ",x);

label1:

gets(C);

for(j=0;j<=strlen(C)-1;j++)

{

y=C[j];

if(y>='a' && y<='z')

goto label;

else

{

printf("\n\t Enter String For %c-> ",y);

goto label1;

}

}

}

}

label:

printf("\n\tFirst(S)->%c%c",y,z);

getch();

}

Page 28: Compiler Design File

Output:

Page 29: Compiler Design File

Program 9: Write a program to find the FOLLOW of a variable.

#include<stdio.h>

#include<conio.h>

#include<math.h>

void first(char ch);

char p[10][10]={"S->aAB","A->Bc","B->d"};

char stk[10];

int top=-1;

int c=0;

int follow(char ch)

{

int i,j,c1,count=0,x;

if(ch=='S')

{

printf("$");

//break;

}

for(i=0;i<3;i++)

{

if(ch==p[i][0])

count++;

for(j=3;p[i][j]!='\0';j++)

Page 30: Compiler Design File

{

if(p[i][j]==ch && p[i][j+1]!='\0')

{

if(p[i][j+1]=='a' || p[i][j+1]=='c' || p[i][j+1]=='d')

printf(",%c",p[i][j+1]);

else

first(p[i][j+1]);

}

if(p[i][j]==ch && p[i][j+1]=='\0')

x=follow(p[i][0]);

}

}

return count;

}

void first(char ch)

{ int i;

for(i=0;i<3;i++)

{

if(ch==p[i][0])

{

if(p[i][3]=='a' || p[i][3]=='c' || p[i][3]=='d')

printf("%c",p[i][3]);

else

Page 31: Compiler Design File

{

top++;

stk[top]=p[i][3];

if(p[i][3]=='B')

{

if(p[i][4]=='a' || p[i][4]=='c' ||p[i][4]=='d')

printf("%c",p[i][4]);

else

{

top++;

stk[top]=p[i][4];

}

}

}

}

}

while(top!=-1)

{

char ch1;

ch1=stk[top];

top--;

first(ch1);

}

Page 32: Compiler Design File

}

void main()

{

int i;

clrscr();

printf("Grammeris-------->S->aAB A->Bc B->d");

for(i=0;i<3;i=i+c)

{

printf("\nFollow of %c is:" ,p[i][0]);

c=follow(p[i][0]);

}

getch();

}

Output:

Page 33: Compiler Design File

Program 10: Write a program to find the Trailing Terminals in the String.#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

#include<string.h>

#include<iostream.h>

void main()

{

clrscr();

char str1[10],str2[10];

char x,y,z;

int i,j,k;

printf("\nEnter String For finding Trailing Terminal\t S-> ");

gets(str1);

for(i=strlen(str1)-1;i>=0;i--)

{

x=str1[i];

if(x>='a' && x<='z')

{

printf("\nTrailing Terminal of the String \t S-> %c",x);

break;

}

else

Page 34: Compiler Design File

{

printf("\nEnter Production for \t %c-> ",x);

label1:

gets(str2);

k=strlen(str2)-1;

y=str2[k];

if(str2[k]>='a' && str2[k]<='z')

{

y=str2[k];

goto label2;

}

else

{

printf("\nEnter Production for \t %c-> ",y);

goto label1;

}

label2:

for(j=i-1;j>=0;j--)

{

z=str1[j];

if(z>='a' && z<='z')

goto label;

}

Page 35: Compiler Design File

}

}

label:

printf("\n\n\Trailing Terminal of the String \tS-> %c%c",y,z);

getch();

}

Output: