Читать «Полный справочник по С++» онлайн - страница 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{).