Символьный Калькулятор на С++. Проблема с возведением в степень
Есть задача выполнить калькулятор, принимающий строки, состоящие из
- символов '0'-'9',
- скобок '(', ')',
- символов '+', '-', '*', '/', '^',
и выполняющий действия над одноразрядными операндами
- сложения
- вычитания
- умножения
- целочисленного деления
- возведения в степень.
Архитектура решения должна содержать рекурсивный спуск.
Удалось написать код:
#include <stdio.h>
#include <setjmp.h>
jmp_buf begin;
char curlex;
void getlex(void);
int expr(void);
int add_sub(void);
int mult_div(void);
int power(void);
void error();
int main() {
int result; /*Переменная результата вычисления*/
setjmp(begin); /*сохранения всех переменных окружения*/
printf("==>");
getlex(); /*Вызов функции чтения символов ввода:
получает первый значащий символ в переменную curlex*/
result=expr(); /*Вычисление результата с помощью функции*/
if ( curlex != '\n') error(); /*Выброс ошибки и повтор ввода выражения
если в потоке попались не 0-9, символы арифметики
скобки или перевод*/
printf("\n%d\n",result);
return 0;
}
/*Функция принимает поток символов и записывает их в глобальную переменную*/
void getlex() {
while ( ( curlex=getchar()) == ' '); /*ПП игнорируются, до первого значащего символа*/
}
/*Функция обработки ошибки: возвращает в исходное состояние переменных*/
void error(void) {
printf("\nОШИБКА!\n");
while(getchar()!='\n');
longjmp(begin,1);
}
/*Функция вычисляющаяя результат*/
int expr() {
int e=add_sub(); /*Результат как возвращаемое значение функции сложения*/
while (curlex == '+' || curlex == '-') /*пока есть символы сложения*/
if (curlex == '+')
{getlex(); e+=add_sub();} /*результат аддитивно растет*/
else if (curlex == '-')
{getlex(); e-=add_sub();} /*результат аддитивно убывает*/
return e;
}
/*Функция сложения и вычитания*/
int add_sub() {
/*Результат как возвращаемой значение функции умножения*/
int a=mult_div();
while (curlex == '*' || curlex == '/') /*пока есть символы умножения*/
if (curlex == '*')
{getlex(); a*=mult_div();} /*Результат мультипликативно растет*/
else if (curlex == '/')
{getlex(); a/=mult_div();} /*Результат мультипликативно убывает*/
return a;
}
/*Функция умножения и деления*/
int mult_div() {
/*Результат как возвращаемой значение функции возведения в степень*/
int a=power();
while (curlex == '^') /*пока есть символы возведения в степень*/
{getlex(); for(int k=0;k<power(); k++, a*=power());} /*Результат экспоненциально растет*/
return a;
}
/*Функция возведения в степень*/
int power() {
int m; /*Инициализация переменной, хранящей результат*/
switch(curlex){ /*Интерпретация считанного символа 0-9*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': m= curlex-'0'; break;
case '(': getlex(); m=expr(); /*Рекурсивный вызов вычисления выражения в скобках*/
if ( curlex == ')') break; /*Закрытие скобок*/
default : error(); /*Вызов функции обработки ошибки при */
}
getlex();
return m;
}
Код делает всё, кроме возведения в степень. Не могу отследить ошибку. Кроме того чувствую, что не учел правоассоциативность возведения в степень. То есть у меня 3^1^2 даст 9, а должно дать 3.
Помогите, пожалуйста.
Ответы (1 шт):
Хочешь найти ответ на сложную задачу - найди его сам.
Код решения:
#include <stdio.h>
#include <setjmp.h>
jmp_buf begin;
char curlex;
void getlex(void);
int expr(void);
int add_sub(void);
int mult_div(void);
int power(void);
void error();
int main() {
int result; /*Переменная результата вычисления*/
setjmp(begin); /*сохранения всех переменных окружения*/
printf("==>");
getlex(); /*Вызов функции чтения символов ввода:
получает первый значащий символ в переменную curlex*/
result=expr(); /*Вычисление результата с помощью функции*/
if ( curlex != '\n') error(); /*Выброс ошибки и повтор ввода выражения
если в потоке попались не 0-9, символы арифметики
скобки или перевод*/
printf("\n%d\n",result);
return 0;
}
/*Функция принимает поток символов и записывает их в глобальную переменную*/
void getlex() {
while ( ( curlex=getchar()) == ' '); /*ПП игнорируются, до первого значащего символа*/
}
/*Функция обработки ошибки: возвращает в исходное состояние переменных*/
void error(void) {
printf("\nОШИБКА!\n");
while(getchar()!='\n');
longjmp(begin,1);
}
/*Функция вычисляющаяя результат*/
int expr() {
int e=add_sub(); /*Результат как возвращаемое значение функции сложения*/
while (curlex == '+' || curlex == '-') /*пока есть символы сложения*/
if (curlex == '+')
{getlex(); e+=add_sub();} /*результат аддитивно растет*/
else if (curlex == '-')
{getlex(); e-=add_sub();} /*результат аддитивно убывает*/
return e;
}
/*Функция сложения и вычитания*/
int add_sub() {
/*Результат как возвращаемой значение функции умножения*/
int a=mult_div();
while (curlex == '*' || curlex == '/') /*пока есть символы умножения*/
if (curlex == '*')
{getlex(); a*=mult_div();} /*Результат мультипликативно растет*/
else if (curlex == '/')
{getlex(); a/=mult_div();} /*Результат мультипликативно убывает*/
return a;
}
/*Функция умножения и деления*/
int mult_div() {
/*Результат как возвращаемой значение функции возведения в степень*/
int a=power(), res=1;
while (curlex == '^') /*пока есть символы возведения в степень*/
{getlex();
int m=mult_div();
for(int k=0 ;k<m; k++, res*=a);
return res;} /*Результат экспоненциально растет*/
return a;
}
/*Функция возведения в степень*/
int power() {
int m; /*Инициализация переменной, хранящей результат*/
switch(curlex){ /*Интерпретация считанного символа 0-9*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': m= curlex-'0'; break;
case '(': getlex(); m=expr(); /*Рекурсивный вызов вычисления выражения в скобках*/
if ( curlex == ')') break; /*Закрытие скобок*/
default : error(); /*Вызов функции обработки ошибки при */
}
getlex();
return m;
}
Возведение в степень реализовано в виде еще одного уровня вложенности функции в порядке приоритета операций expr -> add_sub -> mult_div ->power(анализирует символы строки)
Правая ассоциативность обеспечивается рекурсией на уровне функции mult_div()