%{ #include "Calculator.h" #define yylval Calculatorlval #include "Calculator.tab.h" #include #include #include %} %option noyywrap %option c++ digit [0-9] number {digit}+\.?|{digit}*\.{digit}+ identifier [a-zA-Z]+ %% [ ] { /* Skip blanks. */ } {number} { /* sscanf(yytext, "%lf", &yylval.value); */ std::istrstream(yytext, yyleng) >> yylval.value; return NUMBER; } "sqrt" { yylval.f = &sqrt; return ELEMENTARY_FUNCTION; } "exp" { yylval.f = &exp; return ELEMENTARY_FUNCTION; } "log" { yylval.f = &log; return ELEMENTARY_FUNCTION; } "exp2" { yylval.f = &exp2; return ELEMENTARY_FUNCTION; } "log2" { yylval.f = &log2; return ELEMENTARY_FUNCTION; } "exit" { return EXIT; } {identifier} { yylval.name = std::string(yytext, yyleng).c_str(); return IDENTIFIER; } \n|\r { return '\n'; } . { return yytext[0]; } <> { return Eof; } %% -- Calculator.y, bison --defines --name-prefix=Calculator ------------------- %{ /* Creating C++ syntax for a Bison and Flex calculator. */ #include #include "Calculator.h" #define yyFlexLexer CalculatorFlexLexer #include "FlexLexer.h" FlexLexer* flexLexer; inline int yylex() { return flexLexer->yylex(); } double parse_value = 0; %} %token NUMBER %token ELEMENTARY_FUNCTION %token IDENTIFIER %token Eof %token EXIT %left '+' '-' %right ELEMENTARY_FUNCTION %left '*' '/' %right '^' %right IDENTIFIER %right UMINUS %% lines: lines expr '\n' { parse_value = $2.value; return 0; } | lines expr Eof { parse_value = $2.value; return 0; } | lines EXIT '\n' { throw Exit(0, "Exit: Bye, bye!"); } | lines EXIT Eof { throw Exit(0, "Exit: Bye, bye!"); } | lines '\n' | lines Eof { throw Exit(0, "End of file."); } | | error '\n' { cout << "Please re-enter last line:\n"; yyerrok; } | error Eof { throw Exit(1, "Exit: Error!"); } ; expr: expr '+' expr { $$.value = $1.value + $3.value } | expr '-' expr { $$.value = $1.value - $3.value } | expr '*' expr { $$.value = $1.value * $3.value } | expr '/' expr { $$.value = $1.value / $3.value } | expr '^' expr { $$.value = pow($1.value, $3.value) } | '(' expr ')' { $$.value = $2.value } | '-' expr %prec UMINUS { $$.value = -$2.value } | IDENTIFIER expr { $$.value = sqrt($2.value) } | ELEMENTARY_FUNCTION expr { $$.value = (*$1.f)($2.value) } | NUMBER ; %% Parser::Parser(std::istream* ip, std::ostream* op) : isp(ip), osp(op) { lex = new yyFlexLexer(isp, osp); } Parser::~Parser() { delete lex; } std::istream& Parser::operator>>(double& val) { lex->yyrestart(isp); flexLexer = lex; yyparse(); val = parse_value; return *isp; } #if 0 #include #include #if __MWERKS__ && macintosh #include #endif int main() { #if __MWERKS__ && macintosh SIOUXSettings.asktosaveonclose = 0; SIOUXSettings.autocloseonquit = 1; #endif return yyparse(); } #endif int yyerror(char* errstr) { cerr << "Error: " << errstr << endl; return EXIT_FAILURE; } -- Calculator.h -------------------------------------------------------- #ifndef Calculator_h #define Calculator_h #include #include #include class FlexLexer; #if __MWERKS__ && macintosh #include #endif typedef union calc_type { double value; const char* name; double (*f)(double); } calc_type; #define YYSTYPE calc_type int yyerror(char* errstr); class Parser { std::istream* isp; // istream being parsed std::ostream* osp; // ostream being output to FlexLexer* lex; // Lexical analyzer to use; public: Parser(std::istream* ip = 0, std::ostream* op = 0); ~Parser(); std::istream& operator>>(double&); std::ostream& operator<<(double&); Parser& operator>>(Parser& (*manipulator)(Parser&)) { return manipulator(*this); } Parser& operator<<(Parser& (*manipulator)(Parser&)) { return manipulator(*this); } friend Parser& operator<<(ostream& ost, Parser& parser); friend Parser& operator>>(std::istream& ist, Parser& parser); }; #if 0 inline std::istream& Parser::operator>>(double& val) { val = sentence(*isp); return *isp; } #endif #if 0 inline std::ostream& Parser::operator<<(double& val) { return (*osp) << val; } #endif inline Parser& operator<<(ostream& ost, Parser& parser) { parser.osp = &ost; return parser; } inline Parser& operator>>(std::istream& ist, Parser& parser) { parser.isp = &ist; return parser; } Parser& inprompt(Parser& syn); Parser& outprompt(Parser& syn); class Exit { int error; string message; public: Exit(int err, string mess) : error(err), message(mess) { } int status() { return error; } string what() { return message; } }; #endif -- main.cc ---------------------------------------------------------------- // Creating C++ syntax for a Bison and Flex calculator. #include #include #include #include "Calculator.h" #if __MWERKS__ && macintosh #include #endif int main() { #if __MWERKS__ && macintosh SIOUXSettings.asktosaveonclose = 0; SIOUXSettings.autocloseonquit = 0; #endif Parser calc; double d; std::ifstream ifs("Input", ios_base::in | ios_base::binary); if (!ifs) cout << "Could not open input file." << endl; else { // ifs.exceptions(ios_base::eofbit); // while (ifs && !ifs.eof()) try { for (;;) { ifs >> calc >> d; std::cout << d << endl; } } catch (Exit& ex) { std::cout << ex.what() << endl; std::cout << "Status: " << ex.status() << endl; } catch (...) { cout << "Exception: ..." << endl; } } while (cin) { try { std::cin >> calc >> d; std::cout << d << endl; } catch (Exit& ex) { std::cout << ex.what() << endl; return ex.status(); } } return EXIT_SUCCESS; }