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

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

II Обработка выражения, содержащего скобки, void parser::eval_exp6(double ^result)

{

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

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

}

else atom(result) ,-

II Извлекает число или значение переменной, void parser::atom(double ^result)

[

switch(tok_type) { case VARIABLE:

result = find_var (token)

get_token() ; return; case NUMBER:

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

}

II Возвращает лексему во входной поток, void parser::putback()

{

char * t; t = token

for(; *t; t++) exp_ptr—;

}

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

{

static char *e[]= {

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

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

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

} ;

cout « е[error] « endl;

}

// Получает следующую лексему, 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;

П Переход к следующему символу.

*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 ’ ;

}

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

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

(

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

return 1; return 0;

}

II Возвращает значение переменной, double parser::find_var(char *s)

{

if(!isalpha(*s))[ serror(1); return 0.0;

}

return vars[toupper(*token)-'A1];

}

Для проверки новой версии можно вновь применить функцию main(), приведенную в предыдущем разделе. Теперь можно вычислять более сложные выражения, например:

|А= 10/4 А-В

C=A*(F-21)

Ш Проверка синтаксических ошибок при рекурсивном нисходящем анализе

Прежде чем перейти к шаблонной версии класса parser, дадим краткое описание проверки синтаксических ошибок. При вычислении выражений синтаксической ошибкой считается ситуация, в которой входное выражение не соответствует строгим правилам, установленным анализатором. Как правило, это опечатки, сделанные пользователем. Например, следующие выражения будут отвергнуты анализатором.

110**8 (10—5)*9)

/8

Первое выражение содержит два оператора подряд, во втором нарушен баланс скобок, а последнее выражение начинается со знака операции. Ни одно из этих выражений анализатор не допускает. Поскольку ошибочные выражения могут привести к неверной работе программы синтаксического анализа, необходимо предусмотреть средства защиты от них.

Просматривая код класса parser, вы, возможно, обратили внимание на функцию serror(), которая вызывается в определенных ситуациях. В отличие от других методов синтаксического анализа, рекурсивный нисходящий анализ позволяет легко распознавать ошибки, поскольку они могут возникать, в основном, лишь в функциях atom(), find_var() или eval_exp6 (), где проверяется баланс скобок. Единственная проблема, связанная с распознаванием синтаксических ошибок, заключается в том, что в нашей программе не предусмотрено прекращение программы при их обнаружении. Это может привести к многократному выводу на экран повторяющихся сообщений об ошибках.