Postfix Calculator Using C & Flex
Flex is an aging UNIX utility that helps you write very fast parsers for almost arbitrary file formats. Formally, they implement Look-Ahead-Left-Right (as opposed to "recursive descent") parsing of non-ambiguous context-free (as opposed to "natural language") grammars.
Why should you learn the Flex pattern syntax when you could just write your own parser? Well, several reasons. First, Flex will generate a parser that is virtually guaranteed to be faster than anything you could write manually in a reasonable amount of time. Second, updating and fixing Flex source files is a lot easier than updating and fixing custom parser code. Third, Flex have mechanisms for error handling and recovery, which is something you definitely don't want to try to bolt onto a custom parser. Finally, Flex has been around for a long time, so it is far away from bugs than any newer code.
So, Lets get started with writing our first code in Flex using C Language. We aim to develop a Postfix Calculator. Postfix calculator means that there will be two Operands before an operator and when the parser gets two operands and an operator, it shall evaluate it.
Flex file has an extension of .l (Lex). Now, a typical Flex file has its own Structure and It Looks something like this -
%{
C headers, C code
%}
Regular definitions e.g.:
digit [0-9] //integers from 0 through 9
%%
Token Specifications e.g.:
{digit}+ // Use the previously specified regular // definition digit.
%%
main function
To compile a Flex Code and get the results we will follow the following layout -
Now lets write code for the Postfix Calculator. I'll be explaining things in individual sections.
%{
#include <string.h>
#define stack_size 100
static int sp;
static float stack [stack_size];
static void push (float i) {
if (++sp<stack_size)
stack[sp]= i;
else
{printf ("error: Stack Overflow\n"); exit(1);}
}
static float pop (void) {
if (sp>=0)
return stack[sp--];
else {
printf ("error: Stack Underflow\n"); exit(1);}
}
int int_value;
%}
This is a simple C Code which is self explanatory. We have a Stack of size 100. This is simply to store the inputs. User can input anything. We will take care of what he inputs and understand the nature through the following code.
digit [0-9] integer {digit}+ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+) exp ({integer}|{real})[eE]{integer} exp2 ({integer}|{real})[eE][+-]{integer} exp3 [+-]({integer}|{real})[eE][+-]{integer} integer2 [+-]({integer}|{real})
Essentially, here we simply have defined what are the types of input we want. Digit corresponds to Numbers, then we have real number, exponents etc. Basically, this is just the combination of everything what we can have in a simple postfix calculator. The code that follows to this now is the main LEX code that will parse the input to respective functions and will understand the inputs using the REGEX defined above.
%%
({integer}|{integer2}|{real}|{exp}|{exp2}|{exp3}) {push (atof(yytext));} // yytext contains all the input and we are pushing the float value.
"+" {push (pop() + pop());}
"*" {push (pop() * pop());}
"-" {float rhs= pop(); push (pop() - rhs);}
"/" {float rhs= pop(); push (pop() / rhs);}
<<EOF>> {float answer = pop();
//Small code to simply manipulate the output. Basically handling the float and integer values
char str1[20];
snprintf(str1, 20, "%f", answer);
// To know if the answer has trailing zeroes.
if(strstr(str1,".0000"))
{
memset(str1, 0, strlen(str1));
int_value = answer;
printf("%d \n", int_value);
// If this statement comes true, then we know the answer should be int. Hence Print Integer.
}
else printf ("%.3f \n", answer); // Else Print the value with 3 decimal places.
}
[ \t\n] ;
// This simply bypasses all the tabs and enter key press.
[^-0-9+*/.;eE \t\n]+ {ECHO; fprintf (stderr,"Invalid Character - ");
printf("\n"); exit(1);}
// For every non required character, do not push it to the stack.
%%
int main (void) {sp= -1; yylex(); return 0;}
int yywrap (void) {return 1;}
That is it. go to your prompt, compile the code and run this. Please do let me know if you feel this code can be made more sophisticated or share if you have a different approach to achieve the same. Good Luck.!!