Вход/Регистрация
QT 4: программирование GUI на С++
вернуться

Саммерфилд Марк

Шрифт:

Рис. 4.10. Блок—схема синтаксического анализа выражений электронной таблицы.

Блок—схема синтаксического анализа выражений электронной таблицы представлена на рис. 4.10. Для каждого грамматического символа (Expression, Term и Factor — выражение, терм и фактор) имеется соответствующая функция—член, которая выполняет его синтаксический анализ и структура которой очень хорошо отражает его грамматику. Построенные таким образом синтаксические анализаторы называются парсерами с рекурсивным спуском (recursive—descent parsers).

Давайте начнем с evalExpression, то есть с функции, которая выполняет синтаксический разбор выражения:

01 QVariant Cell::evalExpression(const QString &str, int &pos) const

02 {

03 QVariant result = evalTerm(str, pos);

04 while (str[pos] != QChar::Null) {

05 QChar op = str[pos];

06 if (op != '+' && op != '-') return result;

07 ++pos;

08 QVariant term = evalTerm(str, pos);

09 if (result.type == QVariant::Double

10 && term.type == QVariant::Double) {

11 if (op == '+') {

12 result = result.toDouble + term.toDouble;

13 } else {

14 result= result.toDouble - term.toDouble;

15 }

16 } else {

17 result = Invalid;

18 }

19 }

20 return result;

21 }

Во-первых, мы вызываем функцию evalTerm для получения значения первого терма. Если за ним идет символ «+» или «—», мы вызываем второй раз evalTerm; в противном случае выражение состоит из единственного терма, и мы возвращаем его значение в качестве значения всего выражения. После получения значений первых двух термов мы вычисляем результат операции в зависимости от оператора. Если при оценке обоих термов их значения будут иметь тип double, мы рассчитываем результат в виде числа типа double; в противном случае мы устанавливаем результат на значение Invalid.

Мы продолжаем эту процедуру, пока не закончатся термы. Это даст правильный результат, потому что операции сложения и вычитания обладают свойством «ассоциативности слева» (left—associative), то есть «1—2—3» означает «(1—2)—3», а не «1—(2—3)».

01 QVariant Cell::evalTerm(const QString &str, int &pos) const

02 {

03 QVariant result = evalFactor(str, pos);

04 while (str[pos] != QChar::Null) {

05 QChar op = str[pos];

06 if (op != '*' && op != '/')

07 return result;

08 ++pos;

09 QVariant factor = evalFactor(str, pos);

10 if (result.type == QVariant::Double &&

11 factor.type == QVariant::Double) {

12 if (op == '*') {

13 result = result.toDouble * factor.toDouble;

14 } else {

15 if (factor.toDouble == 0.0) {

16 result = Invalid;

17 } else {

18 result = result.toDouble / factor.toDouble;

19 }

20 }

21 } else {

22 result = Invalid;

23 }

24 }

25 return result;

26 }

Функция evalTerm очень напоминает функцию evalExpression, но, в отличие от последней, она имеет дело с операциями умножения и деления. В функции evalTerm необходимо учитывать одну тонкость, а именно: нельзя допускать деления на нуль, так как это приводит к ошибке на некоторых процессорах. Хотя не рекомендуется проверять равенство чисел с плавающей точкой из-за ошибки округления, можно спокойно делать проверку на равенство значению 0.0 для предотвращения деления на нуль.

01 QVariant Cell::evalFactor(const QString &str, int &pos) const

02 {

03 QVariant result;

04 bool negative = false;

05 if (str[pos] == '-') {

06 negative = true;

07 ++pos;

08 }

09 if (str[pos] == '(') {

10 ++pos;

11 result = evalExpression(str, pos);

12 if (str[pos] != ')')

  • Читать дальше
  • 1
  • ...
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: