Саммерфилд Марк
Шрифт:
Рис. 4.10. Блок—схема синтаксического анализа выражений электронной таблицы.
Блок—схема синтаксического анализа выражений электронной таблицы представлена на рис. 4.10. Для каждого грамматического символа (Expression, Term и Factor — выражение, терм и фактор) имеется соответствующая функция—член, которая выполняет его синтаксический анализ и структура которой очень хорошо отражает его грамматику. Построенные таким образом синтаксические анализаторы называются парсерами с рекурсивным спуском (recursive—descent parsers).
Давайте начнем с evalExpression, то есть с функции, которая выполняет синтаксический разбор выражения:
Во-первых, мы вызываем функцию evalTerm для получения значения первого терма. Если за ним идет символ «+» или «—», мы вызываем второй раз evalTerm; в противном случае выражение состоит из единственного терма, и мы возвращаем его значение в качестве значения всего выражения. После получения значений первых двух термов мы вычисляем результат операции в зависимости от оператора. Если при оценке обоих термов их значения будут иметь тип double, мы рассчитываем результат в виде числа типа double; в противном случае мы устанавливаем результат на значение Invalid.
Мы продолжаем эту процедуру, пока не закончатся термы. Это даст правильный результат, потому что операции сложения и вычитания обладают свойством «ассоциативности слева» (left—associative), то есть «1—2—3» означает «(1—2)—3», а не «1—(2—3)».
Функция evalTerm очень напоминает функцию evalExpression, но, в отличие от последней, она имеет дело с операциями умножения и деления. В функции evalTerm необходимо учитывать одну тонкость, а именно: нельзя допускать деления на нуль, так как это приводит к ошибке на некоторых процессорах. Хотя не рекомендуется проверять равенство чисел с плавающей точкой из-за ошибки округления, можно спокойно делать проверку на равенство значению 0.0 для предотвращения деления на нуль.