Advertisement
baadgeorge

kr_latest

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