Sei sulla pagina 1di 40

ACROPOLIS INSTITUTE OF TECHNOLOGY & RESEARCH BHOPAL (M.P.

DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

Compiler Design Lab Manual

Submitted to: Prof-Shivendra Dubey

submitted by Hariom Dhakad (0171cs101025)

PRACTICAL CONDUCTED IN LAB


(As per syllabus)

S.No 1 2 3 4 5 6 7 8

TOPIC Develop a lexical analyzer to recognize a few patterns. Implement the lexical analyzer using Lex Design predictive parser for the given language Develop LL (1) parser (Construct parse table also). Develop an operator precedence parser (Construct parse table also) Write a program to compute FIRST of non-terminals Write a program to compute FOLLOW of non-terminals Write a program to find leading terminals

Page No. 7-10 11-14 15-21 22-26 27-36 37-40 41-44 45-48

Experiment No-1 Develop a lexical analyzer to recognize a few patterns. ALGORITHM:


Building a Lexical Analyzer needs a language that must describe the tokens, token codes, and token classification. It also needs to design a suitable algorithm to be implemented in program that can translate the language into a working lexical analyzer. We have used C language in particular, for implementation as powerful tool enough to describe the Meta symbols used in regular expressions, as well as non-printable ASCII characters. We have also described a shorthand notation for the range of ASCII characters, e.g. all lower-case letters. Algorithm: Tokenizer(S) Where S = Input string. Output: A set of tokens Step 1: Initialize S. Step 2: Define symbol table. Step 3: Repeat while scanning (left to right) S is not Completed i. If blank (empty space) a. Neglect and eliminate it. ii. If operator op // arithmetic, relational, etc. a. Find its type. b. Write op. iii. If keyword key // if, while, for, etc. a. Write key. iv. If identifier id // a, b, c, etc a. Write id. v. If special character sc // (,), etc. a. Write sc. Step 4: Exit Complexity Analysis: Initially, the input string is considered in anarray. The already built symbol table is used here. Thus, the running time of the above algorithm will be the scanning of the string from left to right i.e. linear in nature.

PROGRAM:
#include<string.h> #include<ctype.h> #include<stdio.h> void keyword(char str[10]) { if(strcmp("for",str)==0||strcmp("while",str)==0||strcmp("do",str)==0||strcmp("int",str)==0||strcmp("f loat",str)==0||strcmp("char",str)==0||strcmp("double",str)==0||strcmp("static",str)==0||strcmp("switc h",str)==0||strcmp("case",str)==0) printf("\n%s is a keyword",str); else printf("\n%s is an identifier",str); } main() { FILE *f1,*f2,*f3; char c,str[10],st1[10]; int num[100],lineno=0,tokenvalue=0,i=0,j=0,k=0; printf("\nEnter the c program");/*gets(st1);*/ f1=fopen("input","w"); while((c=getchar())!=EOF) putc(c,f1); fclose(f1); 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=='$') {
4

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); printf("\nThe no's in the program are"); for(j=0;j<i;j++) printf("%d",num[j]); printf("\n"); f2=fopen("identifier","r"); k=0; printf("The keywords and identifiersare:"); while((c=getc(f2))!=EOF) { if(c!=' ') str[k++]=c; else { str[k]='\0'; keyword(str); k=0; } } fclose(f2); f3=fopen("specialchar","r"); printf("\nSpecial characters are"); while((c=getc(f3))!=EOF) printf("%c",c); printf("\n"); fclose(f3); printf("Total no. of lines are:%d",lineno); }

Input:
Enter the C program a+b*c Ctrl-D

OUTPUT:
The nos in the program are: The keywords and identifiers are: a is an identifier and terminal b is an identifier and terminal c is an identifier and terminal Special characters are: +* Total no. of lines are: 1

Questions
1. What are the following w.r.t. Lexical Analyzers? (i) Definition and role of lexical analyzer (ii) Lexeme (iii)Token (iv) Pattern (v) Regular (Auxiliary) Definitions 2. W.r.t. Lexical analyzers define: (a) Input buffering (b) Specification and recognition of tokens (c) Function of lexical analyzer 3. What are the applications of a Lexical analyzer? Apart from compiler, where be can used a lexical analyzer.

Experiment No-2 Implement the Lexical Analyzer Using LEX Tool. About Lexical Analyzer: Lexical Analyzer reads the source program character by character to produce tokens. 1. It divides the program as a collection of word. 2. Than verify the validity of each and every word & store them in to symbol table. 3. For valid word it returns token and attribute to syntax analyzer. 4. if word is invalid than case is reported to error handler.

About Lex: Lex is a program generator designed for lexical processing of character input streams. It accepts a high-level problem oriented specification for character string matching, and produces a program in a general purpose language which recognizes regular expressions. Input specification file is in 3 parts Declarations: Definitions Rules: Token Descriptions and actions Auxiliary Procedures: User-Written code Three parts are separated by %% The first part defines patterns, the third part defines actions, the second part puts together to express If we see some pattern, then we do some action. ALGORITHM
1. 2. Declare the necessary symbols and header files needed. Write the pattern and corresponding actions to be taken. if the pattern is # , * print it as a header file if the pattern is int / float / char / return / main / print it as a keyword
7

If the pattern is [] [a z A Z ] [] print as a string. similarly identify patterns and actions for all tokens. 3. In the main function declare a file pointer ti read input file and yylex ( ) to find matching patterns and corresponding actions to be taken.

PROGRAM
%{ /* program to recognize a c program */ int COMMENT=0; %} identifier [a-zA-Z][a-zA-Z0-9]* %% #.* { printf("\n%s is a PREPROCESSOR DIRECTIVE",yytext);} int | float | char | double | while | for | do | if | break | continue | void | switch | case | long | struct | const | typedef | return | else | goto {printf("\n\t%s is a KEYWORD",yytext);} "/*" {COMMENT = 1;} /*{printf("\n\n\t%s is a COMMENT\n",yytext);}*/ "*/" {COMMENT = 0;} /* printf("\n\n\t%s is a COMMENT\n",yytext);}*/ {identifier}\( {if(!COMMENT)printf("\n\nFUNCTION\n\t%s",yytext);} \{ {if(!COMMENT) printf("\n BLOCK BEGINS");} \} {if(!COMMENT) printf("\n BLOCK ENDS");} {identifier}(\[[0-9]*\])? {if(!COMMENT) printf("\n %s IDENTIFIER",yytext);} \".*\" {if(!COMMENT) printf("\n\t%s is a STRING",yytext);} 8

[0-9]+ {if(!COMMENT) printf("\n\t%s is a NUMBER",yytext);} \)(\;)? {if(!COMMENT) printf("\n\t");ECHO;printf("\n");} \( = ECHO; {if(!COMMENT)printf("\n\t%s is an ASSIGNMENT OPERATOR",yytext);}

\<= | \>= | \< | == | \> {if(!COMMENT) printf("\n\t%s is a RELATIONAL OPERATOR",yytext);} %% int main(int argc,char **argv) { if (argc > 1) { FILE *file; file = fopen(argv[1],"r"); if(!file) { printf("could not open %s \n",argv[1]); exit(0); } yyin = file; } yylex(); printf("\n\n"); return 0; } int yywrap() { return 0; }

Input:
$vi var.c #include<stdio.h> main() { int a,b; 9

Output:
$lex lex.l $cc lex.yy.c $./a.out var.c #include<stdio.h> is a PREPROCESSOR DIRECTIVE FUNCTION main ( ) BLOCK BEGINS int is a KEYWORD a IDENTIFIER b IDENTIFIER BLOCK ENDS

Questions:
1. What is Lex? What are the Lex Specifications? 2. What are lex and Yacc tools? 3. Difference between Lex and Yacc tools.

10

Experiment No-3 Design predictive parser for the given language About Predictive Parser:
Just as with lexical analysis, we can either hard-code a top-down parser, or build a generic table-driven interpreter. The latter is called a Predictive Parser. Instead of using recursion we store the current state of the parse on a stack: The predictive parser has 1an input stream (list of tokens followed by the end-of-file-marker $), 2a stack with a sequence of grammar symbols, and an end-of-stack-marker $, 3a parsing table M [A, a] P mapping a non-terminal A and a terminal a to a grammar production P. Initially, the stack holds the start symbol, S. At each step, the interpreter looks at the top stack element (X) and the current input symbol (a). There are three cases: 1. 1 X = a = $ success! 2. M[X, a] = error bail! 3. X = a 6= $ match (). Move to next token and pop off X. 4. M[X, a] = {X UVW} a) Pop X off the stack, then b) Push (W), Push (V), Push (U). 2

ALGORITHM :
a := first token repeat X := top() if X is a terminal or $ then if X = a then pop() a := next token else error else if M[X, a] = X Y1Y2 Yk then pop() push(Yk); ; Push(Y1)
11

else error until X = $

PROGRAM:
#include<stdio.h> #include<ctype.h> #include<string.h> #include<stdlib.h> #define SIZE 128 #define NONE -1 #define EOS '\0' #define NUM 257 #define KEYWORD 258 #define ID 259 #define DONE 260 #define MAX 999 char lexemes[MAX]; char buffer[SIZE]; int lastchar=-1; int lastentry=0; int tokenval=DONE; int lineno=1; int lookahead; struct entry { char *lexptr; int token; }symtable[100]; struct entry keywords[]={"if",KEYWORD,"else",KEYWORD,"for",KEYWORD,"int",KEYWORD,"float",KE YWORD,"double",KEYWORD,"char",KEYWORD,"struct",KEYWORD,"return",KEYWORD,0,0 }; void Error_Message(char *m) { fprintf(stderr,"line %d, %s \n",lineno,m); exit(1); } int look_up(char s[ ]) { int k; for(k=lastentry;k>0;k--) if(strcmp(symtable[k].lexptr,s)==0) return k; return 0;
12

} int insert(char s[ ],int tok) { int len; len=strlen(s); if(lastentry+1>=MAX) Error_Message("Symbpl table is full"); if(lastchar+len+1>=MAX) Error_Message("Lexemes array is full"); lastentry=lastentry+1; symtable[lastentry].token=tok; symtable[lastentry].lexptr=&lexemes[lastchar+1]; lastchar=lastchar+len+1; strcpy(symtable[lastentry].lexptr,s); return lastentry; } /*void Initialize() { struct entry *ptr; for(ptr=keywords;ptr->token;ptr+1) insert(ptr->lexptr,ptr->token); }*/ int lexer() { int t; int val,i=0; while(1) { t=getchar(); if(t==' '||t=='\t'); else if(t=='\n') lineno=lineno+1; else if(isdigit(t)) { ungetc(t,stdin); scanf("%d",&tokenval); return NUM; } else if(isalpha(t)) { while(isalnum(t)) { buffer[i]=t; t=getchar(); i=i+1; if(i>=SIZE) Error_Message("Compiler error"); }
13

buffer[i]=EOS; if(t!=EOF) ungetc(t,stdin); val=look_up(buffer); if(val==0) val=insert(buffer,ID); tokenval=val; return symtable[val].token; } else if(t==EOF) return DONE; else { tokenval=NONE; return t; } } } void Match(int t) { if(lookahead==t) lookahead=lexer(); else Error_Message("Syntax error"); } void display(int t,int tval) { if(t=='+'||t=='-'||t=='*'||t=='/') printf("\nArithmetic Operator: %c",t); else if(t==NUM) printf("\n Number: %d",tval); else if(t==ID) printf("\n Identifier: %s",symtable[tval].lexptr); else printf("\n Token %d tokenval %d",t,tokenval); } void F() { //void E(); switch(lookahead) { case '(' : Match('('); E(); Match(')'); break; case NUM : display(NUM,tokenval); Match(NUM); break;
14

case ID : display(ID,tokenval); Match(ID); break; default : Error_Message("Syntax error"); } } void T() { int t; F(); while(1) { switch(lookahead) { case '*' : t=lookahead; Match(lookahead); F(); display(t,NONE); continue; case '/' : t=lookahead; Match(lookahead); display(t,NONE); continue; default : return; } } } void E() { int t; T(); while(1) { switch(lookahead) { case '+' : t=lookahead; Match(lookahead); T(); display(t,NONE); continue; case '-' : t=lookahead; Match(lookahead); T(); display(t,NONE); continue; default : return; } }
15

} void parser() { lookahead=lexer(); while(lookahead!=DONE) { E(); Match(';'); } } main() { char ans[10]; printf("\n Program for recursive decent parsing "); printf("\n Enter the expression "); printf("And place ; at the end\n"); printf("Press Ctrl-Z to terminate\n"); parser(); }

Input:
Program for Predictive parsing Enter the expression and place ; at the end Press Ctrl-Z to terminate a+b*c; 2*3;

OutPut:
Identifier: a Identifier: b Identifier: c Arithmetic Operator: * Arithmetic Operator: + Number: 2 Number: 3 Arithmetic Operator: * +3; line 5,Syntax erro

16

Experiment No-4 Develop LL (1) parser (Construct parse table also). About LL(1) Parser: The key property of a LL(1) parser is that it never requires
backtracking, making it a deterministic parser. LL parsers proceed by reading the input from left-to-right and producing a left-most derivation, hence the name. A LL(1) parser uses an explicit stack rather than the implicit call stack associated with a recursive descent parser, and encodes the production rules in a lookup table rather than code . Much of the work performed by a LL(1) parser, then, involves building the parse table and modifying the grammar to simplify that process.

ALGORITHM:

PROGRAM:
17

#include <stdio.h> #include <ctype.h> #define MAXPRIO 5 #define prio(op) (ptab[op]) struct token { int t_tokno; /* token number */ int t_tval; /* Its attribute */ } stok = { 0,0 }, tok; int nerrors = 0; int regs[26]; /* Space for the registers */ int ptab[128]; /* Attribute table */ struct token nexttok() { /* Read next token and return it */ register c; struct token new; while ((c = getchar()) == || c == \t) { /* nothing */ } if (isdigit(c)) new.t_tokno = DIGIT; else if (islower(c)) new.t_tokno = IDENT; else new.t_tokno = c; if (c >= 0) new.t_tval = ptab[c]; return new; }} %token DIGIT, IDENT; %start parse, list; list : stat* ; stat { int ident, val; } : %if (stok = nexttok(), stok.t_tokno == =) /* The conflict is resolved by looking one further * token ahead. The grammar is LL(2) */ IDENT { ident = tok.t_tval; } = expr(1,&val) \n { if (!nerrors) regs[ident] = val; } | expr(1,&val) \n { if (!nerrors) printf("%d\n",val); } | \n ; expr(int level; int *val;) { int expr; } : factor(val) [ %while (prio(tok.t_tokno) >= level) /* Swallow operators as long as their priority is * larger than or equal to the level of this invocation */ + expr(prio(+)+1,&expr) { *val += expr; } /* This states that + groups left to right. If it * should group right to left, the rule should read: 18

* + expr(prio(+),&expr) */ | - expr(prio(-)+1,&expr) { *val -= expr; } | * expr(prio(*)+1,&expr) { *val *= expr; } | / expr(prio(/)+1,&expr) { *val /= expr; } | % expr(prio(%)+1,&expr) { *val %= expr; } | & expr(prio(&)+1,&expr) { *val &= expr; } | | expr(prio(|)+1,&expr) { *val |= expr; } ]* /* Notice the "*" here. It is important. */ ; factor(int *val;): ( expr(1,val) ) | - expr(MAXPRIO+1,val) { *val = -*val; } | number(val) | IDENT { *val = regs[tok.t_tval]; } ; number(int *val;) { int base; } : DIGIT { base = (*val=tok.t_tval)==0?8:10; } [ DIGIT { *val = base * *val + tok.t_tval; } ]* ; %lexical scanner ; { scanner() { if (stok.t_tokno) { /* a token has been inserted or read ahead */ tok = stok; stok.t_tokno = 0; return tok.t_tokno; } if (nerrors && tok.t_tokno == \n) { printf("ERROR\n"); nerrors = 0; } tok = nexttok(); return tok.t_tokno; - 12 } LLmessage(insertedtok) { nerrors++; if (insertedtok) { /* token inserted, save old token */ stok = tok; 19

tok.t_tval = 0; if (insertedtok < 128) tok.t_tval = ptab[insertedtok]; } } main() { register *p; for (p = ptab; p < &ptab[128]; p++) *p = 0; /* for letters, their attribute is their index in the regs array */ for (p = &ptab[a]; p <= &ptab[z]; p++) *p = p - &ptab[a]; /* for digits, their attribute is their value */ for (p = &ptab[0]; p <= &ptab[9]; p++) *p = p - &ptab[0]; /* for operators, their attribute is their priority */ ptab[*] = 4; ptab[/] = 4; ptab[%] = 4; ptab[+] = 3; ptab[-] = 3; ptab[&] = 2; ptab[|] = 1; parse(); exit(nerrors); }}

Input:
LL(1) PARSER TABLE NT <id> + E Te Error e Error +Te T Vt Error t Error V <id> Error * ; Error Error Error Error Error *Vt Error Error

ENTER THE STRING :<id>+<id>*<id>;

OUTPUT:
CHECKING VALIDATION OF THE STRING E Te Vte <id>te <id>e <id>+Te <id>+Vte <id>+<id>te <id>+<id>*Vte <id>+<id>*<id>te <id>+<id>*<id>e <id>+<id>*<id> ENTERED STRING IS VA

20

Experiment No-5 Develop an operator precedence parser (Construct parse table also) About Operator precedence parser:
Uses a restricted form of shift-reduce parsing to recognize operator grammars: a. Contain no _ productions b.Have no two adjacent non-terminals Table driven approach uses a matrix containing three disjoint precedence relations: 1. < 2. = 3. > Strengths of OPP Easy to implement by hand or by a simple table-driven generator Weaknesses of OPP a. Need clever lexical analyzer to handle certain over- loaded operators e.g., unary + and versus binary + and b. Only handles a small class of languages (operator grammars)

ALGORITHM:
1. Impose anyone of three different relations between each pair to terminals. a) a<.b=> a yields precedence to b b) a.>b=> a takes precedence for b c) a=b=> a has same precedence to b 2. 3. 4. 5. 6. If a is the symbol on top of the stack and b is symbol pointed by input. If a<.b the shift < and b onto stack, advance pointer to next symbol. if a=b, then shift = and b on to stack , advance pointer to next symbol. If a.>b, then pop the symbols off the stack until a<.B is encountered. If stack is $ and input points to $ then announce accept and terminate; else goto step 3.

PROGRAM:
21

# include <stdio.h> # include <stdlib.h> # include <ctype.h> # include <conio.h> # include <string.h> # include <iostream.h> Struct { char nts, trs; } stack[20]; int lead [20] [20], trail[20] [20], nop, top=0; char nr,tr,*p[10], nt[10], t[10], opt[10] [10], starts, stk[20]; void read_grammar( ) { Cout<<\n Enter the terminals : ; Cin >> t ; Cout << \n Enter the nonterminals : ; Cin >> nt ; Cout << \n Enter the productions : ; Cin >> nop ; for (int i = 0 ; i< nop ;i++) { p[i] =new cha [10]; Cin >>p[i]; Starts =p[0] [0] ; } int nt_no (char x ) { if (x!=\0) { for(int i=0; nt[i] !=\0; i++ ) if (nt [i] ==x) return(i); } } int t_no (char x) { If (x ! = \0) { for (int i = 0; t[i] ! = \0 ; i++) if (t [ i] = =x) return (strelen(t)); } 22

} int nonterminal ( char x) if (x ! = \0) } for ( int i = 0;i<= strelen (t) ; i++) if (t[i] = =x ) return(1); } return(0) ; int terminal ( char x) if (x ! = \0) } for ( int i = 0;i<= strelen (t) ; i++) if (t[i] = =x ) return1); } return(0) ;

void push (int r ,int c) { top++; stack[top] .nts =nt[r]; stack[top] .trs =t[c]; } void pop ( ) { nr =stack[top] .nts tr =stack[top] .trs top_ _ } void install (int r, int c, int lt) if (lt = = 1) { if (! Lead [r] [c]) { lead [r] [c] =1 ; push (r ,c) ; } } if (lt = = 2) { if (!trail [r] [c] =1 ; { trail [r] [c] =1; push (r ,c); } } } 23

void leading ( ) { char a ; top = 0; int r ,c ; for (int no =0 ; nt [no] ! =\0 ; np++) { for ( int i = 0 I <nop ; i++) { if (nt[no] = =p[i] [0]) { if (nt[no] = =p[i] [0]) { a = p[i] [3] ; if (terminal (a)) { r =nt_no(p[i] [0]); c= t_no (a) ; install (r,c, l); } else if (nonterminal (a) && terminal (p[i] [4])) { r = nt_no(p[i] [0] ); c=t_no (p[i] [4] ); install (r,c,i); } while ( top ! = 0) { pop ( ); for ( int j=0; j< nop ; j++) { char nont = p [j] [3]; c= t_no ( tr ); install ( r, c, 1); } } } } } } } void trailing ( ) { char a ; int r , o; top = 0; for (int no=0; nt [no] ! = \0 ; no++) { for (int i = 0 ; i< nop; i++) { 24

if (nt [no] = = p[i] [0] ) { int l= strlen (p[i]); a = p[i][l-1]; if (terminal (a)) { r=nt_no (p[i] [0]); c = t_no (a); install (r , c, 2); } else if ( nonterminal (a) && terminal (p[i][l-2]) { r = nt_no (p[i] [0] ); c = t_no ( p[i] [0] ); install (r , c, 2 ); } while ( top ! = 0) { pop( ) ; for (int j=0; n<nop; j++) { int l = strlen (p[j]); char nont= p[j] [l -1 ]; if ( nont = = nr) { r = nt_no(p[j] [0] ); c = t_no(tr); install ( r , c, 2); } } } } } } void prec_tab ( ) { int r , c ; for ( int no =0; no< nop ; no++) { int l = strlen ( p[no] ); for ( int i =3; i<=l-2; i++) { if (terminal (p[no] [i] && terminal( p [no] [i + 1])) { r = t_no(p[no] [i] ); c = t_no(p[no] [i+1]); opt [ r ] [c] = =; } if ( i< l -3) 25

{ if (terminal (p[no] [i])&& terminal( p [no] [i + 1)) { r = t_no(p[no] [i] ); c = t_no(p[no] [i+2]); opt [ r ] [c] = =; } } if (terminal (p[no] [i])&& nonterminal( p [no] [i + 1])) { int pos = nt_no ( p [no] [i + 1]); for ( int j =0 ; j<strlen(t); j++ ) { if (lead [pos] [j] { r = t_no(p[no][i]); opt[r] [j]=<; } } } if (terminal (p[no] [i]) && nonterminal( p [no] [i + 1])) { int pos = nt_no ( p [no] [i ]); for ( int j =0 ; j<strlen(t); j++ ) { if (trail [pos] [j]) { c = t_no(p[no][i+1]); opt[j [c]=>; }} }} }} int pos nt_no (starts); int l =strlen( t); for ( int p=0; p<strlen(t) ; p++) if (lead[pos] [p]) opt [1 ] [p] = <; for (p=0; p<strlen (t); p++) if ( trail [pos] [p]) opt [p] [l] =>; } void show ( ) { cout<< \n leading : ; for ( int x= 0; x<strlen (nt) ; x++) { cout<<\n Leading( << nt [x] <<)= { ; for (int y = 0 ; y<strlen (t) ; y++) if (lead [x] [y]) cout <<t[y] << , ; cout << } } 26

cout << \n Trailing : ; for ( x+ 0 ; < strlen (nt) ; x++) { cout << \n Traing ( << nt [x] << ) = { ; for ( int y= 0 ;y <strelen (t) ; y++) if (trail [x] [y] ) cout << t[y]) cout << } } } void show_tab ( ) { int l = strelen (t) clrscr ( ) cout << \n operetor precedence table : \n\t ; for (int i =0 ; i <=1 i++) cout << $ ; cout < \n ----------------------- \n ; for (i = 0 ; i <= 1 i++) { if ( i = = 1) cout << \n else cout << \n << t[i] ; cout << \t ; for (int j = 0; j<= 1 ; j++) { if ( opt[i][j] = = \0) cout <<\t; else cout << \t << opt [i][j]; } cout<<\n\t; } cout<<\n----------------------------------------; } int parse_str(char *str) { char ts, cs; int r , c pt, pc ; stk[top]=$; cout <<\n STACK \t INPUT \t ACTION \n; cout << <<stk [top] << \t\t << str << \t\t - \n; while ( i ) { if (stk[top] = = $ && str [0] = = $ ) { cout << <<stk [top] << \t << str[0] << \t\t accept \n; return ( i ) ; } else 27

{ ts = stk [top]; cs = str [0]; r = t_no (ts ); c = t_no(cs); if opt [r] [c] = = << || opt[r][c] = = = ) { int t =0 ; cout << while ( t < = top ) {cout << stk [t]; t++; } top++ stk [top] = cs; cout5 << opt [r][c] << stk [top] << \t; strlen (str) ! = 1 ? stropy(str, & str[1] : 0; cout<< str; if(opt[r][c] = = <) cout<<\t\t shift \n ; } else if (opt[r][c] = = >) {do { char pops = stk [top]; int t=0; count<< ; while(t<=top) { cout << stk [t]; t++ } top - - ; if ( stk [top] ! = $) cout << opt [r] [c] < stk <[top]<< \t << str << \t \t Reduce \n ; else cout << opt [r] [c]<< \t << str << \t \t Reduce \n ; pt = t_no ( stk [top]); pc = t_no (pop); } while (opt [pt] [pc] ! = <) ; } else break ; } } return (0); } void main ( ) { 28

char *str , string p[20] ; clrscr ( ) ; read_grammer ( ) ; clrscr ( ) ; leading ( ) ; trailing ( ) ; clrscr ( ) ; show ( ) ; getch ( ); pre_tab ( ); show _tab ( ) ; getch ( ); clrscr ( ); cout << \n Enter string to parse : ; cin >> str ; strcpy ( string , str ) ; int l = strlen (str) ; str [l] = $ ; str [l+i] =\0 ; if (paesse)str (str)) cout <<\n string << string << is accepted ! ; else cout << \n string << string << is not accepted ! ERROR ! ; getch ( ) ; }

Input:
Enter the terminals : + * ( ) i Enter the nonterminals : EFT Enter the no. of productions : 6 E -> E + T E -> T T -> T*F T -> F F -> (E ) F-> i

OUTPUT:
Leading :
Leading ( E ) = { + , * , ( , i } Leading ( F ) = { ( , i, }

29

Experiment No-6 Write a program to compute FIRST of non-terminals How to calculate FRIST symbol:
If a is any string of grammar symbols, let FIRST (a) be the set of terminals that begin the strings derived from a. If a -> e then e is also in FIRST (a).

ALGORITHM:
To compute FIRST(X) for all grammar symbols x, apply the following rules until no more terminals can be added to any FIRST set. 1. if X is terminal, then FIRST(X) is {X}. 2. if X is nonterminal and X -> aa is a production, then add a to FIRST(X). if X-> to FIRST(X) 3. if -> Y1,Y2,.Yk is a production, then for all i such that all of Y1,.Yi-1 are nonterminals and FIRST(Yj) contains for j=1,2, i-1, add every non- symbol in FIRST(Y1) to FIRST(x). if V is in FIRST(Yj) for j=1,2,k, then add to FIRST(X). Now, we can compute FIRST for any string X1X2 . . . Xn as follows. Add to FIRST(X1X2 ... Xn) all the non-e symbols of FIRST(X1). Also add the non-e symbols of FIRST(X2) if e is in FIRST(X1), the non-e symbols of FIRST(X3) if e is in both FIRST(X1) and FIRST(X2), and so on. Finally, add e to FIRST(X1X2 ...X n) if, for all i, FIRST(Xi) contains e.

PROGRAM:
#include<stdio.h> #include<conio.h> #include<string.h> void main() { char t[5],nt[10],p[5][5],first[5][5],temp; int i,j,not,nont,k=0,f=0; clrscr(); printf("\nEnter the no. of Non-terminals in the grammer:"); scanf("%d",&nont); printf("\nEnter the Non-terminals in the grammer:\n"); for(i=0;i<nont;i++)
30

{ scanf("\n%c",&nt[i]); } printf("\nEnter the no. of Terminals in the grammer: ( Enter e for absiline ) "); scanf("%d",&not); printf("\nEnter the Terminals in the grammer:\n"); for(i=0;i<not||t[i]=='$';i++) { scanf("\n%c",&t[i]); } for(i=0;i<nont;i++) { p[i][0]=nt[i]; first[i][0]=nt[i]; } printf("\nEnter the productions :\n"); for(i=0;i<nont;i++) { scanf("%c",&temp); printf("\nEnter the production for %c ( End the production with '$' sign ) :",p[i][0]); for(j=0;p[i][j]!='$';) { j+=1; scanf("%c",&p[i][j]); } } for(i=0;i<nont;i++) { printf("\nThe production for %c -> ",p[i][0]); for(j=1;p[i][j]!='$';j++) { printf("%c",p[i][j]); } } for(i=0;i<nont;i++) { f=0; for(j=1;p[i][j]!='$';j++) { for(k=0;k<not;k++) { if(f==1) break;
31

if(p[i][j]==t[k]) { first[i][j]=t[k]; first[i][j+1]='$ '; f=1; break; } else if(p[i][j]==nt[k]) { first[i][j]=first[k][j]; if(first[i][j]=='e') continue; first[i][j+1]='$ '; f=1; break; } } } } for(i=0;i<nont;i++) { printf("\n\nThe first of %c -> ",first[i][0]); for(j=1;first[i][j]!='$';j++) { printf("%c\t",first[i][j]); } } getch(); }

32

Experiment No-7 Write a program to compute FOLLOW of non-terminals How to calculate FOLLOW symbol:
Define FOLLOW(A), for nonterminal A, to be the set of terminals a that can appear immediately to the right of A in some sentential form, that is, the set of terminals a such that there exists a derivation of the form SaAab for some a and b. Note that there may, at some time during the derivation, have been symbols between A and a, but if so, they derived e and disappeared. If A can be the rightmost symbol in some sentential form, then $, representing the input right end marker, is in FOLLOW(A).

ALGORITHM:
To compute FOLLOW(A) for all nonterminals A, apply the following rules until nothing can be added to any FOLLOW set: 1. Place $ in FOLLOW(S), where S is the start symbol and $ is the input right endmarker. 2. If there is a production A -> aBb, then everything in FIRST(b), except for e, is placed in FOLLOW(B). 3. If there is a production A -> aB, or a production A -> aBb where FIRST(b) contains e (i.e., b -> e), then everything in FOLLOW(A) is in FOLLOW(B).

PROGRAM:
#include"stdio.h" #include<conio.h> #define max 10 #define MAX 15 char array[max][MAX],temp[max][MAX]; int c,n,t;void fun(int,int[]); int fun2(int i,int j,int p[],int key) { int k; if(!key) { for(k=0;k<n;k++) if(array[i][j]==array[k][0]) break; p[0]=i;p[1]=j+1; fun(k,p); return 0;
33

} else { for(k=0;k<=c;k++) { if(array[i][j]==temp[t][k]) break; } if(k>c)return 1; else return 0; } } void fun(int i,int p[]) { int j,k,key; for(j=2;array[i][j]!='\0';j++) { if(array[i][j-1]=='/') { if(array[i][j]>='A'&&array[i][j]<='Z') { key=0; fun2(i,j,p,key); } else {key=1; if(fun2(i,j,p,key)) temp[t][++c]=array[i][j]; if(array[i][j]=='[at]'&&p[0]!=-1) { //taking ,[at], as null symbol. if(array[p[0]][p[1]]>='A'&&array[p[0]][p[1]]<='Z') { key=0; fun2(p[0],p[1],p,key); } else if(array[p[0]][p[1]]!='/'&&array[p[0]][p[1]]!='\0') { if(fun2(p[0],p[1],p,key)) temp[t][++c]=array[p[0]][p[1]]; } } } } } } char fol[max][MAX],ff[max];int f,l,ff0; void ffun(int,int);
34

void follow(int i) { int j,k; for(j=0;j<=ff0;j++) if(array[i][0]==ff[j]) return 0; if(j>ff0)ff[++ff0]=array[i][0]; if(i==0)fol[l][++f]='$'; for(j=0;j<n;j++) for(k=2;array[j][k]!='\0';k++) if(array[j][k]==array[i][0]) ffun(j,k); } void ffun(int j,int k) { int ii,null=0,tt,cc; if(array[j][k+1]=='/'||array[j][k+1]=='\0') null=1; for(ii=k+1;array[j][ii]!='/'&&array[j][ii]!='\0';ii++) { if(array[j][ii]<='Z'&&array[j][ii]>='A') { for(tt=0;tt<n;tt++) if(temp[tt][0]==array[j][ii])break; for(cc=1;temp[tt][cc]!='\0';cc++) { if(temp[tt][cc]=='[at]')null=1; else fol[l][++f]=temp[tt][cc]; } } else fol[l][++f]=array[j][ii]; } if(null)follow(j); } void main() { int p[2],i,j; clrscr(); printf("Enter the no. of productions :"); scanf("%d",&n); printf("Enter the productions :\n"); for(i=0;i<n;i++) scanf("%s",array[i]); for(i=0,t=0;i<n;i++,t++) { c=0,p[0]=-1,p[1]=-1; temp[t][0]=array[i][0]; fun(i,p);
35

temp[t][++c]='\0'; printf("First(%c) : [ ",temp[t][0]); for(j=1;j<c;j++) printf("%c,",temp[t][j]); printf("\b ].\n"); getch(); } /* Follow Finding */ for(i=0,l=0;i<n;i++,l++) { f=-1;ff0=-1; fol[l][++f]=array[i][0]; follow(i); fol[l][++f]='\0'; } for(i=0;i<n;i++) { printf("\nFollow[%c] : [ ",fol[i][0]); for(j=1;fol[i][j]!='\0';j++) printf("%c,",fol[i][j]); printf("\b ]"); getch(); } }

INPUT:
Enter the no. of Non-terminals in the grammer:3 Enter the Non-terminals in the grammer: ETF Enter the no. of Terminals in the grammer: ( Enter e for absiline ) 6 Enter the Terminals in the grammer: +*( ) id Enter the productions: Enter the production for E ( End the production with '$' sign ) : Enter the production for T ( End the production with '$' sign ) : production for F ( End the production with '$' sign ) : ( E ) | id$ OUTPUT The production for E ->: The production for R -> The production for T -> (E) | id The follow of E -> ) , $ The follow of T -> +, ), $ The follow of F -> +, *, ), $
36

$ Enter the

Experiment No-8 Write a program to find leading terminals How To Calculate Leading symbols
(I) LEADING (A) = { a| A =>+ a, where is or a single non-terminal.} (II) If production is of type: A =>+ B {than LEADING (A) = LEADING (B)}

ALGORITHM:
1. Start 2. For each nonterminal A and terminal a do L(A,a):= false; 3. For each production of the form A->a or A->B do INSTALL(A,a); 4. While STACK not empty repeat step 5& 6 5. Pop top pair (B,a) from STACK; 6. For each production of the form A->B do INSTALL(A,a) 7. Stop

Algorithm For INSTALL (A, a)


1. Start 2. If L(A,a) not present do step 3 and 4. 3 . Make L(A,a)=True 4 . Push (A,a) onto stack 5 . Stop

37

PROGRAM:
#include<conio.h> #include<stdio.h> char arr[18][3] = { {'E','+','F'},{'E','*','F'},{'E','(','F'},{'E',')','F'},{'E','i','F'},{'E','$','F'}, {'F','+','F'},{'F','*','F'},{'F','(','F'},{'F',')','F'},{'F','i','F'},{'F','$','F'}, {'T','+','F'},{'T','*','F'},{'T','(','F'},{'T',')','F'},{'T','i','F'},{'T','$','F'}, }; char prod[6] = "EETTFF"; char res[6][3]= { {'E','+','T'},{'T','\0'}, {'T','*','F'},{'F','\0'}, {'(','E',')'},{'i','\0'}, }; char stack [5][2]; int top = -1; void install(char pro,char re) { int i; for(i=0;i<18;++i) { if(arr[i][0]==pro && arr[i][1]==re) { arr[i][2] = 'T'; break; } } ++top; stack[top][0]=pro; stack[top][1]=re; } void main() { int i=0,j; char pro,re,pri=' '; clrscr(); for(i=0;i<6;++i) { for(j=0;j<3 && res[i][j]!='\0';++j) {
38

if(res[i][j] =='+'||res[i][j]=='*'||res[i][j]=='('||res[i][j]==')'||res[i][j]=='i'||res[i][j]=='$') { install(prod[i],res[i][j]); break; } } } while(top>=0) { pro = stack[top][0]; re = stack[top][1]; --top; for(i=0;i<6;++i) { if(res[i][0]==pro && res[i][0]!=prod[i]) { install(prod[i],re); } } } for(i=0;i<18;++i) { printf("\n\t"); for(j=0;j<3;++j) printf("%c\t",arr[i][j]); } getch(); clrscr(); printf("\n\n"); for(i=0;i<18;++i) { if(pri!=arr[i][0]) { pri=arr[i][0]; printf("\n\t%c -> ",pri); } if(arr[i][2] =='T') printf("%c ",arr[i][1]); } getch();}

39

40

Potrebbero piacerti anche