Advertisement
Guest User

Simple Calculator

a guest
Dec 5th, 2011
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.52 KB | None | 0 0
  1. #include <StdAfx.h>
  2. #include <fstream>
  3. #include <iostream>
  4. #include <string>
  5. #include <stack>
  6. #include <queue>
  7. using namespace std;
  8.  
  9.  
  10. /* - Получаване на ОПЗ ------------------
  11.  
  12. Докато има символи в израза:
  13.     Прочитаме един символ.
  14.         Ако символът е операнд (число) го добавяме в изходния запис.
  15.         Ако символът е оператор, примерно оп1:
  16.             Докато има оператор, оп2, на върха на стека, и той е с по-голям
  17.             или равен приоритет от оп1:
  18.                 Измъкваме оп2 от стека и го поставяме в изходния запис.
  19.             Поставяме оп1 в стека.
  20.         Ако символът е отваряща скоба я поставяме в стека.
  21.         Ако символът е затваряща скоба:
  22.             Докато символът на върха на стека не стане отваряща скоба, измъкваме
  23.                 оператори от стека и ги поставяме в изходния запис.
  24.             Премахваме отварящата скоба от стека, без да я поставяме
  25.                 в изходния запис.
  26.             Ако стекът се изпразни без да е намерена отваряща скоба в него,
  27.                 значи има несъответствие на скобите в израза.
  28. Когато символите от входния израз свършат:
  29.     Докато има символи в стека, измъкваме един:
  30.         Ако символът на върха на стека е скоба (отваряща) значи има несъответствие
  31.             на скобите в израза.
  32.         Измъкваме оператор от стека и го поставяме в изходния запис.
  33. Край.  */
  34.  
  35.  
  36. /* --- пресмятане на ОПЗ ---
  37.  
  38. Докато има символи в ОПЗ
  39.     Прочитаме един символ
  40.     Ако е операнд:
  41.         Поставяме го в стека
  42.     Иначе е оператор:
  43.         Ако на върха на стека има по-малко от 2 операнда
  44.             Грешка: Некоректни входни данни
  45.         Иначе:
  46.             Изваждаме 2 операнда от стека
  47.             Прилагаме оператора върху тях. Първият изваден операнд е
  48.                 втори аргумент, а вторият - първи
  49.             Поставяме получената стойност в стека
  50. Ако във стека има само един елемент:
  51.     Това е резултатът
  52. Иначе:
  53.     Грешка: Некоректни входни данни
  54. Край.
  55.  
  56. */
  57.  
  58. struct token
  59. {
  60.     char op;
  61.     int priority;
  62. } tokens[6];
  63.  
  64.  
  65. // помощен клас при изработката на ОПЗ
  66.  
  67. class rpnelem {
  68.  
  69.     public:
  70.  
  71.     // едновременно value и op не могат да се укажат, единия от двата се сетва
  72.     // и инстанцията съдържа или стойност или оператор
  73.        
  74.     float value;
  75.     char op;
  76.    
  77.     // флаг - дали е число
  78.    
  79.     bool number;
  80.    
  81.     // конструктор с оператор
  82.    
  83.     rpnelem(char newoper) {
  84.         number = false;
  85.         op = newoper;
  86.         value = 0;
  87.     }
  88.    
  89.     // конструктор по стойност
  90.    
  91.     rpnelem(float newval) {
  92.         value = newval;
  93.         op = 0;
  94.         number = true;
  95.     }
  96.    
  97.     bool isoper() {
  98.         if (number)
  99.             return false;
  100.         else
  101.             return (op == ')' || op == '(') ? false : true;
  102.     }
  103.    
  104.     bool isnumber() {
  105.         return (number);
  106.     }
  107. };
  108.  
  109. void inittokens()
  110. {
  111.     tokens[0].op='+';
  112.     tokens[0].priority=1;
  113.     tokens[1].op='-';
  114.     tokens[1].priority=1;
  115.     tokens[2].op='*';
  116.     tokens[2].priority=5;
  117.     tokens[3].op='/';
  118.     tokens[3].priority=5;
  119.     tokens[4].op='(';
  120.     tokens[4].priority=10;
  121.     tokens[5].op=')';
  122.     tokens[5].priority=10;
  123. }
  124.  
  125. // проверява дали символът е оператор
  126. // като скобите не са оператор
  127.  
  128. bool isoper(char ch)
  129. {
  130.     if(ch != '(' && ch !=')' )
  131.     {
  132.         for(int i=0;i<6;i++)
  133.         {
  134.             if(ch==tokens[i].op)
  135.                 return true;
  136.         }
  137.     }
  138.     return false;
  139. }
  140.  
  141.  
  142. // проверява дали оператор a е с по-висок приоритет от оператор b
  143.  
  144. bool isgreater(char a, char b)
  145. {
  146.     char p1,p2;
  147.  
  148.     for(int i=0;i<6;i++)
  149.     {
  150.      if(a==tokens[i].op)
  151.          p1=tokens[i].priority;
  152.      if(b==tokens[i].op)
  153.          p2=tokens[i].priority;
  154.     }
  155.      
  156.     return p1>p2;
  157. }
  158.  
  159. // създава ОПЗ по алгоритъма описан по-горе
  160. // по подаден входящ параметър символен низ
  161.  
  162. queue <rpnelem>& convert(string& expr)
  163. {
  164.     // помощен стек за създаване на опЗ
  165.     stack <rpnelem> s;
  166.    
  167.     // резутатът се записва в тази структура опашка
  168.     // като елементи от резултата могат да са както числа
  169.     // така и оператори. ползва се помощен клас rpnelem
  170.     // който позволява запазването с една операция и на двете
  171.    
  172.     queue <rpnelem> &result = *(new queue <rpnelem>);
  173.    
  174.     for (int i=0; i < expr.length(); i++)
  175.     {
  176.      //   Ако символът от входния поток
  177.      //   е операнд (число) го добавяме в изходния запис.
  178.      if(expr[i] >= '0' && expr[i] <= '9') {
  179.         result.push(rpnelem((float)(expr[i]-'0')));
  180.         // проверяваме дали няма още цифри числото
  181.         while(i + 1 < expr.length() && expr[i+1] >= '0' && expr[i+1] <= '9' )
  182.              result.back().value = result.back().value * 10 + (expr[++i] - '0');
  183.      
  184.      }
  185.      //  Ако поредния символ от входния поток
  186.      //  е оператор, (да приемем, че това е ОП1:
  187.      else if(isoper(expr[i]))
  188.      {
  189.          // Докато има оператор (isoper?), ОП2, на върха на стека (s.top()),
  190.          // и той е с по-голям или равен приоритет от ОП1 (isgreater?):
  191.          while(!s.empty() && s.top().isoper() && isgreater(s.top().op, expr[i]))
  192.          {
  193.              //  Измъкваме оп2 от стека и го поставяме в изходния запис.
  194.              //  (заб, тук и result и s работят с елементи от тип <rpnelem>
  195.              //  за това може директно да ги предадем от единия на другия
  196.              
  197.              result.push(rpnelem(s.top()));
  198.              
  199.              //  вадим елемента от върха на стека, тъй като той вече е записан
  200.              //  в изходната опашка
  201.              s.pop();
  202.          }
  203.  
  204.          // Поставяме ОП1 в стека.
  205.          s.push(rpnelem(expr[i]));
  206.      }
  207.  
  208.      // Ако символът е отваряща скоба я поставяме в стека.
  209.      else if(expr[i]=='(')
  210.          s.push(rpnelem('('));
  211.  
  212.      // Ако символът е затваряща скоба:
  213.      else if(expr[i]==')')
  214.      {
  215.          // Докато символът на върха на стека не стане отваряща скоба,
  216.          while(s.top().op != '(' && !(s.empty()))
  217.          {
  218.              // измъкваме елементи от стека и ги поставяме в изходния запис.
  219.              // това могат да са както числа, така и оператори
  220.              
  221.              result.push(s.top());
  222.              s.pop();
  223.          }
  224.          //   Ако стекът се изпразни без да е намерена отваряща скоба,
  225.          // значи има несъответствие на скобите в израза.
  226.          //    заб : в случая ще гръмне с exception
  227.          if (!s.size()) {
  228.              throw logic_error("stack went empty, while no matching bracket was found");
  229.          
  230.          }
  231.  
  232.          // Премахваме отварящата скоба от стека, без да я поставяме в изходния
  233.          s.pop();
  234.      }
  235.  
  236.      // преминаваме към следващия символ
  237.     }
  238.  
  239.     // Когато символите от входния израз свършат:
  240.  
  241.     // Докато има символи в стека
  242.  
  243.     while(!s.empty())
  244.     {
  245.      // ... Измъкваме оператор от стека и го поставяме в изходния запис.  
  246.      result.push(s.top());
  247.  
  248.      //    заб: не е реализирана следната проверка:
  249.      // Ако символът на върха на стека е скоба (отваряща) значи има несъответствие
  250.         //  на скобите в израза.
  251.  
  252.      s.pop();
  253.     }
  254.     return result;
  255. }
  256.  
  257. float calculate(queue <rpnelem>& rpnexpr ) {
  258.  
  259.     stack <rpnelem> s;
  260.    
  261.     // Докато има символи в ОПЗ
  262.  
  263.     while (rpnexpr.size()) {
  264.     //    Прочитаме един символ
  265.     //    Ако е операнд:  Поставяме го в стека
  266.         if (rpnexpr.front().isnumber()) {
  267.             s.push(rpnexpr.front());
  268.         } else {
  269. //    Иначе е оператор:
  270. //        Ако на върха на стека има по-малко от 2 операнда
  271. //            Грешка: Некоректни входни данни
  272.             if (s.size() < 2) {
  273.                 throw logic_error("operands count does not match");
  274.             }
  275.     //        
  276.     //       Иначе:
  277.     //            Изваждаме 2 операнда от стека
  278.     //            Прилагаме оператора върху тях. Първият изваден операнд е
  279.     //            втори аргумент, а вторият - първи
  280.     //                    Поставяме получената стойност в стека
  281.    
  282.             float arg2 = s.top().value;    s.pop();
  283.             float arg1 = s.top().value;    s.pop();
  284.             switch(rpnexpr.front().op) {
  285.                 case '-':
  286.                     s.push(rpnelem(arg2 - arg1));
  287.                     break;
  288.                    
  289.                 case '*':
  290.                     s.push(rpnelem(arg2 * arg1));
  291.                     break;
  292.    
  293.                 case '/':
  294.                     s.push(rpnelem(arg2 / arg1));
  295.                     break;
  296.    
  297.                 case '+':
  298.                     s.push(rpnelem(arg2 + arg1));
  299.                     break;
  300.                    
  301.                 default:
  302.            
  303.                     throw logic_error("unknown operator");
  304.             }        
  305.         }
  306.        
  307.         rpnexpr.pop();
  308.     }
  309.    
  310.     if (s.size() == 1)
  311.         return s.top().value;
  312.     else
  313.         throw logic_error("bad stack count");
  314.     //    Ако във стека има само един елемент:
  315.     //    Това е резултатът
  316.     // Иначе:
  317.     //     Грешка: Некоректни входни данни
  318.     //     Край.
  319. }
  320.  
  321. int main(int argc, char* argv[])
  322. {
  323.     inittokens();
  324.     string line;
  325.     ifstream file;
  326.     file.open("c:\\temp\\INPUT.TXT");
  327.  
  328.     if (file.is_open())
  329.      {
  330.          while (!file.eof())
  331.              {
  332.                  getline(file, line);
  333.                  queue <rpnelem> rpnexpr = convert(line);
  334.                  float result = calculate (rpnexpr);
  335.                  cout << line << " = " << result << endl;
  336.              }
  337.          file.close();
  338.      }
  339.  
  340.     else
  341.         throw logic_error("could not open input file");
  342.  
  343.     system("PAUSE");
  344.     return 0;
  345. }
  346.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement