#include "fiko/parametre/ifade.hpp" #include #include #include #include namespace fiko::parametre { namespace { // Recursive-descent değerlendirici: tek geçişte parse+eval (ayrı AST yok — basit+hızlı). // Dilbilgisi (öncelik artan): ifade → terim → ussu → birli → atom. struct Cozumleyici { const std::string& s; const std::map& deg; size_t i = 0; bool hata = false; std::string hataMsj; void bosluk() { while (i < s.size() && std::isspace((unsigned char)s[i])) ++i; } char bak() { bosluk(); return i < s.size() ? s[i] : '\0'; } void hataVer(const std::string& m) { if (!hata) { hata = true; hataMsj = m; } } f64 karsilastirma() { // < > <= >= == != (en düşük öncelik → tasarım kuralları/if) const f64 sol = ifade(); const char c = bak(); if (c == '<' || c == '>' || c == '=' || c == '!') { ++i; const bool esitli = (i < s.size() && s[i] == '='); if (esitli) ++i; const f64 sag = ifade(); switch (c) { case '<': return (esitli ? sol <= sag : sol < sag) ? 1.0 : 0.0; case '>': return (esitli ? sol >= sag : sol > sag) ? 1.0 : 0.0; case '=': if (esitli) return sol == sag ? 1.0 : 0.0; hataVer("tek '=' geçersiz (== kullan)"); return 0; case '!': if (esitli) return sol != sag ? 1.0 : 0.0; hataVer("tek '!' geçersiz (!= kullan)"); return 0; } } return sol; } f64 ifade() { // toplama / çıkarma f64 v = terim(); while (!hata) { const char c = bak(); if (c == '+') { ++i; v += terim(); } else if (c == '-') { ++i; v -= terim(); } else break; } return v; } f64 terim() { // çarpma / bölme / mod f64 v = birli(); while (!hata) { const char c = bak(); if (c == '*') { ++i; v *= birli(); } else if (c == '/') { ++i; const f64 b = birli(); if (b == 0.0) hataVer("sıfıra bölme"); else v /= b; } else if (c == '%') { ++i; v = std::fmod(v, birli()); } else break; } return v; } f64 birli() { // birli artı/eksi (üs'ten DÜŞÜK öncelik: -2^2 = -(2^2)) const char c = bak(); if (c == '-') { ++i; return -birli(); } if (c == '+') { ++i; return birli(); } return ussu(); } f64 ussu() { // üs ^ (sağ-birleşimli 2^3^2=2^(3^2); üs birli → 2^-3 mümkün) const f64 v = atom(); if (bak() == '^') { ++i; return std::pow(v, birli()); } return v; } f64 atom() { const char c = bak(); if (c == '(') { ++i; const f64 v = karsilastirma(); // parantez içinde karşılaştırma/if de olabilir if (bak() == ')') ++i; else hataVer("kapanmayan parantez"); return v; } if (std::isdigit((unsigned char)c) || c == '.') return sayi(); if (std::isalpha((unsigned char)c) || c == '_') return tanimlayici(); hataVer(std::string("beklenmeyen karakter: ") + (c ? c : '?')); return 0; } f64 sayi() { bosluk(); const size_t bas = i; while (i < s.size()) { const char c = s[i]; if (std::isdigit((unsigned char)c) || c == '.') { ++i; continue; } if ((c == 'e' || c == 'E') && i > bas) { ++i; // üstel gösterim (1e3, 2.5E-4) if (i < s.size() && (s[i] == '+' || s[i] == '-')) ++i; continue; } break; } try { return std::stod(s.substr(bas, i - bas)); } catch (...) { hataVer("geçersiz sayı"); return 0; } } std::string adOku() { bosluk(); const size_t bas = i; while (i < s.size() && (std::isalnum((unsigned char)s[i]) || s[i] == '_')) ++i; return s.substr(bas, i - bas); } f64 tanimlayici() { const std::string ad = adOku(); if (bak() == '(') return fonksiyon(ad); // fonksiyon çağrısı if (ad == "pi") return std::numbers::pi; if (ad == "e") return std::numbers::e; const auto it = deg.find(ad); if (it != deg.end()) return it->second; hataVer("bilinmeyen değişken: " + ad); return 0; } f64 fonksiyon(const std::string& ad) { ++i; // '(' std::vector a; if (bak() != ')') { a.push_back(karsilastirma()); while (bak() == ',') { ++i; a.push_back(karsilastirma()); } } if (bak() == ')') ++i; else hataVer("fonksiyon parantezi kapanmadı"); const auto arg1 = [&](f64 (*f)(f64)) -> f64 { if (a.size() == 1) return f(a[0]); hataVer(ad + ": 1 argüman bekleniyor"); return 0; }; if (ad == "sin") return arg1([](f64 x) { return std::sin(x); }); if (ad == "cos") return arg1([](f64 x) { return std::cos(x); }); if (ad == "tan") return arg1([](f64 x) { return std::tan(x); }); if (ad == "asin") return arg1([](f64 x) { return std::asin(x); }); if (ad == "acos") return arg1([](f64 x) { return std::acos(x); }); if (ad == "atan") return arg1([](f64 x) { return std::atan(x); }); if (ad == "sqrt") return arg1([](f64 x) { return std::sqrt(x); }); if (ad == "abs") return arg1([](f64 x) { return std::fabs(x); }); if (ad == "exp") return arg1([](f64 x) { return std::exp(x); }); if (ad == "log") return arg1([](f64 x) { return std::log(x); }); if (ad == "log10") return arg1([](f64 x) { return std::log10(x); }); if (ad == "floor") return arg1([](f64 x) { return std::floor(x); }); if (ad == "ceil") return arg1([](f64 x) { return std::ceil(x); }); if (ad == "round") return arg1([](f64 x) { return std::round(x); }); if (ad == "deg") return arg1([](f64 x) { return x * std::numbers::pi / 180.0; }); // derece→radyan if (ad == "rad") return arg1([](f64 x) { return x * 180.0 / std::numbers::pi; }); // radyan→derece if (ad == "isaret") return arg1([](f64 x) { return (f64)((x > 0) - (x < 0)); }); if (ad == "atan2") { if (a.size() == 2) return std::atan2(a[0], a[1]); hataVer("atan2: 2 argüman"); return 0; } if (ad == "pow") { if (a.size() == 2) return std::pow(a[0], a[1]); hataVer("pow: 2 argüman"); return 0; } if (ad == "min") { if (a.size() == 2) return std::min(a[0], a[1]); hataVer("min: 2 argüman"); return 0; } if (ad == "max") { if (a.size() == 2) return std::max(a[0], a[1]); hataVer("max: 2 argüman"); return 0; } if (ad == "clamp") { if (a.size() == 3) return std::min(std::max(a[0], a[1]), a[2]); hataVer("clamp: 3 argüman (deger, alt, ust)"); return 0; } // Koşullu/mantık (tasarım kuralları): koşul != 0 → doğru. if (ad == "if" || ad == "eger") { if (a.size() == 3) return a[0] != 0.0 ? a[1] : a[2]; hataVer(ad + ": 3 argüman (kosul, dogru, yanlis)"); return 0; } if (ad == "ve") { if (a.size() == 2) return (a[0] != 0.0 && a[1] != 0.0) ? 1.0 : 0.0; hataVer("ve: 2 argüman"); return 0; } if (ad == "veya") { if (a.size() == 2) return (a[0] != 0.0 || a[1] != 0.0) ? 1.0 : 0.0; hataVer("veya: 2 argüman"); return 0; } if (ad == "degil") return arg1([](f64 x) { return x != 0.0 ? 0.0 : 1.0; }); hataVer("bilinmeyen fonksiyon: " + ad); return 0; } }; } // namespace IfadeSonuc hesapla(const std::string& ifade, const std::map& degiskenler) { IfadeSonuc s; Cozumleyici p{ifade, degiskenler}; if (p.bak() == '\0') { s.hata = "boş ifade"; return s; } const f64 v = p.karsilastirma(); p.bosluk(); if (p.hata) { s.hata = p.hataMsj; return s; } if (p.i != ifade.size()) { s.hata = "beklenmeyen artık karakter"; return s; } if (!std::isfinite(v)) { s.hata = "sonuç sonlu değil (NaN/Inf)"; return s; } s.deger = v; s.basarili = true; return s; } std::vector bagimliliklar(const std::string& ifade) { std::vector sonuc; size_t i = 0; while (i < ifade.size()) { const char c = ifade[i]; if (std::isalpha((unsigned char)c) || c == '_') { const size_t bas = i; while (i < ifade.size() && (std::isalnum((unsigned char)ifade[i]) || ifade[i] == '_')) ++i; const std::string ad = ifade.substr(bas, i - bas); // Sonraki '(' → fonksiyon (boşluk atla); sabitler pi/e; ikisi de bağımlılık değil. size_t j = i; while (j < ifade.size() && std::isspace((unsigned char)ifade[j])) ++j; const bool fonksiyon = j < ifade.size() && ifade[j] == '('; if (!fonksiyon && ad != "pi" && ad != "e") { bool var = false; for (const auto& x : sonuc) if (x == ad) { var = true; break; } if (!var) sonuc.push_back(ad); } } else { ++i; } } return sonuc; } } // namespace fiko::parametre