docs/compiler_faq.pod - Parrot FAQ for compiler writers in PIR
This is the FAQ for anyone interested in writing compilers in PIR, targeting the Parrot Virtual Machine.
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. See the README.pod files in the root directory for more information about building Parrot.
See http://parrot.github.com/html/examples/languages/squaak/doc/tutorial_episode_1.pod.html.
Use .line 42 "file.pir" for this.
.line 42 "file.pir"
This looks like a function call in many HLLs:
where $P0 is the function object, and $P1, $P2, and $P3 are its parameters. You can also use a function's name in place of the object, as long as it's in the same namespace.
You can also get return value(s):
If the function name might collide with a Parrot opcode, quote it:
You can also use the full PCC for these calls. See "pdd19_pir.pod/Parameter Passing and Getting Flags" in docs and other questions below for more information.
Similar to function calls, just append . and the method name to the object. You should quote a literal method name to avoid confusion.
.
The method name may also be a string variable representing a method name:
There are several ways to achieve this, depending on the location of the subroutine.
If the sub is in the same file use a Sub constant:
A more dynamic way is:
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 get_hll_global or get_root_global opcodes:
get_hll_global
get_root_global
This fetches the sub foo in the Foo namespace.
foo
Foo
Closure and Coroutine carry both a dynamic state. Therefore you need to perform two steps. First use one of the above ways to locate the Sub object. Then use the op newclosure to capture the environment.
newclosure
Any subroutine that contains a .yield directive is automatically created as a Coroutine PMC:
.yield
The sub bar will return to the caller of foo. (Warning! This fails in some cases. XXX Find the Trac ticket and reference it here.)
bar
If you have a variable amounts of arguments in an array, you can pass all items of that array with the :flat directive.
:flat
Use a slurpy array:
If you have a few fixed parameters too, you can use a slurpy array to get the rest of the arguments
Use the :optional and :opt_flag pragmas:
:optional
:opt_flag
Please refer to "pdds/pdd20_lexical_vars.pod/Nested Subroutines Have Outies; the ":outer" attribute" in docs for details.
Use the get_root_global or get_hll_global op:
You can retrieve the namespace hash and use the delete opcode.
delete
Please refer to "pdds/pdd20_lexical_vars.pod" in docs for details.
You can't. You can store a PMCNULL as the value though, which will catch all further access to that variable and throw an exception. (You can create a PMCNULL with the null opcode.)
null
Use find_name:
find_name
This will find the name foo in the lexical, global, or builtin namespace, in that order, and store it in $P0.
$P0
or much better, if possible just use the variable defined along with the .lex definition of foo.
.lex
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 the same scope.
store_lex
find_lex
XXX
With the newclass op:
newclass
Each class knows which attributes its objects can have. You can add attributes to a class (not to individual objects) like so:
Methods are declared as functions in the class namespace with the :method keyword appended to the function declaration:
:method
As with methods, but note the new keyword. The vtable name specified must be an existing vtable slot.
Now, given an instance of NearlyPi in $P0
You can access attributes by a short name:
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 get_class op:
get_class
Then you can use the subclass op to create a new class that is a subclass of this class:
subclass
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
Just override the init vtable for that class.
Or you can specify the constructor method by setting the BUILD property of the class PMC:
You can do so either with the class name:
or with the class object:
The chief difference is that using a string constant will produce the specific error "Class 'Dog' not found" if that happens to be the case; the other code has to check explicitly.
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:
The easiest way is the perl-like
You can also explicitly create an exception object and throw it:
Use push_eh to push an exception handler onto the stack. End the set of instructions that might throw the exception you're interested in with pop_eh.
push_eh
pop_eh
An exception handler is called with one argument, which is the exception object. The message of the exception can be easily extracted, as follows:
exit
Rethrow the exception if it has a severity of EXCEPT_EXIT.
EXCEPT_EXIT
Exception example:
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.
See "dynpmc/Makefile" in src for an example of how to build your dynamic 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.
Using the NCI you can invoke functions written in C from a Parrot script. To every NCI invocation, there are two parts: the native function to be invoked, and the PIR code to do the invocation.
First the native function, to be written in C. On Windows, it is necessary to do a DLL export specification of the NCI function:
/* foo.c */ /* specify the function prototype */ #ifdef __WIN32 __declspec(dllexport) void foo(void); #else void foo(void); #endif void foo(void) { printf("Hello Parrot!\n"); }
Then, after having compiled the file as a shared library, the PIR code looks like this:
If you embedded a Parrot in your C file and you want to invoke another function in that same C file, you should pass a null string to loadlib. Do that as follows:
Under Linux, the .c file must then be linked with the -export-dynamic option.
Create a new Env PMC and access it like a hash.
Env
See config_lib.pasm for all the keys in the config hash - or iterate over the config hash.
To install Rakudo::Star, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Rakudo::Star
CPAN shell
perl -MCPAN -e shell install Rakudo::Star
For more information on module installation, please visit the detailed CPAN module installation guide.