Читать «Полный справочник по С++» онлайн - страница 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 (), где проверяется баланс скобок. Единственная проблема, связанная с распознаванием синтаксических ошибок, заключается в том, что в нашей программе не предусмотрено прекращение программы при их обнаружении. Это может привести к многократному выводу на экран повторяющихся сообщений об ошибках.