Witam,
Mam problem, który nie bardzo wiem jak rozwiązać. Napisałem program do obliczania wartości wyrażenia matematycznego na podstawie podanego łańcucha tekstowego. Program jest jednak ograniczony do podstawowych działań arytmetycznych takich jak:
- dodawanie,
- odejmowanie,
- mnożenie,
- dzielenie,
- potęgowanie.
Chciałbym jednak rozszerzyć możliwości programu o obliczanie bardziej złożonych wartości wejściowych, np fukcji sinus, cosinus, logarytm itp... Wykorzystuję algorytm odwrotnej notacji polskiej do zamiany wyrażenia na postać postfixową (beznawiasową) jednak nie wiem jak poradzić sobie z funkcjami. Czy jest jakiś prosty sposób? Czytałem, że powinienem dalej wykorzystywać ONP (nawet z funkcjami sin, cos itp...) jednak nie wiem jak się za to zabrać. Jakieś pomysły, rozwiązania?
Kiedyś robiłem taki interpreter - w C++, więc mogę to sprzedać.
Przykład tablicy - definicji operatorów:
Symbol Symbole0[] = {
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, " " },
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, "pi"},
{ C_NUM, (TFun1)nic, L_OP,R_OP, 0, "e" },
{ N_OTW, (TFun1)nic, L_OP,L_OP, 0, "(" },
{ N_ZAM, (TFun1)nic, R_OP,R_OP, 0, ")" },
{1, sin, L_OP,L_OP, 50, "sin" },
{1, asin, L_OP,L_OP, 50, "asin" },
{1, sinh, L_OP,L_OP, 50, "sinh" },
{1, cos, L_OP,L_OP, 50, "cos" },
{1, acos, L_OP,L_OP, 50, "acos" },
{1, cosh, L_OP,L_OP, 50, "cosh" },
{1, tan, L_OP,L_OP, 50, "tg" },
{1, atan, L_OP,L_OP, 50, "atg" },
{1, tanh, L_OP,L_OP, 50, "tgh" },
{1, sqrt, L_OP,L_OP, 50, "sqrt" },
{1, kwad, L_OP,L_OP, 50, "sqr" },
{1, log, L_OP,L_OP, 50, "ln" },
{1, exp, L_OP,L_OP, 50, "exp" },
{1, fabs, L_OP,L_OP, 50, "abs" },
{1, sgn, L_OP,L_OP, 50, "sgn" },
{1, floor, L_OP,L_OP, 50, "int" },
{1, rndf, L_OP,L_OP, 50, "rnd" },
{',', (TFun1)nic, R_OP,L_OP, 20, ","},
{'=', (TFun1)nic, R_OP,L_OP, 20, "="}, // przypis
{'+', (TFun1)dodaj, R_OP,L_OP, 21, "+"},
{'-', (TFun1)odejm, R_OP,L_OP, 21, "-"},
{'*', (TFun1)mnoz, R_OP,L_OP, 22, "*"},
{'/', (TFun1)dziel, R_OP,L_OP, 22, "/"},
{'^', (TFun1)pow, R_OP,L_OP, 30, "^"},
{'%', (TFun1)fmod, R_OP,L_OP, 22, "mod"},
{'n', (TFun1)npok, R_OP,L_OP, 20, "po"},
{C_NEG, neg, L_OP,L_OP, 25, "-"},
{'!', sil, R_OP,R_OP, 90, "!"},
{ C_NIC, (TFun1)nic, R_OP,0, -1, "" }, // == END
{ C_NIC, (TFun1)nic, R_OP,0, -1, "=" }, // == END
{ C_LVAL, NULL, L_OP,R_OP, 0, "x"}, // zmienna -> nazwę można zmienić
{ C_LVAL, NULL, L_OP,R_OP, 0, "t"}, // zmienna 2
};
Jak widać funkcji jest całkiem sporo.
Mam też to samo ale w wersji nieco rozszerzonej - w tym do operacji na zespolonych, np. piszesz:
2sin(2+i) + i^i/6
no i to się obliczy bez problemu.
Sam kod zajmuje niewiele - kilka prostych funkcji.
Problem polega na podziale operatorów na dwie klasy: prawostronne i lewostronne;
W sumie są tylko 4 typy operatorów/symboli w matematyce,
np. liczba/zmienna jest operatorem typu: LR, a wszelkie funkcje: sin, cos, itp. to operatory LL;
operacje dwuargumentowe, czyli te tradycyjne: +, -, *, /, ^, są typu RL,
no i są jeszcze te końcowe jak np. silnia - to są operatory typu RR.
Więcej nie ma.