baadgeorge

Untitled

Dec 24th, 2020 (edited)
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 22.12 KB | None | 0 0
  1. #define _CRT_SECURE_NO_DEPRECATE
  2.  
  3. #include <locale.h>
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9.  
  10. #define SIZE 64
  11. #define EXP "2,7182818"
  12. #define PI  "3,1415926"
  13.  
  14. // определение структуры для переменных
  15. struct _var
  16. {
  17.     char* name; // имя переменной
  18.     double value; // значение переменной
  19. };
  20.  
  21. // определение имени var для типа _var
  22. typedef struct _var var;
  23.  
  24.  
  25. // определение структуры для стека
  26. struct _stack
  27. {
  28.     double* container; // массив значений
  29.     int size; // размер стека
  30. };
  31.  
  32. // определение имени stack для типа _stack
  33. typedef struct _stack stack;
  34.  
  35.  
  36. // функция выделения памяти под стек
  37. stack* stackInit();
  38.  
  39. // функция очистки стека
  40. void stackClear(stack** myStack);
  41.  
  42. //функция записи значения в стек
  43. int stackPush(double value, stack** myStack);
  44.  
  45. // функция вывода элемента из стека
  46. double stackPop(stack** myStack);
  47.  
  48. // функция создания новой переменной
  49. int createVariable(char* varName, var*** varList, int* varCount);
  50.  
  51. // функция очистки переменных
  52. void clearVariables(var*** varList, int* varCount);
  53.  
  54. // функция выполнения математических операций
  55. double operate(char operator, stack** myStack, int* errCode);
  56.  
  57. // функция проверки лексемы на принадлежность к операторам
  58. int isOperator(char* str);
  59.  
  60. // функция проверки является ли лексема числом
  61. int isNumber(char* str);
  62.  
  63. // функция проверки может ли лексема являться именем переменной
  64. int validVarName(char* str);
  65.  
  66. // функция возвращает результат вычислений в случае успеха или код ошибки в случае неудачи
  67. double calc(char* str, int* errCode, var*** varList, int* varCount);
  68.  
  69. // функция поиска в строке имен переменных
  70. int parsStr(char* str, var*** varList, int* varCount);
  71.  
  72. // функция вывода сообщения об ошибке
  73. void printError(int errCode);
  74.  
  75. char* readStr(int *checkError);
  76.  
  77. // функция выводит результат вычислений в случае успеха или текст сообщения об ошибке в случае неудачи
  78. void main()
  79. {
  80.     var** varList = NULL; // двойной указатель на массив переменных
  81.     int varCount = 0; // число уникальных переменных
  82.  
  83.     char* valueS = NULL; // указатель на буффер под значение переменной
  84.     int checkError = 0; // флаг ошибки
  85.     double result = 0; // результат вычислений
  86.     int i = 0; // индексная переменная
  87.  
  88.     char* str = NULL; // указатель на строку с выражением
  89.     char* copyStr = NULL; // указатель на копию строки с выражением
  90.  
  91.     setlocale(LC_ALL, "RUS");
  92.     printf("Введите выражение в обратной польской записи\n");
  93.     printf("ВВОД: ");
  94.  
  95.     str = readStr(&checkError); // считывание строки с выражением
  96.  
  97.     if(checkError == 0) // ошибок не найдено
  98.     {
  99.         copyStr = malloc(strlen(str) + 1); // выделение памяти под копию считанной строки
  100.  
  101.         if (copyStr == NULL) // память под копию строки не была выделена
  102.         {
  103.             checkError = -1;
  104.             printError(checkError); // вывод сообщения об ошибке
  105.             return;
  106.         }//if
  107.  
  108.         strcpy(copyStr, str); // копирование строки str в strcopy
  109.  
  110.         checkError = parsStr(copyStr, &varList, &varCount); // функция находит имена переменных в строке и возвращает флаг ошибки
  111.  
  112.         if (checkError == 0) // ошибок не найдено
  113.         {
  114.             // считывание значений переменных
  115.             for (i = 0; i < varCount; i++)
  116.             {
  117.                 printf("\nВЫВОД: Введите значение переменной %s\n", varList[i]->name);
  118.                 printf("ВВОД: ");
  119.                 valueS = malloc(SIZE); // выделение памяти под значение переменной
  120.  
  121.                 if (valueS == NULL) // проверка выделения памяти под значение переменной
  122.                 {
  123.                     checkError = -1;
  124.                     break;
  125.                 }//if
  126.                 valueS = readStr(&checkError); // считывание значения переменной
  127.  
  128.                 if (isNumber(valueS) == 1) // считанное значение является числом
  129.                 {
  130.                     varList[i]->value = atof(valueS); // запись соответствующего значения переменной в масссив переменных
  131.                 }//if
  132.                 else
  133.                 {
  134.                     checkError = 3; // в качестве значения переменной введено не число
  135.                     free(valueS); // очистка памяти для считывания значения переменной
  136.                     break;
  137.                 }//else
  138.                 free(valueS); // очистка памяти для считывания значения переменной
  139.             }//for
  140.  
  141.             if (checkError == 0) // ошибок не найдено
  142.             {
  143.                 result = calc(str, &checkError, &varList, &varCount); // присвоение результата вычислений
  144.  
  145.                 if (checkError == 0) // ошибок не выявлено
  146.                 {
  147.                     printf("\nРезультат: %lf\n\n", result);
  148.                 }//if
  149.             }//if
  150.         }//if
  151.     }// if
  152.  
  153.     printError(checkError); // вывод сообщения об ошибке
  154.     clearVariables(&varList, &varCount); // очистка известных переменных
  155.     if (copyStr != NULL) // если память под копию выделена
  156.     {
  157.         free(copyStr); // очистка памяти под копию считанной строки
  158.     }
  159.     system("pause");
  160.     return ;
  161. }//main
  162.  
  163. stack* stackInit()
  164. {
  165.     stack* newStack; // указатель на новый стек
  166.     newStack = malloc(sizeof(stack)); // выделение памяти под новый стек
  167.     if (newStack == NULL) // память под стек не была выделена
  168.     {
  169.         return newStack;
  170.     }//if
  171.     newStack->container = NULL; // инициализация массива стека
  172.     newStack->size = 0; // инициализация размера стека
  173.     return newStack;
  174. }//stackInits
  175.  
  176. void stackClear(stack** myStack)
  177. {
  178.     free((*myStack)->container); // очистка массива стека
  179.     free(*myStack); // удаление указателя на стек
  180.     return;
  181. }//stackClear
  182.  
  183. int stackPush(double value, stack** myStack)
  184. {
  185.     (*myStack)->size += 1; // увеличение размера стека на 1
  186.     (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // выделение памяти под новый элемент стека
  187.     if ((*myStack)->container == NULL) // память не была выделена
  188.     {
  189.         return -1;
  190.     }//if
  191.     else
  192.     {
  193.         (*myStack)->container[(*myStack)->size - 1] = value; // запись нового значения в стек
  194.         return 0;
  195.     }//else
  196. }//stackPush
  197.  
  198. double stackPop(stack** myStack)
  199. {
  200.     double res = 0;
  201.     res = (*myStack)->container[(*myStack)->size - 1]; // присвоение res последнего значения из стека
  202.     (*myStack)->size -= 1; // уменьшени размера стека на 1
  203.     (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // уменьшение выделенной памяти под стек
  204.     return res;
  205. }//stackPop
  206.  
  207. int createVariable(char* varName, var*** varList, int* varCount)
  208. {
  209.     var* newVar = NULL; // указатель на новую переменную
  210.  
  211.     *varList = realloc(*varList, (*varCount + 1) * sizeof(var*)); // выделение дополнительной памяти в массиве переменных под новую переменную
  212.     if (*varList == NULL) // дополнительная память не была выделена
  213.     {
  214.         return -1;
  215.     }//if
  216.  
  217.     newVar = malloc(sizeof(var)); // выделение памяти под новую переменную
  218.     if (newVar == NULL) // дополнительная память не была выделена
  219.     {
  220.         return -1;
  221.     }//if
  222.  
  223.     newVar->name = malloc((strlen(varName) + 1) * sizeof(char)); // выделение памяти под имя новой переменной
  224.     if (newVar->name == NULL) // память под имя новой переменной не была выделена
  225.     {
  226.         free(newVar); // очистка памяти под новую переменную
  227.         return -1;
  228.     }//if
  229.  
  230.     memset(newVar->name, '\0', (strlen(varName) + 1)); // можно использовать strcat, strncat
  231.     memcpy(newVar->name, varName, strlen(varName)); // копирование имени новой переменной в структуру
  232.     newVar->value = 0.0; // задание начального значения новой переменной
  233.  
  234.     (*varList)[*varCount] = newVar; // запись новой переменной в массив переменных
  235.  
  236.     (*varCount)++; // увеличение счетчика количества переменных на 1
  237.     return 0;
  238. }//createVariable
  239.  
  240. void clearVariables(var ***varList, int *varCount)
  241. {
  242.     int i; // индексная переменная
  243.  
  244.     for (i = 0; i < *varCount; i++)
  245.     {
  246.         free((*varList)[i]->name); // очистка памяти под имя переменной
  247.         free((*varList)[i]); // очистка памяти под значение  переменной
  248.     }//for
  249.  
  250.     varCount = 0; // обнуление счетчика количества переменных
  251.     return;
  252. }//clearVariables
  253.  
  254. double operate(char operator, stack** myStack, int* errCode)
  255. {
  256.     double op2 = stackPop(myStack);
  257.     double op1 = stackPop(myStack);
  258.    
  259.     switch (operator)
  260.     {
  261.     case '+':
  262.         return op1 + op2;
  263.     case '-':
  264.         return op1 - op2;
  265.     case '*':
  266.         return op1 * op2;
  267.     case '/':
  268.         if (op2 == 0) // деление на 0
  269.         {
  270.             *errCode = 2;
  271.             return;
  272.         }//if
  273.         else return op1 / op2;
  274.     case '^':
  275.         if (op1 == 0 && op2 < 0) // деление на 0
  276.         {
  277.             *errCode = 2;
  278.             return;
  279.         }//if
  280.         else return pow(op1, op2);
  281.     }//switch
  282. }//operate
  283.  
  284. int isOperator(char* str)
  285. {
  286.     // в лексеме найден символ принадлежащий к списку операторов и длина лексемы 1
  287.     return (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1) ? 1 : 0;
  288. }//isOperator
  289.  
  290. int isNumber(char* str)
  291. {
  292.     int i; // индексная переменная
  293.     int foundPoint = 0; // флаг найден ли символ разделитель в вещественном числе
  294.  
  295.     // проходим по всем символам лексемы
  296.     for (i = 0; i < strlen(str); i++)
  297.     {
  298.         if (isdigit(str[i]) == 0) // текущий символ не число
  299.         {
  300.             if (str[i] == '-' && i == 0 && strlen(str) != 1)
  301.             {
  302.                 continue;
  303.             }//if
  304.             else
  305.             {
  306.                 if (str[i] == ',') // текущий символ - разделитель в вещественном числе
  307.                 {
  308.                     if (foundPoint == 0) // символ разделитель ранее не встречен
  309.                     {
  310.                         foundPoint = 1; // флаг - символ разделитель найден
  311.                     }//if
  312.                     else
  313.                     {
  314.                         return 0;
  315.                     }//else
  316.                 }//if
  317.                 else
  318.                 {
  319.                     return 0;
  320.                 }//else
  321.             }//else
  322.            
  323.         }//if
  324.     }//for
  325.     return 1;
  326. }// isNumber
  327.  
  328. int validVarName(char* str)
  329. {
  330.     int i; // индексная переменная
  331.  
  332.     if (isalpha(str[0]) == 0) // первый символ - не буква
  333.     {
  334.         return 0;
  335.     }//if
  336.  
  337.     // проходим по всем элементам лексемы
  338.     for (i = 1; i < strlen(str); i++)
  339.     {
  340.         if (isalnum(str[i]) == 0) // текущий символ - не буква и не число
  341.         {
  342.             return 0;
  343.         }//if
  344.     }//for
  345.  
  346.     return 1;
  347. }//validVarName
  348.  
  349. double calc(char* str, int* errCode, var ***varList, int *varCount)
  350. {
  351.     double res = 0.0; // результат вычислений
  352.     char* tmp = NULL; // указатель на лексему
  353.     int i; // индексная переменная
  354.     stack* myStack = stackInit(); // создание стека
  355.  
  356.     if (myStack == NULL) // память под стек не была выделена
  357.     {
  358.         *errCode = -1;
  359.         return res;
  360.     }//if
  361.  
  362.     tmp = strtok(str, "\t "); // считывание лексемы
  363.  
  364.     while (tmp != NULL) // найдена лексема
  365.     {
  366.         if (strcmp(tmp, "EXP") == 0) tmp = EXP;
  367.         if (strcmp(tmp, "PI") == 0) tmp = PI;
  368.  
  369.         if (isNumber(tmp) == 1) // лексема - число
  370.         {
  371.             stackPush(atof(tmp), &myStack); // запись числа в стек
  372.         }//if
  373.         else if (isOperator(tmp) == 1) // лексема - оператор
  374.         {
  375.             if (myStack->size >= 2) // в стеке 2 числа или более
  376.             {
  377.                 stackPush(operate(*tmp, &myStack, errCode), &myStack); // в стек результата операции
  378.             }//if
  379.             else
  380.             {
  381.                 stackClear(&myStack); // очистка стека
  382.                 *errCode = 1;
  383.                 return res;
  384.             }//else
  385.         }//else if
  386.         else // встречена переменная
  387.         {
  388.             for (i = 0; i < *varCount; i++)
  389.             {
  390.                 // имя переменной в массиве переменных найдено
  391.                 if (strcmp(tmp, (*varList)[i]->name) == 0)
  392.                 {
  393.                     stackPush((*varList)[i]->value, &myStack); // запись значения переменной в стек
  394.                 }//if
  395.             }//for
  396.         }//else
  397.         tmp = strtok(NULL, "\t "); // переход к следующей лексеме
  398.     }//while
  399.     res = stackPop(&myStack);
  400.     stackClear(&myStack);
  401.     return res;
  402. }//calc
  403.  
  404. int parsStr(char* str, var*** varList, int* varCount )
  405. {
  406.     int operandCount = 0; // число операндов
  407.     int operateCount = 0; // число операторов
  408.     char* tmp = NULL; // указатель на лексему
  409.     int i; // индексная переменная
  410.     int indicator = 0; // код завершения функции
  411.     int knownVariable = 0; // флаг уникальности переменной
  412.  
  413.     tmp = strtok(str, "\t "); // считывание лексемы
  414.  
  415.     while (tmp != NULL)
  416.     {
  417.         knownVariable = 0;
  418.         if (strcmp(tmp, "EXP") == 0) // лексема - экспонента
  419.         {
  420.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  421.             operandCount++; // увеличение на 1 счетчика числа операндов
  422.             continue;
  423.         }//if
  424.  
  425.         if (strcmp(tmp, "PI") == 0) // лексема - число Пи
  426.         {
  427.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  428.             operandCount++; // увеличение на 1 счетчика числа операндов
  429.             continue;
  430.         }//if
  431.  
  432.         if (isOperator(tmp) == 1) // лексема - оператор
  433.         {
  434.             operateCount++; // увеличение на 1 счетчика числа операторов
  435.         }//if
  436.         else  if (isNumber(tmp) == 1) // лексема - число
  437.         {
  438.             operandCount++; // увеличение на 1 счетчика числа операндов
  439.  
  440.         }//else if
  441.         else if (validVarName(tmp) == 1) // может ли лексема являться именем переменной
  442.         {
  443.             operandCount++;  // увеличение на 1 счетчика числа операндов
  444.             // проверка имени переменной на уникальность
  445.             for (i = 0; i < *varCount; i++)
  446.             {
  447.                 if (strcmp(tmp, (*varList)[i]->name) == 0) // переменная не уникальна
  448.                 {
  449.                     knownVariable = 1;
  450.                     break;
  451.                 }//if
  452.             }//for
  453.  
  454.             if (knownVariable == 1)
  455.             {
  456.                 tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  457.                 continue;
  458.             }//if
  459.             else indicator = createVariable(tmp, varList, varCount); // флаг создалась ли переменная: 0 - да, -1 - нет
  460.            
  461.         }//else if
  462.         else
  463.         {
  464.             indicator = -2; // флаг -2, встречена неизвестная лексема
  465.             return indicator;
  466.         }//else
  467.  
  468.         tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  469.     }//while
  470.  
  471.     if (operateCount != operandCount - 1) // недостаточное число операторов или операндов
  472.     {
  473.         indicator = -3;
  474.     }//if
  475.     return indicator;
  476. }//parsStr
  477.  
  478. void printError(int errCode)
  479. {
  480.     switch (errCode)
  481.     {
  482.     case 0:
  483.         return;
  484.     case -1:
  485.         printf("\nОшибка! Невозможно выделить память\n\n");
  486.         return;
  487.     case -2:
  488.         printf("\nОшибка! Встречена неизвестная лексема\n\n");
  489.         return;
  490.     case -3:
  491.         printf("\nОшибка! Недостаточно операторов или операндов\n\n");
  492.         return;
  493.     case 1:
  494.         printf("\nОшибка! Встречен оператор, а количество операндов в стеке меньше двух\n\n");
  495.         return;
  496.     case 2:
  497.         printf("\nОшибка! Деление на 0\n\n");
  498.         return;
  499.     case 3:
  500.         printf("\nОшибка! Недопустимое значение переменной\n\n");
  501.         return;
  502.     case 4:
  503.         printf("\nОшибка! Неудачная попытка чтения строки\n\n");
  504.         return;
  505.     default:
  506.         printf("\nНеизвестный код ошибки.\n\n");
  507.         return;
  508.     }//switch
  509. }//printError
  510.  
  511. char* readStr(int* errCode)
  512. {
  513.     char* pos = NULL; // указатель на элемент в строке
  514.     int i = 1; // индексная переменная
  515.     char tmp[SIZE]; // буфер под считываемую строку на SIZE символов
  516.     char* check;
  517.  
  518.     char* s = malloc(SIZE); // выделение памяти строку
  519.  
  520.     if (s == NULL) // проверка выделения памяти
  521.     {
  522.         *errCode = -1;
  523.     }//if
  524.  
  525.     check = fgets(s, SIZE, stdin); // считывание из консоли строки размера SIZE в s
  526.     if (check == NULL)
  527.     {
  528.         *errCode = 4;
  529.     }//if
  530.  
  531.     if ((pos = strrchr(s, '\n')) != NULL) // в s найден символ перехода на новую строку
  532.     {
  533.         *pos = 0;
  534.         return s;
  535.     }//if
  536.  
  537.     while (1)
  538.     {
  539.         i++;
  540.         check = fgets(tmp, SIZE, stdin); //  // считывание из консоли части строки размера SIZE в tmp
  541.  
  542.         if (check == NULL)
  543.         {
  544.             *errCode = 4;
  545.         }//if
  546.  
  547.         if ((pos = strrchr(tmp, '\n')) != NULL) // в tmp найден символ перехода на новую строку (конец всей строки)
  548.         {
  549.             *pos = 0; // удаление символа перехода на новую строку
  550.             s = realloc(s, SIZE * i); // выделение дополнительной памяти в s
  551.             if (s == NULL) // проверка выделения памяти
  552.             {
  553.                 *errCode = -1;
  554.             }//if
  555.             strcat(s, tmp); // склеивание начала строки и ее конца
  556.             break;
  557.         }//if
  558.         else
  559.         {
  560.             s = realloc(s, SIZE * i); // выделение дополнительной памяти в s
  561.             if (s == NULL) // проверка выделения памяти
  562.             {
  563.                 *errCode = -1;
  564.             }//if
  565.             strcat(s, tmp); // склеивание начала строки и ее продолжения
  566.         }//else
  567.  
  568.     }//while
  569.    
  570.     return s;
  571. }
Add Comment
Please, Sign In to add comment