Читать «Полный справочник по С++» онлайн - страница 442

Герберт Шилдт

result = result / temp; break; case 1 %' :

result = (int) result % (int) temp; break;

}

}

// Возведение в степень

void parser::eval_exp4(double kresult)

{

double temp, ex;

eval_exp5(result); if(*token== ■л ■ ) { get_token(); eval_exp4(temp); ex = result; if(temp==0.0) {

result = 1.0; return;

}

for(t=(int)temp-1; t>0; —t) result = result * (double)ex;

)

}

// Вычисление унарных операций + или -. void parser::eval_exp5(double kresult)

{

register char op; op = 0 ;

if((tok_type == DELIMITER) && *token=='+' || *token == '-') {

op = *token; get_token();

}

eval_exp6(result); if(op=='-') result = -result;

// Распознавание скобок, void parser::eval_exp6(double &result) {

if((*token == 1(')) {

get_token () eval_exp2(result); if(*token != ')') serror(1); get_token();

}

else atom(result);

// Получает число, void parser::atom(double kresult) {

switch(tok_type) { case NUMBER:

result = atof(token); get_token(); return; default: serror(0);

}

// Выводит сообщение о синтаксической ошибке, void parser::serror(int error)

{

static char *e[]= {

"Синтаксическая ошибка“,

"Нарушен баланс скобок",

"Выражение пусто"

} ;

cout << е[error] << endl;

II Извлекает следующую лексему, void parser::get_token()

{

register char *temp;

tok_type = 0,-temp = token;

* temp = ' \ 0 1 ;

if(!*exp_ptr) return; II В конце выражения.

while(isspace(*exp_ptr)) ++exp_ptr; II Пропуск разделителя.

if(strchr("+-*/%Л=()”, *exp_ptr))( tok_type = DELIMITER;

II Переход на следующий символ.

*temp++ = *exp_ptr++;

}

else if(isalpha(*exp_ptr)) {

while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++; tok_type = VARIABLE;

}

else if(isdigit(*exp_ptr)) {

while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++; tok_type = NUMBER;

}

*temp = ' \0 ' ;

}

II Если параметр с является разделителем,

II возвращает значение true, int parser::isdelim(char с)

{

if(strchr(" +-/*%Л=()", с) || c==9 || c=='\r‘ || c==0)

return 1; return 0;

)

Эта программа синтаксического анализа может выполнять операции +, / и %.

Кроме того, она может возводить число в целую степень и выполнять унарную операцию -. Программа синтаксического анализа правильно вычисляет баланс скобок. Фактическое вычисление выражения осуществляется взаимно рекурсивными функциями eval_ejq?2 () — eval_eicp6 (), а также функцией atom(), возвращающей извлеченное число. Предназначение каждой функции описано в комментариях. Продемонстрируем применение этой программы.

int main()

{

parser ob; 11 Создание анализатора.

for(;;) {

cout « "Введите выражение: "; cin.getline(expstr, 79); if(*expstr=='.1) break;

cout « "Ответ: " « ob.eval_exp(expstr) « "ЧпЧп”;

} ;

return 0;

Вот какие результаты можно получить с помощью этой программы.

Для окончания работы введите точку.

Введите выражение: 10-2*3 Ответ: 4

Введите выражение: (10-2)*3 Ответ: 24

Введите выражение: 10/3 Ответ: 3.33333

Введите выражение: .

Принципы работы синтаксического анализатора

Чтобы понять, как работает синтаксический анализатор, применим его к выражению | 10-3*2

При вызове функция eval_exp(), представляющая собой отправную точку анализа, извлекает из выражения первую лексему. Если она является нулем, функция выводит на экран сообщение “Выражение пусто” и возвращает управление вызывающему модулю. Однако в данном случае лексема содержит число 10. Поскольку первая лексема не равна нулю, вызывается функция eval_exp2 (). В результате функция eval_exp2 () вызывает функцию eval_exp3 (), а функция eval_exp3()вызывает функцию eval_exp4(), которая, в свою очередь, вызывает функцию eval_exp5 (). Затем функция eval_exp5 () проверяет, является ли лексема унарным плюсом или минусом, и, если нет, вызывает функцию eval_exp6 (). В этой точке программы функция eval_exp6 () либо рекурсивно вызывает функцию eval_exp2 () (если выражение содержит скобки), либо вызывает функцию atom(), возвращающую число. Поскольку лексема не является открывающей скобкой, выполняется функция atom(), и переменной result присваивается число 10. Затем из выражения извлекается следующая лексема, и функции возвращают управление по цепочке. Поскольку следующая лексема содержит знак -, управление передается функции eval_exp2{).