Вы находитесь на странице: 1из 37

Ex No : 1 Date : LEXICAL ANALYZER

Aim:

ALGORITHM:

PROGRAM:

Ex No : 2 Date : LEXICAL ANALYZER USING LEX TOOL

PROGARM digits[0-9] letters[a-zA-Z] delimiters[\,\:\;] arithmetic[\+\-\*\/\%] relational[\==\!\<\<=\>\>=] %{ int line=0; %} %% #.* {printf("\n%s is a preprocessor directive",yytext);} "/*".*"*/" {printf("\n%s is a comment statement",yytext);} \".*\" {printf("\n%s is a control string",yytext);} int | float | char | double | void | long | if | else | while | do | for | goto | break | continue | switch | case | default | return {printf("\n %s is a keyword",yytext);} {letters}({letters}|{digits})* {printf("\n %s is an identifier",yytext);} {digits}+ {printf("\n %s is a number",yytext);} {delimiters}? {printf("\n %s is a special symbol_delimiter",yytext);} \{ {printf("\n %s is a opening brace",yytext);} \} {printf("\n %s is a closing brace",yytext);} \( {printf("\n %s is a left paranthesis",yytext);} \) {printf("\n %s is a right paranthesis",yytext);} \= {printf("\n %s is an assignment operator",yytext);} {arithmetic}? {printf("\n %s is an arithmetic operator",yytext);} {relational}? {printf("\n %s is a relational operator",yytext);} \n {line++;} %%

int main(int argc,char**argv) { yyin=fopen(argv[1],"r"); yylex(); printf("\n\n\n No of line scanned:%d",line); fclose(yyin); return 0; }

Ex No : 3 Date : RECURSIVE DESCENT PARSER AIM: To write a C program to implement the recursive descent parser. CONCEPT: 1. Recursive descent parsing is one of the simplest parsing techniques that is used in practice. Basic idea is to associate each non-terminal in a procedure. 2. The goal of each such procedure is to read a sequence of input characters that can be generated by the corresponding non-terminal and return a pointer to the root of the parse tree for a non-terminal. 3. The structure of the procedure is dictated by the productions for the corresponding nonterminal. 4. The procedure attempts to match the right hand side of some production for the nonterminal. 5. To match a terminal symbol, the procedure compares the terminal symbol to the input if they agrees then the procedure is successful and it consumes the terminal symbol in the input i.e. moves the input cursor over one symbol. 6. To match a non-terminal symbol, the procedure simply calls the corresponding procedure for that non-terminal symbol. 7. In order to implement a recursive descent cursor for a grammar for each non-terminal of the grammar, it must be possible to determine which production to apply for the nonterminal by looking at only one upcoming input symbol. 8. The look ahead symbol is simply the next terminal that we will try to match in the input. We use a single look ahead symbol to decide what production to match. ALGORITHM: 1. Read the input string and initiate the pointer to zero. 2. If the current character pointed by the pointer is neither a number nor e(epsilon). Then goto step 7. 3. If the current character pointed by the pointer is $, then prompt that input is accepted else increment the pointer. 4. If the current character is an operator then increment the pointer and print that as an operator, else goto step 7. 5. If the current charater is a number then increment the pointer and point that as a number, else goto step 7. 6. Goto step 3. 7. Print that given input string is not accepted by the grammar.

PROGRAM #include <conio.h> #include <stdio.h> void main() { int i=0,l; char a[10]; clrscr(); printf("Enter the input string : "); scanf("%s",a); l=strlen(a); do { if(a[0] == '$') { printf("the string is accepted"); break; } if(isdigit(a[i])&&a[i]!=a[l-2]) { printf("\n%c is a number",a[i]); if(i ==0 ) printf("\tE->NUMT"); else printf("\tT->NUMT"); } else if(isdigit(a[i])&&a[i] == a[l-2]) { printf("\n%c is anumber",a[i]); printf("\tT->S"); } if((a[i+1]=='+')&&(a[l-1]=='$')) { printf("\n%c is a operator",a[i+1]); printf("\tT->+NUMT"); } else if(a[i+1]=='-'&&a[l-1]=='$') { printf("\n%c is a operator",a[i+1]); printf("\tT->NUMT"); } else if(a[i+1] =='*' && (a[l-1]=='$')) { printf("\n%c is a operator",a[i+1]); printf("\tT->*NUMT"); } else if(a[i+1] == '/' && (a[l-1] == '$')) { printf("\n%c is a operator",a[i+1]); printf("\tT->/NUMT");

} if(a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/'||a[l-1]!='$') { if(a[i+2] == '+'||a[i+2]=='-'||a[i+2]=='*'||a[i+2]=='/'||a[l-1]!='$') { printf("is not accepted"); break; } } i++; }while(a[i]!=a[l]); getch(); }

OUTPUT Enter The Input String:1+2-4$ 1 is a number E->NUMT + is a operator T->+NUMT 2 is a number T->NUMT - is a operator T->-NUMT 4 is a number T->$

RESULT: Thus the program to perform recursive descent parser was executed successfully.

Ex No : 4 Date : IMPLEMENT THE PARSER USING LEX AND YACC AIM: To write a program using lex and yacc to implement parser. CONCEPT: The parser generator yacc(yet another compiler compiler) A yacc source program has 3 parts: Declaration %% Translation rules %% Supporting C-routines. 1) The declaration part: The are 2 optional sections declaration part of a yacc program. 1.ordinary(declarations delimited by %{ and %} Eg: %{ #include<ctype.h> %} 2.declaration of grammar tokens Eg:%token DIGIT 2) The translation rules part: each rule consists of a grammar productions and the Eg:<left side> :<alt1> !<alt2> 3) The supporting C routines part: It consists of one main function in which the routine yyparse() will be called and it also consist of required C functions. The typical yacc translator can be represented as

Specification file filename.y

y.tab.c and y.tab.h

Yacc compiler with d option

y.tab.c

a.out

Co-The C compiler

input string

output

Executable program a.out

YACC:PARSER GENERATOR MODEL ALGORITHM: 1. Write the lex code to include all the required header files. 2. In the declaration part of the lex file write the patterns and the corresponding action to reduce the value of yacc. 3. In the yacc code declare the required variables and function globally. 4. And in the corresponding declaration part, write the production as patterns and prompt accept if the input matches the pattern in the action part. 5. Call yyparse() in the main.

PROGRAM //LEXSPECIFIC.L %{ #include<stdlib.h> #include"y.tab.h" void yyerror(char *); %} %% [0-9] { printf ("%s \tis a number \n",yytext); return INTEGER;} [-+/*] { printf ("%s\t is an operator \n",yytext); return *yytext; } [\n] return *yytext; [\t] ; yyerror ("invalid character"); %% //YACCSPECIFIC.Y %{ #include<stdio.h> void yerror(char *); int yylex(void); %} %token INTEGER %left '+' %left '*' %% S: E '\n'{printf("\n \t ACCEPTED\n");exit(0);} | ; %{ #include<stdio.h> void yerror(char *); int yylex(void); %} %token INTEGER %left '+' %left '*' %% S: E '\n'{printf("\n \t ACCEPTED\n");exit(0);} | ; E: E'+'E |T ; T:

T'*'F |F ; F: '('E')' |INTEGER ; %% void yyerror(char*s) { printf(%s \n\t not accepted \n,s); exit(0); } int main() { printf(enter the arithmetic expression); yyparse(); return(); }

OUTPUT: [user@server user]$ lex lexspecific.l [user@server user]$ yacc -d yaccspecific.y [user@server user]$ cc lex.yy.c y.tab.c -ll [user@server user]$ ./a.out Enter the Arithmetic Expression:1*2*3 1 is a number * is an operator 2 is a number * is an operator 3 is a number ACCEPTED [user@server user]$

RESULT: Thus the program using to implement a parser using LEX and YACC was executed successfully.

Ex No : 5

Date :
IMPLEMENTATION OF DESK CALCULATOR USING YACC AIM: To write a program using yacc to implement desk calculator. CONCEPT: The parser generator yacc(yet another compiler compiler) A yacc source program has 3 parts: Declaration %% Translation rules %% Supporting C-routines. 1) The declaration part: The are 2 optional sections declaration part of a yacc program. 1.ordinary(declarations delimited by %{ and %} Eg: %{ #include<ctype.h> %} 2.declaration of grammar tokens Eg:%token DIGIT 2) The translation rules part: each rule consists of a grammar productions and the Eg:<left side> :<alt1> !<alt2> 3) The supporting C routines part: It consists of one main function in which the routine yyparse() will be called and it also consist of required C functions. The typical yacc translator can be represented as ALGORITHM: 1. Write the lex code to include all the required header files. 2. In the declaration part of the lex file write the patterns and the corresponding action to reduce the value of yacc. 3. In the yacc code declare the required variables and function globally. 4. And in the corresponding declaration part, write the production as patterns and prompt accept if the input matches the pattern in the action part. 5. Call yyparse() in the main.

PROGRAM LEXCALC %{ #include<stdlib.h> #include"y.tab.h" #define YYSTYPE int extern YYSTYPE yylval; void yyerror(char*); %} %% [0-9]+ { yylval=atoi(yytext); return INTEGER; } [-+()/*\n] {return *yytext;} [\t] ; yyerror ("invalid character not accepted"); %%

YACCCALC %{ #include<stdlib.h> #include"y.tab.h" #define YYSTYPE int extern YYSTYPE yylval; void yyerror(char*); %} %% [0-9]+ {

yylval=atoi(yytext); return INTEGER; } [-+()/*\n] {return *yytext;} [\t] ; yyerror ("invalid character not accepted"); %%

OUTPUT [user@server user]$ lex calclex.l [user@server user]$ yacc -d calcyacc.y [user@server user]$ cc lex.yy.c y.tab.c -ll [user@server user]$ ./a.out Expression:(1+2)*4/3 Answer=4 [user@server user]$

RESULT: Thus the implementation of desk calculator using LEX and YACC was done and verified.

Ex No : 6

Date : ELIMINATION OF LEFT RECURSION PROGRAM #include<iostream.h> #include<conio.h> #include<stdio.h> #include<string.h> void main() { clrscr(); FILE *f1; int aaaa; int a,t,i1,i2,i,k=0; char a1[10][10],e1[10],e2[10],s1[2]; printf("\t\t LEFT RECURSION \n\n"); f1=fopen("pp.txt","r"); while(!feof(f1)) { fscanf(f1,"%s",a1[k]); printf("%s\n\n",a1[k]); k++; } printf("Total Productions:\t%d",k); printf("\n AFTER LEFT RECURSION:\n\n"); for(int i4=0;i4<k;i4++) { int e=0; a=strlen(a1[i4]); for(int w=0;w<10;w++) { e1[w]=NULL; e2[w]=NULL; } getch(); if(a1[i4][0]==a1[i4][2]) { t=0;i1=0;i2=0; for(i=3;i<=a;i++) { if(t==0) { if(a1[i4][i]!='/') { e1[i1]=a1[i4][i];i1++;

} else t=1; } if(t==1) { e2[i2]=a1[i4][i+1]; i2++; } } } else { e1[i1]=a1[i4][2]; e2[i2]=NULL; printf("\n%s",a1[i4]); e=1; } int i3=238; if(e==0) { printf("\n%c=%s%c'\n",a1[i4][0],&e2,a1[i4][0]); printf("\n%c'=%s%c'/%c\n",a1[i4][0],&e1,a1[i4][0],i3); } } getch(); }

Ex No : 7

Date : SHIFT REDUCE PARSER

PROGRAM:

#include<stdio.h> #include<conio.h> #include<string.h> void main() { int jj=1,i=0,l,o=10,j=1,u=0,k,len; char st[15],in[15],temp[15],tmp[15],stt[15],inn[15]; clrscr(); printf("\n the grammar is"); printf("\n E->E+E \n E->E*E \n E->E-E\n E->E^E\n E->/ \n"); printf("\n enter the input leading with $):"); scanf("%s",&in); len=strlen(in); l=len; for(k=0;k<=15;k++) st[k]=NULL; st[0]='$'; printf("\n stack \t\t input \t\t action"); printf("\n ****\t\t***\t\t****"); printf("\n %c\t\t%s\t\tshift",st[0],in); do { if(in[i]!='$') { st[j]=in[i]; } else { j--; } printf("\n %s",st); len--; printf("\t\t"); for(k=jj;k<=l;k++) { printf("%c",in[k]); tmp[u]=in[k]; u++; } strcpy(temp,tmp); u=0; if(st[j]=='i') printf("\t\t reduce"); else printf("\t\tshift");

getch(); if(st[j]=='i') { st[j]='E'; printf("\n"); printf("%s",st); printf("\t\t"); u=0; for(k=jj;k<=l;k++) { printf("%c",in[k]); tmp[u]=in[k];u++; } strcpy(temp,tmp); if(strlen(st)>=4) printf("\t\t reduce"); else printf("\t\tshift"); getch(); } if(j>=3) if(st[j]=='E'&&(st[j-1]=='+'||st[j-1]=='*'||st[j-1]=='-'||st[j-1]=='/'||st[j-1]=='^')&&st[j2]=='E') { st[1]='E'; printf("\n"); printf("%c%c",st[0],st[1]); printf("\t\t"); for(k=jj;k<=l;k++) printf("%c",in[k]); if((strlen(st)==4)&&(strlen(temp)==1)) printf("\t\t accepted"); else printf("\t\t shift"); getch(); j-=2; for(k=2;k<=15;k++) st[k]=NULL; } jj++;j++;i++;o--; } while((strlen(temp)!=1)); if(strcmp(st,"$E")!=0) printf("\n not accepted"); getch();}

OUTPUT: The grammar is E->E+E E->E*E E->E-E E->E^E E->i Enter the input(ending with $) : i+i*i$ STACK ***** $ $i $E $E+ $E+i $E+E $E $E* $E*i $E*E $E INPUT ***** i+i*i$ +i*i$ +i*i$ i*i$ *i$ *i$ *i$ i$ $ $ $ ACTION ****** Shift Reduce Shift Shift Reduce Reduce Shift Shift Reduce Reduce Accept

Ex No :

Date

: LEADING AND TRAILING

PROGRAM #include<string.h> #include<stdio.h> #include<conio.h> int trial(char a[]); char Id[20],tr[20]; int m=0,n=0,p; char s[20][20]; int lead(char a[]) { int i; if(strlen(a)==3&&(int)a[2]>65&&(int)a[2]<90) { for(i=1;i<=p;i++) { if(a[2]==s[i][0]) { lead(s[i]); trial(s[i]); return 0; } } } else if(strlen(a)==3 && ((int)a[2]<65||(int)a[2]>90)) { Id[m]=a[2];m++; tr[n]=a[2];n++; return 0; } else for(i=2;i<strlen(a);i++) { if((int)a[i]<65||(int)a[i]>90) { Id[m]=a[i];m++;return 0; } } return 0; } int trial(char a[]) { int i; if(strlen(a)==3) return 0; for(i=strlen(a)-1;i>=0;i--)

{ if((int)a[i]<65||(int)a[i]>90) { tr[n]=a[i];n++;return 0; } } return 0; } void main() { int i; clrscr(); printf("\n Enter the no.of production:"); scanf("%d",&p); for(i=1;i<=p;i++) { printf("\n Enter the production %d:",i); scanf("%s",s[i]); } for(i=1;i<=p;i++) { lead(s[i]); trial(s[i]); } printf("\n production leading\t trialing\n"); for(i=0;i<m;i++) { printf("\n%c\t\t%c\t %c",s[i+1][0],Id[i],tr[i]); } getch(); }

OUTPUT Enter the no.of production:3 Enter the production 1:S=aSfeF Enter the production 2:F=T Enter the production 3:T=maf production S F T leading a m m trialing e f f

Ex No : Date :

OPERATOR PRESCEDENCE PARSER

PROGRAM #include<iostream.h> #include<conio.h> #include<stdio.h> #include<string.h> void main() { clrscr(); char s[20]; FILE *f; f=fopen("op.txt","r"); rewind(f); char c1=NULL; int i=0; while(!feof(f)) { if(i==0) { i++; fscanf(f,"%c",&c1); continue; } if(feof(f)) break; printf("%c",c1); fscanf(f,"%c",&c1); i++; } cout<<"\n\nENTER THE EXP:"; cin>>s; if(s[0]=='$'&&(s[1]=='i'||s[1]=='+'||s[1]=='*')) printf("\n\n\n$<.%c",s[1]); if(s[1]=='i'&&(s[2]=='+'||s[2]=='*'||s[2]=='$')) printf(".>%c",s[2]); if((s[2]=='+'||s[2]=='*')&&s[3]=='i') printf("<.%c",s[3]); if(s[3]=='i'&&(s[4]=='+'||s[4]=='*'||s[4]=='$')) printf(".>%c",s[4]); if((s[4]=='+'||s[4]=='*')&&s[5]=='i') printf("<.%c",s[5]); if(s[5]=='i'&&(s[6]=='+'||s[6]=='*'||s[6]=='$')) printf(".>%c",s[6]); getch(); }

INPUT: OP.TXT: PRODUCTIONS: E->E+E E->E*E E->i i+*$ i#>>> +<><> *<><> $<<# OUTPUT: PRODUCTIONS: E->E+E E->E*E E->i i+*$ i#>>> +<><> *<><> $<<# ENTER THE EXP:$i+i*i$ $<.i.>+<.i.>*<.i.>$

Ex No : Date : IMPLEMENTATION OF FRONT END OF THE COMPILER AIM: To write a program to implement the front end of the compiler. CONCEPT: 1. The phases of a compiler are collected into a front end and back end. 2. The front end consists of those phases that depend primarily on the source language and are largely independent of the target machine. 3. These normally include lexical and syntactic analysis, the creation of the symbol table, semantic analysis and the generation of intermediate code. A certain amount of code optimization can be done by the front end as well. 4. The front end also includes the error handling that goes along with each of the phases. 5. The back end includes those portions of the compiler that depend on the target machine, and generally those portions do not depend on the source language, just the intermediate code. ALGORITHM: 1. Get the number of lines of the input program. 2. Get the input code and check for any declaration. 3. Generate symbol table for the declaration using symbol table generation function. 4. Call check function to generate intermediate.

PROGRAM #include<stdio.h> #include<conio.h> #include<string.h> #include<ctype.h> void main() { char str[20]; int i; clrscr(); printf("Enter the expression \n"); scanf("%s",str); printf("\n Intermediate Code Generation\n"); printf("\nt"); for(i=1;i<strlen(str);i++) printf("%c",str[i]); printf("\n %c:=t",str[0]); printf("\n\n Quadraple Form"); printf("\nOpr\tArg1\tArg2\tResult\n"); printf("-------------------------\n"); for(i=0;i<strlen(str);i++) { if(str[i]=='+'||str[i]=='-'||str[i]=='-'||str[i]=='*'||str[i]=='/') { printf("\n %c",str[i]); } } for(i=3;i<=strlen(str);i++) { if(isalpha(str[i])) { printf("\t %c",str[i]); } } printf("\tt\n\n"); printf("=\tt\t\t%c",str[0]); getch(); }

RESULT: Thus the implementation of front end of the compiler was done and verified.

IMPLEMENTATION OF THE FRONT END OF THE COMPILER AIM: To write a C program to implement a three address code generation.

ALGORITHM: 1. Start the program 2. Declare the required variables. 3. Read the expression 4. Generate the intermediate code for the given expression using temporary variables. 5. Print the quadruple form code. 6. Stop the program.

RESULT: Thus the front end of compiler was implemented using three-address code.

IMPLEMENTATION OF THE BACK END OF THE COMPILER AIM: To write a C program to implement the back end of the compiler which takes the address code as input and produces the 8086 assembly language instructions that can be assembled and run using a 8086 assembler. three-

CONCEPT: 1. The final phase in our compiler is the code generator. It takes input as an intermediate representation of the source program and produces as output an equivalent target program. 2. The back end is done in multiple steps: Compiler analysis Optimization Code generation

3. Compiler analysis is the gathering of program information from the intermediate representation derived from the input. Accurate analysis is the basis for any compiler optimization. 4. In optimization, the intermediate language representation is transformed into functionally equivalent but faster forms. 5. Popular optimizations are inline expansions, dead code elimination, constant propagation, loop transformation, register allocation or even automatic parallelization. 6. Code generation is the transformed intermediate language which is translated into the output language, usually the native machine language of the system. This involves resources and storage decisions, such as deciding which variables to fit into registers and memory and the selection of scheduling of the appropriate machine instructions along with their associated addressing modes. 7. Compiler analysis is the prerequisite for any compiler optimization and they tightly work together

ALGORITHM: 1. Read the input file of the intermediate code 2. Open the input file if it is empty, print an error message. 3. Get the contents of the input file in the variable op. 4. If compare op with print, goto, []=, uminus. If it matches then print the respective terms in the target file 5. Pass the operand array in switch case. 6. Compare op[0] with +, *, -, %, /, =, >, <. If it matches then print the respective terms in the target file. 7. Open the target file. If it is empty, print the error message or else display the target file. 8. Stop the program.

PROGRAM #include<stdio.h> #include<string.h> char input [10][10],op[4]="+-*/",oper[5][5]={"add","sub","mul","div"},reg[10]=""; int k=0,len,i=0,j=0,pos; void main() { clrscr(); printf("enter the no of expression"); scanf("%d",&len); printf("\n enter the expression"); for(i=0;i<len;i++) { scanf("%s",input[i]); reg[i]=input[i][0]; } for(i=0;i<len;i++) { // printf("\n\n\n%d\n\n\n ",i); for(j=0;j<strlen(reg);j++) { if(reg[j]==input[1][2]) { pos=4; break; } else if(reg[j]==input[i][4]) { pos=2; break; } // printf("\n%d",j); } if(input[i][3]=='-') { printf("\n MOV %c, R%d",input[i][4],i); pos=2; } else if(j==strlen(reg)) { printf("\n MOV %c,R%d",input[i][2],i); pos=4; } for(k=0;k<4;k++) { if(input[i][3]==op[k]) if(pos!=0&&j!=strlen(reg)) printf("\n %s%c,R%d",oper[k],input[i][pos],j); else printf("\n %s%c,R%d",oper[k],input[i][pos],i);

} if(i==len-1) printf("\n MOV R%d,%c",j-1,input[i][0]); else printf("\n MOV R%d,%c",i,input[i][0]); } getch(); }

RESULT: Thus implementation of back end of compiler was done and verified.

Вам также может понравиться