Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Компактный парсер-транслятор формул на векторах

446
05 сентября 2011 года
Meander
487 / / 04.09.2011
Решил сделать для себя небольшой парсер и сделал, но столкнулся с одной проблемой когда попытался избавиться от производного класса Lexlib и оставить только Lexeme, чтобы в любой момент иметь доступ к свойству S. Однако при такой замене функция Translate() выполняется неправильно, это обнаруживает Analyses() с сообщением "Недопустимая лексема в конце!".
Помогите исправить.
Код:
#include <string>
#include "math.h"
#include <vector>
using namespace std;
enum                    Type { num,var,con, opb,clb, alu,alb,bou };//Возможные типы лексем
enum                    Moda { alg, dif };//Возможные модальности строк
typedef int             Inst;//Инструкция парсеру
typedef int             Prop;//Приоретет операции
struct                  Lexeme;
typedef long double     Real;
typedef unsigned        Unsi;
typedef vector<Real>    Valu;
typedef vector<Lexeme*> Lxms;
typedef vector<Lexeme>  Numb;
struct                  Lexlib;
typedef vector<Lexlib>  Libr;
//---------------------------------------------------------------------------
struct Lexeme
{
Type   T;
Inst   I;
Prop   P;
//-----------------------
Lexeme(Type t,Inst i,Prop p){T=t;I=i;P=p;}
};

struct Lexlib : Lexeme
{
string S;
//-----------------------
Lexlib(string s,Type t,Inst i,Prop p):Lexeme(t,i,p)
{S=s;}
};
//---------------------------------------------------------------------------
struct Library
{
Unsi  M;//длина самого длинного слова
Libr L;
Valu C;
Valu V;
//-----------------------
void SetM(){
M = 0;
for(Unsi i=0;i<L.size();i++)
if (L.S.length() > M) M = L.S.length();
}
//-----------------------
Lexeme *Find(string s){
Lexeme *f;
for(Unsi i=0;i<L.size();i++)
if (L.S == s) f = &L;
return f;
}
//-----------------------
Library(){
//скобки
L.push_back(Lexlib("(",opb,1,0));
L.push_back(Lexlib("{",opb,1,0));
L.push_back(Lexlib("[",opb,1,0));
L.push_back(Lexlib(")",clb,2,0));
L.push_back(Lexlib("}",clb,2,0));
L.push_back(Lexlib("]",clb,2,0));
//арифметические
L.push_back(Lexlib("+",bou,-3,6));//if I=+3 -> P=2
L.push_back(Lexlib("-",bou,-4,6));//if I=+4 -> P=2
L.push_back(Lexlib("*",alb,5,3));
L.push_back(Lexlib("/",alb,6,3));
L.push_back(Lexlib("^",alb,7,4));
//функции
L.push_back(Lexlib("abs",alu,-8,6));//модуль
L.push_back(Lexlib("exp",alu,-9,6));//экспонента
L.push_back(Lexlib("ln",alu,-10,6));//натуральный логарифм
L.push_back(Lexlib("lg",alu,-11,6));//десятичный логарифм
L.push_back(Lexlib("log",alb,12,5));//логарифм по произвольному основанию
L.push_back(Lexlib("max",alb,13,5));//максимальное из двух чисел
L.push_back(Lexlib("min",alb,14,5));//минимальное из двух чисел
L.push_back(Lexlib("arccos",alu,-15,6));//арккосинус
L.push_back(Lexlib("arcsin",alu,-16,6));//арксинус
L.push_back(Lexlib("arctg",alu,-17,6));//арктангенс
L.push_back(Lexlib("arcctg",alu,-18,6));//арккотангенс
L.push_back(Lexlib("sin",alu,-19,6));//синус
L.push_back(Lexlib("cos",alu,-20,6));//косинус
L.push_back(Lexlib("tg",alu,-21,6));//тангенс
L.push_back(Lexlib("ctg",alu,-22,6));//котангенс
L.push_back(Lexlib("sh",alu,-23,6));//синус гиперболический
L.push_back(Lexlib("ch",alu,-24,6));//косинус гиперболический
L.push_back(Lexlib("th",alu,-25,6));//тангенс гиперболический
L.push_back(Lexlib("cth",alu,-26,6));//котангенс гиперболический
L.push_back(Lexlib("arcsh",alu,-27,6));//арксинус гиперболический
L.push_back(Lexlib("arcch",alu,-28,6));//арккосинус гиперболический
L.push_back(Lexlib("arcth",alu,-29,6));//арктангенс гиперболический
L.push_back(Lexlib("arccth",alu,-30,6));//арккотангенс гиперболический
//константы
L.push_back(Lexlib("pi",con,C.size(),0));//число пи
C.push_back(M_PI);
SetM();
}
//-----------------------
} Lib;
//---------------------------------------------------------------------------
struct Baseline
{
string K;
Moda   D;
Valu   V;//числовые значения
Numb   N;//вектор лексем
//-----------------------
void Analyses(){
int cbr=0;//счетчик скобок
for (Unsi i=0;i<N.size();i++){
if(N.T==opb)cbr++; if(N.T==clb)cbr--;
if(i==0){
if(N.T==clb || N.T==alb)ShowMessage("Недопустима лексема в начале!"), Abort();
}else{
if(N.T==opb &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед '('!"), Abort();

if((N.T==num || N.T==var || N.T==con) &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед числом!"), Abort();

if(N.T==alb &&
  (N[i-1].T!=clb && N[i-1].T!=num &&
   N[i-1].T!=var && N[i-1].T!=con))ShowMessage("Недопустимая лексема перед бинарной операцией!"), Abort();

if(N.T==clb &&
  (N[i-1].T!=clb && N[i-1].T!=num &&
   N[i-1].T!=var && N[i-1].T!=con))ShowMessage("Недопустимая лексема перед ')'!"), Abort();

if(N.T==alu &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед унарной операцией!"), Abort();

if(N.T==bou &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))N.I = -N.I, N.P = 2;
}
if(i==(N.size()-1)){
if((N.T != clb) && (N.T != num) &&
   (N.T != var) && (N.T != con))ShowMessage("Недопустима лексема в конце!"), Abort();
}

}
if(cbr != 0)ShowMessage("Несоответствие скобок!"), Abort();
}
//-----------------------
Real Get_num(string st){
string chislo; Unsi j = 0;
while ((st[j] == ',' || st[j] == '.' || isdigit (st[j])) && (st.length() - j) > 0){
if (st[j] == ',') st[j] = '.'; chislo += st[j++];}
return (Real)_strtold(chislo.c_str(),NULL);
}
//-----------------------
string Get_str(string st){
string chislo; Unsi j = 0;
while ((st[j] == ',' || st[j] == '.' || isdigit (st[j])) && (st.length() - j) > 0){
if (st[j] == ',') st[j] = '.'; chislo += st[j++];} return chislo;
}
//-----------------------
void fcalc(Valu &st, int op){
if (op < 0) {
Real l = st.back();  st.pop_back();
switch (-op) {
case 3:  st.push_back (l);  break;
case 4:  st.push_back (-l);  break;
           }
}else {
Real r = st.back();  st.pop_back();
Real l = st.back();  st.pop_back();
switch (op) {
case 3:  st.push_back (l + r);  break;
case 4:  st.push_back (l - r);  break;
case 5:  st.push_back (l * r);  break;
case 6:  if(r!=0)st.push_back (l / r);
else ShowMessage("Попытка деления на ноль!"), Abort();  break;
           }
    }

}
//-----------------------
Real ParsIt(){
Valu st; Lxms op;//  Code
for (Unsi i=0; i<N.size(); ++i)//идем вдоль строки
if(N.T == opb)op.push_back (&N);
else
if(N.T == clb){
while((*op.back()).T != opb) fcalc(st,(*op.back()).I), op.pop_back();
op.pop_back();
                 }else
if (N.T == bou || N.T == alu || N.T == alb){
while(!op.empty()                                &&
           (  N.I >= 0 && ((*op.back()).P >= N.P) ||
             N.I <  0 && ((*op.back()).P >  N.P))  )
             fcalc(st, (*op.back()).I),  op.pop_back();
      op.push_back(&N);
    }
    else
    if (N.T == num)
    {
     st.push_back (V[N.I]);
    }
    else
    if (N.T == var)
    {
     st.push_back (Lib.V[N.I]);
    }
    else
    if (N.T == con)
    {
     st.push_back (Lib.C[N.I]);
    }
    while (!op.empty())
          fcalc(st,(*op.back()).I), op.pop_back();
    return st.back();
}
//-----------------------
void Translate(string s){
Unsi   curL;//длина оставшейся части строки
string stp;//строка_пробная;
Type   code;
Lexeme *f;
curL = s.length();//определяем длину строки

if(curL>Lib.M)
  for (Unsi i=0;i<Lib.M;i++)stp += s;//берем первые M символов
else
  stp = s; f = Lib.Find(stp); code = f->T;
if(code > 0){//если найдена
  N.push_back(Lexeme(f->T,f->I,f->P));
  K.erase(0,stp.length());//удаляем из строки stp.length() символов
  curL = K.length();
  if
14
05 сентября 2011 года
Phodopus
3.3K / / 19.06.2008
А есть этот же код [COLOR="silver"]но с розовыми пуговицами?[/COLOR] но в хорошо отформатированном виде?
446
05 сентября 2011 года
Meander
487 / / 04.09.2011
Выше приведен рабочий код, в нем лишь нет некоторых дополнительных опций.
Ниже представлен проблемный вариант, с указанием места неправильной работы.

[COLOR="gray"]Это мое наследие, моя 7-я симфония, моя Эйфелева башня...[/COLOR]

Код:
#include <string>
#include "math.h"
#include <vector>
using namespace std;
enum                    Type { num,var,con, opb,clb, alu,alb,bou };//Возможные типы лексем
/*num-числовые,var-переменные,con-константы,
   opb-открывающие скобки,clb-закрывающие скобки,
   alu-всегда унарные,alb-всегда бинарные,bou-бинарно-унарные*/

enum                    Moda { alg, dif };//Возможные модальности строк
typedef int             Inst;//Инструкция парсеру
typedef int             Prop;//Приоретет операции
struct                  Lexeme;
typedef long double     Real;
typedef unsigned        Unsi;
typedef vector<Real>    Valu;
typedef vector<Lexeme*> Lxms;
typedef vector<Lexeme>  Numb;
typedef vector<Lexeme>  Libr;
//---------------------------------------------------------------------------
struct Lexeme
{
string S;
Type   T;
Inst   I;
Prop   P;
//-----------------------
Lexeme(string s,Type t,Inst i,Prop p){S=s;T=t;I=i;P=p;}
};
//---------------------------------------------------------------------------
struct Library
{
Unsi  M;//длина самого длинного слова
Libr L;
Valu C;
Valu V;
//-----------------------
void SetM(){
M = 0;
for(Unsi i=0;i<L.size();i++)
if (L.S.length() > M) M = L.S.length();
}
//-----------------------
Lexeme *Find(string s){
Lexeme *f;
for(Unsi i=0;i<L.size();i++)
if (L.S == s) f = &L;
return f;
}
//-----------------------
Library(){
//скобки
L.push_back(Lexeme("(",opb,1,0));
L.push_back(Lexeme("{",opb,1,0));
L.push_back(Lexeme("[",opb,1,0));
L.push_back(Lexeme(")",clb,2,0));
L.push_back(Lexeme("}",clb,2,0));
L.push_back(Lexeme("]",clb,2,0));
//арифметические
L.push_back(Lexeme("+",bou,-3,6));//if I=+3 -> P=2
L.push_back(Lexeme("-",bou,-4,6));//if I=+4 -> P=2
L.push_back(Lexeme("*",alb,5,3));
L.push_back(Lexeme("/",alb,6,3));
L.push_back(Lexeme("^",alb,7,4));
//функции
L.push_back(Lexeme("abs",alu,-8,6));//модуль
L.push_back(Lexeme("exp",alu,-9,6));//экспонента
L.push_back(Lexeme("ln",alu,-10,6));//натуральный логарифм
L.push_back(Lexeme("lg",alu,-11,6));//десятичный логарифм
L.push_back(Lexeme("log",alb,12,5));//логарифм по произвольному основанию
L.push_back(Lexeme("max",alb,13,5));//максимальное из двух чисел
L.push_back(Lexeme("min",alb,14,5));//минимальное из двух чисел
L.push_back(Lexeme("arccos",alu,-15,6));//арккосинус
L.push_back(Lexeme("arcsin",alu,-16,6));//арксинус
L.push_back(Lexeme("arctg",alu,-17,6));//арктангенс
L.push_back(Lexeme("arcctg",alu,-18,6));//арккотангенс
//константы
L.push_back(Lexeme("pi",con,C.size(),0));//число пи
C.push_back(M_PI);
SetM();
}
//-----------------------
} Lib;
//---------------------------------------------------------------------------
struct Baseline
{
string K;
Moda   D;
Valu   V;//числовые значения
Numb   N;//вектор лексем
//-----------------------
void Analyses(){
int cbr=0;//счетчик скобок
for (Unsi i=0;i<N.size();i++){
if(N.T==opb)cbr++; if(N.T==clb)cbr--;
if(i==0){
if(N.T==clb || N.T==alb)ShowMessage("Недопустима лексема в начале!"), Abort();
}else{
if(N.T==opb &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед '('!"), Abort();

if((N.T==num || N.T==var || N.T==con) &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед числом!"), Abort();

if(N.T==alb &&
  (N[i-1].T!=clb && N[i-1].T!=num &&
   N[i-1].T!=var && N[i-1].T!=con))ShowMessage("Недопустимая лексема перед бинарной операцией!"), Abort();

if(N.T==clb &&
  (N[i-1].T!=clb && N[i-1].T!=num &&
   N[i-1].T!=var && N[i-1].T!=con))ShowMessage("Недопустимая лексема перед ')'!"), Abort();

if(N.T==alu &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))ShowMessage("Недопустимая лексема перед унарной операцией!"), Abort();

if(N.T==bou &&
  (N[i-1].T==clb || N[i-1].T==num ||
   N[i-1].T==var || N[i-1].T==con))N.I = -N.I, N.P = 2;
}
if(i==(N.size()-1)){
if((N.T != clb) && (N.T != num) &&
   (N.T != var) && (N.T != con))ShowMessage("Недопустима лексема в конце!"), Abort();//<-если строка пуста, то это выскакивает
}

}
if(cbr != 0)ShowMessage("Несоответствие скобок!"), Abort();
}
//-----------------------
Real Get_num(string st){
string chislo; Unsi j = 0;
while ((st[j] == ',' || st[j] == '.' || isdigit (st[j])) && (st.length() - j) > 0){
if (st[j] == ',') st[j] = '.'; chislo += st[j++];}
return (Real)_strtold(chislo.c_str(),NULL);
}
//-----------------------
string Get_str(string st){
string chislo; Unsi j = 0;
while ((st[j] == ',' || st[j] == '.' || isdigit (st[j])) && (st.length() - j) > 0){
if (st[j] == ',') st[j] = '.'; chislo += st[j++];} return chislo;
}
//-----------------------
void fcalc(Valu &st, int op){
if (op < 0) {
Real l = st.back();  st.pop_back();
switch (-op) {
case 3:  st.push_back (l);  break;
case 4:  st.push_back (-l);  break;
           }
}else {
Real r = st.back();  st.pop_back();
Real l = st.back();  st.pop_back();
switch (op) {
case 3:  st.push_back (l + r);  break;
case 4:  st.push_back (l - r);  break;
case 5:  st.push_back (l * r);  break;
case 6:  if(r!=0)st.push_back (l / r);
else ShowMessage("Попытка деления на ноль!"), Abort();  break;
           }
    }
}
//-----------------------
Real ParsIt(){
Valu st; Lxms op;//  Code
for (Unsi i=0; i<N.size(); ++i)//идем вдоль строки
if(N.T == opb)op.push_back (&N);
else
if(N.T == clb){
while((*op.back()).T != opb) fcalc(st,(*op.back()).I), op.pop_back();
op.pop_back();
                 }else
if (N.T == bou || N.T == alu || N.T == alb){
while(!op.empty()                                &&
           (  N.I >= 0 && ((*op.back()).P >= N.P) ||
             N.I <  0 && ((*op.back()).P >  N.P))  )
             fcalc(st, (*op.back()).I),  op.pop_back();
      op.push_back(&N);
    }
    else
    if (N.T == num) st.push_back (V[N.I]);
    else
    if (N.T == var) st.push_back (Lib.V[N.I]);
    else
    if (N.T == con) st.push_back (Lib.C[N.I]);
    while (!op.empty()) fcalc(st,(*op.back()).I), op.pop_back();
    return st.back();
}
//-----------------------
void Translate(string s){
Unsi   curL;//длина оставшейся части строки
string stp;//строка_пробная;
Type   code;
Lexeme *f;
curL = s.length();//определяем длину строки

if(curL>Lib.M)
  for (Unsi i=0;i<Lib.M;i++)stp += s;//берем первые M символов
else
  stp = s; f = Lib.Find(stp); code = f->T;
if(code > 0){//если найдена
  N.push_back(Lexeme(f->S,f->T,f->I,f->P));//<-не инициализируется нормально
  K.erase(0,stp.length());//удаляем из строки stp.length() символов
  curL = K.length();
  if( curL > 0)
    Translate(K);
            }
else {//если не найдена
      if(stp.length() > 1){
      stp.erase(stp.length()-1,1);//удаляем из stp 1 символ
      Translate(stp);
                          }else{
      if(stp[0] == ' ')ShowMessage("Пробел не допустим!"), Abort();
        else
          if(!isdigit(stp[0]) && (stp.length() != 0) && stp[0] != ' ')
           { AnsiString err; err = stp.c_str();
             ShowMessage("Не допустимый символ: " + err), Abort();
           }else{
          N.push_back(Lexeme(Get_str(K),num,V.size(),0));
          V.push_back(Get_num(K));//записываем в стуктуру хранящую числа значение strtod(chislo,NULL) ;
          K.erase(0,Get_str(K).length()); curL = K.length();
          if( curL > 0) Translate(K);
                }
                               }
      }
}
//-----------------------
Baseline(AnsiString str){K
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог