Are you sure you want PASM?
When you're writing code for parrot, most of the time you will want to be generating PIR code, not PASM. That said, here's some examples!
Hello world!
The first example clearly has to be one that prints out "Hello world!".
# ``the'' example print "Hello world!\n" end
When you run this example, you'll get:
Hello world!
Note that the first line of code is a comment, which starts with a '#' character - everything until the end of the line is ignored comment.
Registers
Parrot has four types of registers: integer, float, string, pmc.
The integer, float, and string registers are the basic types used by parrot. PMCs correspond to classes or objects.
One of the few advantages PASM provides over raw bytecode is that it matches the opcode print in PASM to the appropriate print variant. The print opcode that takes a single argument, for example, has eight variants. PASM automatically translated our print to print_sc, or print-string-constant.
Assignment
Assignment between registers is done with the set operator. The following code sets the first integer register to 1, the first number register to 4.2 and the first string register to "Resting"
set I1, 1 set N1, 4.2 set S1, "Resting" print I1 print ", " print N1 print ", " print S1 print "\n" end
Prints:
1, 4.200000, Resting
Note how it seems that the print operator is polymorphic - it can print integers, numbers, strings, and string constants. Actually, these are all separate operators (for details look in core.ops) - the assembler decides which to use, keeping our code simple.
The set operator can also copy between registers of the same type.
set I1, 10 set I3, 30 set I1, I3 print I1 print "\n" end
Prints:
30
Remember that the first operand is the destination register, so that last command sets the value of register I1 to the value of register I3. That is, I1 will hold the value 30.
To copy between registers of different types, the set operator is also used:
set I1, 10 set N1, I1 set N2, 4.2 set I2, N2 print N1 print ", " print I2 print "\n" end
Prints:
10.000000, 4
Note that at the moment there are no operators to convert from or to strings.
Arithmetic opcodes
A number of Parrot opcodes are concerned with arithmetic. The inc and dec opcodes increase/decrease an integer or number register by a constant. If no constant is given, 1 is assumed.
set I1, 10 inc I1 # I1 is now 11 inc I1 # I1 is now 12 inc I1 # I1 is now 13 set N1, 42.0 dec N1 # N1 is now 41.0 dec N1 # N1 is now 40.0 dec N1 # N1 is now 39.0 print I1 print ", " print N1 print "\n" end
Prints:
13, 39.000000
More common arithmetic operators are: add, sub, mul and div, which add, subtract, multiply and divide the contents of registers:
set I1, 2 set I2, 4 add I3, I1, I2 # I3 is now 6 (2+4) sub I3, I1, I2 # I3 is now -2 (2-4) mul I3, I1, I2 # I3 is now 8 (2*4) div I3, I2, I1 # I3 is now 2 (4/2) add I1, I1, 5 # I1 is now 7 set N1, 1 set N2, 3 div N3, N1, N2 # N3 is now 0.333333 print I1 print ", " print N3 print "\n" end
Prints:
7, 0.333333
Note that add I1, I1, 5 is also valid: both constants and registers are allowed for the last operand.
There are also other arithmetic operators, such as mod (modulo) and a whole host of transcendental operators (sin, cos, pow, exp, log10...).
String operators
Parrot includes a minimal set of string operators: length (find the length of a string), chopn (remove characters from the end of the string), concat (concatenate one string to the end of another), substr (extract substrings), repeat (repeat a string), index (search for a substring):
set S1, "Fourty" set S2, "two" length I1, S2 # I1 is now 3 print I1 print ", " concat S1, S2 # S1 is "Fourtytwo" concat S3, S1, S2 # S3 is "Fourtytwotwo" substr S2, S1, 0, 4 # S2 is "Four" chopn S1, 3 # S1 is "Fourty" print S1 print ", " print S2 print ", " print S3 print "\n" end
Prints:
3, Fourty, Four, Fourtytwotwo
Note that the two-argument concat concatenates the second string onto the end of the first: unlike most other operators is does not create a whole new concatenated string. There is a three-argument version which can do this, however.
Branching and conditionals
Branching is terribly useful in a program. The branch operator is similar to a "goto", and takes a label. Labels are presented at the start of the line with a colon.
set S1, "Beautiful" branch CHOIR EX: print S1 branch END CHOIR: set S2, " plumage!\n" concat S1, S2 branch EX END: end
Prints:
Beautiful plumage!
The following conditional operators are available: eq (equal), ne (not equal), lt (less than), le (less than or equal), gt (greater than), ge (greater than or equal). They take two integer or numeric registers and a label to jump to if the condition is true. If the condition is false, then execution goes to the next statement.
The following code prints the numbers from 1 to 10, by looping over until I1 is greater than 10:
set I1, 1 REDO: gt I1, 10, END print I1 print " " inc I1 branch REDO END: print "\n" end
Prints:
1 2 3 4 5 6 7 8 9 10
The conditional operators take a register and either a constant or another register.
The if opcode tests if a register holds a true value. Any value other than zero is true.
set I1, 1 if I1, TRUE print "False!\n" branch END TRUE: print "True!\n" END: end
Prints:
True!
Subroutines
Subroutines are a vital part of larger programs.
The simplest kind of subroutine is one that does not pass or return arguments. The important operators here are bsr (Branch SubRoutine, which jumps to a label) and ret (RETurn, which returns from a subroutine). The following code jumps to a subroutine named HELLO which prints a message and returns.
bsr HELLO end HELLO: print "Hello there!\n" ret
Prints:
Hello there!
The parrot calling conventions have recently changed. While examples will be generated for PASM-based calling conventions, it is recommended that you use PIR for actual subroutines.
PMCs (Parrot Magic Cookies)
PMCs are a completely abstracted data type; they may be string, integer, code or anything else. They are roughly equivalent to the SV, AV and HV (and more complex types) defined in Perl 5, and almost exactly equivalent to PythonObject types in Python.
The various types of PMCs shipped with Parrot are defined in the file include/parrot/pmc.h
To use a PMC, you must first create it using the new operator. You can then assign it a value and treat it much like the lower-level types. The following code creates two Integer PMCs and
adds them together.
new P0, .Integer set P0, 123 new P1, .Integer set P1, 321 add P1, P1, P0 print P1 print "\n" end
Prints:
444
The following code concatenates a number and a string.
new P0, .Integer set P0, 42 new P1, .Integer set P1, " is the answer!" concat P0, P0, P1 print P0 print "\n" end
Prints:
42 is the answer!
You may notice that in the last example, we declare P1 as an Integer type, but then set it to a string value. As with their Perl or Tcl counterparts, PMCs have the ability to change their own type on the fly. (also known as morphing or shimmering). If you trace this code: parrot -t1 foo.pasm ...
0 new P0, 30 P0=PMCNULL 3 set P0, 42 P0=Integer=PMC(0xf004f4: 0) 6 new P1, 30 P1=PMCNULL 9 set P1, " is the answer!" P1=Integer=PMC(0xf004e0: 0) 12 i_concatenate P0, P1 P0=Integer=PMC(0xf004f4: 42) P1=String=PMC(0xf004e0 Str:" is the answer!") 16 print P0 P0=String=PMC(0xf004f4 Str:"42 is the answer!") 18 print "\n" 42 is the answer! 20 end
... you see that the P0 and P1 registers are both initialized as the same type (Integers), but at line 12, the concat opcode is processing a Integer (P0) and a String (P1). The assignment on line 9 morphed the PMC in P1 to a different type automatically.