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

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

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

Чтобы лучше понять процесс разделения выражения на лексемы, рассмотрим пример.

| А+ 100-(В*С)/2

Вот какие лексемы и типы возвращает функция get_token() в этом примере.

ЛексемаТип лексемы
АVARIABLE
+DELIMITER
100NUMBER
-DELIMITER
DELIMITER
вVARIABLE
*DELIMITER
сVARIABLE
)DELIMITER
DELIMITER
2NUMBER
nullnull

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

Простая программа синтаксического анализа выражений

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

/* Программа, выполняющая рекурсивный нисходящий анализ выражений, не содержащих переменные.

*/

♦include <iostream>

♦include <cstdlib>

♦include <cctype>

♦include <cstring> using namespace std;

enum types { DELIMITER = 1, VARIABLE, NUMBER};

class parser {

char *exp_ptr; // Ссылается на выражение, char token[80]; // Хранит текущую лексему, char tok_type; // Хранит тип лексемы.

void eval_exp2 (double Scresult); void eval_exp3 (double Scresult) ; void eval_exp4 (double Scresult); void eval_exp5 (double Scresult); void eval_exp6 (double Scresult); void atom (double Scresult) ; void get_token(); void serror(int error); int isdelim(char c); public: parser();

double eval_exp(char *exp);

};

// Конструктор синтаксического анализатора, parser::parser О {

exp_ptr = NULL;

}

// Отправная точка синтаксического анализа, double parser::eval_exp(char *exp)

{

double result;

exp_ptr = exp;

get_token () ,-if(!*token) {

serror(2); // Выражение пусто.

}

eval_exp2(result);

if(*token) serror(O); // Последней лексемой должен быть

// нулевой символ.

return result;

// Складываем или вычитаем два терма, void parser::eval_exp2(double kresult)

{

register char op;

double temp;

eval_exp3(result);

while((op = *token) == '+ ‘ || op == '-') {

get_token(); eval_exp3(temp); switch(op) { case '-':

result = result - temp; break; case 1+1:

result = result + temp; break;

}

}

// Умножаем или делим два фактора, void parser::eval_exp3(double kresult)

{

register char op;

double temp;

eval_exp4(result);

while((op = *token) == '*' || op == '/' || op == '%') {

get_token(); eval_exp4(temp); switch(op) { case 1 * 1:

result = result * temp; break; case '/':