开发手册 欢迎您!
软件开发者资料库

Parrot - 编程实例

Parrot编程示例 - SOAP XML-RPC Web服务的免费教程和参考AJAX JavaScript J2EE ASP.NET VB.NET C#C ++ C Pro * C Makefile PERL Parrot Ruby JAVA J2EE CORBA BILLING CRM OM DLL PHP CGI MySQL PL / SQL SDLC CSS ASP DHTML Flash。

Parrot编程与汇编语言编程类似,您有机会在较低级别工作.以下是编程示例列表,让您了解Parrot编程的各个方面.

  • 经典Hello世界!

  • 使用寄存器

  • 求和方块

  • Fibonacci数字

  • 计算因子

  • 编译到PBC

  • PIR与PASM

Clas sic Hello world!

创建一个名为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存储在寄存器中,然后将该寄存器与print指令一起使用.

.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之间)需要register.以下'.local'是一种类型.这可以是int(对于I寄存器),float(对于N寄存器),字符串(对于S寄存器),pmc(对于P寄存器)或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指令修改寄存器的内容时,这将是以汇编形式写入指令时的第一个寄存器.

与汇编语言一样,循环和选择用术语实现条件分支语句和标签,如上所示.汇编编程是一个使用goto不是一个糟糕形式的地方!

Fibonacci数字

Fibonacci系列的定义如下:取两个数字,1和1.然后重复将系列中的最后两个数字加在一起,形成下一个数字:1,1,2,3,5,8,13等等.斐波纳契数fib(n)是该系列中的第n个数.这是一个简单的Parrot汇编程序,它找到前20个Fibonacci数:

# 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, NEXTNEXT:   set     I5, I4        add     I4, I3, I4        set     I3, I5        print   I3        print   "\n"        inc     I1        branch  REDODONE:   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++;}

注意:作为一个优秀的兴趣点,最短的,当然也是最美丽的方式之一在Perl中打印出Fibonacci系列是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 returnrecurse:   $I0 = n - 1   result = _fact($I0)   result *= nreturn:   .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.首先,寄存器$ I0中的值被移入适当的寄存器,以便由_fact函数作为整数参数接收.然后设置其他调用相关寄存器,然后调用_fact.然后,一旦_fact返回,_fact返回的值将被放入给定名称结果的寄存器中.

在_fact子的.end之前,使用.return指令来确保登记册中的价值;命名结果被放入正确的寄存器中,以便通过调用sub的代码将其视为返回值.

在main中对_fact的调用与递归的方式相同在sub _fact本身内调用_fact.新语法的唯一剩余部分是:main,写在.sub _main之后.默认情况下,PIR假定执行从文件中的第一个子开始.可以通过将子标记为以下开头来更改此行为:main.

编译到PBC

要将PIR编译为字节码,请使用-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指令,而是在说明开头用标签替换它们.