Thread overview
Girişten gelen aritmetik ifadeleri okutmak
Feb 22, 2016
erdem
Feb 22, 2016
Mengu
Feb 22, 2016
erdem
Feb 22, 2016
erdem
Feb 22, 2016
erdem
February 22, 2016

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.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

Alıntı (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

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

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);
}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

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);
}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

Nasıl yapıldığını görmek için "recursive descent parser" diye aratabilirsin. Rasgele bir sayfa:

https://www.strchr.com/expression_evaluator

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

Alıntı (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 gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

Biz ise okuduktan sonra o ifadeyi işletmek istiyorsun sandık. :)

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 22, 2016

Alıntı (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

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

March 03, 2016

Vakti zamanında https://www.talhadurmus.com/matematiksel-ifadelerin-ayristirilmasi-kendi-dilini-tasarla 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.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]