Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синтаксический анализатор, Непонятна логика части кода 
:(
    Опции темы
AlanG
Дата 8.7.2006, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.5.2006
Где: РашЫн ФидирейшЫн

Репутация: нет
Всего: нет



Всем доброго времени суток.
Последние пару дней, без преувеличения, разбирал синтаксический анализатор, в целом логика кода понятна, но имеется ньюанс. Сам код что ниже особо не читайте, он большой и запутанный, сам не мало литров пива выкушал smile , смотрите еще ниже. В книге полного описания и разбора кода нет к сожелению.
А непонятно следующее: Когда происходит анализ типа лексемы (Number, переменная или оператор), то в двух случаях, когда значение по адресу на который ссылается exp_ptr является Number или переменная, происходит вызов функции isdelim() почемуто smile  проверяет значение на +-*/%^=()  или c==9 или  c=='\r' или c==0, т.е. когда происходит первый вызов, функция без базара возвратит ноль, что повлечет за собой занесение значение в исходный массив и инкрементирование адреса. Далее, что интересно, проверяется следующий символ smile Ну к примеру он есть знак +, получается что функция возвратит 1 и цикл while прекратится, при этом этот + ни куда не заносится, мало того за место него потом будет знак \0 когда функция подойдет к концу.

Блин кучу лишней инфы наверное привел, если что извините, просто уже второй день парюсь smile  
Может логика у меня кривая, может что не так делаю, подскажите плиз smile 
Вот часть кода.
Код

void parser::get_token(){

 register char *temp;

 tok_type = 0;
 temp=token; //
 *temp='\0';

 if(!*exp_ptr) return;

 while(isspace(*exp_ptr)) ++exp_ptr;

 if(strchr("+-*/%^=()", *exp_ptr)){
   tok_type=DELIMITER;
   //Ia?aoia ia neaao?uee neiaie
   *temp++=*exp_ptr++;
  }
  else if(isalpha(*exp_ptr)){
   while(!isdelim(*exp_ptr)) *temp++=*exp_ptr++;
   tok_type=VARIABLE;
 }
  else if(isdigit(*exp_ptr)){
   while(!isdelim(*exp_ptr)) *temp++=*exp_ptr++;
   tok_type=NUMBER;
  }
 *temp='\0';

}
 int parser:: isdelim(char c){

  if(strchr(" +-*/%^=()", c) || c==9 || c=='\r' ||c==0)
   return 1;
  return 0; //

}


Полный код:
Код

#include<iostream>
#include<cstdlib>
#include<cctype>
#include<cstring>
using namespace std;

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

class parser {
 char tok_type;
 char token[80];
 char* exp_ptr;

 void eval_exp2(double &result);
 void eval_exp3(double &result);
 void eval_exp4(double &result);
 void eval_exp5(double &result);
 void eval_exp6(double &result);
 void atom(double &result);
 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);
  return 0.0;
 }
 eval_exp2(result);
 if(*token) serror(0);
 return result;
}
void parser:: eval_exp2(double &result){
  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 '+':
     result=result+temp;
     break;

  }
 }
}
 void parser:: eval_exp3(double &result){
  register char op;
  double temp;

 eval_exp4(result);
 while((op=*token)=='*' || op=='/' || op =='%') {
    get_token();
    eval_exp4(temp);
    switch(op){
     case '*':
      result = result*temp;
      break;
     case '/':
      result=result/temp;
      break;
     case '%':
      result=(int)result % (int)temp;
      break;
    }
  }
 }
void parser:: eval_exp4(double &result)
{
  double temp, ex;
  register int t;

 eval_exp5(result);
  if(*token=='^'){
  get_token();
  eval_exp4(temp);
  ex=result;
  if(temp==0.0) {
   result=1.0;
   return;

   }
  for(t=(int)temp-1; t>0; --t) result = result*(double)ex;
 }
}
 void parser:: eval_exp5(double &result)
{
  register char op;
  op=0;
  if((tok_type == DELIMITER) && *token=='+' || *token == '-') {
  op = *token;
  get_token();
 }
 eval_exp6(result);
 if(op=='-') result=-result;
}
  void parser:: eval_exp6(double &result)
{
  if(*token =='(') {
  get_token();
  eval_exp2(result);
   if(*token!=')')
   serror(1);
  get_token();
  }
  else atom(result);
}
 void parser:: atom(double &result)
{
  switch(tok_type){
  case NUMBER:
   result=atof(token);
   get_token();
   return;
  default:
   serror(0);
 }
}
 void parser:: serror(int error){

    static char *e[]={
    "Sintaxicheskii Oshibka",
    "Balance scoboc",
    "Pusto"
  };
  cout << e[error] << endl;
 }

 void parser::get_token(){

 register char *temp;

 tok_type = 0;
 temp=token; //
 *temp='\0';

 if(!*exp_ptr) return;

 while(isspace(*exp_ptr)) ++exp_ptr;

 if(strchr("+-*/%^=()", *exp_ptr)){
   tok_type=DELIMITER;
   //Ia?aoia ia neaao?uee neiaie
   *temp++=*exp_ptr++;
  }
  else if(isalpha(*exp_ptr)){
   while(!isdelim(*exp_ptr)) *temp++=*exp_ptr++;
   tok_type=VARIABLE;
 }
  else if(isdigit(*exp_ptr)){
   while(!isdelim(*exp_ptr)) *temp++=*exp_ptr++;
   tok_type=NUMBER;
  }
 *temp='\0';

}
 int parser:: isdelim(char c){

  if(strchr(" +-*/%^=()", c) || c==9 || c=='\r' ||c==0)
   return 1;
  return 0; //

}

int main()
{
  char expstr[80];

  cout<<"Aey ieii?aiey aaaaeoa oi?eo, \n";

  parser ob;

  for(;;) {
   cout<<"Aaaaeoa au?a?aiea:";
   cin.getline(expstr, 79);
   if(*expstr=='.') break;
   cout<<"Ioaao:" << ob.eval_exp(expstr)<<"\n\n";
 };
 return 0;
}
  

Это сообщение отредактировал(а) AlanG - 8.7.2006, 17:12
PM MAIL   Вверх
slava72
Дата 10.7.2006, 10:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 23.6.2006

Репутация: 1
Всего: 1



Дык все прозрачно  smile Функция isdelim - являтся (крайне коряво сделанной) функциий проверки символа, на "разделитель".  Т.е. встретив число алфавитночисловой символ - мы считываем строку до первого разделителя, не включая его в лексемму.

А корявость функции - например '\b' и '\n' - разделителями не являются ! smile 
Как правило такие функции пишутся на основе массива флагов, что -то типа:

Код


class parser {
...
public:
  enum {IS_DELIM = 1, IS_SPACE = 2, IS_ALPHA = 4, IS_OP = 8, ... }; // определяем флаги
  void InitFlags(); // Либо в конструкторе
  ...
  bool IsDelim(unsigned char c) { return is_flags_[c] & IS_DELIM; }
protected:
  unsigned is_flags_[256]; // массив флагов
}



Если нужно несколько экземпляров анализатора, то InitFlags() и is_flags можно сделать статическими.

 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0438 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.