Parrot - Ví dụ về lập trình
Lập trình vẹt tương tự như lập trình hợp ngữ và bạn có cơ hội làm việc ở trình độ thấp hơn. Dưới đây là danh sách các ví dụ lập trình để giúp bạn biết các khía cạnh khác nhau của Lập trình vẹt.
Chào thế giới cổ điển!
Sử dụng sổ đăng ký
Tổng bình phương
Số Fibonacci
Tính giai thừa
Biên dịch sang PBC
PIR so với PASM
Chào thế giới cổ điển!
Tạo một tệp có tên hello.pir chứa mã sau:
.sub _main
print "Hello world!\n"
end
.end
Sau đó chạy nó bằng cách gõ:
parrot hello.pir
Như mong đợi, nó sẽ hiển thị dòng chữ 'Hello world!' trên bảng điều khiển, theo sau là một dòng mới (do \ n).
Trong ví dụ trên, '.sub _main' nói rằng các hướng dẫn theo sau tạo nên một chương trình con có tên '_main', cho đến khi gặp phải '.end'. Dòng thứ hai chứa hướng dẫn in. Trong trường hợp này, chúng tôi đang gọi biến thể của lệnh chấp nhận một chuỗi không đổi. Trình lắp ráp sẽ đảm nhận việc quyết định biến thể của hướng dẫn sẽ sử dụng cho chúng tôi. Dòng thứ ba chứa lệnh 'end', lệnh này khiến trình thông dịch kết thúc.
Sử dụng sổ đăng ký
Chúng ta có thể sửa đổi hello.pir để lưu trữ chuỗi Hello world! \ N trước tiên trong một thanh ghi và sau đó sử dụng thanh ghi đó với lệnh in.
.sub _main
set S1, "Hello world!\n"
print S1
end
.end
Ở đây chúng tôi đã nêu chính xác đăng ký nào để sử dụng. Tuy nhiên, bằng cách thay thế S1 bằng $ S1, chúng ta có thể ủy quyền lựa chọn đăng ký nào để sử dụng cho Parrot. Cũng có thể sử dụng ký hiệu = thay vì viết lệnh thiết lập.
.sub _main
$S0 = "Hello world!\n"
print $S0
end
.end
Để làm cho PIR dễ đọc hơn, có thể sử dụng các thanh ghi đã đặt tên. Sau đó chúng được ánh xạ tới các thanh ghi được đánh số thực.
.sub _main
.local string hello
hello = "Hello world!\n"
print hello
end
.end
Chỉ thị '.local' chỉ ra rằng thanh ghi được đặt tên chỉ cần thiết bên trong đơn vị biên dịch hiện tại (nghĩa là giữa .sub và .end). Theo sau '.local' là một kiểu. Đây có thể là int (đối với thanh ghi I), float (đối với thanh ghi N), chuỗi (đối với thanh ghi S), pmc (đối với thanh ghi P) hoặc tên của một loại PMC.
Tổng bình phương
Ví dụ này giới thiệu thêm một số hướng dẫn và cú pháp PIR. Các dòng bắt đầu bằng dấu # là nhận xét.
.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 cung cấp một chút cú pháp khiến nó trông cao cấp hơn so với lắp ráp. Ví dụ:
temp = i * i
Chỉ là một cách viết khác của assembly-ish:
mul temp, i, i
Và:
if i <= maxnum goto loop
Giống như:
le i, maxnum, loop
Và:
total += temp
Giống như:
add total, temp
Theo quy luật, bất cứ khi nào một lệnh Parrot sửa đổi nội dung của một thanh ghi, đó sẽ là thanh ghi đầu tiên khi viết lệnh ở dạng hợp ngữ.
Như thường lệ trong hợp ngữ, các vòng lặp và vùng chọn được thực hiện theo các câu lệnh và nhãn nhánh có điều kiện, như được hiển thị ở trên. Lập trình hợp ngữ là một nơi mà sử dụng goto không phải là một hình thức tồi!
Số Fibonacci
Dãy Fibonacci được định nghĩa như thế này: lấy hai số, 1 và 1. Sau đó cộng lại liên tục hai số cuối cùng với nhau để tạo thành dãy tiếp theo: 1, 1, 2, 3, 5, 8, 13, v.v. . Số Fibonacci fib (n) là số thứ n trong chuỗi. Đây là một chương trình hợp ngữ Parrot đơn giản để tìm 20 số Fibonacci đầu tiên:
# 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
Đây là mã tương đương trong 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:Như một điểm đáng quan tâm, một trong những cách ngắn nhất và chắc chắn đẹp nhất để in ra một chuỗi Fibonacci ở Perl là perl -le '$ b = 1; in $ a + = $ b trong khi in $ b + = $ a '.
Giai thừa tính toán đệ quy
Trong ví dụ này, chúng ta định nghĩa một hàm giai thừa và gọi một cách đệ quy nó để tính toán giai thừ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
Trước tiên hãy nhìn vào sub _fact. Một điểm đã được chú ý trước đó là tại sao tên của các chương trình con, tất cả đều bắt đầu bằng dấu gạch dưới! Điều này được thực hiện đơn giản như một cách để cho thấy rằng nhãn là toàn cục thay vì phạm vi đến một chương trình con cụ thể. Điều này rất quan trọng vì nhãn sau đó được hiển thị cho các chương trình con khác.
Dòng đầu tiên, .param int n, chỉ định rằng chương trình con này nhận một tham số số nguyên và chúng tôi muốn tham chiếu đến sổ đăng ký mà nó được chuyển vào bằng tên n cho phần còn lại của chương trình con.
Phần lớn những gì sau đây đã được nhìn thấy trong các ví dụ trước, ngoại trừ việc đọc dòng:
result = _fact($I0)
Dòng PIR đơn này thực sự đại diện cho khá nhiều dòng PASM. Đầu tiên, giá trị trong thanh ghi $ I0 được chuyển vào thanh ghi thích hợp để nó được hàm _fact nhận như một tham số nguyên. Các thanh ghi liên quan đến việc gọi khác sau đó được thiết lập, theo sau là _fact được gọi. Sau đó, khi _fact trả về, giá trị do _fact trả về sẽ được đưa vào thanh ghi với kết quả tên.
Ngay trước .end của _fact phụ, một chỉ thị .return được sử dụng để đảm bảo giá trị được giữ trong thanh ghi; kết quả được đặt tên được đặt vào đúng thanh ghi để nó được xem như một giá trị trả về bởi mã gọi sub.
Lệnh gọi tới _fact trong chính hoạt động giống như cách gọi đệ quy tới _fact bên trong chính _fact phụ. Một chút duy nhất còn lại của cú pháp mới là: main, được viết sau .sub _main. Theo mặc định, PIR giả định rằng việc thực thi bắt đầu với con đầu tiên trong tệp. Hành vi này có thể được thay đổi bằng cách đánh dấu phụ bắt đầu bằng: main.
Biên dịch sang PBC
Để biên dịch PIR sang bytecode, hãy sử dụng cờ -o và chỉ định tệp đầu ra có phần mở rộng .pbc.
parrot -o factorial.pbc factorial.pir
PIR so với PASM
PIR có thể được chuyển thành PASM bằng cách chạy:
parrot -o hello.pasm hello.pir
PASM cho ví dụ cuối cùng trông như thế này:
_main:
set S30, "Hello world!\n"
print S30
end
PASM không xử lý cấp phát thanh ghi hoặc cung cấp hỗ trợ cho các thanh ghi được đặt tên. Nó cũng không có các chỉ thị .sub và .end, thay vào đó hãy thay thế chúng bằng một nhãn ở đầu hướng dẫn.