Implementation of A Simple Calculator Using Flex and Bison: Abstract
Implementation of A Simple Calculator Using Flex and Bison: Abstract
Implementation of A Simple Calculator Using Flex and Bison: Abstract
Somasundaram Meiyappan
Abstract:
A simple calculator program is created using the compiler tools – flex and bison - and using the C
programming language. The calculator takes is simple numerical expressions as input and
evaluate them to give the result of the evaluation to the user. Apart from providing some standard
mathematical functions and capabilities, this implementation also lets the user to define functions
that will extend the built-in capabilities of the calculator. It also generates vcg files for all trees
that the program constructs giving the user a glimpse of the internals.
Description:
This assignment is about creating a simple calculator using flex and bison with C as the
programming language. This implementation of the assignment can take in simple numerical
expressions, evaluate them and give the result of the evaluation to the user. This calculator
provides the user with some standard mathematical and logical operators and some standard built-
in functions. The user can define his/her own functions that use these capabilities and can pass
them normally just as the other expressions are entered or as files in the command line itself.
These functions have to defined in the language of the calculator and will be described shortly.
The program can also used to generate vcg files for all trees that it constructs giving the user a
glimpse of the internals. These trees are used when evaluating an expression or function. These
vcg files can be viewed using graph visualizing tools like xvcg or aiSee (after changing the
extension to gdl).
Tree Builder
(calc_treebuilder.c)
Execution Engine
(calc_runtime.c)
• lex_src : contains the *.l files that are inputs to flex, the lexical analyzer
generator
o calc.l
• yacc_src: contains the *.y files that are input to bison, the parser generator
o calc.y
• src: contains the *.c source files
o calc_runtime.c
o calc_treebuilder.c
o calc_frontend.c
• inc: contains the *.h header files
o more_types.h
o calc_struct.h
o calc_operators.h
o calc_treebuilder.h
The lexical analyzer, that is generated using flex, emits tokens to the parser for use in its
grammar. The lexical analyzer uses some services from the calc_frontend.c file to get some
tokens. For example: the function isThisUserDefinedFunction searches the function table, that
has the list of all functions defined by the user, and tells the parser that this is a user-defined
function and also passes the unique index of the function. Another example is the
isThisAnOperator function, which not only tells the lexer that the passed in string is an operator,
but also gives the token of that corresponds to that operator. Some unrecognized stream of input
are reported as error directly by the lexical analyzer whereas some other unrecognized characters
are passed to the parser which signals that we have an error. This file also hosts the main
function.
The parser, that is generated using bison, uses the tokens from the lexical analyzer in reducing the
various productions that are in grammar of the language accepted by the program. The parser uses
the services provided by the calc_treebuilder.c file to build its parse-trees that are later used in
execution. All allocations are kept track of locally and the memory is released either on
successful execution or on error conditions. In the case of user-defined functions, the memory is
not released as the functions are intended to be visible for this entire instance of the program.
The parser generates trees for all expressions and then reduces them following certain rules to
evaluate them. Parse trees are also generated for user-defined functions and parameters are passed
into these trees at appropriate places for evaluating the function. Examples of the internal trees
and expressions are given below.
The trees are evaluated by post-order traversal of the tree. In the last tree below, g(0,0,0) is
represented with ‘g’ as the parent of three children, one corresponding to each parameter. The
edge, with label 1, points to the first parameter 0 and so on. This also means that the value of
g(0,0,0) will be computed first and then 45*3 will be computed and then (g(0,0,0)) + (45*3) will
be computed.
Parameters that go into to a function are actually placed in the respective locations in pArgs
member. And the arg0, arg1, arg2 that in the trees of f(x,y,z) and g(x,y,z) point to these locations
in the function table and hence, they have the values directly.
Traversing the parse-tree in pre-order generates the vcg files. Please note that the label name of
the edges and they can be useful in cases like above when 45 which is edge 1 for * operator
comes to the right of 3, which is edge 2.
Future enhancements:
With this infrastructure, variables can be allowed very easily. These variables can be used to store
results of some expressions for use later in the session. This was not included in this
implementation because of lack of time. User definable functions can be made to have more than
1 statement. Also, support for loops can also be added. After all, we can try to bring all the
features that C has.