Parrot - ตัวอย่างการเขียนโปรแกรม

การเขียนโปรแกรม Parrot นั้นคล้ายกับการเขียนโปรแกรมภาษาแอสเซมบลีและคุณมีโอกาสทำงานในระดับต่ำกว่า นี่คือรายการตัวอย่างการเขียนโปรแกรมเพื่อให้คุณทราบถึงแง่มุมต่างๆของ Parrot Programming

  • คลาสสิกสวัสดีชาวโลก - - '

  • ใช้รีจิสเตอร์

  • กำลังสองรวม

  • Fibonacci Numbers

  • การคำนวณแฟกทอเรียล

  • รวบรวมไปยัง PBC

  • PIR กับ PASM

คลาสสิกสวัสดีชาวโลก - - '

สร้างไฟล์ชื่อ hello.pir ที่มีรหัสต่อไปนี้:

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

จากนั้นเรียกใช้โดยพิมพ์:

parrot hello.pir

ตามที่คาดไว้สิ่งนี้จะแสดงข้อความ "Hello world!" บนคอนโซลตามด้วยบรรทัดใหม่ (เนื่องจาก \ n)

ในตัวอย่างข้างต้นนี้ ".sub _main" ระบุว่าคำสั่งที่ตามมาประกอบเป็นรูทีนย่อยชื่อ '_main' จนกว่าจะพบ ".end" บรรทัดที่สองประกอบด้วยคำแนะนำในการพิมพ์ ในกรณีนี้เรากำลังเรียกตัวแปรของคำสั่งที่ยอมรับสตริงคงที่ แอสเซมเบลอร์จะดูแลในการตัดสินใจว่าจะใช้ชุดคำสั่งใดสำหรับเรา บรรทัดที่สามมีคำสั่ง 'end' ซึ่งทำให้ล่ามยุติการทำงาน

การใช้รีจิสเตอร์

เราสามารถแก้ไข hello.pir เพื่อจัดเก็บสตริง Hello world! \ n ในรีจิสเตอร์ก่อนแล้วใช้รีจิสเตอร์นั้นกับคำสั่งการพิมพ์

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

ที่นี่เราได้ระบุไว้อย่างชัดเจนว่าจะใช้การลงทะเบียนใด อย่างไรก็ตามการแทนที่ S1 ด้วย $ S1 เราสามารถมอบสิทธิ์ตัวเลือกในการลงทะเบียนเพื่อใช้กับ Parrot ได้ นอกจากนี้ยังสามารถใช้สัญกรณ์ = แทนการเขียนชุดคำสั่งได้

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

เพื่อให้ PIR อ่านได้ง่ายยิ่งขึ้นสามารถใช้ชื่อรีจิสเตอร์ สิ่งเหล่านี้ถูกจับคู่กับการลงทะเบียนที่มีหมายเลขจริงในภายหลัง

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

คำสั่ง ".local" ระบุว่าจำเป็นต้องมีการลงทะเบียนที่ระบุชื่อภายในหน่วยคอมไพล์ปัจจุบันเท่านั้น (นั่นคือระหว่าง. sub และ. end) การติดตาม ".local" เป็นประเภทหนึ่ง ซึ่งอาจเป็น int (สำหรับ I register), float (สำหรับ N register), string (สำหรับ S register), pmc (สำหรับ P register) หรือชื่อประเภท PMC

กำลังสองรวม

ตัวอย่างนี้แนะนำคำแนะนำเพิ่มเติมและไวยากรณ์ PIR บรรทัดที่ขึ้นต้นด้วย # คือความคิดเห็น

.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 ให้น้ำตาลซินแทติกเล็กน้อยซึ่งทำให้ดูมีระดับมากกว่าการประกอบ ตัวอย่างเช่น:

temp = i * i

เป็นอีกวิธีหนึ่งในการเขียนแอสเซมบลีเพิ่มเติม:

mul temp, i, i

และ:

if i <= maxnum goto loop

เหมือนกับ:

le i, maxnum, loop

และ:

total += temp

เหมือนกับ:

add total, temp

ตามกฎแล้วเมื่อใดก็ตามที่คำสั่ง Parrot แก้ไขเนื้อหาของรีจิสเตอร์นั่นจะเป็นรีจิสเตอร์แรกเมื่อเขียนคำสั่งในรูปแบบแอสเซมบลี

ตามปกติในภาษาแอสเซมบลีการวนซ้ำและการเลือกจะถูกนำไปใช้ในรูปแบบของคำสั่งสาขาตามเงื่อนไขและป้ายกำกับดังที่แสดงไว้ด้านบน การเขียนโปรแกรม Assembly เป็นที่หนึ่งที่การใช้ goto ไม่ใช่รูปแบบที่ไม่ดี!

Fibonacci Numbers

อนุกรมฟีโบนักชีถูกกำหนดไว้เช่นนี้: ใช้ตัวเลขสองตัวคือ 1 และ 1 จากนั้นจึงบวกตัวเลขสองตัวสุดท้ายเข้าด้วยกันซ้ำ ๆ เพื่อสร้างหมายเลขถัดไป: 1, 1, 2, 3, 5, 8, 13 และอื่น ๆ . Fibonacci number fib (n) คือเลขที่ n ในอนุกรม นี่คือโปรแกรมแอสเซมเบลอร์ Parrot ง่ายๆที่ค้นหาหมายเลข Fibonacci 20 ตัวแรก:

# 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

นี่คือรหัสเทียบเท่าใน Perl:

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:ในฐานะที่เป็นจุดสนใจที่ดีหนึ่งในวิธีที่สั้นที่สุดและสวยงามที่สุดในการพิมพ์ชุดฟีโบนักชีใน Perl คือ perl -le '$ b = 1; พิมพ์ $ a + = $ b ในขณะที่พิมพ์ $ b + = $ a '

การคำนวณแฟกทอเรียลซ้ำ ๆ

ในตัวอย่างนี้เรากำหนดฟังก์ชันแฟกทอเรียลและเรียกมันซ้ำเพื่อคำนวณแฟกทอเรียล

.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

มาดูย่อย _fact กันก่อน จุดที่ถูกปัดสวะก่อนหน้านี้คือสาเหตุที่ชื่อของรูทีนย่อยทั้งหมดเริ่มต้นด้วยขีดล่าง! สิ่งนี้ทำขึ้นเพื่อแสดงให้เห็นว่าเลเบลเป็นแบบโกลบอลแทนที่จะกำหนดขอบเขตไปยังรูทีนย่อยเฉพาะ สิ่งนี้มีความสำคัญเนื่องจากเลเบลจะปรากฏแก่รูทีนย่อยอื่น ๆ

บรรทัดแรก. param int n ระบุว่ารูทีนย่อยนี้รับพารามิเตอร์จำนวนเต็มหนึ่งพารามิเตอร์และเราต้องการอ้างถึงรีจิสเตอร์ที่ถูกส่งโดยชื่อ n สำหรับส่วนที่เหลือของส่วนย่อย

สิ่งต่อไปนี้มีให้เห็นมากมายในตัวอย่างก่อนหน้านี้นอกเหนือจากการอ่านบรรทัด:

result = _fact($I0)

PIR บรรทัดเดียวนี้แสดงถึง PASM ไม่กี่บรรทัด ขั้นแรกค่าใน register $ I0 จะถูกย้ายไปยังรีจิสเตอร์ที่เหมาะสมเพื่อให้ได้รับเป็นพารามิเตอร์จำนวนเต็มโดยฟังก์ชัน _fact จากนั้นจะมีการตั้งค่าการลงทะเบียนอื่น ๆ ที่เกี่ยวข้องกับการโทรตามด้วย _fact ถูกเรียกใช้ จากนั้นเมื่อ _fact ส่งคืนค่าที่ส่งกลับโดย _fact จะถูกใส่ลงในรีจิสเตอร์ที่ได้รับชื่อผลลัพธ์

ก่อนหน้า. end ของย่อย _fact คำสั่ง. return ถูกใช้เพื่อให้แน่ใจว่าค่าที่เก็บไว้ในรีจิสเตอร์ ผลลัพธ์ที่ตั้งชื่อจะถูกวางลงในรีจิสเตอร์ที่ถูกต้องเพื่อให้เห็นเป็นค่าส่งคืนโดยรหัสที่เรียกซับ

การเรียก _fact ใน main ทำงานในลักษณะเดียวกับการเรียกซ้ำไปยัง _fact ภายใน _fact ย่อยเอง ไวยากรณ์ใหม่ที่เหลือเพียงบิตเดียวคือ: main เขียนตามหลัง. sub _main โดยค่าเริ่มต้น PIR จะถือว่าการเรียกใช้งานเริ่มต้นด้วยส่วนย่อยแรกในไฟล์ พฤติกรรมนี้สามารถเปลี่ยนแปลงได้โดยการทำเครื่องหมายย่อยเพื่อเริ่มต้นด้วย: main

รวบรวมไปยัง PBC

ในการคอมไพล์ PIR เป็น bytecode ให้ใช้แฟล็ก -o และระบุไฟล์เอาต์พุตที่มีนามสกุล. pbc

parrot -o factorial.pbc factorial.pir

PIR กับ PASM

PIR สามารถเปลี่ยนเป็น PASM ได้โดยเรียกใช้:

parrot -o hello.pasm hello.pir

PASM สำหรับตัวอย่างสุดท้ายมีลักษณะดังนี้:

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

PASM ไม่จัดการการจัดสรรการลงทะเบียนหรือให้การสนับสนุนสำหรับการลงทะเบียนที่ระบุชื่อ นอกจากนี้ยังไม่มีคำสั่ง. sub และ. end ให้แทนที่ด้วยป้ายกำกับที่จุดเริ่มต้นของคำแนะนำ