📄 ccalc.cpp
字号:
//-< CCALC.CPP >-----------------------------------------------------*--------*// Ccalc Version 1.02 (c) 1998 GARRET * ? *// (C expression command line calculator) * /\| *// * / \ *// Created: 20-Oct-98 K.A. Knizhnik * / [] \ *// Last update: 20-Oct-98 K.A. Knizhnik * GARRET *//-------------------------------------------------------------------*--------*#include <stdio.h>#include <string.h>#include <ctype.h>#include <math.h>#include <errno.h>#include <stdlib.h>#ifdef USE_READLINE#include <readline/readline.h>#include <readline/history.h>#endif#include "ccalc.h"int_t to_int(int_t val) { return val; }double to_float(double val) { return val; }int_t prime(int_t n) { if (n <= 3) { return n; } n |= 1; while (true) { int_t m = (int_t)sqrt((double)n) + 1; int_t k = 3; while (true) { if (k > m) { return n; } if (n % k == 0) break; k += 2; } n += 2; }}char* to_bin(int nval, char* pbuf, int nbufsize){ int ncnt; int bcnt; int nlen = sizeof(int) * 8 + sizeof(int); if (pbuf != NULL && nbufsize > nlen) { pbuf[nlen] = '\0'; pbuf[nlen - 1] = 'b'; for(ncnt = 0, bcnt = nlen - 2; ncnt < nlen; ncnt ++, bcnt --) { if (ncnt > 0 && (ncnt % 8) == 0) { pbuf[bcnt] = '.'; bcnt --; } pbuf[bcnt] = (nval & (1 << ncnt))? '1' : '0'; } } return pbuf;}int_t gcd(int_t x, int_t y) { while(x) { int_t r = y%x; y=x; x=r; } return y;}int_t invmod(int_t x, int_t y) { int_t m = y; int_t u = 1, v = 0; int_t s = 0, t = 1; while(x) { int_t q = y/x; int_t r = y%x; int_t a = s - q*u; int_t b = t - q*v; y=x; s=u; t=v; x=r; u=a; v=b; } if(y!=1) return 0; while(s<0) s+=m; return s;}const char* help = "\Input for this calculator are normal C expressions containing operators, float\n\or integer constants, variables and and references to previous results ($n).\n\Precedence and semantic of operators is the same as in C language. There are\n\two extra binary operators: >>> unsigned shift right and ** raising to power.\n\Calculator supports standard set of functions from C mathematics library and\n\also defines function prime(n) for the smallest prime number >= n, gcd(n,m) for\the greatest common divisor of n and m, and invmod(n,m) for inverse of n modulo m.\n\Operators:\n\ ++ -- ! ~ unary + -\n\ **\n\ * / %\n\ + -\n\ << >> >>>\n\ < <= > >= \n\ == != \n\ &\n\ ^\n\ |\n\ = += -= *= /= %= <<= >>= >>>= &= |= ^= **= \n\Functions:\n\ abs\t atan\t cosh\t float\t prime\t sqrt\n\ acos\t atan2\t exp\t log\t sin\t tan\n\ asin\t cos\t int\t log10\t sinh\t tanh\n\ gcd\t invmod\n\Type \"exit\" or \"quit\" to terminate program, \"help\" or \"?\" to show this help\n";int main(int argc, char* argv[]) { calculator ccalc; symbol* sp; symbol::add(FFUNC1, "abs", (void*)(double(*)(double))fabs); symbol::add(FFUNC1, "acos", (void*)(double(*)(double))acos); symbol::add(FFUNC1, "asin", (void*)(double(*)(double))asin); symbol::add(FFUNC1, "atan", (void*)(double(*)(double))atan); symbol::add(FFUNC2, "atan2", (void*)(double(*)(double,double))atan2); symbol::add(FFUNC1, "cos", (void*)(double(*)(double))cos); symbol::add(FFUNC1, "cosh", (void*)(double(*)(double))cosh); symbol::add(FFUNC1, "exp", (void*)(double(*)(double))exp); symbol::add(FFUNC1, "log", (void*)(double(*)(double))log); symbol::add(FFUNC1, "log10", (void*)(double(*)(double))log10); symbol::add(FFUNC1, "sin", (void*)(double(*)(double))sin); symbol::add(FFUNC1, "sinh", (void*)(double(*)(double))sinh); symbol::add(FFUNC1, "tan", (void*)(double(*)(double))tan); symbol::add(FFUNC1, "tanh", (void*)(double(*)(double))tanh); symbol::add(FFUNC1, "sqrt", (void*)(double(*)(double))sqrt); symbol::add(FFUNC1, "float", (void*)to_float); symbol::add(IFUNC1, "int", (void*)to_int); symbol::add(IFUNC2, "gcd", (void*)(int_t(*)(int_t,int_t))gcd); symbol::add(IFUNC2, "invmod", (void*)(int_t(*)(int_t,int_t))invmod); symbol::add(IFUNC1, "prime", (void*)prime); sp = symbol::add(VARIABLE, "pi"); sp->val.tag = FLOAT; sp->val.fval = 3.1415926535897932385E0; sp = symbol::add(VARIABLE, "e"); sp->val.tag = FLOAT; sp->val.fval = 2.7182818284590452354E0; if (argc > 1) { for (int i = 1; i < argc; i++) { ccalc.evaluate(argv[i]); } } else { #ifndef USE_READLINE char buf[max_expression_length];#endif char *p_buf = NULL; printf("C expression command line calculator. Author: http://www.garret.ru/~knizhnik\nType \"help\" for more information\n\n"); do {#ifndef USE_READLINE printf(prompt); p_buf = fgets(buf, sizeof buf, stdin);#else p_buf = readline(prompt);#endif if (p_buf != NULL) { if (strncmp(p_buf, "help", 4) == 0 || strncmp(p_buf, "HELP", 4) == 0 || *p_buf == '?') { printf(help); } else if (strncmp(p_buf,"exit",4)==0 || strncmp(p_buf,"EXIT",4)==0 || strncmp(p_buf,"quit",4)==0 || strncmp(p_buf,"QUIT",4)==0) { return 0; } else if (*p_buf != '\x0') { #ifdef USE_READLINE add_history(p_buf);#endif ccalc.evaluate(p_buf); }#ifdef USE_READLINE free(p_buf);#endif } } while (p_buf != NULL); } return 0;}inline unsigned string_hash_function(char* p) { unsigned h = 0, g; while(*p) { h = (h << 4) + *p++; if ((g = h & 0xF0000000) != 0) { h ^= g >> 24; } h &= ~g; } return h;}symbol* symbol::hash_table[hash_table_size];symbol* symbol::add(t_symbol tag, char* name, void* func) { unsigned h = string_hash_function(name) % hash_table_size; symbol* sp; for (sp = hash_table[h]; sp != NULL; sp = sp->next) { if (strcmp(sp->name, name) == 0) { return sp; } } sp = new symbol; sp->tag = tag; sp->func = func; sp->name = strdup(name); sp->val.tag = INT; sp->val.ival = 0; sp->next = hash_table[h]; hash_table[h] = sp; return sp;} void calculator::error(int pos, char* msg) { pos += strlen(prompt); if (pos < 80) { while (--pos >= 0) putc('.', stderr); fprintf(stderr, "^\n"); } fprintf(stderr, "Error: %s\n\n", msg);}t_operator calculator::scan(bool operand){ char name[max_expression_length], *np; while (isspace(buf[pos])) pos += 1; switch (buf[pos++]) { case '\0': return END; case '(': return LPAR; case ')': return RPAR; case '+': if (buf[pos] == '+') { pos += 1; return operand ? PREINC : POSTINC; } else if (buf[pos] == '=') { pos += 1; return SETADD; } return operand ? PLUS : ADD; case '-': if (buf[pos] == '-') { pos += 1; return operand ? PREDEC : POSTDEC; } else if (buf[pos] == '=') { pos += 1; return SETSUB; } return operand ? MINUS : SUB; case '!': if (buf[pos] == '=') { pos += 1; return NE; } return NOT; case '~': return COM; case '*': if (buf[pos] == '*') { if (buf[pos+1] == '=') { pos += 2; return SETPOW; } pos += 1; return POW; } else if (buf[pos] == '=') { pos += 1; return SETMUL; } return MUL; case '/': if (buf[pos] == '=') { pos += 1; return SETDIV; } return DIV; case '%': if (buf[pos] == '=') { pos += 1; return SETMOD; } return MOD; case '<': if (buf[pos] == '<') { if (buf[pos+1] == '=') { pos += 2; return SETASL; } else { pos += 1; return ASL; } } else if (buf[pos] == '=') { pos += 1; return LE; } return LT; case '>': if (buf[pos] == '>') { if (buf[pos+1] == '>') { if (buf[pos+2] == '=') { pos += 3; return SETLSR; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -