// Formula -> Term {+|- Term} // Term -> Factor {*|/ Factor} // Factor -> Const | ( Formula ) | // StdFunc // StdFunc -> StdFuncName ( ExprList ) // StdFuncName -> "sin" | "cos" | "sqrt" ... // ExprList -> Formula {,Formula} // #include #include #include #include #include #include typedef const char* char_ptr; bool processFormula(char_ptr& txt, double& v); bool processTerm(char_ptr& txt, double& v); bool processFactor(char_ptr& txt, double& v); bool processStdFunc(char_ptr& txt, double& v); bool processExprList( char_ptr& txt, double v[], int maxLen ); static bool debug_print = false; static void dbPrint(const char* s1, const char *s2); int peekLex( // Return lexeme code or LEX_ILLEGAL char_ptr& txt, // In/out: character stream char_ptr& lextxt, // Out: pointer to beginning of lexeme int& lexlen, // Out: length of lexeme double& dblval, // Out: value of lexeme, // when it is a number int& intval // Out: value of lexeme, when it // is a standard function - // the index of std. funct ); void skipSpace(char_ptr& txt); void skipLex(char_ptr& txt, int lexlen); static double myLog2(double); // List of lexemes static const int LEX_NUMBER = 0; static const int LEX_PLUS = 1; static const int LEX_MINUS = 2; static const int LEX_MULT = 3; static const int LEX_DIV = 4; static const int LEX_LPAR = 5; static const int LEX_RPAR = 6; static const int LEX_COMMA = 7; static const int LEX_STD_FUNC_NAME = 8; static const int LEX_ILLEGAL = (-1); // Table of standard functions class StdFuncDef { public: const char* name; int nameLen; int numArgs; double (*func1)(double); double (*func2)(double, double); StdFuncDef( const char* n, int nLen, int nArgs, double (*f1)(double), double (*f2)(double, double) ): name(n), nameLen(nLen), numArgs(nArgs), func1(f1), func2(f2) {} }; const StdFuncDef stdFuncTable[] = { StdFuncDef( "sin", 3, 1, &sin, 0 ), StdFuncDef( "asin", 4, 1, &asin, 0 ), StdFuncDef( "arcsin", 6, 1, &asin, 0 ), StdFuncDef( "sinh", 4, 1, &sinh, 0 ), StdFuncDef( "cos", 3, 1, &cos, 0 ), StdFuncDef( "acos", 4, 1, &acos, 0 ), StdFuncDef( "arccos", 6, 1, &acos, 0 ), StdFuncDef( "cosh", 3, 1, &cosh, 0 ), StdFuncDef( "sqrt", 4, 1, &sqrt, 0 ), StdFuncDef( "exp", 3, 1, &exp, 0 ), StdFuncDef( "log", 3, 1, &log, 0 ), StdFuncDef( "ln", 2, 1, &log, 0 ), StdFuncDef( "log10", 5, 1, &log10, 0 ), StdFuncDef( "log2", 4, 1, &myLog2, 0 ), StdFuncDef( "tan", 3, 1, &tan, 0 ), StdFuncDef( "tg", 2, 1, &tan, 0 ), StdFuncDef( "atan", 4, 1, &atan, 0 ), StdFuncDef( "arctg", 5, 1, &atan, 0 ), StdFuncDef( "atan2", 5, 2, 0, &atan2 ), StdFuncDef( "tanh", 4, 1, &tanh, 0 ), StdFuncDef( "abs", 3, 1, &fabs, 0 ), StdFuncDef( "fabs", 4, 1, &fabs, 0 ), StdFuncDef( "pow", 3, 2, 0, &pow ), StdFuncDef( "fmod", 4, 2, 0, &fmod ), StdFuncDef( "mod", 3, 2, 0, &fmod ), StdFuncDef( 0, 0, 0, 0, 0 ) }; int main(int argc, char *argv[]) { char line[256]; double v; HANDLE hStdin, hStdout, hStderr; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); hStdin = GetStdHandle(STD_INPUT_HANDLE); hStderr = GetStdHandle(STD_ERROR_HANDLE); if ( (hStdout == INVALID_HANDLE_VALUE) || (hStdin == INVALID_HANDLE_VALUE) ) return(-1); if (argc > 1) debug_print = true; while (true) { /*... if (fgets(line, 254, stdin) <= 0) break; if (line[0] == '\n') // Empty line break; ...*/ // Read from standard input. DWORD numRead = 0; BOOL fSuccess = ReadFile( hStdin, line, 254, &numRead, NULL ); if (!fSuccess || numRead == 0) break; line[numRead] = 0; /*??? //... fprintf(stderr, "Received %s\n", line); DWORD numWrite = 0; fSuccess = WriteConsole( hStdin, line, numRead, &numWrite, NULL ); if (!fSuccess || numWrite == 0) break; ???*/ if ( numRead == 0 || line[0] == '\n' || // Empty line line[0] == '\r' || line[0] == 'q' || // quit line[0] == 'Q' ) break; const char *txt = line; /*... if (!processFormula(txt, v)) printf("Syntax error.\n"); else printf("= %f\n", v); ...*/ if (!processFormula(txt, v)) sprintf(line, "Syntax error.\n"); else sprintf(line, "= %f\n", v); DWORD len = (DWORD) strlen(line); DWORD written = 0; // Write to standard output. fSuccess = WriteFile( hStdout, line, len, &written, NULL ); if (!fSuccess) break; } return 0; } bool processFormula(char_ptr& txt, double& v) { double t; int lexlen, intval; double dblval; char_ptr lextxt; dbPrint("processFormula", txt); if (!processTerm(txt, t)) return false; v = t; int op = peekLex( txt, lextxt, lexlen, dblval, intval ); while (op == LEX_PLUS || op == LEX_MINUS) { skipLex(txt, lexlen); if (!processTerm(txt, t)) return false; if (op == LEX_PLUS) v += t; else v -= t; op = peekLex( txt, lextxt, lexlen, dblval, intval ); } return true; } bool processTerm(char_ptr& txt, double& v) { double t; int lexlen, intval; double dblval; char_ptr lextxt; dbPrint("processTerm", txt); if (!processFactor(txt, t)) return false; v = t; int op = peekLex( txt, lextxt, lexlen, dblval, intval ); while (op == LEX_MULT || op == LEX_DIV) { skipLex(txt, lexlen); if (!processFactor(txt, t)) return false; if (op == LEX_MULT) v *= t; else v /= t; op = peekLex( txt, lextxt, lexlen, dblval, intval ); } return true; } bool processFactor(char_ptr& txt, double& v) { int lexlen, intval; double dblval; char_ptr lextxt; dbPrint("processFactor", txt); int lex = peekLex( txt, lextxt, lexlen, dblval, intval ); if (lex == LEX_NUMBER) { skipLex(txt, lexlen); v = dblval; return true; } else if (lex == LEX_LPAR) { skipLex(txt, lexlen); if (!processFormula(txt, v)) return false; lex = peekLex( txt, lextxt, lexlen, dblval, intval ); if (lex != LEX_RPAR) return false; skipLex(txt, lexlen); return true; } else if (lex == LEX_STD_FUNC_NAME) { return processStdFunc(txt, v); } else if (lex == LEX_MINUS) { // Unary minus skipLex(txt, lexlen); if (!processFactor(txt, v)) return false; v = (-v); return true; } else { return false; } } bool processStdFunc(char_ptr& txt, double& v) { int funcIdx; int lexlen, intval; double dblval; char_ptr lextxt; dbPrint("processStdFunc", txt); int lex = peekLex( txt, lextxt, lexlen, dblval, funcIdx ); if (lex != LEX_STD_FUNC_NAME) return false; const StdFuncDef* f = stdFuncTable + funcIdx; skipLex(txt, lexlen); lex = peekLex( txt, lextxt, lexlen, dblval, funcIdx ); if (lex != LEX_LPAR) return false; skipLex(txt, lexlen); double values[2]; if (!processExprList(txt, values, 2)) return false; v = 0.; if (f->numArgs == 1) v = (*(f->func1))(values[0]); else if (f->numArgs == 2) v = (*(f->func2))(values[0], values[1]); lex = peekLex( txt, lextxt, lexlen, dblval, funcIdx ); if (lex != LEX_RPAR) return false; skipLex(txt, lexlen); return true; } bool processExprList( char_ptr& txt, double values[], int maxLen ) { int lexlen, intval; double dblval, v; char_ptr lextxt; dbPrint("processExprList", txt); if (!processFormula(txt, v)) return false; int i = 1; values[0] = v; int lex = peekLex( txt, lextxt, lexlen, dblval, intval ); while (lex == LEX_COMMA) { skipLex(txt, lexlen); if (!processFormula(txt, v)) return false; if (i < maxLen) { values[i] = v; ++i; } lex = peekLex( txt, lextxt, lexlen, dblval, intval ); } return true; } int peekLex( char_ptr& txt, // In/out: character stream char_ptr& lextxt, // Out: pointer to beginning of lexeme int& lexlen, // Out: length of lexeme double& dblval, // Out: value of lexeme, // when it is a number int& intval // Out: value of lexeme, when it // is a standard function - // the index of std. funct ) { char number[32]; skipSpace(txt); lextxt = txt; char_ptr t = txt; int i = 0; char c = *t; if (isdigit(c)) { // Integer part of real number while (i < 31 && isdigit(c)) { number[i] = *t; ++i; ++t; c = *t; } number[i] = 0; } if (c == '.') { // Fractional part of real number number[i] = c; ++i; ++t; c = *t; if (i == 1 && !isdigit(c)) return false; // Single point while (i < 31 && isdigit(c)) { number[i] = c; ++i; ++t; c = *t; } number[i] = 0; } if (i > 0) { dblval = atof(number); lexlen = i; return LEX_NUMBER; } lexlen = 1; switch (c) { case '+': return LEX_PLUS; case '-': return LEX_MINUS; case '*': return LEX_MULT; case '/': return LEX_DIV; case '(': return LEX_LPAR; case ')': return LEX_RPAR; case ',': return LEX_COMMA; } if (isalpha(c)) { // Extract name char_ptr e = t; while (*e != 0 && isalnum(*e)) ++e; int nameLen = e - t; // Check for a standard function name const StdFuncDef* f = stdFuncTable; int funcIdx = 0; while (f->name != 0) { if ( nameLen == f->nameLen && strncmp(f->name, t, f->nameLen) == 0 ) { lexlen = f->nameLen; intval = funcIdx; return LEX_STD_FUNC_NAME; } ++f; ++funcIdx; } lexlen = 0; return LEX_ILLEGAL; } lexlen = 0; return LEX_ILLEGAL; } void skipSpace(char_ptr& txt) { while (*txt != 0 && isspace(*txt)) ++txt; } void skipLex(char_ptr& txt, int lexlen) { txt += lexlen; } static void dbPrint(const char* s1, const char* s2) { if (debug_print) printf("%s: %s", s1, s2); } static double myLog2(double x) { return log(x)/log(2.); }