# Implement an interpreter for simple recursive programs. The # following syntax is taken unchanged from ‹s1/a_while›: # # • one line = one statement (no exceptions), # • blocks are delimited by indentation (1–5 spaces), # • there are following statement types: # ◦ assignment, # ◦ ‹if› statement. # # There are also two important changes: # # 1. The right-hand side of an assignment can be a function call, in # addition to a built-in operation, written as: # # name₀ = func name₁ name₂ … nameₙ # # 2. There is a new statement type, «function definition», which can # only appear in the top-level scope (and is the only statement # than can appear there), of the form: # # def funcname name₁ name₂ … nameₙ # # All functions can call all other functions, regardless of the # order in which they are defined in the source. Function names # follow the same rules as variable names. # # Semantics change in the following way: # # • all variables are «local» to the function in which they are # used (declarations are still not needed), # • the result of a function call is the value of a variable with # the same name, i.e. in function ‹foo›, the statement ‹foo = 7› # sets the return value to ‹7› (but does «not» terminate the # function), # • the namespaces for variables and for functions are separate; # operation names (‹add›, ‹and›, …) «must not» be used for # functions (but they can be used for variables). # # Like ‹if›, a ‹def› statement is followed by a body, indented by a # single space. Other restrictions on blocks remain the same as in # ‹s1/a_while›. # # Example program: # # def fib n # one = 1 # two = 2 # fib = 1 # rec = gt n two # if rec # n_1 = sub n one # n_2 = sub n two # fib_1 = fib n_1 # fib_2 = fib n_2 # fib = add fib_1 fib_2 # # Write a function ‹do_rec› which takes a recursive program (as a # string), a function name, and an arbitrary number of integers. The # result is the return value of the function invoked, or a tuple of # (line number, error string) in case the program fails. Return the # first error in this order (within a group, return the number of # the first line with an error): # # 1. syntax errors (including attempts to redefine a function), # 2. errors in function calls: # ◦ use of an undefined function or # ◦ mismatch in the number of arguments, # 3. runtime errors (division by zero). # # Errors of type 2 should be reported even if they are in unused # code (i.e. the test must be static). If the function passed to # ‹do_rec› does not exist or the number of arguments does not match, # return an error on (virtual) line 0.