Game Programming Language
Phase 5: Expressions

This is the hardest phase of the project.  Students who finish this phase on time usually finish the entire project.  Start right away.

Usually this assignment is due before spring break.  However, this year spring break is early so it is due at the end of the week after spring break.  I strongly suggest that you start right away and finish before spring break.

It is unlikely that you will be able to finish this assignment if you don't start until after spring break.  I will be out of town for spring break and will not be able to help.


Overview:

Implement a class to hold expressions.  
Specifically, you need to implement a class that describes a node in an expression tree.  Since a pointer to the root of an expression tree (which is a node in the tree) is a pointer to an entire expression tree, an expression tree can be stored with a single pointer to the root.  In my implementation and in this document, I named this class Expression.  You may name your class whatever you want.

After you have implemented the expression class, add actions to your gpl.y that build an expression tree when an expression is parsed.  Specifically, you need to implement actions for all rules that have the following non-terminals as their left-hand-side (it will help you design the expression class if you understand the code you will write for these actions):
expression
primary_expression
optional_initializer
math_operator
geometric_operator
variable // except for the rules that have a T_PERIOD on the right-hand-side, will do them later

Once your parser is building expression trees, add actions to initialize integer, double, and string variables to the value of the given expression.  This is done in the rules that have optional_initializer as their left-hand-side.  When you are done, you will be able to initialize int/double/string variables to any legal expression:
int i = 42;
int j = i * 42;
double x = i * j * 1.42 / (55 + 2 * i);  // integers are automatically cast to doubles
string = "hello" + " " + "world";
string = "x = " + x;                     // doubles and integers are automatically cast to string

For assignment p4 you changed the rule for declaring arrays:
simple_type T_ID T_LBRACKET expression T_RBRACKET
Was changed to:
simple_type T_ID T_LBRACKET T_INT_CONSTANT T_RBRACKET
For p5, you need to change it back (replace T_INT_CONSTANT to expression) and update your action for creating an array so that the expression is evaluated to get the size of the array.  My code looks like this:
simple_type T_ID T_LBRACKET expression T_RBRACKET
{
...
// check that $4 is of type int
int array_size = $4->eval_int(); // my Expression class has a function eval_int()
...
}

The bulk of this assignment is the creation of the data structure to hold an expression tree.   In many gpl statements expressions are evaluated at run-time, and thus we need a data structure to hold an expression so that we can evaluate it at run time.  In this phase of the assignments you will use expression only in one place: variable initialization.  Since variables are initialize only once it would be possible to avoid building an expression tree and simply calculate the value of the expression like you did in p1.  HOWEVER, since we will need the expression tree in the next phase YOU MUST IMPLEMENT IT NOW and use it for variable declarations.

A small but important part of this assignment is to develop a class that can represent a variable.  I call this class Variable (you can use whatever name you want).  There are three forms of variables in gpl, simple variables (such as the variable i), member variables (such as the member variable x of a rectangle variable:  my_rectangle.x), and array variables (such as i[x*y] and my_rectangle[42].x).  There are two types of operations that are performed on variables, set and get.  Class Variable provides a single interface to the three types of variables (simple, member, and array) and to both types of operations (get and set).  A simple variable contains a pointer to a symbol.  If the variable is a member variable, it contains the name of the field plus a pointer to a symbol.  If the variable is an array, it contains a pointer to the expression used to calculate the index and after the index is calculated at run time the symbol can be looked up in the symbol table.
 

Requirements:

In addition to the requirements from p4,  your interpreter must be able to initializes variable (integers, doubles, strings) using an expression and your parser must handle an expression as the size of and array.

In p4 all variables (integer, double, string) were initialized to the constants 42, 3.145, "Hello world".  In this assignment if an optional initializer is not specified, use the values 0, 0.0, "".  Since gpl arrays can never have initial values, they should always be initialized to these default values.


Hints:

WARNING: In order to initialize variables you do not need an expression tree.  You could simply evaluate the expression while parsing it.  DO NOT DO THIS.  In order to implement statements you need to be able to represent an expression (using an expression tree).  If you do not build an expression tree in this assignment you will not be able to complete the rest of the project (and you won't have enough time to implement the expression tree when you are implementing statements).  

The variable class is needed for future assignments, make sure you implement the variable class as I describe it.  If you don't understand the variable class, talk to me until you do understand it.

If you do not implement an expression class and a variable class you will not be able to complete future assignments.

Expressions in gpl are strongly typed.  The types are integer, double, string, and animation_block (since you don't need them for this phase, it is easier if you add animation_block to your expressions in a later phase).  Since expressions are strongly typed, you must keep type information in the expression class.  If you don't keep type information you will not be able to perform the required error checking.  Consider the following example:

int i = 42 + "hello world";

This input will match the following rule:
simple_type T_ID optional_initializer
The <int> will match simple_type, the <i> will match T_ID, and the <42 + "hello world"> will match expression (optional_initializer derives expression).  Since integers are automatically converted to strings when in a string expression, the expression <42 + "hello world"> is a valid string expression (it has the value "42hello").  In other words, this legal expression is of type string.   In gpl it is a semantic error to assign a string to an integer and thus the above input should generate an error.

The check for correct type can be made as follows (assume that optional_initializer returns a pointer to an expression) and your expression class has a get_type() function:

simple_type T_ID optional_initializer
{
if ($1 == INT) // the type of my simple_type token is Gpl_type
{
int initial_value = 0;  // 0 is the default value for integers
// if an initializer was specified
if ($3 != NULL)
{
if ($3->get_type() != INT)
error -- the initializer is not of the correct type
else initial_value = $3->eval_int();
}
// now a new symbol can be created using initial_value


}
// do other cases here (e.g. $1 == DOUBLE)
}

There are two primary functions of class Expression.   (1) you need to construct the tree, and (2) you need to be able to evaluate it.

The construction is straight forward.  For each expression and primary_expression rule in the grammar, you create a new node in the expression tree.  Since the parser will match the expression in a bottom up fashion, you just build the tree as you parse the expression.  Consider the example of the addition rule:

expression:
    expression T_PLUS expression
    {
         // check that the type of $1 and $3 are compatible
$$ = new Expression(PLUS, $1, $3);
    }

All you have to do is create constructors for Expression that can handle all the different configurations of an expression tree and call them in the appropriate actions.   The constructor shown in the above example is for binary expressions.  It takes an operator (I used an enumerated type Operator_type from gpl_type.h) and pointers to two other expressions.   Expression_grammar shows all the rules used to parse expressions. 

Note: for this assignment you will not be adding an action for the following rule:
expression -> variable geometric_operator variable

The Expression evaluation function recursively evaluates each node in the tree.  The algorithm performs a depth-first traversal of the tree.  When a node's evaluation function is called, if the node has children, it calls evaluate on the left child, then the right child, then applies its operator.  If the node holds a constant (integer, double, string), it returns the value.  If it holds a variable, it evaluates the variable (e.g. my_variable->get_int_value() ) and returns the value.

You will need to add a pointer to your expression class to the union in gpl.y.  This means that you will have to add an include for the expression's .h file in parser.h.

Variable class:

The expression node class has to handle several different basic forms:

Expression Node Forms Node Contents
Binary operator operator, pointer to left child, pointer to right child
Unary operator operator, pointer to child
Integer constant value of integer constant
Double constant value of double constant
String constant value of string constant

These forms handle all expressions that do not contain any variables:

3 + 4
7 * -3
6 * sin(42)

In order to handle expressions that contain variables, the expression node will have to handle all the forms of variables.  Consider the following expressions
a
my_rectangle.x
nums[a + b]
rectangles[i + 2].y

We could implement several expression nodes to handle all these possible

Expression Node Forms Node contents
a pointer to a symbol that holds a integer, double, or string variable
my_rectangle.x pointer to a symbol that holds a game object, AND a string to describe the field
nums[a + b] a symbol for an array AND an expression for the index of the array
rectangles[i + 2].y a symbol for an array AND an expression for the index of the array AND a string for the field


Or we could implement a class to encapsulate all the possible variables:

Expression Node Forms Node contents
a pointer to a Variable object
my_rectangle.x pointer to a Variable object
nums[a + b] pointer to a Variable object
rectangles[i + 2].y pointer to a Variable object

The variable class simply encapsulate these possible forms of a variable into a single interface. 

Note: for this assignment you will not be implementing variables that have fields (i.e. no game object variables).

An added advantage of the Variable class is that when you implement the assignment statement you will be able to use this class to represent variables on the left-hand-side of the assignment operator.



Turning in and Testing:

See docs/turnin.html for a description of how to turn in assingments.

See docs/testing.html for a description of how to test your program.