Skip to content

Commit

Permalink
Update tutorial describing setting up $?BLOCK and @?BLOCK.
Browse files Browse the repository at this point in the history
  • Loading branch information
tcurtis committed Jul 17, 2010
1 parent 2462f25 commit 758d575
Showing 1 changed file with 42 additions and 42 deletions.
84 changes: 42 additions & 42 deletions doc/tutorial_episode_5.pod
Expand Up @@ -150,46 +150,25 @@ are parsed (and their parse actions are executed -- these might need to enter
symbols in the block's symbol table), we add a few extra parse actions. Let's
take a look at them.

rule TOP {
{*} #= open
<statement>*
[ $ || <.panic: syntax error> ]
{*} #= close
}
Add this token to the grammar:

We now have two parse actions for TOP, which are differentiated by an
additional key parameter. The first parse action is executed before any input
is parsed, which is particularly suitable for any initialization actions you
might need. The second action (which was already there) is executed after the
whole input string is parsed. Now we can create a C<PAST::Block> node before
any statements are parsed, so that when we need the current block, it's there
(somewhere, later we'll see where exactly). Let's take a look at the parse
action for TOP.

method TOP($/, $key) {
our $?BLOCK;
our @?BLOCK;

if $key eq 'open' {
$?BLOCK := PAST::Block.new( :blocktype('declaration'),
:node($/) );
token begin_TOP {
<?>
}

@?BLOCK.unshift($?BLOCK);
}
else { # key is 'close'
my $past := @?BLOCK.shift();
It uses something we haven't seen before, <?>. The null pattern <?> always returns true without consuming any text. Tokens consisting of only <?> are frequently used to invoke additional action methods.

for $<statement> {
$past.push( $( $_ ) );
}
Add this method to Actions.pm:

make $past;
}
method begin_TOP ($/) {
our $?BLOCK := PAST::Block.new(:blocktype<declaration>, :node($/),
:hll<squaak>);
our @?BLOCK;
@?BLOCK.unshift($?BLOCK);
}

Let's see what's happening here. When the parse action is invoked for the first
time (when C<$key> equals "open"), a new C<PAST::Block> node is created and
assigned to a strange-looking (if you don't know Perl, like me. Oh wait,
We create a new C<PAST::Block> node and
assign it to a strange-looking (if you don't know Perl, like me. Oh wait,
this is Perl. Never mind..) variable called C<$?BLOCK>. This variable is
declared as "our", which means that it is a package variable. This means that
the variable is shared by all methods in the same package (or class), and,
Expand All @@ -201,14 +180,35 @@ After that, this block is unshifted onto another funny-looking variable, called
C<@?BLOCK>. This variable has a "@" sigil, meaning this is an array. The
unshift method puts its argument on the front of the list. In a sense, you
could think of the front of this list as the top of a stack. Later we'll see
why this stack is necessary.

This C<@?BLOCK> variable is also declared with "our", meaning it's also
package-scoped. However, as we call a method on this variable, it should have
been already created; otherwise you'd invoke the method on an undefined
("Undef") variable. So, this variable should have been created before the
parsing starts. We can do this in the compiler's main program, squaak.pir.
Before doing so, let's take a quick look at the "else" part of the parse action
why this stack is necessary. This C<@?BLOCK> variable is also declared with "our", meaning it's also
package-scoped. Since it's an array variable, it is automatically initialized with an empty ResizablePMCArray.

Now we need to modify our TOP rule to call begin_TOP.

rule TOP {
<.begin_TOP>
<statementlist>
[ $ || <.panic: "Syntax error"> ]
}

"<.begin_TOP>" is just like <begin_TOP>, calling the subrule begin_TOP, with one difference: The <.subrule> form does not capture. Normally, when match a subrule <foo>, $<foo> on the match object is bound to the subrule's match result. With <.foo>, $<foo> is not bound.

The parse action for begin_TOP is executed before any input
is parsed, which is particularly suitable for any initialization actions you
might need. The action for TOP is executed after the
whole input string is parsed. Now we can create a C<PAST::Block> node before
any statements are parsed, so that when we need the current block, it's there
(somewhere, later we'll see where exactly). Let's take a look at the parse
action for TOP.

method TOP($/, $key) {
our @?BLOCK;
my $past := @?BLOCK.shift();
$past.push($<statementlist>.ast);
make $past;
}

Let's take a quick look at the updated parse action
for TOP, which is executed after the whole input string is parsed. The
C<PAST::Block> node is retrieved from C<@?BLOCK>, which makes sense, as it was
created in the first part of the method and unshifted on C<@?BLOCK>. Now this
Expand Down

0 comments on commit 758d575

Please sign in to comment.