132 lines
3.3 KiB
C
132 lines
3.3 KiB
C
#include <ctype.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
#define MAXOP 100 // Максимальный размер операдна (цифры) или оператора
|
||
#define MAXVAL 100 // Максимальный размер стека (глубина)
|
||
#define NUMBER '0' // Признак числа
|
||
#define BUFSIZE 100
|
||
|
||
int getop(char[]);
|
||
void push(double);
|
||
double pop(void);
|
||
int getch(void);
|
||
void ungetch(int);
|
||
|
||
int sp = 0; /* Следующая свободная позиция в стеке */
|
||
int bufp = 0; /* след, свободная позиция в буфере */
|
||
double val[MAXVAL]; /* stack */
|
||
char buf[BUFSIZE]; /* буфер для ungetch */
|
||
|
||
int getch(void) /* взять (возможно возвращенный) символ */
|
||
{
|
||
return (bufp > 0) ? buf[--bufp] : getchar();
|
||
}
|
||
void ungetch(int с) /* вернуть символ на ввод */
|
||
{
|
||
if (bufp >= BUFSIZE)
|
||
printf("ungetch: слишком много символов\n");
|
||
else
|
||
buf[bufp++] = с;
|
||
}
|
||
|
||
void push(double f) {
|
||
if (sp < MAXVAL) {
|
||
val[++sp] = f;
|
||
}
|
||
else {
|
||
printf("Stack maximum depth reached: %c", MAXVAL);
|
||
}
|
||
}
|
||
|
||
double pop(void) {
|
||
if (sp > 0) {
|
||
return val[--sp];
|
||
} else {
|
||
printf("Stack is empty. Returning 0.0");
|
||
return 0.0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Функция получения следующего оператора или операнда
|
||
*
|
||
* @param s массив символов для оценки
|
||
*/
|
||
int getop(char s[]) {
|
||
int i, c;
|
||
|
||
while ((s[0] = c = getch()) == ' ' || c == '\t')
|
||
;
|
||
s[1] = '\0';
|
||
if (!isdigit(c) && c != '.')
|
||
return c;
|
||
i = 0;
|
||
/* Накапливаем целую часть */
|
||
if (isdigit(c))
|
||
while (isdigit(s[++i] = c = getch()))
|
||
;
|
||
/* Накапливаем дробную часть */
|
||
if (c == '.')
|
||
while (isdigit(s[++i] = c = getch()))
|
||
s[i] = '\0';
|
||
if (c != EOF)
|
||
ungetch(c);
|
||
return NUMBER;
|
||
}
|
||
|
||
int main() {
|
||
int type;
|
||
double pop2;
|
||
char s[MAXOP];
|
||
|
||
while ((type = getop(s)) != EOF) {
|
||
switch (type) {
|
||
case NUMBER:
|
||
push(atof(s));
|
||
break;
|
||
case '+':
|
||
push(pop() + pop());
|
||
break;
|
||
case '*':
|
||
push(pop() * pop());
|
||
break;
|
||
case '-':
|
||
/*
|
||
* Тут сначала извлекаем верхний операнд, из которого надо
|
||
* вычитать. В отличии от `+`, `*` для `-` и `/` порядок операндов
|
||
* важен.
|
||
*
|
||
* ----------
|
||
* -
|
||
* 10
|
||
* 20
|
||
* ...
|
||
* ----------
|
||
*
|
||
* Чтобы сделать вычитание - надо из 20 вычесть 10 - получается
|
||
* излекам со стека 10, затем 20 и делаем вычитание
|
||
*/
|
||
pop2 = pop();
|
||
push(pop() - pop2);
|
||
break;
|
||
case '/':
|
||
/*
|
||
* Тут примерно то-же самое, только еще надо сделать проверку
|
||
* на ноль
|
||
*/
|
||
pop2 = pop();
|
||
if (pop2 != 0.0)
|
||
push(pop() / pop2);
|
||
else
|
||
printf("Error: Division by zero\n");
|
||
break;
|
||
case '\n':
|
||
printf("\t%.g\n", pop());
|
||
break;
|
||
default:
|
||
printf("Error: Unknown operation %s\n", s);
|
||
break;
|
||
}
|
||
}
|
||
}
|