Синтаксис языков программирования. Нисходящий синтаксический анализ, процедурная и автоматная реализации, страница 5

   curWordIndex=getWordIndex();

  return true;

  }

  if((curWordIndex>=0)&&SelSet[47].get(curWordIndex)){

   curWordIndex=getWordIndex();

  return true;

  }

  return false;

 }

 public String getStatistic(int i){

  if(i==0)

   return " "+cCnt+" ";

  else

   return"";

 }

}

//end of Part_5

//Part_7: обработка HTTP-запроса, создание экземпляра синтаксического акцептора/анализатора

//start:

decoderEscaped dE=new decoderEscaped();

String qs="";

if((qs=request.getParameter("inputText"))==null)

 if(request.getQueryString()!=null)qs=new String(request.getQueryString());

if((qs!=null)&&(qs.length()>0))

  qs=dE.decode(qs).toString();

else qs="";

textReader str=new textReader(qs);

parser p=new parser(qs);

Программная реализация рекурсивного спуска:

//Part_6: синтаксический акцептор/анализатор

//Part_6_3: собственно восстановление дерева грамматического разбора

 public boolean parse(){

  if(la==null)return false;

  curWordIndex=getWordIndex();    //возьмем индекс первого терминала

  if(FirstOne())            //вызовем метод, разбирающий начальный нетерминал

   if(curWordIndex==0)         //если этот метод возвратил истину и весь входной поток прочитан

    return true;  //последовательность слов правильна, возвращаем истину

  return false;  //если что-то не так - вернем признак ошибки

 }

//все далее следующие методы:

//          - имеют имя нетерминала, разбором которого каждый из них занимается

//          - возвращают логическое значение

//          - содержат ровно столько последовательно выполняющихся блоков, сколько правил в грамматике есть для данного нетерминала

//          - каждый блок выполняется только при условии, что текущий терминал принадлежит множеству выбора донного правила

//          - внутри блока организована обработка правой части правила последовательно символ за символом слева направо;

//                     в зависимости от того, чем является каждый очередной символ, делается следующее:

//                     - для нетерминала - вызывается метод, имеющий его имя и, если от него получена ложь, то ложь возвращается выше;

//                     - для терминала - его индекс сравнивается с индексом текущего терминала, при несовпадении возвращается ложь (эта проверка не выполняется, если терминал есть первый символ правила),

//                       затем из входного потока читается следующий терминал; терминал указывается в примечании к оператору сравнения;

//                     - для действия - оно выполняется (пустая правая часть правила приравнивается к действию, для таких правил формируется {});

//                     если выполнена обработка всех символов правой части (и не была возвращена ложь), то возвращается истина

//          - если не будет выполнен ни один блок (текущий терминал не принадлежит множеству выбора ни одного правила) - возвращается значение ложь

 private boolean FirstOne(){cCnt+=1;

  if((curWordIndex>=0)&&SelSet[0].get(curWordIndex)){

   if(!objects())return false;

   return functions();

  }

  return false;

 }

 private boolean objects(){cCnt+=1;

  if((curWordIndex>=0)&&SelSet[1].get(curWordIndex)){

   curWordIndex=getWordIndex();

   if(curWordIndex!=1)return false;

   curWordIndex=getWordIndex();

   if(curWordIndex!=32)return false;

   curWordIndex=getWordIndex();

   if(!definitions())return false;

   if(curWordIndex!=33)return false;

   curWordIndex=getWordIndex();

   return objects();

  }

  if((curWordIndex>=0)&&SelSet[2].get(curWordIndex)){{}return true;

  }

  return false;

 }

 private boolean definitions(){cCnt+=1;

  if((curWordIndex>=0)&&SelSet[3].get(curWordIndex)){