Assignment Traversals
Pt04
The purpose of this assignment is to understand how traversal
strategies work. The assignment consists of two parts. In the first
part, you will implement some small exercises using congruences and
generic traversals. In the second part, you will define a format
checker and implementation of a transformation to a normal form.
More Stratego
Using the Stratego Library
From now, you are allowed to use the Stratego Library. The library
contains many useful strategies for io, list processing, traversals,
and so
on.
API and source documentation of the Stratego Library is available
online.
Stratego Unit
In this exercise, you will define test suites in the Stratego Unit
(
sunit) unit testing framework. The Stratego/XT manual explains how
to use
sunit to define test suites:
Unit Testing with SUnit.
Stratego Compiler and Interpreter
You have already used the Stratego Shell extensively during the
previous assignment. The Stratego Shell is an interface to the
Stratego Interpreter. In this assignment, you will use an alternative
front-end,
stri, which allows you to execute modules with a certain
entry point (
main by default). Invocation of
stri will be
explained later. You can still use the Stratego Shell to experiment
with the language and your solutions.
Stratego modules can also be compiled using the Stratego Compiler:
$ strc -i module.str
The resulting program will be
much faster than the interpreter, but
the compilation itself takes some time. However, for larger examples
in the
innermost assignment, this additional compilation time is
well spent.
(A) Small Traversals
File Instructions
- Define your solutions in a Stratego module
cong-traversal.str.
- Define a test suite in the Stratego module
traversal-tests.str. Parameterize all test cases with the actual implementation of the strategy. This is important to make your test suite reusable for the generic traversal exercise.
- Apply your test suite to the
cong-traversal strategies in the Stratego module cong-traversal-tests.str.
For your convenience, we provide skeletons for the various files:
cong-traversal.str
module cong-traversal
imports Tiger
strategies
foo = id
cong-traversal-tests.str
module cong-traversal-tests
imports
cong-traversal
traversal-tests
Tiger
sunit
strategies
main =
test-suite(!"Congruence traversal tests",
foo-test(foo)
)
traversal-tests.str
module traversal-tests
imports
Tiger
sunit
strategies
foo-test(s) =
apply-test(!"Identity test", s, !Int("2"), !Int("3"))
You can now run the test suite using
stri. =stri executes the
main
strategy of a specified Stratego module.
$ stri cong-traversal-tests.str
test suite: Congruence traversal tests
Identify test
result not equal : Int("2")
expected : Int("3")
successes: 0
failures: 1
stri: rewriting failed
Running a Stratego module
foo.str with
stri is equivalent to
entering the following commands in the Stratego Shell:
stratego> import foo
stratego> main
Tiger Subset
In this part of the assignment, we use the following subset of Tiger:
regular tree grammar
start Exp
productions
Exp -> Int(<string>)
Exp -> Var(<string>)
Exp -> Uminus(Exp)
Exp -> Plus(Exp,Exp)
Exp -> Times(Exp,Exp)
(A.1) Congruence Exercises
For each item in the list below you should write:
- a strategy definition in
cong-traversal.str
- a few parameterized tests in
traversal-tests.str
- applications of these tests in
cong-traversal-tests.str
You are not allowed to use generic traversals. All traversing code
must be implemented using congruences. The tests should demonstrate
the working of the strategy and of course you can use them to test
your solution by running the test suite.
Tip: it is useful to define reusable primitives for traversing the
Tiger subset (i.e.
one-Tiger,
some-Tiger,
all-Tiger, etc).
- Replace all
Var("x") by Int("3").
- Replace all
Var("x") by Int(x), where x is a given integer (i.e. parameterize the strategy of the previous exercise).
- Replace all multiplications by 2 (i.e.
e*2 or 2*e) by an addition (i.e. e+e).
- Replace all outermost additions by multiplications (yes, this entirely meaningless). An outermost term is the first term from the root. For example, in
B(A(A(1))) the outermost A is A(A(1)).
- Replace all innermost additions by multiplications. An innermost term is the first term from the leaves. In the previous example, the innermost
A is A(1).
(A.2) Generic Traversal Exercises
Now, create the modules
generic-traversal.str and
generic-traversal-tests.str. Repeat the previous exercise, this time
using generic traversals. The traversals should be as generic as
allowed by the description: your solutions should support the full
Tiger language. Invoke all the tests you developed in the previous
exercise and add some more tests for the full Tiger language to the
generic-traversal-tests.str module.
(B) Additive Normal Form
(B.1) Format Checking
A format checker is a `transformation' which checks the format of a
term. For instance, the
TAS-Format component of the Tiger compiler
checks if a term is a well-formed Tiger abstract syntax tree. Format
checkers can be defined nicely using congruence operators. See the
source
of the
TAS-Format component.
Define a format checker that checks if a Tiger expression is in
additive normal form (ANF). This means that the expression only
consists of additions of multiplications. Also, the only place where a
constant integer is allowed, is at the first point of the
multiplication and as the last addition. In other words, an expression
in ANF has the form
a * x + b * y + ... + c, where
a,
b, and
c
are integer constants and
x and
y are variables. Multiple
variables are allowed in a single multiplication and the same
variable is allowed to occur in more then one multiplication.
For example, the ANF of
4 + (x + 5) * 2 + 3 * y * 5 * z + x
is
2 * x + 15 * y * z + x + 14
Define a format checker strategy in a Stratego module
anf-format.str
that checks that an expression is in ANF form. The strategy should
fail if an expression is not in ANF.
(B.2) Innermost Normalization
In this part of the assignment you will implement the transformation
that achieves the ANF. Use the ANF format checker to test more complex
examples and test smaller examples by explicitly mentioning the
expected outcome.
Extend the following skeleton of a Stratego Module with rewrite rules
that achieve the transformation of an expression in our Tiger subset
mentioned before to ANF. You are not allowed to do any traversal
related stuff in the rewrite rules. The skeleton defines a
main
strategy that handles input and output.
module anf
imports
fixpoint-traversal
options
Tiger
strategies
main =
io-wrap(anf)
anf =
innermost(fail /* Invoke your rules here */ )
Use
stri to run the tool:
echo 'Int("1")' | stri anf.str
or, for a Tiger file in concrete syntax:
parse-tiger -i foo.tig | stri anf.str
Of course, you implement a test suite for your
anf transformation
(for example in module called
anf-tests.str).
Submission
Pack your Stratego modules in a
.tar.gz or
.zip file and send your
solution by email to
martin@cs.uu.nl at least 15 minutes before the
lecture of Tuesday, i.e. 8:45. The same day, you will get a short
notification that I've received your solution. If you don't get this
reply, then please contact me.
Questions
After the lab session you can still send questions to
pt@cs.uu.nl or
join
#stratego at
irc.freenode.com.