Due: Tuesday, Oct 29th by 11:59 PM

Update 10/23 - due date extended to Tues, Oct 29th, and new version of ASTBuilderTest.rb posted

Getting Started

Download CS340_Assign05.zip and unzip it. This should create a directory called CS340_Assign05.

Note: If you downloaded CS340_Assign05.zip prior to Oct 23rd, please download the following new version of ASTBuilderTest.rb:

ASTBuilderTest.rb

Copy all of the .rb files for your lexer and parser that you made in Assignment 4 into the CS340_Assign05 directory.

Your task is to modify ASTBuilder.rb as described below.

Abstract Syntax Trees

Your task in this assignment is to take the parse trees created by your parser (from Assignment 4 and use it to build an abstract syntax tree (AST). A full explanation of abstract syntax trees can be found in Lecture 9.

The basic idea of an abstract syntax tree is that it encodes the same meaning as a parse tree, but removes all redundant/extraneous information.

In the next assignment, you will use the ASTs generated by your AST builder to implement a simple compiler for the language accepted by the parser!

Your Task

Complete the _build method in in ASTBuilder.rb so that it takes the root node of a parse tree and returns an equivalent AST.

The _build method should check the type of the parse tree node n (its parameter) and return an AST. Use the following strategies for each kind of parse tree node.

statement_list: Return a "flattened" statement list. All of the statements in the statement list (as produced by the parser) should be added as children of a single statement_list AST node.

var_decl_statement: Return an AST node labeled with the symbol var_decl that has the identifier as its single child.

Binary operators (such as op_add, op_assign, etc.): return an AST node labeled with the operator, and whose children are the result of converting the two subexpressions to ASTs.

primary: If the parse node represents a parenthesized expression, convert just the expression to an AST and return it. Otherwise, the primary is either an identifier, integer literal, or string literal, so just return the single child node.

All other nodes that have a single child (e.g., unit, statement, expression_statement): Return the result of converting the single child to an AST.

Hint

The _build method will be recursive. If you need to convert a child into an AST, make a recursive call to _build, passing the child to convert as the argument.

Testing

To test your ASTBuilder class, run the command

ruby ASTBuilderTest.rb

Enter a source program. Type Control-D on an empty line to notify the lexer that you are done typing input. The result of the program will be a textual representation of the parse tree, followed by a textual representation of the AST created by ASTBuilder.

Examples

Example run (user input in bold):

var a;
var b;
a := 4;
b := a ^ 2;
a ^ (b + 3);
Parse Tree:
unit
+--statement_list
   +--statement
   |  +--var_decl_statement
   |     +--var("var")
   |     +--identifier("a")
   |     +--semicolon(";")
   +--statement_list
      +--statement
      |  +--var_decl_statement
      |     +--var("var")
      |     +--identifier("b")
      |     +--semicolon(";")
      +--statement_list
         +--statement
         |  +--expression_statement
         |     +--op_assign
         |     |  +--primary
         |     |  |  +--identifier("a")
         |     |  +--primary
         |     |     +--int_literal("4")
         |     +--semicolon(";")
         +--statement_list
            +--statement
            |  +--expression_statement
            |     +--op_assign
            |     |  +--primary
            |     |  |  +--identifier("b")
            |     |  +--op_exp
            |     |     +--primary
            |     |     |  +--identifier("a")
            |     |     +--primary
            |     |        +--int_literal("2")
            |     +--semicolon(";")
            +--statement_list
               +--statement
                  +--expression_statement
                     +--op_exp
                     |  +--primary
                     |  |  +--identifier("a")
                     |  +--primary
                     |     +--lparen("(")
                     |     +--op_plus
                     |     |  +--primary
                     |     |  |  +--identifier("b")
                     |     |  +--primary
                     |     |     +--int_literal("3")
                     |     +--rparen(")")
                     +--semicolon(";")

Abstract Syntax Tree:
statement_list
+--var_decl
|  +--identifier("a")
+--var_decl
|  +--identifier("b")
+--op_assign
|  +--identifier("a")
|  +--int_literal("4")
+--op_assign
|  +--identifier("b")
|  +--op_exp
|     +--identifier("a")
|     +--int_literal("2")
+--op_exp
   +--identifier("a")
   +--op_plus
      +--identifier("b")
      +--int_literal("3")

Example run (user input in bold):

a * b + c;
Parse Tree:
unit
+--statement_list
   +--statement
      +--expression_statement
         +--op_plus
         |  +--op_mul
         |  |  +--primary
         |  |  |  +--identifier("a")
         |  |  +--primary
         |  |     +--identifier("b")
         |  +--primary
         |     +--identifier("c")
         +--semicolon(";")

Abstract Syntax Tree:
statement_list
+--op_plus
   +--op_mul
   |  +--identifier("a")
   |  +--identifier("b")
   +--identifier("c")

Example run (user input in bold):

a ^ b ^ c;
Parse Tree:
unit
+--statement_list
   +--statement
      +--expression_statement
         +--op_exp
         |  +--primary
         |  |  +--identifier("a")
         |  +--op_exp
         |     +--primary
         |     |  +--identifier("b")
         |     +--primary
         |        +--identifier("c")
         +--semicolon(";")

Abstract Syntax Tree:
statement_list
+--op_exp
   +--identifier("a")
   +--op_exp
      +--identifier("b")
      +--identifier("c")

Example run (user input in bold):

(a ^ b) ^ c;
Parse Tree:
unit
+--statement_list
   +--statement
      +--expression_statement
         +--op_exp
         |  +--primary
         |  |  +--lparen("(")
         |  |  +--op_exp
         |  |  |  +--primary
         |  |  |  |  +--identifier("a")
         |  |  |  +--primary
         |  |  |     +--identifier("b")
         |  |  +--rparen(")")
         |  +--primary
         |     +--identifier("c")
         +--semicolon(";")

Abstract Syntax Tree:
statement_list
+--op_exp
   +--op_exp
   |  +--identifier("a")
   |  +--identifier("b")
   +--identifier("c")

Submitting

To submit, run the command

make submit

from the directory containing the lexical analyzer files. Type your Marmoset username and password when prompted.

You can also create a zip file containing your code, and upload it to Marmoset as assign05 using the web interface:

https://cs.ycp.edu/marmoset