# Copyright (C) 2001-2007, The Perl Foundation. # $Id: compiler_faq.pod 23286 2007-11-30 15:51:26Z kjs $ =head1 NAME docs/compiler_faq.pod - Parrot FAQ for compiler writers =head1 General Questions =head2 Which C compilers can I use with Parrot? 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 C. See the F files in the root directory for more information about building Parrot. =head2 How can I implement a compiler to use as a compiler object from within Parrot? (For example, with the C op.) 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 another compiler object (for example, the C compiler), which you can get with: .local pmc pir_compiler pir_compiler = compreg 'PIR' =head2 How do I embed source locations in my code for debugging? Use C<#line 42 "file.pir"> for this. Note that this command must be in the first column; there must not be any leading space, otherwise the command is treated as a comment (due to the C<#> character). =head1 Subroutines =head2 How do I generate a sub call in PIR? IMCC makes this easy, handling the calling conventions for you. $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) =head2 How do I generate a method call in PIR? Similar to function calls, just append C<.> and the method name to the object. You should quote a literal method name to avoid confusion. 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() =head2 How do I locate or create a subroutine object? 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 I is used, but the compiler can't figure out, where the function is. If the subroutine is in a different namespace, use the C opcode: foo = find_global 'Foo', 'foo' This searches the sub C in the C namespace. =head2 How do I create a Closure or Coroutine? 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 C to capture the environment. .local pmc coro coro = find_name 'my_coro' coro = newclosure coro Any subroutine that contains a C<.yield> directive is automatically created as a Coroutine PMC: .sub my_coro # automagically a Coroutine PMC ... .yield (result) ... .end =head2 How do I generate a tail call in PIR? .sub foo # do something .return bar(42) # tail call sub bar .end .sub bar # ... .end The sub C will return to the caller of C. =head2 How do I generate a sub call with a variable-length parameter list in PIR? If you have a variable amounts of arguments in an array, you can pass all items of that array with the C<:flat> directive. ar = new 'ResizablePMCArray' push ar, "arg 1\n" push ar, "arg 2\n" ... foo(ar :flat) ... =head2 How to I retrieve the contents of a variable-length parameter list being passed to me? 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 ... =head2 How do I pass optional arguments? Use the C<:optional> and C<:opt_flag> pragmas: .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 ... =head2 How do I create nested subroutines? Please refer to L for details: look for C<:outer>. =head1 Variables =head2 How do I fetch a variable from the global namespace? There are two possible ways. Either use the special PIR syntax: $P0 = global 'name_of_the_global' or the C op: find_global $P0, 'name_of_the_global' =head2 How can I delete a global? You can retrieve the namespace hash and use the C opcode. .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 =head2 How do I use lexical pads to have both a function scope and a global scope? Please refer to L for details. =head2 How can I delete a lexical variable? 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. =head2 How do I resolve a variable name? Use C: $P0 = find_name '$x' find_name $P0, 'foo' # same thing This will find the name C in the lexical, global, or builtin namespace, in that order, and store it in C<$P0>. =head2 How do I fetch a variable from the current lexical pad? find_lex $P0, 'foo' or much better, if possible just use the variable defined along with the C<.lex> definition of C. =head2 How do I fetch a variable from any nesting depth? That is still the same: find_lex $P0, 'foo' This finds a C variable at any B depth starting from the top. If your language looks up variables differently, you have to walk the 'caller' chain. See also F. =head2 How can I produce more efficient code for lexicals? Don't emit C at all. Use C only if the compiler doesn't know the variable. You can always just use the register that was defined in the C<.lex> directive as an alias to that lexical, if you are in the same scope. =head1 Modules, Classes, and Objects =head2 How do I create a module? TODO =head2 How do I create a class? With the C op: newclass $P0, 'Animal' =head2 How do I add instance variables/attributes? 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' =head2 How do I add instance methods to a class? Methods are declared as functions in the class namespace with the C<:method> keyword appended to the function declaration: .namespace [ 'Animal' ] .sub run :method print "slow and steady\n" .end =head2 How do I override a vtable on a class? As with methods, but note the new keyword. The vtable name specified B be an existing vtable slot. .namespace [ 'NearlyPi' ] .sub get_string :vtable .return ('three and a half') .end Now, given an instance of NearlyPi in $P0 $S0 = $P0 say $S0 # prints 'three and a half' =head2 How do I access attributes? You can access attributes by a short name: $P0 = getattribute self, 'legs' assign $P0, 4 # set attribute's value a fully qualified name: $P0 = getattribute self, "Animal\0legs" assign $P0, 4 # set attribute's value or by an index: .local int offs offs = classoffset 'Animal' $I0 = offs + 0 # 1st attribute $P0 = getattribute self, $I0 $I0 = offs + 1 # 2nd attribute $P0 = getattribute self, $I0 =head2 When should I use properties vs. attributes? Properties aren't inherited. If you have some additional data that don't fit into the class's hierarchy, you could use properties. =head2 How do I create a class that is a subclass of another class? You first have to get the class PMC of the class you want to subclass. Either you use the PMC returned by the C op if you created the class, or use the C op: getclass $P0, 'Animal' Then you can use the C op to create a new class that is a subclass of this class: subclass $P1, $P0, 'Dog' This stores the newly created class PMC in $P1. =head2 How do I create a class that has more than one parent class? First, create a class without a parent class using C (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. =head2 How do I add another parent class to my class? If you have a class PMC (created with C or by C), you can add more parent classes to it with the C op: getclass $P1, 'Dog' subclass $P2, $P1, 'SmallDog' getclass $P3, 'Pet' addparent $P2, $P3 # make "SmallDog" also a "Pet" =head2 How can I specify the constructor of a class? Just override the init vtable for that class. newclass $P0, 'Dog' # create a class named Dog # ... .namespace ['Dog'] .sub init :vtable # ... 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 =head2 How do I instantiate a class? You can do so either with the class name: new $P0, 'Dog' or with the class object: $P1 = get_class 'Dog' # find the 'Dog' class unless null $P1 goto have_dog_class printerr "Oops; can't find the 'Dog' class.\n" .return () have_dog_class: new $P0, $P1 # creates a Dog object and stores it in register $P0 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 C opcode the constructor is called. =head2 How can I pass arguments to a constructor? 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 =head2 How do I add module/class methods? TODO =head2 How do I access module/class variables? TODO =head1 Exceptions =head2 How do I throw an exception in PIR? Create an Exception object and throw it! $P0 = new 'Exception' throw $P0 Not too hard, is it? =head2 How do I throw an exception with an error message in PIR? $P0 = new 'Exception' $P0['_message'] = 'something happened' throw $P0 =head2 How do I catch an exception in PIR? Use C to push an exception handler onto the stack. push_eh handler $P0 = new 'Exception' # or any other code ... throw $P0 # ... that might throw pop_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 ($P0, $S0) print 'Exception caught:' print $S0 print "\n" exit 1 =head2 How do I let exceptions from C pass through my handler? Rethrow the exception if it has a severity of C. handler: .include 'except_severity.pasm' .get_results ($P0, $S0) $I0 = $P0[2] if $I0 == .EXCEPT_EXIT goto unexceptional print "Exception caught!\n" exit 1 unexceptional: rethrow $P0 =head2 How do I access the error message of an exception I've caught? push_eh handler $P0 = new 'Exception' $P0['_message'] = 'something happened' throw $P0 pop_eh exit 0 handler: .local pmc exception .local string message .get_results (exception, message) print 'Exception: ' print message print "\n" exit 1 =head1 C Extensions =head2 How do I create PMCs for my compiler? Parrot supports dynamic PMCs, loadable at runtime, to allow compiler writers to extend Parrot with additional types. For more information about writing PMCs, see L and L. 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) && $(PMCBUILD) generate $(PMCS) @cd $(PMCDIR) && $(PMCBUILD) compile $(PMCS) @cd $(PMCDIR) && $(PMCBUILD) linklibs $(PMCS) @cd $(PMCDIR) && $(PMCBUILD) copy "--destination=$(DESTDIR)" $(PMCS) =head2 How do I add another op to Parrot? 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 L. 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) =head2 How do I use the Native Calling Interface (NCI)? 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: .sub main :main .local pmc lib, func # load the shared library lib = loadlib "hello" # no extension, .so or .dll is assumed # get a reference to the function from the library just # loaded, called "foo", and signature "void" (and no arguments) func = dlfunc lib, "foo", "v" # invoke func() .end 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: .local pmc lib .local string libname null libname lib = loadlib libname Under Linux, the .c file must then be linked with the -export-dynamic option. =head1 Misc =head2 How can I access a program's environment? Create a new C PMC and access it like a hash. .local pmc e e = new 'Env' $P0 = e['USER'] # lt =head2 How can I access Parrot's configuration? .include 'iglobals.pasm' .local pmc interp, cfg interp = getinterp cfg = interp[.IGLOBALS_CONFIG_HASH] $S0 = cfg['VERSION'] # "0.3.0" See F for all the keys in the config hash - or iterate over the config hash. =head1 Languages =head2 What files do I need to modify to add my new language compiler? 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.