📄 calculator.c
字号:
/* calculator.c by Dr. Gerhard Wanderer (gerhard.wanderer@i-dail.de) $Id: calculator.c,v 1.3 2002/12/17 15:31:55 gerhard Exp gerhard $ Subroutines to evaluate a string and calculate the contained formulas ===================================================================== The evaluation is done recursively, working on the line from left to right. The subroutine "Calculator" is the main entry point and needs two arguments: the formula, which should be calculated and a structure CALCFKT, which stores the local or user-defined variables. The subroutine "Calculator" first checks, whether a function definition is given (indicated by ":=" in the comandline). In this case it creates a entry in the CalculatorFkt list and stores the remainder of the line as the funtion definition and returns. Otherwise it calls Calculator_Sub with local variables as working variables for Calculator_Sub. If the recursion ended or no recursion was necessary, the returned result of Calculator_Sub is stored in the CalculatorHistory List for future use. ------------------ Calculator_Sub parses the commandline and divides the line into subexpressions. If it is called the first time for a certain command line (istack == 0), it checks, whether the values should be stored in a variable (this is indicated by the character "=". If this is the case, it searches for this variable or creates a new one. Next it searches for the first operand and puts it on the stack If it is called again, it expects the first character to be a operator ("+", "-", "*", "/" or "^"). If none is found, "*" is assumed. The operator is saved on the stack. If the operator level is lower or equal the previouse one, the operand stack is reduced. Now the next operand is searched and put on the stack. If the line ends, the stack is reduced and result is returned. The operand search is divided into five actions: - first it is checked, wether a sub-formula is given by surrounding brackets "(", ")". If this is the case, the included substring is isolated and the subroutine "Calculator" is called with this substring, resulting in an recursion loop. The result of this ip put on the stack. - if no sub-formula is given, it checkes, whether a number is given. This number is put on the stack - if no number is give, i.e. the remaining string begins with a character a..z or A..Z, if is looked up in the table of build in funtions. Most of the build in functions require one argument, which has to be provided in brackets after the function name ("sin(3.2)"). The subroutine FindBrackets isolates the included substring and calls the subroutine Calulator to evaluate this substring and return the calculated value. - if no build-in function is found, the list of user-defined variables is examined. If one is found, it磗 value is copied to the stack. - if no user-defined variable is found, the list of user-defined functions is examined. If one is found, the subroutine CalculateFkt examines the parameter list and calculates the function with the given arguments. The returned value is put on the stack. -------------------------------- The Subroutine CalculateFkt examines the argument list given within brackets. The arguments are separated by the character ";". Each argument is calculated by calling the subroutine Calculator with the argument parameters as the formula string and the global variables. This means, that the user-defined variables can be used, when the parameters are given as formulas. The results are stored in the functions local variable list. To calculate the function, Calculator is called with the funtion definition as the formula an the local variable list.*///#include <ctype.h>#include <malloc.h>#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#define _CALCULATOR_#include "calculator.h"// pre-definition of internal functionsdoubleFindBrackets(char *text, int *end, CALCFKT *cal);doubleFindDualParam(char *text, int *end, CALCFKT *cal, double *pa1);double Calculator_Sub (char *formel, double *NumStack, char *OpStack, char *OpLvlStack, int *iStack, CALCFKT *cal);char *interncons[] = {"ANS", "PI"};#define INTERNCONS 2char *internfkt[] = {"LN", "EXP", "LG", "LOG10", "LOG2", "LOG", "ABS", "SQRT","ATAN2","SIGN", "AHSIN", "ASINH", "HASIN", "ASIN", "HSIN", "SINH", "SIN", "AHCOS", "ACOSH", "HACOS", "ACOS", "HCOS", "COSH", "COS", "AHTAN", "ATANH", "HATAN", "ATAN", "HTAN", "TANH", "TAN", "AHSEC", "ASECH", "HASEC", "ASEC", "HSEC", "SECH", "SEC", "AHCOT", "ACOTH", "HACOT", "ACOT", "HCOT", "COTH", "COT", "AHCSC", "ACSCH", "HACSC", "ACSC", "HCSC", "CSCH", "CSC",};int internfktid[] = {0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11, 11, 12, 13, 13, 13, 14, 15, 15, 16, 17, 17, 17, 18, 19, 19, 20, 21, 21, 21, 22, 23, 23, 24, 25, 25, 25, 26, 27, 27, 28, 29, 29, 29, 30, 31, 31, 32};#define INTERNFKT (int) sizeof(internfktid)/sizeof(int)////voidInsertVariable(char *name, double var) { int iVar, i, ilast, ip; iVar = -1; for (i = 0; i < CalculatorFkt[0].Vars; i++) if (strcmp(CalculatorFkt[0].Var[i].Name, name) == 0) iVar = i; if (iVar < 0) {// Variable does not exist if (CalculatorFkt[0].Vars < CALCULATOR_VARS-1) { // create new user-defined variable CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Name = (char*) malloc(strlen(name)+1); strcpy(CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Name, name); iVar = CalculatorFkt[0].Vars; CalculatorFkt[0].Vars++; } else { // already 99 Variables uses; need to free the longest unused ilast = CalculatorFkt[0].RefCnt; ip = -1; for (i = 0; i < CalculatorFkt[0].Vars; i++) { if (CalculatorFkt[0].Var[i].Ref < ilast) { ip = i; ilast = CalculatorFkt[0].Var[i].Ref; } } if (ip >= 0) { iVar = ip; free(CalculatorFkt[0].Var[ip].Name); CalculatorFkt[0].Var[ip].Name = (char*) malloc(strlen(name)+1); strcpy(CalculatorFkt[0].Var[ip].Name, name); } else { return; // setting impossible } } } CalculatorFkt[0].RefCnt++; CalculatorFkt[0].Var[iVar].Valu = var; CalculatorFkt[0].Var[iVar].Ref = CalculatorFkt[0].RefCnt;}voidReadHistory (FILE *config){ char inpline[256]; char *ptr, *ptr2, *p1, *p2; int i, mode, fktready; mode = 0; ptr2 = NULL; CalculatorFktAnz = 0; // if a configuration file already exists, read in the content if (config) { while (!feof(config)) { if (fgets(inpline, 256, config)) { if (strstr(inpline, "[REF]") == inpline) // last timestamp mode = 1; else if (strstr(inpline, "[VAR]") == inpline) // the list of user-defined variables begins now mode = 2; else if (strstr(inpline, "[HIST]") == inpline) { // the formula history list begins now mode = 3; ptr2 = NULL; } else if (strstr(inpline, "[FKT]") == inpline) { // the list of user-defined functions begins now mode = 4; ptr2 = NULL; CalculatorFktAnz = 0; } else if (strstr(inpline, "[VHIST]") == inpline) // the result (value) history list begins now mode = 5; else { switch (mode) { case 1: // REF if (strstr(inpline, "radian=")) { p1 = strchr(inpline, '='); sscanf(&p1[1], "%d", &CalculatorRad); } else if (strstr(inpline, "format=")) { p1 = strchr(inpline, '='); sscanf(&p1[1], "%d", &CalculatorFmt); } else if (strstr(inpline, "autoans=")) { p1 = strchr(inpline, '='); sscanf(&p1[1], "%d", &CalculatorAutoAns); } else if (strstr(inpline, "autohighlight=")) { p1 = strchr(inpline, '='); sscanf(&p1[1], "%d", &CalculatorAutoHighlight); } else sscanf(inpline, "%d", &CalculatorFkt[0].RefCnt); break; case 2: // read the list of userdefined variables // each line has three fields, separated by ";" // 1. field: name of variable // 2. field: last value // 3. timestamp // example: "AA; 20;1" ptr = strchr(inpline, ';'); if (ptr) { // only read, if it磗 a valid entry ptr[0] = 0; // store the name of the variable CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Name = (char*) malloc (strlen(inpline)+1); strcpy(CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Name, inpline); ptr++; ptr2 = strchr(ptr, ';'); // read the value and the timestamp if(ptr2) { ptr2[0] = 0; sscanf(ptr, "%lf", &CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Valu); ptr2++; sscanf(ptr2, "%d", &CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Ref); } else { CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Valu = 0; CalculatorFkt[0].Var[CalculatorFkt[0].Vars].Ref = 0; } CalculatorFkt[0].Vars++; } break; case 3: // read the formula history list. Formulas may be longer // than the maximum linelength of 255 character. In this case // the formula is written to many lines with the character "\ " // at the end of all lines except the last (continuation // character). i = strlen(inpline); // remove unwanted blanks while((i > 0) && ((inpline[i] <= ' ') || ((unsigned)inpline[i] >= 0x80))) {inpline[i] = 0; i--;} if (strlen(inpline)) { // if there is already a part of the formula read, append // the next part if (ptr2) { ptr = (char*) realloc(ptr2, strlen(inpline)+strlen(ptr2)+1); strcat(ptr, inpline); } else { // store this part ptr = (char*) malloc(strlen(inpline)+1); strcpy(ptr, inpline); } // will the next line belong to this line? if (ptr[strlen(ptr)-1] == '\\') { // remember the current part for continuation ptr2 = ptr; ptr[strlen(ptr)-1] = 0; } else { // if complete add the formula to the history list if (CalculatorCmdHistoryAnz < CALCULATOR_FHISTORY) { CalculatorCmdHistory[CalculatorCmdHistoryAnz] = ptr; CalculatorCmdHistoryAnz++; } ptr2 = NULL; } } break; case 4: // read the user-defined functions // the first line containes the function name and the number of // parameters; the names of the parameters follow, each on a // separate line; after the parameters the function definition // follows, if necessary on several lines, marked with the // continuation character. // The name of the function as well as the names of the // parameters are surrounded by the characters "<" and ">". CalculatorFktAnz++; fktready = 0; // isolate function name p1 = strchr(inpline, '<'); p2 = strchr(inpline, '>'); p1++; p2[0] = 0; p2++; CalculatorFkt[CalculatorFktAnz].Name = (char*) malloc(strlen(p1)+1); strcpy(CalculatorFkt[CalculatorFktAnz].Name, p1); // get number of paramters sscanf (p2, "%d", &CalculatorFkt[CalculatorFktAnz].Vars); // read in the paramter names for (i = 0; i < CalculatorFkt[CalculatorFktAnz].Vars; i++) { fgets(inpline, 256, config); p1 = strchr(inpline, '<'); p2 = strchr(inpline, '>'); p1++; p2[0] = 0; CalculatorFkt[CalculatorFktAnz].Var[i].Name = (char*) malloc(strlen(p1)+1); strcpy(CalculatorFkt[CalculatorFktAnz].Var[i].Name, p1); } ptr2 = NULL; // read in the function formula while (!fktready) { fgets(inpline, 256, config); i = strlen(inpline); // remove blanks at end of line while((i > 0) && (inpline[i] <= ' ')) {inpline[i] = 0; i--;} if (ptr2) { // append new text to previous ptr = (char*) realloc(ptr2, strlen(inpline)+strlen(ptr2)+1); strcat(ptr, inpline); } else { // begining of definition ptr = (char*) malloc(strlen(inpline)+1); strcpy(ptr, inpline); } // check for continuation line if (ptr[strlen(ptr)-1] == '\\') { // save current text for appening of continuation line ptr2 = ptr; ptr[strlen(ptr)-1] = 0; } else { // save function definition and signal successful // definition fktready = 1; CalculatorFkt[CalculatorFktAnz].Def = ptr; } } break; case 5: // read Result History if (CalculatorHistCnt < CALCULATOR_HISTORY) { sscanf(inpline, "%lf", &CalculatorHistory[CalculatorHistCnt]); CalculatorHistCnt++; } break; } } } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -