10.2 Variables and Constants

     

10.2 Variables and Constants

Literal constants in PIR are the same as constants in PASM. Integers and floating-point numbers are numeric literals and strings are enclosed in quotes. PIR strings use the same escape sequences as PASM.

10.2.1 Parrot Registers

PIR code has a variety of ways to store values while you work with them. The most basic way is to use Parrot registers directly. PASM register names always start with a single character that shows whether it is an integer, numeric, string, or PMC register, and end with the number of the register (between 0 and 31):

 S0 = "Hello, Polly.\n" print S0 

When you work directly with Parrot registers, you can only have 32 registers of any one type at a time. [1] If you have more than that, you have to start shuffling stored values on and off the user stack. You also have to manually track when it's safe to reuse a register. This kind of low-level access to the Parrot registers is handy when you need it, but it's pretty unwieldy for large sections of code.

[1] Only 31 for PMC registers, because P31 is reserved for spilling.

10.2.2 Temporary Registers

PIR provides an easier way to work with Parrot registers. The temporary register variables are named like the PASM registers ”with a single character for the type of register and a number ”but they start with a $ character:

 set $S42, "Hello, Polly.\n" print $S42 

The most obvious difference between Parrot registers and temporary register variables is that you have an unlimited number of temporaries. Parrot handles register allocation for you. It keeps track of how long a value in a Parrot register is needed and when that register can be reused.

The previous example used the $S42 temporary. When the code is compiled, that temporary is allocated to a Parrot register. As long as the temporary is needed, it is stored in the same register. When it's no longer needed, the Parrot register is re-allocated to some other value. This example uses two temporary string registers:

 $S42 = "Hello, " print $S42 $S43 = "Polly.\n" print $S43 

Since they don't overlap, Parrot allocates both to the S16 register. If you change the order a little so both temporaries are needed at the same time, they're allocated to different registers:

 $S42 = "Hello, "  # allocated to S17 $S43 = "Polly.\n" # allocated to S16 print $S42 print $S43 

In this case, $S42 is allocated to S17 and $S43 is allocated to S16 .

Parrot allocates temporary variables [2] to Parrot registers in ascending order of their score. The score is based on a number of factors related to variable usage. Variables used in a loop have a higher score than variables outside a loop. Variables that span a long range have a lower score than ones that are used only briefly .

[2] As well as named variables, which we talk about next .

If you want to peek behind the curtain and see how Parrot is allocating registers, you can run it with the -d switch to turn on debugging output:

 $ parrot -d1000 hello.imc 

If hello.imc contains this code from the previous example (wrapped in a subroutine definition so it will compile):

 .sub _main   $S42 = "Hello, "  # allocated to S17   $S43 = "Polly.\n" # allocated to S16   print $S42   print $S43   end .end 

it produces this output:

 code_size(ops) 11  oldsize 0 0 set_s_sc 17 1 set S17, "Hello, " 3 set_s_sc 16 0 set S16, "Polly.\n" 6 print_s 17    print S17 8 print_s 16    print S16 10 end  end Hello, Polly. 

That's probably a lot more information than you wanted if you're just starting out. You can also generate a PASM file with the -o switch and have a look at how the PIR code translates :

 $ parrot -o hello.pasm hello.imc 

or just:

 $ parrot -o- hello.imc 

to see resulting PASM on stdout .

You'll find more details on these options and many others in Section 11.4 in Chapter 11.

10.2.3 Named Variables

Named variables can be used anywhere a register or temporary register is used. They're declared with the .local statement or the equivalent .sym statement, which require a variable type and a name :

 .local string hello set hello, "Hello, Polly.\n" print hello 

This snippet defines a string variable named hello , assigns it the value "Hello, Polly.\n", and then prints the value.

The valid types are int , float , string , and pmc or any Parrot class name (like PerlInt or PerlString ). It should come as no surprise that these are the same divisions as Parrot's four register types. Named variables are valid from the point of their definition to the end of the compilation unit.

The name of a variable must be a valid PIR identifier. It can contain letters , digits, and underscores, but the first character has to be a letter or underscore . Identifiers don't have any limit on length yet, but it's a safe bet they will before the production release. Parrot opcode names are normally not allowed as variable names, though there are some exceptions.

10.2.3.1 PMC variables

PMC registers and variables act much like any integer, floating-point number, or string register or variable, but you have to instantiate a new PMC object before you use it. The new instruction creates a new PMC. Unlike PASM, PIR doesn't use a dot in front of the class name.

 P0 = new PerlString        # same as new P0, .PerlString P0 = "Hello, Polly.\n" print P0 

This example creates a PerlString object, stores it in the PMC register P0 , assigns the value "Hello, Polly.\n" to it, and prints it. The syntax is exactly the same for temporary register variables:

 $P4711 = new PerlString $P4711 = "Hello, Polly.\n" print $P4711 

With named variables, the type passed to the .local directive is either the generic pmc or a type compatible with the type passed to new :

 .local PerlString hello    # or .local pmc hello hello = new PerlString hello = "Hello, Polly.\n" print hello 

10.2.4 Named Constants

The .const directive declares a named constant. It's very similar to .local and requires a type and a name. The value of a constant must be assigned in the declaration statement. As with named variables, named constants are visible only within the compilation unit where they're declared. This example declares a named string constant hello and prints the value:

 .const string hello = "Hello, Polly.\n" print hello 

Named constants function in all the same places as literal constants, but have to be declared beforehand:

 .const int the_answer = 42        # integer constant .const string mouse = "Mouse"     # string constant .const float pi = 3.14159         # floating point constant 

10.2.5 Register Spilling

As we mentioned earlier, Parrot allocates all temporary register variables and named variables to Parrot registers. When Parrot runs out of registers to allocate, it has to store some of the variables elsewhere. This is known as spilling . Parrot spills the variables with the lowest score and stores them in a PerlArray object while they aren't used, then restores them to a register the next time they're needed. Consider an example that creates 33 integer variables, all containing values that are used later:

 set $I1, 1 set $I2, 2  . . .  set $I33, 33  . . .  print $I1 print $I2  . . .  print $I33 

Parrot allocates the 32 available integer registers to variables with a higher score and spills the variables with a lower score. In this example, it picks $I1 and $I2 . Behind the scenes, Parrot generates code to store the values:

 new P31, .PerlArray  . . .  set I0, 1           # I0 allocated to $I1 set P31[0], I0      # spill $I1 set I0, 2           # I0 reallocated to $I2 set P31[1], I0      # spill $I2 

It creates a PerlArray object and stores it in register P31 . [3] The set instruction is the last time $I1 is used for a while, so immediately after that, Parrot stores its value in the spill array and frees up I0 to be reallocated.

[3] P31 is reserved for register spilling in PIR code, so generally it shouldn't be accessed directly.

Just before $I1 and $I2 are accessed to be printed, Parrot generates code to fetch the values from the spill array:

 . . .  set I0, P31[0]       # fetch $I1 print I0 

You cannot rely on any particular register assignment for temporary variables or named variables. The register allocator does follow a set of precedence rules for allocation, but these rules may change. Also, if two variables have the same score, Parrot may assign registers based on the hashed value of the variable name. Parrot randomizes the seed to the hash function to guarantee you never get a consistent order.



Perl 6 and Parrot Essentials
Perl 6 and Parrot Essentials, Second Edition
ISBN: 059600737X
EAN: 2147483647
Year: 2003
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net