The Shakespeare Programming Language, on Parrot


SPL is a language designed to allow usage of the beatiful shakespear wording
while writing executable code.

The reference implementation is at [1] and you can see some more info in the page for the shakespeare frontend for GCC [2]

Quoting from the original project:

    The design goal was to make a language with beautiful source code that
    resembled Shakespeare plays. There are no fancy data or control structures,
    just basic arithmetic and gotos. You could say we have combined the ex-
    pressiveness of BASIC with the user-friendliness of assembly language.

How Reductive! SPL is a great achievement in unifying art and code, a noble
goal which must not be underestimated.

So, to try to learn a bit about Parrot[3], I did this.


    $ parrot setup.pir
    $ parrot setup.pir test
    $ parrot setup.pir spectest
    $ sudo parrot setup.pir install

If you are reading this you must have obtained the shakespeare-parrot
distribution, and I congratulate you.
Put the files in a languages/shakespeare/ directory in a parrot source tree
and run make.
make test will execute the test suite, to run your own file use
    ../../parrot shakespeare.pir filename.spl
since we used the standard parrot's HLLCompiler you can use the usual flags
such as --target=(parse|pir) to see the parse three and the PIR output.

You can also access the interpreter interactively.
Since setting up a whole play would be useless, you can input single sentences
and see how they will be parsed:
$ parrot shakespeare.pir
Thou hast entered the interactive sentence verifier
Enter a Sentence to see How It Parses
no match
: <king @ 0> 0
<value>: <king @ 0> 0
<value><immediate>: <king @ 0> 0
<value><immediate><noun>: <king @ 0> 0
<value><immediate><noun><positive_noun>: <king @ 0> 0

>twice a pretty king
: <twice a pretty king @ 0> 0
<value>: <twice a pretty king @ 0> 0
<value><computation>: <twice a pretty king @ 0> 0
<value><computation><unary>: <twice a pretty king @ 0> 0
<value><computation><unary><value>: <a pretty king @ 6> 0
<value><computation><unary><value><immediate>: <a pretty king @ 6> 0
<value><computation><unary><value><immediate><article>[0]: <a @ 6> 0
<value><computation><unary><value><immediate><adjective>[0]: <pretty @ 8> 0
<value><computation><unary><value><immediate><adjective>[0]<positive_adjective>: <pretty @ 8> 0
<value><computation><unary><value><immediate><noun>: <king @ 15> 0
<value><computation><unary><value><immediate><noun><positive_noun>: <king @ 15> 0

>let us proceed to scene III
: <let us proceed to scene iii @ 0> 0
<branch>: <let us proceed to scene iii @ 0> 0
<branch><roman>: <iii @ 24> 0

The original SPL project generates C code through spl2c that con
be compiled and linked and linked with libspl to generate executables.
The parser is built with yacc/bison and the lexer is flex. The Perl port[4] uses
the same parser and lexer.

This parrot version uses PGE to parse the grammar and generate an AST,
The parrot toolchain allows automatic transformation of the PAST (Parrot AST) into
POST and then PIR (parrot's high level assembly).

When executed this intermediate code is translated into bytecode and it uses
the functions defined in src/builtins/base.pir to operate.

The runtime uses some global variables:
* the_cast contains a list of characters, each one a tuple
  (value, stack, name, onstage flag)
* the_speaker refers the current speaker, so that the references "thou" and "me"
  are meaningful. Using objects was another option.
* the_condition is a boolean value that gets set from a 'question' statement
  ("is foo better than bar?") and is referenced later. Inlining of the
  value would require a lot of work when building the AST, while the bytecode
  compiler should have no problems doing it.

Although I did not initially look at the original source code while writing
the interpreter it seems that the behaviour of spl2c+libspl is the same.

The list of valid words was originally generated from a list of wordlist files
with an AWK script I have lost track of. It's in the TODO list to fix it.

Notice that since PGE doesn't do (yet) longest token matching, a token like this
    token article  {
        | 'a'
        | 'an'
        | 'the'
would cause a failure to parse "an empty bottle" because the token 'a'
is matched and the token does not backtracks. The grammar goes on trying to
match 'n' and thus fails.
The words where I had test failures were hand fixed, some may still
cause failurese the interactive loop to check.


Shakespeare did not originally support testing explicitly, but in the modern
world of software engineering this would have prohibited building large scale
dramatic-software projects.

Thus, I've added two new instructions to the language to minimally support the
Test Anything Protocol (TAP)[5]
 * plan an evil thing!
   will print "1..2". Every valid value can be used after the word 'plan'.
   Suggestions for improving are welcome, I'm thinking of using
   [othello plans an evil thing]
 * proove yourself!
   will print "ok x" where x is the value of the spoken character.
   Every valid value can be used after the word 'proove'

Test failure is reached through out-of order printing, so for example

   Scene I: a test.
   juliet: art thou better than me?
   romeo: if so, let us proceed to scene ii.
   juliet: proove nothing.

   Scene II: the right branch.
   juliet: proove the joy!

Will print "ok 1" if juliet is better than romeo, which is fine.
If Romeo has an higher value than Juliet "ok 0" will be printed, and considered
as a test failure from the test harness.

The grammar also ignores she-bang lines #!.


I wrote the parser trying not to look at the original grammar, using only the
examples. This means that in some ways the parser is more restrictive and in
some ways it is more loose. Until we have an ISO specification for SPL it is
assumed that this is ok.

The files in example are the original files used in both Lingua::Shakespeare and
spl2c, and their operation is checked through the script t/test.rb.
To verify that everything works you can run "make fulltest" which will execute
both the standard test suite and the examples' test suite.