Parrot - Hızlı Kılavuz

Programımızı geleneksel Perl ile beslediğimizde, önce dahili bir temsil veya bayt kodu olarak derlenir; bu bayt kodu daha sonra yorumlanmak üzere Perl içinde neredeyse ayrı bir alt sisteme beslenir. Yani Perl'in çalışmasının iki farklı aşaması vardır:

  • Bayt koduna derleme ve

  • Bayt kodunun yorumlanması.

Bu Perl'e özgü değildir. Bu tasarımı takip eden diğer diller arasında Python, Ruby, Tcl ve hatta Java bulunur.

Java bayt kodunu makine diline çevirip çalıştıran, platformdan bağımsız bir yürütme ortamı olan Java Sanal Makinesi (JVM) olduğunu da biliyoruz. Bu kavramı anlarsanız, Parrot'u anlayacaksınız.

Parrotyorumlanan diller için bayt kodunu verimli bir şekilde derlemek ve yürütmek için tasarlanmış sanal bir makinedir. Parrot, son Perl 6 derleyicisinin hedefidir ve Pugs ve Tcl, Ruby, Python vb. Gibi çeşitli diğer diller için arka uç olarak kullanılır.

Papağan, en popüler dil olan "C" kullanılarak yazılmıştır.

Başlamadan önce Parrot'un son bir kopyasını indirip makinemize kuralım.

Parrot indirme bağlantısı Parrot CVS Snapshot'ta mevcuttur . Parrot'un en son sürümünü indirin ve kurmak için aşağıdaki adımları izleyin:

  • İndirilen dosyanın sıkıştırmasını açın ve açın.

  • Makinenizde zaten Perl 5'in kurulu olduğundan emin olun.

  • Şimdi şunları yapın:

% cd parrot
% perl Configure.pl
Parrot Configure
Copyright (C) 2001 Yet Another Society
Since you're running this script, you obviously have
Perl 5 -- I'll be pulling some defaults from its configuration.
...
  • Daha sonra yerel yapılandırmanızla ilgili bir dizi soru sorulacak; neredeyse her zaman her biri için return / enter tuşuna basabilirsiniz.

  • Son olarak, make test_prog yazmanız söylenecek ve Parrot test yorumlayıcısını başarıyla oluşturacaktır.

  • Şimdi bazı testler yapmalısınız; bu nedenle 'test yap' yazın ve aşağıdaki gibi bir okuma görmelisiniz:

perl t/harness
t/op/basic.....ok,1/2 skipped:label constants unimplemented in
assembler
t/op/string....ok, 1/4 skipped:  I'm unable to write it!
All tests successful, 2 subtests skipped.
Files=2, Tests=6,......

Bunu okuduğunuzda, daha fazla test olabilir ve atlananlardan bazıları atlamayabilir, ancak hiçbirinin başarısız olmamasına dikkat edin!

Bir papağan yürütülebilir dosyasını yükledikten sonra, Parrot 'Örnekler' bölümünde verilen çeşitli örnek türlerine göz atabilirsiniz . Parrot deposundaki örnekler dizinine de bakabilirsiniz.

Parrot şu anda dört şekilde uygulama talimatlarını kabul edebiliyor. PIR (Parrot Intermediate Representation) insanlar tarafından yazılacak ve derleyiciler tarafından oluşturulacak şekilde tasarlanmıştır. Parametrelerin işlevlere aktarılma şekli gibi bazı düşük düzeyli ayrıntıları gizler.

PASM (Parrot Assembly), PIR'ın altındaki bir seviyedir - hala insan tarafından okunabilir / yazılabilir ve bir derleyici tarafından oluşturulabilir, ancak yazarın çağrı kuralları ve kayıt tahsisi gibi ayrıntılarla ilgilenmesi gerekir. PAST (Parrot Abstract Syntax Tree), Parrot'un soyut sözdizimi ağaç stili girdisini kabul etmesini sağlar - derleyiciler yazanlar için yararlıdır.

Yukarıdaki giriş biçimlerinin tümü, Parrot içinde otomatik olarak PBC'ye (Parrot Bytecode) dönüştürülür. Bu, makine koduna çok benzer, ancak Parrot yorumlayıcısı tarafından anlaşılır.

İnsan tarafından okunabilir veya insanlar tarafından yazılabilir olması amaçlanmamıştır, ancak diğer formlardan farklı olarak uygulama, bir montaj aşamasına ihtiyaç duymadan hemen başlayabilir. Parrot bayt kodu platformdan bağımsızdır.

Talimat seti

Parrot komut seti aritmetik ve mantıksal operatörler, karşılaştırma ve dallanma / atlama (döngüleri uygulamak için, eğer ... sonra inşa eder, vb.), Genel ve sözcüksel değişkenleri bulma ve depolama, sınıflar ve nesnelerle çalışma, alt rutinleri ve yöntemleri çağırma parametreleri, G / Ç, iş parçacıkları ve daha fazlası ile.

Java Virtual Machine gibi, Parrot da sizi bellek tahsisi konusunda endişelenmekten kurtarır.

  • Parrot, çöp toplama sağlar.

  • Parrot programlarının hafızayı açık bir şekilde boşaltmasına gerek yoktur.

  • Ayrılan bellek, artık kullanılmadığında yani artık referans gösterilmediğinde serbest bırakılacaktır.

  • Parrot Garbage Collector, istenmeyen hafızayla ilgilenmek için periyodik olarak çalışır.

Parrot CPU'nun dört temel veri türü vardır:

  • IV

    Bir tamsayı türü; bir işaretçiyi tutacak kadar geniş olması garantilidir.

  • NV

    Mimariden bağımsız bir kayan nokta türü.

  • STRING

    Soyutlanmış, kodlamadan bağımsız bir dize türü.

  • PMC

    Skaler.

İlk üç tür hemen hemen kendinden açıklamalıdır; son tür - Parrot Magic Cookies'in anlaşılması biraz daha zordur.

PMC'ler nedir?

PMC, Parrot Magic Cookie anlamına gelir. PMC'ler, toplu veri türleri (diziler, karma tablolar vb.) Dahil olmak üzere herhangi bir karmaşık veri yapısını veya türünü temsil eder. Bir PMC, üzerinde gerçekleştirilen aritmetik, mantıksal ve dizgi işlemleri için kendi davranışını uygulayabilir ve dile özgü davranışın uygulanmasına izin verir. PMC'ler, Parrot yürütülebilir dosyasında yerleşik olabilir veya gerektiğinde dinamik olarak yüklenebilir.

Mevcut Perl 5 sanal makine bir yığın makinesidir. İşlemler arasında değerleri bir yığın üzerinde tutarak iletişim kurar. İşlemler değerleri yığına yükler, yapmaları gereken her şeyi yapar ve sonucu yığına geri koyar. Bununla çalışmak kolay ama yavaştır.

İki sayıyı birbirine eklemek için, üç yığın itme ve iki yığın çıkarma yapmanız gerekir. Daha da kötüsü, yığının çalışma zamanında büyümesi gerekir ve bu, belleği ayırmak istemediğinizde bellek ayırmak anlamına gelir.

Yani Parrot, sanal makineler için yerleşik geleneği kıracak ve gerçek bir donanım CPU mimarisine daha çok benzer bir kayıt mimarisi kullanacak. Bunun başka bir avantajı var. Yazılım CPU'larımız için kayıt tabanlı CPU'lar için derleyicilerin ve optimize edicilerin nasıl yazılacağına dair tüm mevcut literatürü kullanabiliriz!

Parrot, her tür için uzman kayıtlara sahiptir: 32 IV kaydı, 32 NV kaydı, 32 dizi kaydı ve 32 PMC kaydı. Parrot assembler'da bunlar sırasıyla I1 ... I32, N1 ... N32, S1 ... S32, P1 ... P32 olarak adlandırılır.

Şimdi bir montajcıya bakalım. Bu kayıtları set operatörü ile ayarlayabiliriz:

set I1, 10
	set N1, 3.1415
	set S1, "Hello, Parrot"

Tüm Parrot operasyonları aynı formata sahiptir: operatörün adı, hedef kayıt ve ardından işlenenler.

Gerçekleştirebileceğiniz çeşitli işlemler vardır. Örneğin, bir kaydın veya sabitin içeriğini yazdırabiliriz:

set I1, 10
print "The contents of register I1 is: "
print I1
print "\n"

Yukarıdaki talimatlar I1 yazmacının içeriği şu şekilde sonuçlanacaktır : 10

Kayıtlar üzerinde matematiksel işlemler yapabiliriz:

# Add the contents of I2 to the contents of I1
add I1, I1, I2
# Multiply I2 by I4 and store in I3
mul I3, I2, I4
# Increment I1 by one
inc I1
# Decrement N3 by 1.5
dec N3, 1.5

Hatta bazı basit dize manipülasyonları bile yapabiliriz:

set S1, "fish"
set S2, "bone"
concat S1, S2       # S1 is now "fishbone"
set S3, "w"
substr S4, S1, 1, 7
concat S3, S4       # S3 is now "wishbone"
length I1, S3       # I1 is now 8

Akış kontrolü olmadan kod biraz sıkıcı hale gelir; yeni başlayanlar için, Parrot dallanma ve etiketleri biliyor. Şube operasyonu Perl'in goto'suna eşdeğerdir:

branch TERRY
JOHN:    print "fjords\n"
         branch END
MICHAEL: print " pining"
         branch GRAHAM
TERRY:   print "It's"
         branch MICHAEL
GRAHAM:  print " for the "
         branch JOHN
END:     end

Ayrıca, bir kaydın gerçek bir değer içerip içermediğini görmek için basit testler gerçekleştirebilir:

set I1, 12
         set I2, 5
         mod I3, I2, I2
         if I3, REMAIND, DIVISOR
REMAIND: print "5 divides 12 with remainder "
         print I3
         branch DONE
DIVISOR: print "5 is an integer divisor of 12"
DONE:    print "\n"
         end

Karşılaştırma için Perl'de nasıl görüneceği aşağıda açıklanmıştır:

$i1 = 12;
    $i2 = 5;
    $i3 = $i1 % $i2;
    if ($i3) {
      print "5 divides 12 with remainder ";
      print $i3;
    } else {
      print "5 is an integer divisor of 12";
    }
    print "\n";
    exit;

Papağan Operatörü

Tüm sayısal karşılaştırıcılara sahibiz: eq, ne, lt, gt, le ve ge. Bu operatörleri farklı türlerdeki argümanlar üzerinde kullanamayacağınızı unutmayın; Hatta, ne tür bir argüman kullandığınızı söylemek için op'a _i veya _n sonekini eklemeniz bile gerekebilir, gerçi siz bunu okuduğunuzda assembler bunu sizin için tanrılaştırmalı.

Parrot programlama, assembly dili programlamasına benzer ve daha düşük seviyede çalışma şansınız olur. Parrot Programlamanın çeşitli yönlerinden haberdar olmanızı sağlayacak programlama örneklerinin listesi burada.

  • Klasik Merhaba dünya!
  • Kayıtları kullanma
  • Toplam kareler
  • Fibonacci Sayıları
  • Faktöriyel hesaplama
  • PBC'ye Derleme
  • PIR ve PASM

Klasik Merhaba dünya!

Aşağıdaki kodu içeren hello.pir adında bir dosya oluşturun:

.sub _main
      print "Hello world!\n"
      end
  .end

Ardından şunu yazarak çalıştırın:

parrot hello.pir

Beklendiği gibi, bu "Merhaba dünya!" Metnini görüntüleyecektir. konsolda, ardından yeni bir satır (\ n nedeniyle).

Yukarıdaki örnekte, '.sub _main', bir '.end' ile karşılaşılıncaya kadar, takip eden talimatların '_main' adlı bir alt yordamı oluşturduğunu belirtir. İkinci satır, yazdırma talimatını içerir. Bu durumda, sabit bir dizeyi kabul eden talimatın varyantını çağırıyoruz. Montajcı, talimatın hangi varyantını bizim için kullanacağına karar verir. Üçüncü satır, yorumlayıcının sonlandırmasına neden olan 'son' talimatını içerir.

Kayıtları Kullanma

Hello.pir'i ilk önce Hello world! \ N dizgesini bir kayıtta saklayacak ve sonra bu kaydı yazdırma talimatıyla birlikte kullanacak şekilde değiştirebiliriz.

.sub _main
      set S1, "Hello world!\n"
      print S1
      end
  .end

Burada tam olarak hangi kaydın kullanılacağını belirttik. Bununla birlikte, S1'i $ S1 ile değiştirerek, Parrot'a hangi kaydın kullanılacağına ilişkin seçim yetkisi verebiliriz. Ayrıca set talimatını yazmak yerine bir notasyon kullanmak da mümkündür.

.sub _main
      $S0 = "Hello world!\n"
      print $S0
      end
  .end

PIR'ı daha da okunabilir hale getirmek için, adlandırılmış kayıtlar kullanılabilir. Bunlar daha sonra gerçek numaralı kayıtlarla eşleştirilir.

.sub _main
      .local string hello
      hello = "Hello world!\n"
      print hello
      end
  .end

'.Local' yönergesi, adlandırılmış yazmacın yalnızca mevcut derleme biriminde (yani .sub ve .end arasında) gerekli olduğunu belirtir. Aşağıdaki ".local" bir türdür. Bu int (I kayıtları için), float (N kayıtları için), dize (S kayıtları için), pmc (P kayıtları için) veya bir PMC tipi adı olabilir.

Toplam kareler

Bu örnek, biraz daha fazla talimat ve PIR sözdizimi sunar. # İle başlayan satırlar yorumlardır.

.sub _main
      # State the number of squares to sum.
      .local int maxnum
      maxnum = 10

      # Some named registers we'll use. 
      # Note how we can declare many
      # registers of the same type on one line.
      .local int i, total, temp
      total = 0

      # Loop to do the sum.
      i = 1
  loop:
      temp = i * i
      total += temp
      inc i
      if i <= maxnum goto loop

      # Output result.
      print "The sum of the first "
      print maxnum
      print " squares is "
      print total
      print ".\n"
      end
  .end

PIR, montajdan daha yüksek seviyede görünmesini sağlayan bir miktar sözdizimsel şeker sağlar. Örneğin:

temp = i * i

Daha montajlı yazmanın başka bir yolu:

mul temp, i, i

Ve:

if i <= maxnum goto loop

Aynıdır:

le i, maxnum, loop

Ve:

total += temp

Aynıdır:

add total, temp

Kural olarak, bir Parrot talimatı bir kaydın içeriğini her değiştirdiğinde, bu, talimatı montaj biçiminde yazarken ilk kayıt olacaktır.

Montaj dillerinde olağan olduğu gibi, döngüler ve seçimler, yukarıda gösterildiği gibi koşullu dal ifadeleri ve etiketler açısından uygulanır. Assembly programlama, goto kullanmanın kötü bir form olmadığı bir yerdir!

Fibonacci Sayıları

Fibonacci serisi şu şekilde tanımlanır: 1 ve 1 olmak üzere iki sayı alın.Sonra bir sonrakini yapmak için serideki son iki sayıyı tekrar tekrar ekleyin: 1, 1, 2, 3, 5, 8, 13, vb. . Fibonacci numarası fib (n), serideki n'inci sayıdır. İşte ilk 20 Fibonacci sayısını bulan basit bir Parrot assembler programı:

# Some simple code to print some Fibonacci numbers

        print   "The first 20 fibonacci numbers are:\n"
        set     I1, 0
        set     I2, 20
        set     I3, 1
        set     I4, 1
REDO:   eq      I1, I2, DONE, NEXT
NEXT:   set     I5, I4
        add     I4, I3, I4
        set     I3, I5
        print   I3
        print   "\n"
        inc     I1
        branch  REDO
DONE:   end

Bu, Perl'deki eşdeğer koddur:

print "The first 20 fibonacci numbers are:\n";
        my $i = 0;
        my $target = 20;
        my $a = 1;
        my $b = 1;
        until ($i == $target) {
           my $num = $b;
           $b += $a;
           $a = $num;
           print $a,"\n";
           $i++;
        }

NOTE:İnce bir ilgi noktası olarak, Perl'de bir Fibonacci serisini yazdırmanın en kısa ve kesinlikle en güzel yollarından biri perl -le '$ b = 1'dir; print $ a + = $ b iken print $ b + = $ a '.

Özyinelemeli hesaplama faktöryel

Bu örnekte faktöriyel bir fonksiyon tanımlıyoruz ve onu faktöriyel hesaplamak için yinelemeli olarak çağırıyoruz.

.sub _fact
      # Get input parameter.
      .param int n

      # return (n > 1 ? n * _fact(n - 1) : 1)
      .local int result

      if n > 1 goto recurse
      result = 1
      goto return

  recurse:
      $I0 = n - 1
      result = _fact($I0)
      result *= n

  return:
      .return (result)
  .end


  .sub _main :main
      .local int f, i

      # We'll do factorial 0 to 10.
      i = 0
  loop:
      f = _fact(i)

      print "Factorial of "
      print i
      print " is "
      print f
      print ".\n"

      inc i
      if i <= 10 goto loop

      # That's it.
      end
  .end

Önce _fact alt kısmına bakalım. Daha önce gözden geçirilen bir nokta, alt yordamların adlarının neden hepsinin bir alt çizgiyle başlamasıdır! Bu, belirli bir alt yordamı kapsamaktan çok, etiketin küresel olduğunu göstermenin bir yolu olarak yapılır. Etiket daha sonra diğer alt programlar tarafından görülebileceği için bu önemlidir.

İlk satır, .param int n, bu alt yordamın bir tamsayı parametresi aldığını ve alt yordamın geri kalanı için n adıyla geçirildiği kayda başvurmak istediğimizi belirtir.

Aşağıdakilerin çoğu, satır okuması dışında önceki örneklerde görülmüştür:

result = _fact($I0)

Bu tek PIR satırı aslında epeyce PASM satırını temsil eder. İlk olarak, $ I0 yazmacındaki değer, _fact fonksiyonu tarafından bir tamsayı parametresi olarak alınabilmesi için uygun kayda taşınır. Diğer arama ile ilgili kayıtlar daha sonra kurulur ve ardından _fact çağrılır. Ardından, _fact döndüğünde, _fact tarafından döndürülen değer, sonuç adıyla birlikte kayda yerleştirilir.

_Fact alt kısmının .endinden hemen önce, kayıtta tutulan değeri sağlamak için bir .return yönergesi kullanılır; adlandırılmış sonuç, alt'ı çağıran kod tarafından bir dönüş değeri olarak görülebilmesi için doğru kayda yerleştirilir.

_Fact in main çağrısı, sub _fact içinde _fact için yinelemeli çağrı ile aynı şekilde çalışır. Yeni sözdiziminin geriye kalan tek biti: main, .sub _main'den sonra yazılır. Varsayılan olarak PIR, yürütmenin dosyadaki ilk alt ile başladığını varsayar. Bu davranış, başlangıç ​​olarak alt işaretlenerek değiştirilebilir: ana.

PBC'ye Derleme

PIR'ı bayt koduna derlemek için -o işaretini kullanın ve .pbc uzantılı bir çıktı dosyası belirtin.

parrot -o factorial.pbc factorial.pir

PIR ve PASM

PIR, aşağıdakileri çalıştırarak PASM'ye dönüştürülebilir:

parrot -o hello.pasm hello.pir

Son örnek için PASM şuna benzer:

_main:
      set S30, "Hello world!\n"
      print S30
      end

PASM, kayıt tahsisini işlemez veya adlandırılmış kayıtlar için destek sağlamaz. Ayrıca, .sub ve .end direktiflerine sahip değildir, bunun yerine talimatların başında bir etiketle değiştirilir.