Parrot: Tutorial 4

Last modification: 2008/07/20 23:55

Tutorial 4: Macros and Subroutines

As you can see, programming in Parrot is powerful but the lack of many common idioms found in programming languages (even if .. then .. else) makes it very verbose.

To reduce duplication and effort, Parrot provides a number of ways to package and re-use code.

Macros

The first is the .macro directive. Here's a simple example:

.macro swap (A, B, TEMP) .TEMP = .A # Note: use '.A', not 'A' within macro .A = .B .B = .TEMP .endm .sub do_macro .local string a, b, t a = "first" b = "second" .swap (a, b, t) print a print "\n" print b .end

Macros use in-code expansion, so the above is equivalent to writing:

.sub do_macro .local string a, b, t a = "first" b = "second" t = a a = b b = t print a print "\n" print b .end

Because macros provide a literal, in-place expansion, it is impossible to use labels for logic control. For example, this macro evaluating a simple if-statement will fail, saying that "compare_bigger is already defined":

.macro compare (RESULT, A, B) if .B > .A goto bigger .RESULT = .A goto compare_skip compare_bigger: .RESULT = .B compare_skip: .endm .sub do_macro .local string a, b, c, r a = 6 b = 4 c = 9 .compare(r, a, b) print r print "\n" .compare(r, a, c) print r print "\n" .end

Clearly a more robust option is needed in most cases, which brings us to subroutines.

Subroutines

Of course, we have been using the .sub .. .end notation for all of the examples seen to date. However, subroutine support in Parrot is fully fledged, allowing multiple, typed parameter input and output.

Rewriting our compare example above to use subroutines, we end up with this:

.sub compare .param int a # no shortcuts here .param int b # one parameter per line if b > a goto bigger .begin_return .return a .end_return bigger: .begin_return .return b .end_return .end .sub do_compare :main .local string a, b, c, r a = 6 b = 4 c = 9 r = compare(a, b) print r print "\n" r = compare(a, c) print r print "\n" .end

You'll notice that sub do_compare now has a :main tacked on the end. This tells Parrot which subroutine to start executing when compilation is finished. Without this, Parrot would have run the compare subroutine.

You can also return multiple results from a sub:

.sub poly .param int a .local int b, c b = a * a c = b * a .begin_return .return b .return c .end_return .end .sub do_poly :main .local string a, b, c a = 6 (b, c) = poly(a) print b print ", " print c print "\n" .end

Parrot has a lot of opcodes, so there's a reasonable chance that you may end up with a conflicting sub name. To get around this, just quote the function name when you call it:

.sub band .param int a .param int b return c = a - b unless c < 0 goto positive c = -c positive: .begin_return .return c .end_return .end .sub do_dup :main .local int a, b, c a = 6 b = -8 c = 'band'(a, b) # 'band' is also the Parrot opcode for binary AND print c print "\n" .end