Сложение, вычитание и скобки
Усложним предыдущий пример. Пусть теперь помимо чисел и знаков "плюс" и "минус", в выражении допустимо использование круглых скобок любой вложенности.
Во-первых, для корректной работы программы в этом случае потребуется модифицировать функцию get_next_lexem(), чтобы она "научилась" распознавать лексемы типа LT_OPEN и LT_CLOSE
Во-вторых, потребуется изменить функцию evaluate_expression(). При этом будем воспользуемся следующим наблюдением: часть выражения, заключенная в скобки, тоже является выражением, поэтому можно использовать функцию evaluate_expression() рекурсивно.
На рисунке разными цветами показаны области, для вычисления которых будут использоваться отдельные вызовы функции evaluate_expression().
Изменения коснутся функций calc_plus() и calc_plus().
void calc_plus() {
// в эту функцию мы попадем, если текущая лексема - это LT_PLUS
get_next_lexem();
// возьмем следующую лексему
// если следующая за плюсом лексема является числом, то ничего не изменилось:
if (current_lexem_type == LT_NUMBER) {
current_result = current_result + current_lexem_value;
}
else {
// но в этом примере слагаемое может быть не только числом,
// но и целым выражением в скобках.
// предположим, что исходное выражение корректно
current_result = current_result + evaluate_expression();
// вычислили выражение до закрывающейся скобки
get_next_lexem();
// за выражением будет следовать закрывающаяся скобка, ее нужно пропустить
}
}
Функция calc_minus() изменяется аналогично.
Также должна немного измениться основная логика функции evaluate_expression()
while ((current_lexem_type != LT_END) && (current_lexem_type != LT_CLOSE)) {
if (current_lexem_type == LT_PLUS) {
calc_plus();
}
else {
calc_minus();
}
get_next_lexem();
}
Теперь эту функцию могут вызвать для разбора основного выражения (признаком конца которого является LT_END, или для разбора выражения в скобках, признаком конца которого является LT_CLOSE.
Следует отдельно уделить внимание частному случаю, когда основное выражение начинается со скобки. Для этого потребуется внести изменения в начало функции evaluate_expression()
int current_result = 0;
get_next_lexem();
if (current_lexem_type == LT_NUMBER) {
// в случае, если первая лексема выражения - это число, ничего не меняется
current_result = current_lexem_value;
get_next_lexem();
}
else {
// в противном случае сделаем рекурсивный вызов
// который вычислит для нас выражение в скобках
current_result = evaluate_expression();
get_next_lexem();
// как и ранее, вызов get_next_lexem(); нужен чтобы пропустить
// закрывающуюся скобку
}