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.3.0) 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 )
If the function name might collide with a Parrot opcode, quote it:
i = "new"(42)
Similar to function calls, just append . to the object 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()
There are several ways to achieve this, depending on the location of the subroutine.
If the sub is in the same compilation unit use a Sub constant:
.const .Sub foo = "foo"
The subroutine object is available in PASM too with a similar syntax:
.const .Sub P2 = "foo" # any P register will do ... .pcc_sub foo: # denote a Sub constant
If the PIR compiler finds a "foo" function during compiling a file, then the syntax:
foo()
gets translated to above constant declaration.
A more dynamic way is:
.local pmc foo foo = find_name "foo"
This searches for a subroutine "foo" in the current lexical pad, in the current namespace, in the global, and in the builtin namespace in that order. This opcode is generated, if foo() is used, but the compiler can't figure out, where the function is.
If the subroutine is in a different namespace, use the find_global opcode:
find_global
foo = find_global "Foo", "foo"
This searches the sub "foo" in the "Foo" namespace.
Both carry dynamic state, therefore you use one of the above ways to locate the sub object, then you just clone it to get a distinct copy of it:
.local pmc coro coro = find_name "my_coro" coro = clone coro
Any subroutine that contains a .yield directive is automatically created as a Coroutine PMC:
.yield
.sub my_coro # automagically a Coroutine PMC ... .yield (result) ... .end
.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
If you have a variable amounts of arguments in an array, you can pass all items of that array with the :flat directive.
:flat
ar = new .ResitablePMCArray push ar, "arg 1\n" push ar, "arg 2\n" ... foo(ar :flat) ...
Use a slurpy array:
.sub mysub .param pmc argv :slurpy .local int argc argc = argv ...
If you have a few fixed parameters too, you can use a slurpy array to get the rest of the arguments
.sub mysub .param pmc arg0 .param pmc arg1 .param pmc varargs :slurpy .local int num_varargs num_varargs = varargs ...
Use the :optional and :opt_flag pragmas:
:optional
:opt_flag
.sub foo .param pmc arg1 :optional .param int has_arg1 :opt_flag .param pmc arg2 :optional .param int has_arg2 :opt_flag if has_arg1 goto got_arg1 ...
Please refer to "pdds/pdd20_lexical_vars.pod" in docs for details.
There are two possible ways. Either use the special PIR syntax:
$P0 = global "name_of_the_global"
or the find_global op:
find_global $P0, "name_of_the_global"
You can retrieve the namespace hash and use the delete opcode.
delete
.sub main :main $P0 = new .Integer store_hll_global "foo", $P0 store_hll_global ["Bar"], "baz", $P0 # ... .local pmc ns, Bar_ns ns = get_hll_namespace delete ns["foo"] # delete from top level Bar_ns = ns["Bar"] # get Bar namespace delete Bar_ns["baz"] $P0 = get_hll_global ["Bar"], "baz" print "never\n" .end
You can't. You can store a Null PMC as the value though, which will catch all further access to that variable and throw an exception.
Use find_name:
find_name
$P0 = find_name "$x" find_name $P0, "foo" # same thing
This will find the name foo in the lexical, global, or builtin namespace, in that order, and store it in $P0.
$P0
find_lex $P0, "foo"
or much better, if possible just use the variable defined along with the '.lex' definition of "foo".
That is still the same:
This finds a foo variable at any outer depth starting from the top.
If your language looks up variables differently, you have to walk the 'caller' chain. See also t/dynpmc/dynlexpad.t.
Don't emit store_lex at all. Use find_lex only if the compiler doesn't know the variable. You can always just use the register that was defined in the .lex directive as an alias to that lexical, if you are in t the same scope.
store_lex
find_lex
.lex
TODO
With the newclass op:
newclass
newclass $P0, "Animal"
Each class knows which attributes its objects 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
You can access attributes by a short name, a fully qualified name, or by an 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 class's 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 of 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, .String # 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
An exception handler is called with two arguments: the exception and the message. More information is available inside the exception 'object' (TBD).
handler: get_results '(0,0') P0, S0 # PASM syntax print "Exception caught!\n" exit 1
push_eh handler $P0 = new .Exception $P0["_message"] = "something happened" throw $P0 clear_eh exit 0 handler: .local pmc exception .local string message .get_results (exception, message) # PIR syntax print "Exception: " print message print "\n" exit 1
Parrot supports dynamic PMCs, loadable at runtime, to allow compiler writers to extend Parrot with additional types. For more information about writing PMCs, see "build/pmc2c.pl" in tools and "pmc.pod" in docs.
To build dynamic PMCs, add something like the following to your Makefile:
PERL = /usr/bin/perl PMCBUILD = $(PERL) /path/to/parrot/tools/build/dynpmc.pl DESTDIR = /path/to/parrot/runtime/parrot/dynext LOAD_EXT = .so PMCDIR = pmc PMCS = MyInteger MyFloat MyString MyObject PMC_FILES = MyInteger.pmc MyFloat.pmc MyString.pmc MyObject.pmc dynpmcs : $(PMC_FILES) @cd $(PMCDIR) && $(BUILD) generate $(PMCS) @cd $(PMCDIR) && $(BUILD) compile $(PMCS) @cd $(PMCDIR) && $(BUILD) linklibs $(PMCS) @cd $(PMCDIR) && $(BUILD) copy "--destination=$(DESTDIR)" $(PMCS)
Parrot supports dynamic op libraries. These allow for ops specific to one language to be used without having to place them into the Parrot core itself. For examples of dynamic op libraries, see "dynoplibs" in src.
To build dynamic op libraries, add something like the following to your makefile:
PERL = /usr/bin/perl OPSBUILD = $(PERL) /path/to/parrot/tools/build/dynops.pl DESTDIR = /path/to/parrot/runtime/parrot/dynext LOAD_EXT = .so OPSDIR = ops OPLIBS = myops OPS_FILES = myops.ops dynops : $(OPS_FILES) @cd $(OPSDIR) && $(BUILD) generate $(OPLIBS) @cd $(OPSDIR) && $(BUILD) compile $(OPLIBS) @cd $(OPSDIR) && $(BUILD) linklibs $(OPLIBS) @cd $(OPSDIR) && $(BUILD) copy "--destination=$(DESTDIR)" $(OPLIBS)
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.3.0"
See config_lib.pasm for all the keys in the config hash - or iterate over the config hash.
Aside from the files in your new language directory, you must modify
CREDITS MANIFEST config/gen/languages.pm config/gen/makefiles/languages.in languages/LANGUAGES.STATUS.pod
Inside your language dir, you may consider adding the following:
LICENSE MAINTAINER README STATUS
Look to existing languages for some examples.
To install SmartLink, copy and paste the appropriate command in to your terminal.
cpanm
cpanm SmartLink
CPAN shell
perl -MCPAN -e shell install SmartLink
For more information on module installation, please visit the detailed CPAN module installation guide.