0% found this document useful (0 votes)
30 views44 pages

CD Practical File

Uploaded by

anushkakotiyal1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views44 pages

CD Practical File

Uploaded by

anushkakotiyal1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 44

GANGA INSTITUTE OF TECHNOLOGY AND

MANAGEMENT

Department of Computer Science and


Engineering
Practical file
of
Compiler Design
SUBMITTED TO :- SUBMITTED BY :-
Mrs.Upasna Ma’am NAME:-
Assistant Professor(CSE) ROLL NO:-
GITAM, Jhajjar COURSE:-B.Tech
BRANCH:-CSE-(6th Sem)
INDEX
S.NO NAME OF PROGRAM DONE ON CHECKED ON SIGNATURE

1 STUDY OF LEX & YACC


TOOLS
LEX - A LEXICAL ANALYZER
GENERATOR
2 Write a program to
count the total number
of Blank Spaces in the
String.
3 Write a program to find
whether a given String is
Identifier or not.
4 Write a program to
check whether a string is
keyword or not.
5 Write a program to find
whether a string is
constant or not.
6 Program to check and
generate parse tree.
7 Write a Program to find
the First of non
terminals in the String.
8 Write a Program to find
the LEFT RECURSION.
9 Program to find Left
Factoring in the String.
10 Write a program for
operations of stack.
PRACTICAL-1
STUDY OF LEX & YACC TOOLS
LEX - A LEXICAL ANALYZER GENERATOR
ABSTRACT

Lex helps write programs whose control flow is directed by instances of


regular expressions in the input stream. It is well suited for editor-script
type transformations and for segmenting input in preparation for a
parsing routine.
Lex source is a table of regular expressions and corresponding program
fragments. The table is translated to a program which reads an input
stream, copying it to an output stream and partitioning the input into
strings which match the given expressions. As each such string is
recognized the corresponding program fragment is executed. The
recognition of the expressions is performed by a deterministic finite
automaton generated by Lex. The program fragments written by the
user are executed in the order in which the corresponding regular
expressions occur in the input stream. The lexical analysis programs
written with Lex accept ambiguous specifications and choose the
longest match possible at each input point. If necessary, substantial
look ahead is performed on the input, but the input stream will be
backed up to the end of the current partition, so that the user has
general freedom to manipulate it. Lex can generate analyzers in either
C or Rat for, a language which can be translated automatically to
portable Fortran. It is available on the PDP-11 UNIX, Honeywell GCOS,
and IBM OS systems.

1. Introduction.
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. The regular
expressions are specified by the user in the source specifications given
to Lex. The Lex written code recognizes these expressions in an input
stream and partitions the input stream into strings matching the
expressions. At the boundaries between strings program sections
provided by the user are executed. The Lex source file associates the
regular expressions and the program fragments. As each expression
appears in the input to the program written by Lex, the corresponding
fragment is executed.
The user supplies the additional code beyond expression matching
needed to complete his tasks, possibly including code written by other
generators. The program that recognizes the expressions is generated
in the general purpose programming language employed for the user's
program fragments. Thus, a high level expression language is provided
to write the string expressions to be matched while the user's freedom
to write actions is unimpaired. This avoids forcing the user who wishes
to use a string manipulation language for input analysis to write
processing programs in the same and ofteninappropriate string
handling language.
Lex is not a complete language, but rather a generator representing a
new language feature which can be added to different programming
languages, called ``host languages.'' Just as general purpose languages
can produce code to run on different computer hardware, Lex can write
code in different host languages. The host language is used for the
output code generated by Lex and also for the program fragments
added by the user. Compatible runtime libraries for the different host
languages are also provided. This makes Lex adaptable to different
environments and different users. Each application may be directed to
the combination of hardware and host language appropriate to the
task, the user's background, and the properties of local
implementations. At present, the only supported host language is C,
although Fortran (in the form of Ratfor [2] has been available in the
past. Lex itself exists on UNIX, GCOS, and OS/370; but the code
generated by Lex may be taken
anywhere where appropriate compilers exist.
Lex turns the user's expressions and actions (called source in this pic)
into the host general-purpose language; the generated program is
named yylex. The yylex program will recognize expressions in a stream
(called input in this pic) and perform the specified actions for each
expression as it is detected.
+-------+
Source -> | Lex | -> yylex
+-------+
+-------+
Input -> | yylex | -> Output
+-------+
An overview of Lex

For a trivial example, consider a program to delete from the input all
blanks or tabs at the end of lines.
%%
[ \t]+$ ;

is all that is required. The program contains a %% delimiter to mark the


beginning of the rules, and one rule. This rule contains a regular
expression which matches one or more instances of the characters
blank or tab (written \t for visibility, in accordance with the C language
convention) just prior to the end of a line. The brackets indicate the
character class made of blank and tab; the + indicates ``one or
more ...''; and the $ indicates ``end of line,'' as in QED. No action is
specified, so the program generated by Lex (yylex) will ignore these
characters. Everything else will be copied. To change any remaining
string of blanks or tabs to a single blank, add another rule:
%%
[ \t]+$ ;
[ \t]+ Printf(" ");

The finite automaton generated for this source will scan for both rules
at once, observing at the termination of the string of blanks or tabs
whether or not there is a new line character, and executing the desired
rule action. The first rule matches all strings of blanks or tabs at the end
of lines, and the second rule all remaining strings of blanks or tabs. Lex
can be used alone for simple transformations, or for analysis and
statistics gathering on a lexical level. Lex can also be used with a parser
generator to perform the lexical analysis phase; it is particularly easy to
interface Lex and Yacc [3]. Lex programs recognize only regular
expressions; Yacc writes parsers that accept a large class of context
free grammars, but require a lower level analyzer to recognize input
tokens. Thus, a combination of Lex and Yacc is often appropriate. When
used as a preprocessor for a later parser generator, Lex is used to
partition the input stream, and the parser generator assigns structure
to the resulting pieces. The flow of control in such a case (which might
be the first half of a compiler, for example) is shown in Figure 2.
Additional programs, written by other generators or by hand, can be
added easily to programs written by Lex.
lexical grammar
rules
||
vv
+---------+ +---------+
| Lex | | Yacc |
+---------+ +---------+
||
vv
+---------+ +---------+
Input -> | yylex | -> | yyparse | -> Parsed input
+---------+ +---------+

Lex with Yacc


Yacc users will realize that the name yylex is what Yacc expects its
lexical analyzer to be named, so that the use of this name by Lex
simplifies interfacing. Lex generates a deterministic finite automaton
from the regular expressions in the source. The automaton is
interpreted, rather than compiled, in order to save space. The result is
still a fast analyzer. In particular, the time taken by a Lex program to
recognize and partition an input stream is proportional to the length of
the input. The number of Lex rules or the complexity of the rules is not
important in determining speed, unless rules which include forward
context require a significant amount of rescanning. What does increase
with the number and complexity of rules is the size of the finite
automaton, and therefore the size of the program generated by Lex. In
the program written by Lex, the user's fragments (representing the
actions to be performed as each regular expression is found) are
gathered as cases of a switch. The
automaton interpreter directs the control flow. Opportunity is provided
for the user to insert either declarations or additional statements in the
routine containing the actions, or to add subroutines outside this action
routine. Lex is not limited to source which can be interpreted on the
basis of one character look ahead. For example, if there are two rules,
one looking for ab and another for abcdefg,
and the input stream is abcdefh, Lex will recognize ab and leave the
input pointer just before cd. . . Such backup is more costly than the
processing of simpler languages.
2. Lex Source.
The general format of Lex source is:
{definitions}
%%
{rules}
%%
{user subroutines}
where the definitions and the user subroutines are often omitted. The
second %% is optional, but the first is required to mark the beginning of
the rules. The absolute minimum Lex program is thus
%%

(no definitions, no rules) which translates into a program which copies


the input to the output unchanged.
In the outline of Lex programs shown above, the rules represent the
user's control decisions; they are a table, in which the left column
contains regular expressions and the right column contains actions,
program fragments to be executed when the expressions are
recognized. Thus an individual rule might appear
integer printf("found keyword INT");

to look for the string integer in the input stream and print the message
``found keyword INT'' whenever it appears. In this example the host
procedural language is C and the C library function printf is used to
print the string. The end of the expression is indicated by the first blank
or tab character. If the action is merely a single C expression, it can just
be given on the right side of the line; if it is compound, or takes more
than a line, it should be enclosed in braces. As a slightly more useful
example, suppose it is desired to change a number of words from
British to American spelling. Lex rules such as
colour printf("color");
mechanise printf("mechanize");
petrol printf("gas");

would be a start. These rules are not quite enough, since the word
petroleum would become gaseum; a way of dealing with this will be a
bit more complex.

3. Lex Regular Expressions.


A regular expression specifies a set of strings to be matched. It contains
text characters (which match the corresponding characters in the
strings being compared) and operator characters (which specify
repetitions, choices, and other features). The letters of the alphabet
and the digits are always text characters; thus the regular expression
integer matches the string integer wherever it appears and the
expression a57D looks for the string a57D. Operators: The operator
characters are
"\[]^-?.*+|()$/{}%<>

and if they are to be used as text characters, an escape should be used.


The quotation mark operator (") indicates that whatever is contained
between a pair of quotes is to be taken as text characters. Thus xyz"++"

matches the string xyz++ when it appears. Note that a part of a string
may be quoted. It is harmless but unnecessary to quote an ordinary
text character; the expression "xyz++"
is the same as the one above. Thus by quoting every non-alphanumeric
character being used as a text character, the user can avoid
remembering the list above of current operator characters, and is safe
should further extensions to Lex lengthen the list.
An operator character may also be turned into a text character by
preceding it with \ as in xyz\+\+
which is another, less readable, equivalent of the above expressions.
Another use of the quoting mechanism is to get a blank into an
expression; normally, as explained above, blanks or tabs end a rule. Any
blank character not contained within [] must be quoted.
Several normal C escapes with \ are recognized: \n is new line, \t is tab,
and \b is backspace. To enter \ itself, use \\. Since new line is illegal in
an expression, \n must be used; it is not required to escape tab and
backspace. Every character but blank, tab, new line and the list above is
always a text character.
Character classes: Classes of characters can be specified using the
operator pair []. The construction [abc] matches a single character,
which may be a, b, or c. Within square brackets, most operator
meanings are ignored. Only three characters are special: these are \ -
and ^. The - character indicates ranges. For example, [a-z0-9<>_] indicates
the character class containing all the lower case letters, the digits, the
angle brackets, and underline. Ranges may be given in either order.
Using - between any pair of characters which are not both upper case
letters, both lower case letters, or both digits is
implementation dependent and will get a warning message. (E.g., [0-z]
in ASCII is many more characters than it is in EBCDIC). If it is desired to
include the character - in a character class, it should be first or last; thus
[-+0-9] matches all the digits and the two signs. In character classes, the ^
operator must appear as the first character after the left bracket; it
indicates that the resulting string is to be complemented with respect
to the computer character set. Thus [^abc] matches all characters except
a, b, or c, including all special or control characters; or [^a-zA-Z] is any
character which is not a letter. The \ character provides the usual
escapes within character class brackets. Arbitrary character. To match
almost any character, the operator character is the class of all
characters except newline. Escaping into octal is possible although non-
portable: [\40-\176] matches all printable characters in the ASCII
character set, from octal 40 (blank) to octal 176 (tilde).
Optional expressions. The operator ? indicates an optional element of
an expression. Thus ab?c
matches either ac or abc.
Repeated expressions. Repetitions of classes are indicated by the
operators * and +.
a* is any number of consecutive a characters, including zero; while a+ is
one or more instances of a. For example, [a-z]+ is all strings of lower case
letters. And [A-Za-z][A-Za-z0-9]* indicates all alphanumeric strings with a
leading alphabetic character. This is a typical expression for recognizing
identifiers in computer languages. Alternation and Grouping. The
operator | indicates alternation: (ab|cd) matches either ab or cd. Note
that parentheses are used for grouping, although they are not
necessary on the outside level; ab|cd would have sufficed. Parentheses
can be used for more complex expressions: (ab|cd+)?(ef)* matches such
strings as abefef, efefef, cdef, or cddd; but not abc, abcd, or abcdef.
Context sensitivity. Lex will recognize a small amount of surrounding
context. The two simplest operators for this are ^ and $. If the first
character of an expression is ^, the
expression will only be matched at the beginning of a line (after a
newline character, or at the beginning of the input stream). This can
never conflict with the other meaning of ^, complementation of
character classes, since that only applies within the [] operators. If the
very last character is $, the expression will only be matched at the end
of a line (when immediately followed by newline). The latter operator is
a special case of the / operator character, which indicates trailing
context. The expression ab/cd matches the string ab, but only if followed
by cd. Thus ab$ is the same as ab/\n.
Left context is handled in Lex by start conditions as explained in section
10. If a rule is only to be executed when the Lex automaton interpreter
is in start condition x, the rule should be prefixed by
<x> using the angle bracket operator characters. If we considered ``being
at the beginning of a line'' to be start condition ONE, then the ^
operator would be equivalent to <ONE> Start conditions are explained
more fully later.
Repetitions and Definitions. The operators {} specify either repetitions
(if they enclose numbers) or definition expansion (if they enclose a
name). For example {digit} looks for a predefined string named digit and
inserts it at that point in the expression. The definitions are given in the
first part of the Lex input, before the rules. In contrast, a{1,5} looks for 1
to 5 occurrences of a.
Finally, initial % is special, being the separator for Lex source segments.
4. Lex Actions.
When an expression written as above is matched, Lex executes the
corresponding action. This section describes some features of Lex which
aid in writing actions. Note that there is a default action, which consists
of copying the input to the output. This is performed on all strings not
otherwise matched. Thus the Lex user who wishes to absorb the entire
input, without producing any output, must provide rules to match
everything. When Lex is being used with Yacc, this is the normal
situation. One may consider that actions are what is done instead of
copying the input to the output; thus, in general, a rule which merely
copies can be omitted. Also, a character combination which is omitted
from the rules and which appears as input is likely to be printed on the
output, thus calling attention to the gap in the rules.
One of the simplest things that can be done is to ignore the input.
Specifying a C null statement, ; as an action causes this result. A
frequent rule is [ \t\n] ; which causes the three spacing characters (blank,
tab, and new line) to be ignored.
Another easy way to avoid writing actions is the action character |,
which indicates that the action for this rule is the action for the next
rule. The previous example could also have been written
""
"\t"
"\n"

with the same result, although in different style. The quotes around \n
and \t are not required.
In more complex actions, the user will often want to know the actual
text that matched some expression like [a-z]+. Lex leaves this text in an
external character array named yytext. Thus, to print the name found, a
rule like
[a-z]+ printf("%s", yytext);

will print the string in yytext. The C function printf accepts a format
argument and data to be printed; in this case, the format is ``print
string'' (% indicating data conversion, and s indicating string type), and
the data are the characters in yytext. So this just places the matched
string on the output. This action is so common that it may be written as
ECHO:
[a-z]+ ECHO;

is the same as the above. Since the default action is just to print the
characters found, one might ask why give a rule, like this one, which
merely specifies the default action? Such rules are often required to
avoid matching some other rule which is not desired. For example, if
there is a rule which matches read it will normally match the instances
of read contained in bread or readjust; to avoid this, a rule of the form
[a-z]+ is needed. This is explained further below.
Sometimes it is more convenient to know the end of what has been
found; hence Lex also provides a count yyleng of the number of
characters matched. To count both the number of words and the
number of characters in words in the input, the user might write [a-zAZ]
+ {words++; chars += yyleng;} which accumulates in chars the number
of characters in the words recognized. The last character in the string
matched can be accessed by yytext[yyleng-1].
Occasionally, a Lex action may decide that a rule has not recognized the
correct span of characters. Two routines are provided to aid with this
situation. First, yymore() can be called to indicate that the next input
expression recognized is to be tacked on to the end of this input.
Normally, the next input string would overwrite the current entry in
yytext. Second, yyless (n) may be called to indicate that not all the
characters matched by the currently successful expression are wanted
right now. The argument n indicates the number of characters in yytext
to be retained. Further characters previously matched are returned to
the input. This provides the same sort of lookahead offered by the /
operator,
but in a different form.
Example: Consider a language which defines a string as a set of
characters between quotation (") marks, and provides that to include a
" in a string it must be preceded by a \.
The regular expression which matches that is somewhat confusing, so
that it might be preferable to write
\"[^"]* {
if (yytext[yyleng-1] == '\\')
yymore();
else
... normal user processing
}

which will, when faced with a string such as "abc\"def" first match the
five characters "abc\; then the call to yymore() will cause the next part
of the string, "def, to be tacked on the end. Note that the final quote
terminating the string should be picked up in the code labeled ``normal
processing''.
The function yyless() might be used to reprocess text in various
circumstances. Consider the C problem of distinguishing the ambiguity
of ``=-a''. Suppose it is desired to treat this as ``=- a'' but print a
message. A rule might be
=-[a-zA-Z] {
printf("Op (=-) ambiguous\n");
yyless(yyleng-1);
... action for =- ...
}

which prints a message, returns the letter after the operator to the
input stream, and treats the operator as ``=-''. Alternatively it might be
desired to treat this as ``= -a''. To do this, just return the minus sign as
well as the letter to the input:
=-[a-zA-Z] {
printf("Op (=-) ambiguous\n");
yyless(yyleng-2);
... action for = ...
}

will perform the other interpretation. Note that the expressions for the
two cases might more easily be written =-/[A-Za-z] in the first case and =/-
[A-Za-z] in the second; no backup would be required in the rule action. It
is not necessary to recognize the whole identifier to observe the
ambiguity. The possibility of ``=-3'', however, makes =-/[^ \t\n] a still
better rule.
In addition to these routines, Lex also permits access to the I/O routines
it uses. They are:
1) input () which returns the next input character;
2) output (c) which writes the character c on the output; and
3) unput (c) pushes the character c back onto the input stream to be
read later by input().
By default these routines are provided as macro definitions, but the
user can override them and supply private versions. These routines
define the relationship between external files and internal characters,
and must all be retained or modified consistently. They may be
redefined, to cause input or output to be transmitted to or from
strange places, including other programs or internal memory; but the
character set used must be consistent in all routines; a value of zero
returned by input must mean end of file; and the relationship between
unput and input must be retained or the Lex lookahead will not work.
Lex does not look ahead at all if it does not have to, but every rule
ending in + * ? or $ or containing / implies lookahead. Lookahead is also
necessary to match an expression that is a prefix of another expression.
See below for a discussion of the character set used by Lex. The
standard Lex library imposes a 100 character limit on backup. Another
Lex library routine that the user will sometimes want to redefine is
yywrap() which is called whenever Lex reaches an end-of-file. If yywrap
returns a 1, Lex continues with the normal wrapup on end of input.
Sometimes, however, it is convenient to arrange for more input to
arrive from a new source. In this case, the user should provide a yywrap
which arranges for new input and returns 0. This instructs Lex to
continue processing. The default yywrap always returns 1. This routine
is also a convenient place to print tables, summaries, etc. at the end of
a program. Note that it is not possible to write a normal rule which
recognizes end-of-file; the only access to this condition is through
yywrap. In fact, unless a private version of input() is supplied a file
containing nulls cannot be handled, since a value of 0 returned by input
is taken to be end-of-file.
PRACTICAL-2
Write a program to count the total number of Blank Spaces in
the String.
-#include<iostream.h>
#include<iostream.h>
#include<conio.h>
#include<string.h>
void main()
{
int c=0,len;
clrscr();
char a[30]="My name is ashish batra";
len=strlen(a);
for(int i=0;i<len;i++)
{
if(a[i]==' ')
{
c=c++;
}
}
cout<<"Total Number of Blank Spaces in the String are:" <<c;
getch();
}
OUTPUT:-
PRACTICAL-3
Write a program to find whether a given String is Identifier or
not.
#include<iostream.h>
#include<conio.h>
#include<string.h>
void main()
{
clrscr();
char a[15]=”Aarti”;
int len,c=0;
len=strlen(a);
for(int i=0;i<len;i++)
{
if(a[i]>=’a’&&a[i]<=’z’|| a[i] >= ‘A’ && a[i] <= ‘Z’)
c=c++;
}
if(len==c)
cout<<”This is an Identifier”;
else
cout<<”This is not an Identifier”;
getch();
}
OUTPUT:-
PRACTICAL- 4
Write a program to check whether a string is 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();
}
OUTPUT:

enter the string : return


it is a keyword
enter the string : hello
it is not a keyword
PRACTICAL-5
Write a program to find whether a 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");
break;
}
}
if(a==len)
{
printf(" It is a Constant");
}
getch();
}

OUTPUT :

Input a string :23


It is a Constant
Input a string :a_123
It is not a Constant
PRACTICAL- 6
Program to check and generate parse tree.
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
#include<string.h>
#include<iostream.h>
void main()
{
clrscr();
char s[5],a[5][5],b[5][2],cq[5][2],z[5];
int p=0;
printf(“\nEnter the production for S--> ");
scanf(“%s”,&s);
int len=strlen(s);
for(int i=0;i<5;i++)
{
if(s[i]>='A' && s[i]<='Z')
{
z[p]=s[i];
p++;
}
}
int o=p;
printf("\nNo. of non-terminals are:%d",o);
for(p=0;p<o;p++)
{
Printf("\n\n\nEnter the production for %c--> ",z[p]);
Scanf(“%s”,&a[p]);
Printf("\nProduction for %c --> %s",z[p],a[p]);
}
clrscr();
int driver,mode;
driver=DETECT;
initgraph(&driver,&mode,"c:\\tc1\\bgi");
outtextxy(320,50,"S");
int count;
int g=0,h=-100,c,u,y=200;
p=0;
for(u=0;u<len;u++)
{
y=y+50;
lineto(y,100);
b[u][0]=s[u];
b[u][1]='\0';
outtext(b[u]);
if((s[u]>='A')&&(s[u]<='Z'))
{
count=strlen(a[g]);
a[g][count+1]='\0';
c=0;
for(int q=0;q<count;q++)
{
h=h+50;
moveto(y,100);
linerel(h,100);
cq[p][0]=a[g][c];
cq[p][1]='\0';
outtext(cq[p]);
++p;
++c;
}
g++;
}
moveto(320,50);
}
getch();
}

OUTPUT:
PRACTICAL- 7
Write a Program to find the First of non terminals in the
String

//Header Files
#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
{
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();
}
OUTPUT
PRACTICAL- 8
Write a Program to find the LEFT RECURSION
We've barely started trying to figure out exactly what an expression is and then
how to code a recursive descent parser for it and already we've encountered an
embarrassing problem -- how to decide between several options for a given
production -- particularly when it causes our code to call itself over and over
again, infinitely, or else simply quit too early. This is a common problem in setting
up useful productions for any language. And algebraic expressions are no
exception.

Left Recursion
Here are the productions, so far:
expression := term | expression + term | expression - term
term := number | ( expression )

The first production, expression, has its last two choices using the production
expression and, as such, it recursively calls the production expression. But note
that this recursive use is on the left side of each of these last two choices. In other
words, it implies that we'd need to recursively call the Expression function before
a check is made for a plus or minus, not after. Of course, we already know this
from trying to code it. And it is a problem. This is called left-recursion and in
recursive descent parsing circles, this is a bad thing. What you really want is right-
recursion, as that means you only make a recursive call if and only if everything
else has already been verified. It's just fine to recursively call a production, if it's
the last thing you do as by then you've already figured out which choice is better.
You really want to arrange things so that recursive calls are the last thing to do --
sometimes called 'tail recursion.

Program For Identifying & Removing Left Recursion

#include<iostream.h>
#include<conio.h>
#include<string.h>
#include<stdio.h>
#include<process.h>
void main()
{
char pro[15],alpha[15],beta[15];
int len,i,c=0,k=0;
clrscr();
cout<<"Enter Production\t";
gets(pro);
len=strlen(pro);
if(pro[3]!=pro[0]) //Checking Left Recursion In Given Production
{
cout<<"\nThere is No Left Recursion";
getch();
exit(0);
}
else //Removing Left Recursion
{
cout<<"\nLeft Recursion Found";
for(i=4;i<len,pro[i]!='/';i++)
{
alpha[c]=pro[i]; //Copying Alpha To A Temporary Variable
c++;
}
for(i=i+1;i<len-1,pro[i]!=NULL;i++)
{
beta[k]=pro[i]; //Copying Beta To A Temporary Variable
k++;
}
//Printing Productions After Removing Left Recursion
cout<<"\n"<<pro[0]<<"->";
for(i=0;i<k;i++)
{
cout<<beta[i];
}
cout<<pro[0]<<"'";
//Printing Second Production
cout<<"\n"<<pro[0]<<"'->";
len=strlen(alpha);
for(i=0;i<len;i++)
{
cout<<alpha[i];
}
cout<<pro[0]<<"'/^";
}
getch();
}

OUTPUT:
Enter Production A->AL/B

Left Recursion Found


A->BA'
A'->LA'/

PRACTICAL- 9
Program to find Left Factoring in the String
//Header Files
#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 Left Factoring\t A-> ");
gets(str1);
for(i=0;i<=strlen(str1)-1;i++)
{
k=i+3;
if(str1[i]==str1[k])
{
printf("\n\t\t A-> %cA'",str1[i]);
printf("\n\t\t A'-> %c/%c",str1[i+1],str1[i+4]);
break;
}
else
printf("Sorry! Wrong String");
}
getch();
}
OUTPUT
PRACTICAL- 10
Write a program for operations of stack.
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
char a[20]={NULL},inp;
int ans=0,pos,i;
clrscr();
while(ans<4)
{
pos=0;
while(a[pos]!=NULL && pos<=20)
pos++;
// printf("\n\n####\tstack=%s, pos=%d",a,pos);
printf("\n\n\t\t-- Main Menu --\n\n1. Push\n2. Pop\n3. View Stack\n4.
Exit\nYour Choice: ");
scanf("%d",&ans);
switch(ans)
{
case 1:
{
if(pos==20)
printf("\nStack is already Full.");
else
{
printf("\nEnter input character: ");
scanf("%s",&a[pos]);
printf("\nPush Operation Successful.");
}
break;
}
case 2:
{
if(pos==0)
printf("\nStack already empty.");
else
{
a[pos-1]=NULL;
printf("\nPop operation Successful.");
}
break;
}
case 3:
{
if(pos==0)
printf("\nEmpty Stack.");
else
{
printf("\nStack Content:--\n");
for(i=pos-1;i>=0;i--)
{
printf("\n %c",a[i]);
if(i==pos-1)
printf(" (Top of the Stack.)");
}
}
break;
}
case 4:
{
exit();
break;
}
default:
{
printf("\nInvalid Input.");
getch();
exit();
}
}
getch();
}}

OUTPUT:

You might also like