docs/compiler_faq.pod - Parrot FAQ for compiler writers
Whoa, there--you're looking at the wrong FAQ. This document is for people writing compilers that target Parrot.
To answer your question, though, Parrot should theoretically work with any C89-compliant C compiler, although some features require gcc. See the README files in the root directory for more information about building Parrot.
gcc
compile
Define a sub that takes as input a string, and returns something invokable. The easiest way to create something invokable at the moment is to use the builtin PIR or PASM compilers.
PIR
PASM
See languages/tcl/tcl.pir_template's .sub _tcl_compile as an example.
languages/tcl/tcl.pir_template
.sub _tcl_compile
You can do this using either the setfile and setline opcodes or with C-like #line comments:
setfile
setline
#line
#line 27 "my_source.file"
Simply set the source file name or line number whenever it changes. But note that currently (Parrot 0.2.x) both are ignored in the lexer.
If you have a fixed-length parameter list, IMCC makes this blindingly easy:
$P0( $P1, $P2, $P3 )
where $P0 is the function object, and $P1, $P2, and $P3 are its parameters. You can also use a function's label in place of the object:
somefunctionlabel( $P1, $P2, $P3 )
You can also get return value(s):
($P1,$P2) = $P0( $P1, $P2, $P3 )
Similar to function calls, just append . and the method:
.
ret_val = some_obj."some_meth"(arg)
The method name may also be a string variable representing a method name:
.local string m m = "bold" curses_obj.m()
.sub foo # do something .return bar(42) # tail call sub bar .end .sub bar # ... .end
The sub bar will return to the caller of foo.
bar
foo
Use unprototyped calls and functions and pass as many arguments as you have. If you have a variable amounts of arguments in an array, you can pass all items of that array with the .flatten_arg directive.
.flatten_arg
ar = new PerlArray push ar, "arg 1\n" push ar, "arg 2\n" .pcc_begin non_prototyped .flatten_arg ar .pcc_call sub ...
You can check the passed PMC parameter count in the subroutine with the argcP variable (an alias to I3). Remember, the first eleven PMC parameters are passed in P5 through P15, with overflow parameters an array-like PMC in P3.
A simpler way is to use the foldup opcode, which creates an array of all passed PMC arguments.
foldup
.sub _mysub non_prototyped .local pmc argv .local int argc argv = foldup argc = argv ...
If you have a few fixed parameters too, you can use a variant of foldup to capture variable arguments from that position on.
.sub _mysub non_prototyped .param pmc arg0 .param pmc arg1 .local pmc varargs .local int num_varargs varargs = foldup, 2 num_varargs = varargs ...
PIR doesn't support nested subroutines. You have to emit subroutines one by one. If lexicals of the outer subroutine are visible inside the nested sub, you have to include the outer pad depth in new_pad opcodes.
new_pad
There are two possible ways. Either use the special PIR syntax:
$P0 = global "name_of_the_global"
or the find_global op:
find_global
find_global $P0, "name_of_the_global"
You can retrieve the namespace hash and use the delete opcode. Nested namespace names have a NULL char prepended to their name.
delete
.sub main @MAIN $P0 = new Integer store_global "foo", $P0 store_global "Bar", "baz", $P0 # ... .include "interpinfo.pasm" .local pmc ns, Bar_ns ns = interpinfo .INTERPINFO_NAMESPACE_ROOT delete ns["foo"] # delete from top level Bar_ns = ns["\0Bar"] # get Bar namespace delete Bar_ns["baz"] $P0 = find_global "Bar", "baz" print "never\n" .end
To create lexical variables, you'll need to keep track of how deeply nested each block of code is. Say you have some HLL code like so:
# depth 0 lexical $bar $foo = 3 # global foo $bar = 5 # bar at depth 0 { # depth 1 lexical $foo $foo = 5 # foo at depth 1 { # depth 2 lexical $bar $foo = 7 # also foo at depth 1 $bar = 2 # bar at depth 2 } { # depth 2, again lexical $foo $foo = 11 # foo at depth 2 } }
When you are building your program tree, have each block reference its parent block, note its depth, and keep a list of all its lexical variables. At the opening of each block (that has lexical variables), emit code to push a lexical pad:
new_pad n
where n is the lexical depth of the block. After the first new_pad 0, you can also use:
n
new_pad 0
new_pad -1
to create a new pad with a nesting of outer + 1.
outer + 1
At any point that you exit a block, you should emit
pop_pad
This isn't necessary if you leave a block by invoking a continuation (by returning from a subroutine, for instance), as the continuation will automatically put the lexical pad stack back the way it was when the continuation was created.
return
When you need to figure out how to access a certain variable, simply look at the topmost block and work your way down the tree until you finds a block that declares lexical variables. Then take the lexical depth of the block in which you found it and emit some code like so:
find_lex $P0, 2, "foo"
where 2 is the depth the variable was found at, foo is the name of the variable, and $P0 is a PMC register in which to store the variable.
2
Note that, by convention (and confusing IMCC syntax), variables, not direct values, are stored. So to assign to this lexical variable, you would say:
find_lex $P0, 2, "foo" assign $P0, some_value
instead of:
store_lex 2, "foo", some_value
You will still need to do a store_lex at some point (probably at the start of the block in which it is declared) to create the variable in the first place. Put a Undef PMC in it or something.
store_lex
Undef
If, on the other hand, you never find said lexical variable (or if a block declares that variable to be global, or whatever other tricks your compiler likes to do), you might assume it to be a global, which you can access much the same way:
find_global $P0, "bar" assign $P0, value_to_store
You can peek_pad the current pad and use delete.
peek_pad
.sub main @MAIN new_pad 0 $P0 = new Integer store_lex -1, "foo", $P0 .local pmc pad pad = peek_pad delete pad["foo"] # delete from current pad $P0 = find_lex "foo" print "never\n" .end
Use find_name:
find_name
$P0 = find_name "$x" find_name $P0, "foo" # same thing
This will find the name foo in lexical, global or builtin namespace, in that order, and store it in $P0.
$P0
Use lexical depth -1:
find_lex $P0, -1, "foo"
Omit the depth parameter:
find_lex $P0, "foo"
This finds a foo variable at any depth starting from the top.
Use numeric indices instead of variable names for lexical retrieval. Lexicals of one pad depth are numbered from 0..n-1 in the order of their declaration.
find_lex $P0, -1, 0 # get first lexical from top pad find_lex $P1, -2, 3 # get forth lexical from next inner pad ...
With the newclass op:
newclass
newclass $P0, "Animal"
Each class knows what attribute its object can have. You can add attributes to a class (not to individual objects) like so:
addattribute $P0, "legs"
Methods are declared as functions in the class namespace with the method keyword appended to the function declaration:
method
.namespace [ "Animal" ] .sub __init method $P0 = new Integer setattribute self, "legs", $P0 ... .end .sub run method ... .end
Attributes can be access by a short name, fully qualified name or by index.
$P0 = getattribute self, "legs" assign $P0, 4 # set attribute's value
or
$P0 = getattribute self, "Animal\0legs" assign $P0, 4 # set attribute's value
.local int offs offs = classoffset "Animal" $I0 = offs + 0 # 1st attribute $P0 = getattribute self, $I0 $I0 = offs + 1 # 2nd attribute $P0 = getattribute self, $I0
Properties aren't inherited. If you have some additional data that don't fit into the classes hierarchy, you could use properties.
You first have to get the class PMC of the class you want to subclass. Either you use the PMC returned by the newclass op if you created the class, or use the getclass op:
getclass
getclass $P0, "Animal"
Then you can use the subclass op to create a new class that is a subclass of this class:
subclass
subclass $P1, $P0, "Dog"
This stores the newly created class PMC in $P1.
First, create a class without a parent class using newclass (or with only one subclass, see previous question). Then add the other parent classes to it. Please refer to the next question for an example.
If you have a class PMC (created with newclass or by subclass), you can add more parent classes to it with the addparent op:
addparent
getclass $P1, "Dog" subclass $P2, $P1, "SmallDog" getclass $P3, "Pet" addparent $P2, $P3 # make "SmallDog" also a "Pet"
Just define a method named __init in the namespace if the class.
__init
newclass $P0, "Dog" # create a class named Dog # ... .namespace ["Dog"] .sub __init method # ...
Or you can specify the constructor method by setting the BUILD property of the class PMC:
newclass $P0, "Dog" # create a class named Dog new $P1, .PerlString # create a string set $P1, "initialise" # set it to the name of the constructor method setprop $P0, "BUILD", $P1 # set the BUILD property
First, you have to retrieve the type id of class you want to instantiate:
find_type $I0, "Dog"
Then, you can create an instance of Dog with the new op:
new $P0, $I0 # creates a Dog object and stores it in register $P0
or for short:
new $P0, "Dog"
During the new opcode the constructor is called.
new
You can pass only a single argument to a constructor. By convention, a hash PMC is passed to the constructor that contains the arguments as key/value pairs:
new $P0, .Hash set $P0["greeting"], "hello" set $P0["size"], 1.23 find_type $I0, "Alien" new $P1, $I0, $P0 # create an Alien object and pass # the hash to the constructor
Create an Exception object and throw it!
$P0 = new Exception throw $P0
Not too hard, is it?
$P0 = new Exception $P0["_message"] = "something happened" throw $P0
Use push_eh to push an exception handler onto the stack.
push_eh
push_eh handler $P0 = new Exception # or any other code ... throw $P0 # ... that might throw clear_eh exit 0 handler: print "Exception caught!\n" exit 1
P5 is the register used for the Exception object.
push_eh handler $P0 = new Exception $P0["_message"] = "something happened" throw $P0 clear_eh exit 0 handler: print "Exception: " $S0 = P5["_message"] print $S0 print "\n" exit 1
Create a new Env PMC and access it like a hash.
Env
.local pmc e e = new .Env $P0 = e['USER'] # lt
.include "iglobals.pasm" .local pmc interp, cfg interp = getinterp cfg = interp[.IGLOBALS_CONFIG_HASH] $S0 = cfg['VERSION'] "0.2.2"
See config_lib.pasm for all the keys in the config hash - or iterate over the config hash.
To install Ruby, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Ruby
CPAN shell
perl -MCPAN -e shell install Ruby
For more information on module installation, please visit the detailed CPAN module installation guide.