Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2213 / 889 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 6:

Синтаксические анализаторы. Нисходящие анализаторы

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >

Формула, содержащая операции типа умножения

Общий вид формулы, содержащей операции типа умножения:

F1*F2*…*Fn

Мы сможем понять, что имеем дело с подобной формулой только в момент встречи операции умножения или операции деления. Обрабатывать такие формулы будет процедура Term , параметром которой является целочисленное значение, представляющее левый операнд формулы F1*F2, т.е. F1. Для того, чтобы вычислить значение такой формулы, мы должны выбрать ее правый операнд, который может быть простейшей формулой, а затем выполнить операцию. Это приводит нас к следующему фрагменту кода:

int Term (int left)
{
   char ch = getChar(); int right;
   if (ch != '*' && ch !='/')
   {
    /* как оказалось, очередной символ не является обозначением ожидаемой нами       
       операции, поэтому мы должны вернуть ненужный нам операнд*/
      returnChar(); /* возвращаем неиспользованную литеру */
      return left;  /* и неиспользованное значение */
   }
/* теперь все в порядке и нам необходимо вычислить значение правого операнда */
   right = Factor();
   if (ch == '*')
   {
      return Term(left * right); 
      /* Этот вызов позволит нам вычислить остальную часть формулы */
   }
   if (right == 0) return error ("Деление на нуль"); 
   return Term(left / right); 
}

Формула, содержащая операции типа сложения

Общий вид формулы, содержащей операции типа сложения:

T1 +T2 +…+Tn

Мы сможем понять, что имеем дело с такой формулой только тогда, когда встретим операцию сложения или операцию вычитания. Такие формулы будет обрабатывать процедура Expression, параметром которой является целочисленное значение, представляющее левый операнд операции типа сложения.

int Expression (int left)
{
   char ch = getChar (); int right;
   if (ch != '+' && ch != '-')
   {
    /* как оказалось, очередной символ не является обозначением ожидаемой нами    
       операции, поэтому мы должны вернуть ненужный нам операнд*/
      returnChar(); /* возвращаем неиспользованную литеру */
      return left;  /* и неиспользованное значение */
   }
/* теперь все в порядке и нам необходимо вычислить значение правого операнда */
   right = Term (Factor());
   if (ch == '+')
   {
      return Expression(left + right); 
      /* Этот вызов позволит нам вычислить остальную часть формулы */
   }
   return Expression(left - right);
}

Методы, которые следует разработать самостоятельно

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

  • Существует метод без параметров getChar, выдающий очередную литеру из входного потока
  • Метод returnChar возвращает неиспользованную литеру обратно во входной поток
  • Кроме того, мы не будем описывать методы isDigit и getValue. Первый из этих методов возвращает true только в том случае, когда ее параметр является цифрой. Второй метод извлекает из входного потока все цифры, которые непосредственно следуют за литерой, передаваемой ей в качестве параметра, и вычисляет соответствующее целочисленное значение.
  • Метод error используется для вывода сообщений об ошибках.

Эти методы необходимо реализовать самостоятельно. При реализации некоторых из этих методов на платформе .NET можно воспользоваться методами стандартных классов.

Заметим, что при реализации этого примера мы использовали метод рекурсивного спуска с возвратами (recursive descent with backtracking). Чуть позже мы увидим, почему нам не удалось ограничиться методом рекурсивного спуска без возвратов.

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >