Forum: D Programlama Dili RSS
Girişten gelen aritmetik ifadeleri okutmak
erdem (Moderatör) #1
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Girişten gelen aritmetik ifadeleri okutmak
Girişten gelen aritmetik ifadeleri okutmak için en iyi yöntem nasıl olabilir acaba.

((1+kök(5))/2.0)

Örneğin bu gelen değerleri sayı ise bir double değişkene, kök, / gibi aritmetik işleç ise katar türünde bir değişkene atmak istiyorum.

( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )

( ( 1 + kök ( 5 ) ) / 2.0 )

Bu şekilde açık girilince okumak kolay oluyor ama örneğin en üstteki örnekteki gibi kullanıcının boşluk bırakmadan değerleri girdiğini, hatta bazı parantezleri yazmayı unuttuğunu düşünelim.

Bu durumda bu gelen değerleri okumak için en iyi yöntem nasıl olabilir acaba.
Mengu (Moderatör) #2
Kullanıcı başlığı: NONSERVIAM
Üye Tem 2009 tarihinden beri · 347 mesaj · Konum: Dersaadet
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
erdem:
Girişten gelen aritmetik ifadeleri okutmak için en iyi yöntem nasıl olabilir acaba.

((1+kök(5))/2.0)

Örneğin bu gelen değerleri sayı ise bir double değişkene, kök, / gibi aritmetik işleç ise katar türünde bir değişkene atmak istiyorum.

( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )

( ( 1 + kök ( 5 ) ) / 2.0 )

Bu şekilde açık girilince okumak kolay oluyor ama örneğin en üstteki örnekteki gibi kullanıcının boşluk bırakmadan değerleri girdiğini, hatta bazı parantezleri yazmayı unuttuğunu düşünelim.

Bu durumda bu gelen değerleri okumak için en iyi yöntem nasıl olabilir acaba.

keske d'de pattern matching olsaydi da kendi veri yapilarimizla cok kolay bir sekilde parse edebilseydik bu inputu. standart kutuphaneyle sen de yapabilirsin ama kanimca amerika'yi yeniden kesfetmek olur. o yuzden pegged [0] kullan derim.

ornekleri okudugunda ilk ornegin direkt senin yapmak istedigin oldugunu goreceksin. :)

[0] https://github.com/PhilippeSigaud/Pegged
http://www.mengu.net - some kind of monster
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Nasıl yapıldığını görmek için "recursive descent parser" diye aratabilirsin. Rasgele bir sayfa:

  https://www.strchr.com/expression_evaluator

Ali
erdem (Moderatör) #4
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #2
Evet oradaki arithmetic.d örneğini inceledim.

Örneğin ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) için sonucu hesaplıyor. 101 veriyor.

Ama bu hesaplamayı ben yapmak istiyorum. Hem de ( ( 1 + kök ( 5 ) ) / 2.0 ) gibi kullanıcı tanımlı değerler için de çalışmıyor. Ya da oradaki gramer yapısını mı değiştireceğiz bilmiyorum.
import pegged.grammar;
import std.stdio;
 
mixin(grammar(`
Arithmetic:
    Term     < Factor (Add / Sub)*
    Add      < "+" Factor
    Sub      < "-" Factor
    Factor   < Primary (Mul / Div)*
    Mul      < "*" Primary
    Div      < "/" Primary
    Primary  < Parens / Neg / Number / Variable
    Parens   < :"(" Term :")"
    Neg      < "-" Primary
    Number   < ~([0-9]+)
    Variable <- identifier
`));
 
float interpreter(string expr)
{
    auto p = Arithmetic(expr);
 
    //writeln(p);
 
    float value(ParseTree p)
    {
        switch (p.name)
        {
            case "Arithmetic":
                return value(p.children[0]);
            case "Arithmetic.Term":
                float v = 0.0;
                foreach(child; p.children) v += value(child);
                return v;
            case "Arithmetic.Add":
                return value(p.children[0]);
            case "Arithmetic.Sub":
                return -value(p.children[0]);
            case "Arithmetic.Factor":
                float v = 1.0;
                foreach(child; p.children) v *= value(child);
                return v;
            case "Arithmetic.Mul":
                return value(p.children[0]);
            case "Arithmetic.Div":
                return 1.0/value(p.children[0]);
            case "Arithmetic.Primary":
                return value(p.children[0]);
            case "Arithmetic.Parens":
                return value(p.children[0]);
            case "Arithmetic.Neg":
                return -value(p.children[0]);
            case "Arithmetic.Number":
                return to!float(p.matches[0]);
            default:
                return float.nan;
        }
    }
 
    return value(p);
}
 
void main()
{
    auto sonuc = interpreter("( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )");
    writeln (sonuc);
}
erdem (Moderatör) #5
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Benim çözümüm daha basitçe oldu:
import std.stdio;
 
string boslukluMetin(string metin)
{
    string sonuc;
    for (int i = 0; i < metin.length; ++i)
    {
        if (metin[i] == '(')
            sonuc ~= "( ";
        else if (metin[i] == ')')
            sonuc ~= " ) ";
        else if (metin[i] == '+')
            sonuc ~= " + ";
        else if (metin[i] == '/')
            sonuc ~= " / ";
        else if (metin[i] == 'k')
        {
            sonuc ~= " kök ";
            i += 3;
        }
        else
            sonuc ~= metin[i];
    }
    return sonuc;
}
 
void main()
{
    auto sonuc = boslukluMetin("((1+kök(5))/2.0)");
    writeln(sonuc);
}
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Biz ise okuduktan sonra o ifadeyi işletmek istiyorsun sandık. :)

Ali
erdem (Moderatör) #7
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
Biz ise okuduktan sonra o ifadeyi işletmek istiyorsun sandık. :)

Doğru düşünmüşsünüz :)

Gene de benim sormak istediğim girişten gelen ifadeyi parçalara ayırmakla ilgiliydi.

Bahsettiğiniz programı  Dijkstra'nın iki yığıt kullanan algoritmasını kullanarak yazdığımızda  buna benziyor.
import std.stdio;
import std.string;
import std.array;
import std.math;
import std.conv;
 
class Yığıt(T)
{
    private T[] elemanlar;
 
    @property bool boşMu() { return elemanlar.empty(); }
 
    void ekle(T üstteki) { elemanlar ~= üstteki; }
 
    T çıkar()
    {
        if (this.boşMu)
            throw new Exception("Boş yığıt.");
        auto üstteki = elemanlar.back;
        elemanlar.popBack();
        return üstteki;
    }
}
 
string boslukluMetin(string metin)
{
    string sonuc;
    for (int i = 0; i < metin.length; ++i)
    {
        if (metin[i] == '(')
            sonuc ~= "( ";
        else if (metin[i] == ')')
            sonuc ~= " ) ";
        else if (metin[i] == '+')
            sonuc ~= " + ";
        else if (metin[i] == '*')
            sonuc ~= " * ";
        else if (metin[i] == '/')
            sonuc ~= " / ";
        else if (metin[i] == 'k')
        {
            sonuc ~= " kök ";
            i += 3;
        }
        else if (metin[i] == '\n')
        {
        }
        else
            sonuc ~= metin[i];
    }
    return sonuc;
}
 
void main()
{
    auto işleçler = new Yığıt!string();
    auto değerler = new Yığıt!double();
 
    auto sonuc = split(boslukluMetin(readln()).idup);
    foreach (harf; sonuc)
    {
        if (harf == "(") {}
        else if (harf == "+" || harf == "-" || harf == "*" || harf == "/" || harf == "kök")
            işleçler.ekle(harf);
        else if (harf == ")")
        {
            auto işleç = işleçler.çıkar();
            double değer = değerler.çıkar();
            if      (işleç == "+") değer += değerler.çıkar();
            else if (işleç == "-") değer -= değerler.çıkar();
            else if (işleç == "*") değer *= değerler.çıkar();
            else if (işleç == "/") değer /= değerler.çıkar();
            else if (işleç == "kök") değer = sqrt(değer);
            değerler.ekle(değer);
        }
        else değerler.ekle(to!double(harf));
    }
 
    writeln(değerler.çıkar());
}
Yalnız benim merak ettiğim konu örneğin C stili dizilerde yığıt gerçeklemesini dizi kullanarak yapıldığı zaman her eleman eklendiğinde dizinin boyutunu bir arttırırsak o zaman yığıtın performansı düşüyor.

Bunun yerine diziye her eleman eklendiğinde sığayı iki katına çıkarıp, eleman çıkarıldığında ise dizi boyutu 1/4'üne kadar düştüğünde diziyi tekrar boyutlandırarak daha hızlı çalışan bir yığıt algoritması oluşturmuş oluyoruz.

Acaba D'deki durum da bu şekilde mi.
Bu mesaj erdem tarafından değiştirildi; zaman: 2016-02-22, 23:16.
Değişiklik nedeni: boşlukluMetin() işlevinde çarpma işlemini ekledim
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
erdem:
Bunun yerine diziye her eleman eklendiğinde sığayı iki katına çıkarıp, eleman çıkarıldığında ise dizi boyutu 1/4'üne kadar düştüğünde diziyi tekrar boyutlandırarak daha hızlı çalışan bir yığıt algoritması oluşturmuş oluyoruz.

Acaba D'deki durum da bu şekilde mi.
O işi diziler hallediyorlar: Üstelik, eleman için kullanılan bellek alanının hemen sonrası tesadüfen boşsa ikiye (veya başka bir katına) katlamadan önce orayı kullanıyorlar. (Bu arada, iki katına çıkartmak eski yöntem kabul edilir; %50 arttırmanın daha uygun olduğu gösterilmiştir.)

Ancak, D dizileri (ve C++'ın vector'ü) eleman çıkartma konusunda bellekle ilgili bir şey yapmazlar. Dizi, en uzun ne kadar olmuşsa o kadar bellek kullanmaya devam eder.

Ali
Avatar
zekeriyadurmus #9
Kullanıcı başlığı: Talha Zekeriya Durmuş
Üye Eki 2012 tarihinden beri · 701 mesaj · Konum: Samsun/Türkiye
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Vakti zamanında https://www.talhadurmus.com/matematiksel-ifadelerin-ayrist…  bir yazı yazmıştım basit bir yorumlayıcı yazımı üzerine.

Bu kadar karmaşık bir şey istemediğine eminim ancak bakmanda yarar olabilir.
Bilgi meraktan gelir...
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-19, 19:52:33 (UTC -08:00)