FLAMEScript

Extra Credit: CS226
Due: June 6, 2001, 11:59 p.m.

Introduction

After hearing about the incredible ease of FLAME programming, the University development office has decided that FLAME would make the the ultimate internet programming language. However, lacking a nice scripting language interface, they have hired you to create FLAMEScript--the ultimately lame scripting language. Of course, to sell more books and to capitalize on the hype, FLAMEScript has nothing whatsoever to do with FLAME--in fact, it has a completely different syntax.

An example of a FLAMEScript program is as follows:

fun fact(n) {
    r := 1
    while n > 0 {
         r := r * n
         n := n - 1
    }
    return r
}

n := 1
while n < 10 {
    print n, "factorial is", fact(n)
    n := n + 1
}

Your task is to implement a simple scripting language interpreter for FLAMEScript. Your interpreter should read an entire program from standard input and execute it.

FLAMEScript overview

A FLAMEScript program is simply a sequence of statements. The following BNF roughly describes the syntax:
program       :  statements

statements    :  statements statement
              |  empty
              ;
                 
statement     :  ID := expr          
              |  ID ( exprlist )
              |  print exprlist
              |  while relop statement
              |  if relop statement
              |  if relop statement else statement
              |  return expr
              |  break
              |  { statements }
              |  fun ID ( idlist ) { statements }
              ;

expr          :  expr + expr
              |  expr - expr
              |  expr * expr
              |  expr / expr
              |  ( expr )
              |  -expr
              |  +expr
              |  ID
              |  ID ( exprlist )
              |  INTEGER
              |  FLOAT
              |  STRING
              ;

relop         : expr < expr
              | expr <= expr
              | expr > expr
              | expr >= expr
              | expr == expr
              | expr != expr
              | relop and relop
              | relop or relop
              | not relop
              | ( relop )
              ;

exprlist      : exprlist1
              | empty
              ;

exprlist1     : exprlist1 COMMA expr
              | expr
              ;
        
idlist        : idlist1
              | empty
              ;

idlist1       : idlist1 COMMA ID
              | ID
              ;

FLAMEScript is somewhat similar to FLAME in functionality except for the following details:

Scoping rules

All FLAMEScript programs run within two scopes. The global scope contains function definitions and variables assigned in the outer level (outside of a function definition). A local scope contains variables that are defined within the body of each function. When each function is called, a new local scope is created for the locals of that function. When accessing variables, the local scope is first checked followed by the global scope.

When a variable assignment "x := expr" is made, two rules are applied:

(Note that this behavior is different than Python).

Writing your interpreter

Writing an interpreter for FLAMEScript is almost exactly the same as the work you did on FLAME. Specifically, you will need to do the following:

Implementation Hints

  1. Because FLAMEScript is dynamically typed, you can get away with essentially no symbol table management or type checking during compilation (especially if you don't care about error messages). Instead, we'll deal with this at run time.

  2. When executing a FLAMEScript program, simply use a Python dictionary to store information about the defined variables and other aspects of the program. For example, if you have the following FLAMEScript program:
    a = 4
    b = a * 10
    print a, b
    
    This can be emulated in Python as follows:
    symbols = { }             # Symbol table
    symbols['a'] = 4
    symbols['b'] = symbols['a'] * 10
    print symbols['a'], symbols['b']
    

  3. Let Python do all of the expression evaluation and type checking for you. Use Python exceptions to catch type errors and print an appropriate error message.

  4. Evaluation of functions is the most tricky part of the assignment. You will need to store the parse tree for each function in the symbol table someplace. To execute a function, create a new local scope and walk the corresponding function parse tree using this local scope to hold local variables.

  5. At no point during execution should your parser print a Python error message. However, if a runtime error occurs, you should produce some kind of sensible error message. For example:
    a := 4 - "Hello"      /* Type error in - operator */
    
    When a runtime error occurs, your interpreter should print a message and immediately stop execution.

What to turn in

Your FLAMEScript interpreter should consist of three files in a directory called 'flamescript': To run your interpreter, we will simply type:
% python flamescript.py <program.fs
Your interpreter should parse the program supplied on standard input and run it immediately to produce program output.

To hand in your program, create a tar file:

tar -cf yourloginname.tar flamescript
and copy it to /stage/classes/current/CS326/handin/flamescript.

Extra credit will be awarded in proportion to the completeness of your solution. Partial solutions are accepted, but to receive any extra credit points, your solution must minimally be able to parse any syntactically correct FLAMEScript program. More extra credit points will be awarded depending on your interpreter's ability to actually run these programs.

Note: The implementation of this project should not be nearly as involved as FLAME. If you allow Python to do a lot of your work and you have a reasonable grasp of everything we have done this quarter, you should be able to bang this out in a day or so.