Advertisement
baadgeorge

Untitled

Dec 25th, 2020
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 22.42 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. int parsStr(char* str, var*** varList, int* varCount);
  68.  
  69. // функция возвращает результат вычислений в случае успеха или код ошибки в случае неудачи
  70. double calc(char* str, int* errCode, 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 = NULL; // указатель на новый стек
  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)); // выделение памяти под имя новой переменной
  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)); // копирование имени новой переменной в массив name
  232.     newVar->name[strlen(varName)] = '\0';
  233.     newVar->value = 0.0; // задание начального значения новой переменной
  234.  
  235.     (*varList)[*varCount] = newVar; // запись новой переменной в массив переменных
  236.  
  237.     (*varCount)++; // увеличение счетчика количества переменных на 1
  238.     return 0;
  239. }//createVariable
  240.  
  241. void clearVariables(var ***varList, int *varCount)
  242. {
  243.     int i; // индексная переменная
  244.  
  245.     for (i = 0; i < *varCount; i++)
  246.     {
  247.         free((*varList)[i]->name); // очистка памяти под имя переменной
  248.         free((*varList)[i]); // очистка памяти под значение  переменной
  249.     }//for
  250.  
  251.     varCount = 0; // обнуление счетчика количества переменных
  252.     return;
  253. }//clearVariables
  254.  
  255. double operate(char operator, stack** myStack, int* errCode)
  256. {
  257.     double op2 = stackPop(myStack);
  258.     double op1 = stackPop(myStack);
  259.    
  260.     switch (operator)
  261.     {
  262.     case '+':
  263.         return op1 + op2;
  264.     case '-':
  265.         return op1 - op2;
  266.     case '*':
  267.         return op1 * op2;
  268.     case '/':
  269.         if (op2 == 0) // деление на 0
  270.         {
  271.             *errCode = 2;
  272.             return;
  273.         }//if
  274.         else return op1 / op2;
  275.     case '^':
  276.         if (op1 == 0 && op2 < 0) // деление на 0
  277.         {
  278.             *errCode = 2;
  279.             return;
  280.         }//if
  281.         else return pow(op1, op2);
  282.     }//switch
  283. }//operate
  284.  
  285. int isOperator(char* str)
  286. {
  287.     // в лексеме найден символ принадлежащий к списку операторов и длина лексемы 1
  288.     return (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1) ? 1 : 0;
  289. }//isOperator
  290.  
  291. int isNumber(char* str)
  292. {
  293.     int i; // индексная переменная
  294.     int foundPoint = 0; // флаг найден ли символ разделитель в вещественном числе
  295.  
  296.     // проходим по всем символам лексемы
  297.     for (i = 0; i < strlen(str); i++)
  298.     {
  299.         if (isdigit(str[i]) == 0) // текущий символ не число
  300.         {
  301.             if (str[i] == '-' && i == 0 && strlen(str) != 1)
  302.             {
  303.                 continue;
  304.             }//if
  305.             else
  306.             {
  307.                 if (str[i] == ',') // текущий символ - разделитель в вещественном числе
  308.                 {
  309.                     if (foundPoint == 0) // символ разделитель ранее не встречен
  310.                     {
  311.                         foundPoint = 1; // флаг - символ разделитель найден
  312.                     }//if
  313.                     else
  314.                     {
  315.                         return 0;
  316.                     }//else
  317.                 }//if
  318.                 else
  319.                 {
  320.                     return 0;
  321.                 }//else
  322.             }//else
  323.            
  324.         }//if
  325.     }//for
  326.     return 1;
  327. }// isNumber
  328.  
  329. int validVarName(char* str)
  330. {
  331.     int i; // индексная переменная
  332.  
  333.     if (isalpha(str[0]) == 0) // первый символ - не буква
  334.     {
  335.         return 0;
  336.     }//if
  337.  
  338.     // проходим по всем элементам лексемы
  339.     for (i = 1; i < strlen(str); i++)
  340.     {
  341.         if (isalnum(str[i]) == 0) // текущий символ - не буква и не число
  342.         {
  343.             return 0;
  344.         }//if
  345.     }//for
  346.  
  347.     return 1;
  348. }//validVarName
  349.  
  350. double calc(char* str, int* errCode, var ***varList, int *varCount)
  351. {
  352.     int i; // индексная переменная
  353.     double res = 0.0; // результат вычислений
  354.     char* tmp = NULL; // указатель на лексему
  355.     stack* myStack = stackInit(); // создание стека
  356.  
  357.     if (myStack == NULL) // память под стек не была выделена
  358.     {
  359.         *errCode = -1;
  360.         return res;
  361.     }//if
  362.  
  363.     tmp = strtok(str, "\t "); // считывание лексемы
  364.  
  365.     while (tmp != NULL) // найдена лексема
  366.     {
  367.         if (strcmp(tmp, "EXP") == 0) tmp = EXP;
  368.         if (strcmp(tmp, "PI") == 0) tmp = PI;
  369.  
  370.         if (isNumber(tmp) == 1) // лексема - число
  371.         {
  372.             stackPush(atof(tmp), &myStack); // запись числа в стек
  373.         }//if
  374.         else if (isOperator(tmp) == 1) // лексема - оператор
  375.         {
  376.             if (myStack->size >= 2) // в стеке 2 числа или более
  377.             {
  378.                 stackPush(operate(*tmp, &myStack, errCode), &myStack); // в стек результата операции
  379.             }//if
  380.             else
  381.             {
  382.                 stackClear(&myStack); // очистка стека
  383.                 *errCode = 1;
  384.                 return res;
  385.             }//else
  386.         }//else if
  387.         else // встречена переменная
  388.         {
  389.             for (i = 0; i < *varCount; i++)
  390.             {
  391.                 // имя переменной в массиве переменных найдено
  392.                 if (strcmp(tmp, (*varList)[i]->name) == 0)
  393.                 {
  394.                     stackPush((*varList)[i]->value, &myStack); // запись значения переменной в стек
  395.                 }//if
  396.             }//for
  397.         }//else
  398.         tmp = strtok(NULL, "\t "); // переход к следующей лексеме
  399.     }//while
  400.     res = stackPop(&myStack);
  401.     stackClear(&myStack);
  402.     return res;
  403. }//calc
  404.  
  405. int parsStr(char* str, var*** varList, int* varCount )
  406. {
  407.     int operandCount = 0; // число операндов
  408.     int operateCount = 0; // число операторов
  409.     int i = 0; // индексная переменная
  410.     int indicator = 0; // код завершения функции
  411.     int knownVariable = 0; // флаг уникальности переменной
  412.     char* tmp = NULL; // указатель на лексему
  413.  
  414.     tmp = strtok(str, "\t "); // считывание лексемы
  415.  
  416.     while (tmp != NULL)
  417.     {
  418.         knownVariable = 0;
  419.         if (strcmp(tmp, "EXP") == 0) // лексема - экспонента
  420.         {
  421.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  422.             operandCount++; // увеличение на 1 счетчика числа операндов
  423.             continue;
  424.         }//if
  425.  
  426.         if (strcmp(tmp, "PI") == 0) // лексема - число Пи
  427.         {
  428.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  429.             operandCount++; // увеличение на 1 счетчика числа операндов
  430.             continue;
  431.         }//if
  432.  
  433.         if (isOperator(tmp) == 1) // лексема - оператор
  434.         {
  435.             operateCount++; // увеличение на 1 счетчика числа операторов
  436.         }//if
  437.         else  if (isNumber(tmp) == 1) // лексема - число
  438.         {
  439.             operandCount++; // увеличение на 1 счетчика числа операндов
  440.  
  441.         }//else if
  442.         else if (validVarName(tmp) == 1) // может ли лексема являться именем переменной
  443.         {
  444.             operandCount++;  // увеличение на 1 счетчика числа операндов
  445.             // проверка имени переменной на уникальность
  446.             for (i = 0; i < *varCount; i++)
  447.             {
  448.                 if (strcmp(tmp, (*varList)[i]->name) == 0) // переменная не уникальна
  449.                 {
  450.                     knownVariable = 1;
  451.                     break;
  452.                 }//if
  453.             }//for
  454.  
  455.             if (knownVariable == 1)
  456.             {
  457.                 tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  458.                 continue;
  459.             }//if
  460.             else indicator = createVariable(tmp, varList, varCount); // флаг создалась ли переменная: 0 - да, -1 - нет
  461.            
  462.         }//else if
  463.         else
  464.         {
  465.             indicator = -2; // флаг -2, встречена неизвестная лексема
  466.             return indicator;
  467.         }//else
  468.  
  469.         tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  470.     }//while
  471.  
  472.     if (operateCount != operandCount - 1) // недостаточное число операторов или операндов
  473.     {
  474.         indicator = -3;
  475.     }//if
  476.     return indicator;
  477. }//parsStr
  478.  
  479. void printError(int errCode)
  480. {
  481.     switch (errCode)
  482.     {
  483.     case 0:
  484.         return;
  485.     case -1:
  486.         printf("\nОшибка! Невозможно выделить память\n\n");
  487.         return;
  488.     case -2:
  489.         printf("\nОшибка! Встречена неизвестная лексема\n\n");
  490.         return;
  491.     case -3:
  492.         printf("\nОшибка! Недостаточно операторов или операндов\n\n");
  493.         return;
  494.     case 1:
  495.         printf("\nОшибка! Встречен оператор, а количество операндов в стеке меньше двух\n\n");
  496.         return;
  497.     case 2:
  498.         printf("\nОшибка! Деление на 0\n\n");
  499.         return;
  500.     case 3:
  501.         printf("\nОшибка! Недопустимое значение переменной\n\n");
  502.         return;
  503.     case 4:
  504.         printf("\nОшибка! Неудачная попытка чтения строки\n\n");
  505.         return;
  506.     default:
  507.         printf("\nНеизвестный код ошибки.\n\n");
  508.         return;
  509.     }//switch
  510. }//printError
  511.  
  512. char* readStr(int* errCode)
  513. {
  514.     char tmp[SIZE]; // буфер для считывания части строки  на SIZE символов
  515.     char* pos = NULL; // указатель на элемент в строке
  516.     int i = 1; // индексная переменная
  517.     char* check = NULL; // переменная для проверки ошибок при чтении
  518.     char* s = NULL; // указатель на итоговую строку
  519.  
  520.     s = malloc(SIZE); // выделение памяти строку
  521.  
  522.     if (s == NULL) // проверка выделения памяти
  523.     {
  524.         *errCode = -1;
  525.         return s;
  526.     }//if
  527.  
  528.     check = fgets(s, SIZE, stdin); // считывание из консоли строки размера SIZE в s
  529.     if (check == NULL)
  530.     {
  531.         *errCode = 4;
  532.         return s;
  533.     }//if
  534.  
  535.     if ((pos = strrchr(s, '\n')) != NULL) // в s найден символ перехода на новую строку
  536.     {
  537.         *pos = 0;
  538.         return s;
  539.     }//if
  540.  
  541.     while (1)
  542.     {
  543.         i++;
  544.         check = fgets(tmp, SIZE, stdin); //  // считывание из консоли части строки размера SIZE в tmp
  545.  
  546.         if (check == NULL)
  547.         {
  548.             *errCode = 4;
  549.         }//if
  550.  
  551.         if ((pos = strrchr(tmp, '\n')) != NULL) // в tmp найден символ перехода на новую строку (конец всей строки)
  552.         {
  553.             *pos = 0; // удаление символа перехода на новую строку
  554.             s = realloc(s, SIZE * i); // выделение дополнительной памяти в s
  555.             if (s == NULL) // проверка выделения памяти
  556.             {
  557.                 *errCode = -1;
  558.                 return s;
  559.             }//if
  560.             strcat(s, tmp); // склеивание начала строки и ее конца
  561.             break;
  562.         }//if
  563.         else
  564.         {
  565.             s = realloc(s, SIZE * i); // выделение дополнительной памяти в s
  566.             if (s == NULL) // проверка выделения памяти
  567.             {
  568.                 *errCode = -1;
  569.                 return s;
  570.             }//if
  571.             strcat(s, tmp); // склеивание начала строки и ее продолжения
  572.         }//else
  573.  
  574.     }//while
  575.    
  576.     return s;
  577. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement