-
Notifications
You must be signed in to change notification settings - Fork 2
Example: Calculator Flow Variables
Ronald Franco edited this page Dec 21, 2018
·
1 revision
Let us modify the previous example to use more flow variables. More specifically, we’ll use adjust the previous example’s AFG to require inherited attributes, or in this case in-flow variables. The example employs a parser that parses the following grammar:
<E> ::= <T> <TT> { TT.st := T.val; E.val := TT.val }
<TT1> ::= + <T> <TT2> { TT2.st := TT1.st + T.val; TT1.val := TT2.val }
<TT1> ::= - <T> <TT2> { TT2.st := TT1.st - T.val; TT1.val := TT2.val }
<TT> ::= ε { TT.val := TT.st }
<T> ::= <F> <FT> { FT.st := F.val; T.val := FT.val }
<FT1> ::= * <F> <FT2> { FT2.st := FT1.st * F.val; FT1.val := FT2.val }
<FT1> ::= / <F> <FT2> { FT2.st := FT1.st / F.val; FT1.val := FT2.val }
<FT> ::= ε { FT.val := FT.st }
<F1> ::= - <F2> { F1.val := -F2.val }
<F> ::= { <E> ) { F.val := E.val }
<F> ::= unsigned_int{ F.val := unsigned_int.val }
Where st is an inherited attribute and val is a synthesized attribute. The Flex specification is the same as the previous example's. Notice the use of flow variables in the AFG implement some of the above semantic rules, like “TT.st := T.val” and “TT.val := TT.st”, automatically.
Driver Program:
#include <iostream>
#include "parser.h"
#include "flextokenizer.h"
int main()
{
/* calculator w/ in-flow variables example */
/* define tokens */
Parser<> plus('+'), minus('-'), times('*'), divides('/'), num(2);
/* define nonterminals */
Parser<int> line, expr, fact, fact_tail, term, term_tail;
/* define flow variables */
int a(0), b(0), c(0), d(0);
/* AFG */
line>>a = expr>>a & '\n';
expr>>a = term>>a & term_tail(a)>>a;
term_tail(b)>>b = -('+' & term>>c & [&]{ d = b + c; } & term_tail(d)>>b
| '-' & term>>c & [&]{ d = b - c; } & term_tail(d)>>b);
term>>a = fact>>a & fact_tail(a)>>a;
fact_tail(b)>>b = -('*' & fact>>c & [&]{ d = b * c; } & fact_tail(d)>>b
| '/' & fact>>c & [&]{ d = b / c; } & fact_tail(d)>>b);
fact>>a = num>>a | '(' & expr>>a & ')';
/* FlexTokenizer will use stdin */
FlexTokenizer tokens;
/* maintain current position */
size_t pos = 0;
while (true)
{
/* user prompt */
std::cout << "============================================================";
std::cout << "\nA calculator that supports:";
std::cout << "\n\t- integers and doubles";
std::cout << "\n\t- +, -, *, /";
std::cout << "\n\t- parenthesis";
std::cout << "\nFormat: <arithmetic expression>";
std::cout << "\nExamples:\n\t1) 4 + 3 * 2\n\t2) (7 - 2) / 5\n";
std::cout << "============================================================";
std::cout << "\nGive me a mathematical expression.";
std::cout << "\nCtrl + C to quit: ";
/* if we can parse sucessfully starting at position pos,
* print result, i.e. the output flow variable of the starting
* nonterminal */
if (line.parse(&tokens,&pos))
{
std::cout << "Expression computed succesfully!\nResult: " << a << "\n" << std::endl;
}
else
{
std::cout << "Expression computation failed\n" << std::endl;
}
tokens.clear();
pos = 0;
}
return 0;
}