CDSS Notes
CDSS Notes
CDSS Notes
This section contains example programs for the lex and yacc commands.
Together, these example programs create a simple, desk-calculator program that performs addition,
subtraction, multiplication, and division operations. This calculator program also allows you to assign
values to variables (each designated by a single, lowercase letter) and then use the variables in
calculations. The files that contain the example lex and yacc programs are as follows:
File Content
calc.lex Specifies the lex command specification file that defines the lexical analysis rules.
Specifies the yacc command grammar file that defines the parsing rules, and calls
calc.yacc
the yylex subroutine created by the lex command to provide input.
The following descriptions assume that the calc.lex and calc.yacc example programs are located in
your current directory.
1. Process the yacc grammar file using the -d optional flag (which informs the yacc command to
create a file that defines the tokens used in addition to the C language source code):
yacc -d calc.yacc
2. Use the ls command to verify that the following files were created:
y.tab.c
The C language source file that the yacc command created for the parser
y.tab.h
A header file containing define statements for the tokens used by the parser
lex calc.lex
4. Use the ls command to verify that the following file was created:
lex.yy.c
The C language source file that the lex command created for the lexical analyzer
“”
cc y.tab.c lex.yy.c
6. Use the ls command to verify that the following files were created:
y.tab.o
The object file for the y.tab.c source file
lex.yy.o
The object file for the lex.yy.c source file
a.out
The executable program file
To run the program directly from the a.out file, type:
$ a.out
OR
To move the program to a file with a more descriptive name, as in the following example, and run it,
type:
$ mv a.out calculate
$ calculate
In either case, after you start the program, the cursor moves to the line below the $ (command
prompt). Then, enter numbers and operators as you would on a calculator. When you press the
Enter key, the program displays the result of the operation. After you assign a value to a variable, as
follows, the cursor moves to the next line.
m=4 <enter>
_
When you use the variable in subsequent calculations, it will have the assigned value:
m+5 <enter>
9
_
The following example shows the contents of the calc.yacc file. This file has entries in all three
sections of a yacc grammar file: declarations, rules, and programs.
%{
#include<stdio.h>
int regs[26];
int base;
%}
%start list
%union { int a; }
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /*supplies precedence for unary minus */
list: /*empty */
|
list stat '\n'
|
list error '\n'
{
yyerrok;
}
;
stat: expr
{
printf("%d\n",$1);
}
|
LETTER '=' expr
{
regs[$1.a] = $3.a;
}
|
number
;
number: DIGIT
{
$$ = $1;
base = ($1.a==0) ? 8 : 10;
} |
number DIGIT
{
$$.a = base * $1.a + $2.a;
}
;
%%
main()
{
return(yyparse());
}
yyerror(s)
char *s;
{
fprintf(stderr, "%s\n",s);
}
yywrap()
{
return(1);
}
The file contains the following sections:
SubroutineDescription
Main The required main program that calls the yyparse subroutine to start the program.
yyerror(s) This error-handling subroutine only prints a syntax error message.
yywrap The wrap-up subroutine that returns a value of 1 when the end of input occurs.
This file contains include statements for standard input and output, as well as for the y.tab.h file. If
you use the -d flag with the yacc command, the yacc program generates that file from
the yacc grammar file information. The y.tab.h file contains definitions for the tokens that the
parser program uses. In addition, the calc.lex file contains the rules to generate these tokens from
the input stream. The following are the contents of the calc.lex file.
%{
#include <stdio.h>
#include "y.tab.h"
int c;
%}
%%
" " ;
[a-z] {
c = yytext[0];
yylval.a = c - 'a';
return(LETTER);
}
[0-9] {
c = yytext[0];
yylval.a = c - '0';
return(DIGIT);
}
[^a-z0-9\b] {
c = yytext[0];
return(c);
}
%%
/*
*/
#include<stdio.h>
int main() {
int x, y;
INPUT:
char op;
switch (op)
case '+':
break;
case '-':
// Subtraction ('-')
break;
case '*':
// Product/Mutliplication ('*')
break;
case '/':
// Division ('/')
break;
case '%':
break;
default:
goto INPUT;
break;
return 0;
Program Output:
We are using the GCC Compiler to compile and run the program.
$ gcc arithmetic-operations-switch.c
The gcc compiler by default generates the executable file with the a.out Name. So we are
going to run the a.out using the ./a.out command. ( As we are in the same directory as
where the file is located )
Example 1: Addition test case:
1$ ./a.out
Example 2: Subtraction:
1$ ./a.out
4Subtraction: 30 - 10 = 20
4Product: 20 * 50 = 1000
5$ ./a.out
8Division: 25 / 5 = 5
9$ ./a.out
12Modulo Division: 20 % 3 = 2
13$
6Modulo Division: 70 % 20 = 10
7$
Example 5: If the user enters the wrong Operator:
1$ ./a.out
7Addition: 60 + 20 = 80
8$
3*/
5#include<stdio.h>
6int main() {
8 int x, y;
9
10 // If user provides wrong operator, we are using goto statement
12 INPUT:
13
18
19
21 char op;
24
26
27 if(op == '+')
28 {
31 }
33 {
34 // Subtraction ('-')
36 }
38 {
39 // Product/Mutliplication ('*')
40 printf("Product: %d * %d = %d \n", x, y, x*y);
41 }
43 {
44 // Division ('/')
46 }
48 {
51 }
52 else{
55
58 goto INPUT;
59 }
60
61 return 0;
62}
Program Output:
1$ gcc arithmetic-operations-if-else-ladder.c
2$ ./a.out
5Subtraction: 80 - 70 = 10
6$ ./a.out
9Product: 4 * 9 = 36
10$ ./a.out
13Division: 45 / 7 = 6
14$ ./a.out
17Modulo Division: 30 % 4 = 2
18$ ./a.out
21Addition: 30 + 40 = 70
22$ ./a.out
31Modulo Division: 90 % 10 = 0
32$
3. Else
• Else, Pop all the operators, that have greater or equal precedence than the
scanned operator. Once you pop them push this scanned operator. (If we
see a parenthesis while popping then stop and push the scanned operator
in the stack)
5. If the scanned character is an ‘)’, pop the stack and output it until a ‘(‘ is
encountered, and discard both the parenthesis.
6. Now, we should repeat steps 2 – 6 until the whole infix i.e. whole characters are
scanned.
7. Print output
8. Do the pop and output (print) until the stack is not empty
Method 1: Array-based stack approach to Convert Infix to Postfix
• C
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
char stk[20];
int isEmpty(){
return top == -1;
int isFull(){
char peek(){
return stk[top];
char pop(){
if(isEmpty())
return -1;
char ch = stk[top];
top--;
return(ch);
if(isFull())
printf("Stack Full!!!!");
else{
top++;
stk[top] = oper;
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
switch (ch)
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
return -1;
}
int i, j;
if (checkIfOperand(expression[i]))
expression[++j] = expression[i];
push(expression[i]);
expression[++j] = pop();
else
pop();
else // if an opertor
{
while (!isEmpty() && precedence(expression[i]) <= precedence(peek()))
expression[++j] = pop();
push(expression[i]);
while (!isEmpty())
expression[++j] = pop();
expression[++j] = '\0';
int main()
covertInfixToPostfix(expression);
return 0;
Output: pqr*+s-
lex example.l
gcc lex.yy.c -ll -o example
./example
This compiles the program, links the lex libraries with it, and renames the output file. Notice that we're using "gcc" - lex is
basically a C program!
7. To compile the lex and the yacc programs together (assuming that lex tokenizes the input and passes the tokens to
yacc)
lex example.l
yacc -d example.y
gcc lex.yy.c y.tab.c -ll -ly -o example
./example
Termwork 01:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#define max 100
//main class
int main()
{
char str[max];
int f=1; //state
int i;
// reading the string to be checkeed from the user//
printf("\nENTER THE STREAM OF INPUT SYMBOLS:\n");
scanf("%s",str);
//char f='str'; //state
//printf("Input Taken");
//for statement start
for(i=0;str[i]!='\0';i++)
{
printf("%c",f);
//printf("For loop");
switch(f)
{
printf("Inside switch\n");
//first state
case 1:
if(str[i]=='a')
{
f=3;
printf("PROCESSING a and further checking for next symbols");
}
else if(str[i]=='.')
{
f=8;
}
else
{
//printf("\nOther symbol\n");
f=2;
}
break;
case 2:
if(str[i]== '.')
{
f=8;
}
else if(str[i]=='c')
{
printf("PROCESSING c and further checking for next symbols");
f=4;
}
else
{
f=2;
}
break;
case 3:
if(str[i]=='.')
{
f=8;
}
else if(str[i]=='/')
{
printf("\nPROCESSING '/' and further checking for next symbols\n");
f=5;
}
else
{
f=6;
}
break;
case 4:
if(str[i]=='.')
{
f=8;
}
else if(str[i]=='#')
{
printf("\n # Detected\n");
//printf("\nPATTERN FOUND\n");
f=6;
}
else
{
f=2;
}
break;
case 5:
if(str[i]=='.')
{
f=8;
}
else if(str[i]=='#')
{
printf("\nPATTERN FOUND\n");
f=2;
}
else
{
f=2;
}
break;
case 6:
if(str[i]=='.')
{
printf("\nPROGRAM HALTED AS '.' APPERAED\n");
exit(0);
}
else
{
f=1;
}
break;
case 'default':
printf("No Input detected");
}//end of switch
}//end of for loop
return 0;
}
USING GOTO
#include <stdio.h>
#include <string.h>
#define max 100
//main class
int main()
{
char str[max];
char f='a';//state
int i;
// reading the string to be checkeed from the user//
printf("ENTER THE STRING : ");
scanf("%s",str);
else if (str[i]=='.') {
f='b';
printf("Program halted\n");
break;
} else if (str[i]=='b')
f='e';
else f='a';
break;
//---------------------------------------------------------------------------------
--------//
//fourth state d
case 'd' :
if(str[i]=='1') {
f='d';
printf("Ok\n");
}
else if(str[i]=='!' || str[i]=='@' || str[i]=='$' || str[i]=='&') {
f='a';
printf("ERROR in input\n");
} else if (str[i]=='.') {
f='b';
printf("Program halted\n");
break;
}
else if (str[i]=='b')
f='e';
else f='a';
break;
//---------------------------------------------------------------------------------
--------//
//fifth state e
case 'e':
if(str[i]=='1') {
f='c';
} else if(str[i]=='!' || str[i]=='@' || str[i]=='$' || str[i]=='&') {
f='a';
printf("ERROR in input\n");
}
else if (str[i]=='.') {
f='b';
printf("Program halted\n");
break;
}
else if (str[i]=='b')
f='f';
else f='a';
break;
//---------------------------------------------------------------------------------
--------//
//sixth state f
case 'f':
if(str[i]=='1') {
f='c';
} else if(str[i]=='!' || str[i]=='@' || str[i]=='$' || str[i]=='&') {
f='a';
printf("ERROR in input\n");
}
else if (str[i]=='.') {
f='b';
printf("Program halted\n");
break;
}
else if (str[i]=='b')
f='f';
else if(str[i]=='#')
f='g';
else f='a';
break;
//---------------------------------------------------------------------------------
--------//
else if (str[i]=='.') {
f='b';
printf("Program halted\n");
break;
}
else if (str[i]=='b')
f='e';
else if(str[i]==';') {
f='h';
printf("FOUND special\n");
} else f='a';
break;
} //end of switch
}//end of for
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
char ch;
goto s0;
s0:
printf("enter the characters:\n");
ch=getchar();
if(ch=='.')
exit(0);
else if(ch=='b')
goto s3;
else if(ch=='#' || ch=='!' || ch=='$')
{
printf("Error in Input\n");
goto s0;
}
else if(ch=='1')
goto s1;
else
goto s0;
s1:
ch=getchar();
if(ch=='.')
exit(0);
else if(ch=='b')
goto s3;
else if(ch=='1')
{
printf("ok 1 \n");
goto s2;
}
else if(ch=='#'||ch=='!'||ch=='&'||ch=='$')
{
printf("Error\n");
goto s0;
}
else
goto s0;
s2:
ch=getchar();
if(ch=='.')
exit(0);
else if(ch =='b')
goto s3;
else if(ch=='1')
{
printf("ok2\n");
goto s2;
}
else if(ch=='#'||ch=='!'||ch=='&'||ch=='$')
{
printf("Error\n");
goto s0;
}
else
goto s0;
s3:
ch=getchar();
if(ch=='.')
exit(0);
else if(ch=='b')
goto s4;
else if(ch=='1')
{
goto s1;
}
else if(ch=='@'||ch=='&'||ch=='$')
{
printf("Error\n");
goto s0;
}
else
goto s0;
s4:
ch=getchar();
if(ch=='.')
exit(0);
else if(ch=='b')
goto s3;
else if(ch=='#')
goto s5;
else if(ch=='1')
{
goto s1;
}
else if(ch=='@'||ch=='&'||ch=='$')
{
printf("Error\n");
goto s0;
}
else
goto s0;
s5:
ch=getchar();
if(ch=='.')
exit(0);
else if(ch=='b')
goto s3;
else if(ch=='#')
goto s0;
else if(ch='!'){
printf("Special case\n");
goto s0;
}
else if(ch=='1')
{
goto s1;
}
else if(ch=='@'||ch=='&'||ch=='$')
{
printf("Error\n");
goto s0;
}
else
{
goto s0;
}
return 0;
}
#include<stdio.h>
#include<stdlib.h> /* for exit() */
#include<ctype.h> /* for isdigit(char ) */
#include<string.h>
if(top <0)
{
printf("stack under flow: invalid infix expression");
getchar();
/* underflow may occur for invalid expression */
/* where ( and ) are not matched */
exit(1);
}
else
{
item = stack[top];
top = top-1;
return(item);
}
}
/* define function that is used to determine whether any symbol is operator or not
(that is symbol is operand)
* this fucntion returns 1 if symbol is opreator else return 0 */
i=0;
j=0;
item=infix_exp[i]; /* initialize before loop*/
while(item != '\0') /* run loop till end of infix expression */
{
if(item == '(')
{
push(item);
}
else if( isdigit(item) || isalpha(item))
{
postfix_exp[j] = item; /* add operand symbol to postfix expr
*/
j++;
}
else if(is_operator(item) == 1) /* means symbol is operator */
{
x=pop();
while(is_operator(x) == 1 && precedence(x)>= precedence(item))
{
postfix_exp[j] = x; /* so pop all higher precendence
operator and */
j++;
x = pop(); /* add them to postfix expresion */
}
push(x);
/* because just above while loop will terminate we have
oppped one extra item
for which condition fails and loop terminates, so that one*/
return 0;
}