Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* calc.cpp - simple weighted calculator
- * Copyright (C) 2010 ed <irc.rizon.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, please refer to the following URL:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- */
- /* CHANGELOG:
- * 2010.08.21 11:40 - 2010.08.21 12:18 - parser completed
- * 2010.08.21 12:18 - 2010.08.21 13:37 - calculation completed
- * 2010.08.22 15:56 - 2010.08.22 16:02 - handle division by zero
- * 2010.08.23 06:53 - 2010.08.23 06:55 - minor cleanup
- * 2010.08.26 09:54 - 2010.08.26 09:57 - expression from arguments
- */
- /* USER'S MANUAL
- *
- * Compile and run program
- * Type in numbers and operators
- * - spaces are optional
- * Hit enter
- * Profit
- */
- /* ed@neetbook:~$ nano calc.cpp; g++ -Wall -o calc calc.cpp && ./calc
- * expr> 17.68 + 32.14 * 8.1284 / -5.17 * 4.825 - 192.326
- *
- * Parser output:
- * 17.68 + 32.14 * 8.13 / -5.17 * 4.82 - 192.33
- *
- * Calculation output:
- * 8.13 / -5.17 = -1.57
- * 32.14 * -1.57 = -50.53
- * -50.53 * 4.82 = -243.81
- * -243.81 - 192.33 = -436.14
- * 17.68 + -436.14 = -418.46
- *
- * Final answer: -418.459481
- */
- #include <cstdlib>
- #include <stdio.h>
- #include <math.h>
- const int OPC = 6;
- const int MAX = 9000;
- const char opc[OPC+1] = {
- ' ', '^', '%',
- '/', '*',
- '-', '+' };
- // The basic idea:
- // 1+2-3*4/5 - expression
- // 0 + - * / ND - opc
- // 0 1 2 3 4 -1 - o
- // 1 2 3 4 5 ND - v
- // ND = not defined
- // In-depth on opc:
- // opc[1..6] operators
- // opc[ 0] no-op (calculated)
- // opc[ -1] EOF
- void dump(int max, int *o, double *v) {
- for (int i=0; i<max; i++) {
- if (o[i]<0) fprintf(stderr, "\nSEMANTICAL ERROR\n");
- printf("%c %1.2f ", opc[o[i]], v[i]);
- }
- putc('\n',stdout);
- }
- bool compute(int max, int *o, double *v, int op, bool verbose) {
- int i=0, j=0;
- // Scan for the operator we're looking for
- for (i=0; i<max; i++) {
- // Is this it?
- if (o[i]==op) {
- // Yup. Look for closest uncomputed number...
- for (j=i-1; j>=0; j--) {
- // Does this number have an operator?
- if (o[j]>0) break;
- // ...if so, we have the correct value of j.
- }
- // Default back to root if no other options
- if (j<0) j=0;
- // NOTE: at this point, opc[o[i]]==opc[op]
- if (verbose) printf(
- " %12.2f %c %12.2f = ",
- v[j], opc[op], v[i]);
- // Check for division by zero
- if (v[i] == 0 && (
- opc[op]=='/' ||
- opc[op]=='%'))
- return false;
- // Do the actual calculation
- if (opc[op]=='+') v[j] += v[i];
- else if (opc[op]=='-') v[j] -= v[i];
- else if (opc[op]=='*') v[j] *= v[i];
- else if (opc[op]=='/') v[j] /= v[i];
- else if (opc[op]=='^') pow(v[j], v[i]);
- else if (opc[op]=='%') v[j] = (int)v[j] % (int)v[i];
- o[i] = 0; //nothing to see here
- if (verbose) printf("%12.2f\n", v[j]);
- }
- }
- return true;
- }
- int main(int argc, char **argv) {
- char *arg = (char *)"\0";
- if (argc>1) arg = argv[1];
- // Verbose? Default yes; "n" disables
- bool verbose = !(arg[0]=='n');
- if (!verbose) arg++;
- // Expression from argument?
- bool farg = arg[0]!='\0';
- // Expression management
- int max; //itemcount
- int o[MAX]; //operator
- double v[MAX]; //value
- max = -1;
- // Vars for STDIN parsing
- int i,j; //indice/offset
- char c; //stdin buffer
- int frac; //fraction
- bool neg; //v*=-1
- i=j=c=frac=0; //clear
- neg=false;
- if(verbose) printf("expr> ");
- while (i<MAX && max<0) {
- if (farg) {c=arg[0];arg++;}
- else scanf("%c",&c);
- // Parse digits
- if (c >= '0' &&
- c <= '9') {
- c -= '0';
- // Integer
- if (frac<1) {
- v[i] *= 10;
- v[i] += c;
- // Floating point
- } else {
- frac *= 10;
- v[i] += c/1.0/frac;
- }
- // Set floating point
- } else if (c=='.' || c==',') {
- frac = 1;
- // End of input
- } else if (c=='\n' || c=='\0') {
- i++; //1-based
- max = i; //setmax
- o[i] =-1; //eof
- // Operator?
- } else if (c!=' '){
- // Check if it's a value negation
- if (c=='-' && v[i]==0) {
- neg = true;
- } else {
- if(neg) v[i]*=-1;
- neg=false;
- frac=0;
- i++;
- // Scan for operator
- for (j=1; j<=OPC; j++) {
- if (c==opc[j]) o[i]=j;
- }
- // Invalid input
- if (o[i]<1) {
- fprintf(stderr, "\nPARSER ERROR\n");
- return 1;
- }
- }
- }
- }
- if (verbose) {
- printf("\nParser output:\n");
- dump(max,o,v);
- printf("\nCalculation output:\n");
- }
- // Do calculations in decreasing weight
- for (i=1; i<=OPC; i++) {
- if (!compute(max,o,v,i,verbose)) {
- fflush(stdout);
- fprintf(stderr, "\nILLEGAL ARITHMETIC OPERATION\n");
- return 1;
- }
- }
- if (!verbose) printf("%f\n", v[0]);
- else printf("\nFinal answer: %f\n", v[0]);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment