Java代写:CS316 Interpreter

扩展之前写的parser.

Requirement

The objective of this project is to extend the parser implemented in Project 2 by an interpreter for our project language except for arrays. Project 4 will extend the interpreter to implement arrays.

The interpreter is to be implemented by Eval and M functions in syntactic-category classes. Implement function-call states by HashMap[String, Val] where Val is the class of values of variables; it maps the variable represented by a string to its value. The function state.put(id, val) can be used to set string id to value val, and the function state.get(id) can be used to get the value of id. Here are the specifications of java.util.HashMap. The Val class included in the sample program is suggested.

The general descriptions of Eval and M functions are provided in Course Notes #7, for function calls in Course Notes #8. You may implement Eval and M functions baed on this sample program. Note however that this sample program uses a single, global program state Interpreter.varState due to the absence of functions, whereas in this project all program states must be local function-call states created at the time of function calls. Include Eval and M functions in pertinent classes involving arrays and leave their bodies trivial, e.g., Eval just returning null and M having an empty body, so that you can implement them in Project 4.

Since our project language is type-free, the interpreter must perform runtime type checking according to a certain set of type rules. In this regard let us adopt the following rules:

  • All arguments of the arithmetic operators +, -, *, / must be numbers, i.e., integers or floating-point numbers. For the binary arithmetic operators, if both arguments are integers, the result will be an integer; otherwise, the result will be a floating-point number.
  • All arguments of the Boolean operators ||, &&, ! must be Boolean values.
  • Both arguments of the comparison operators must be numbers or else Boolean values; in the latter case assume that false < true.
  • If the above type rules are violated, the interpreter should issue appropriate error messages.

The runtime error value can be represented by null or a special subclass of Val.

The operators || and && may be implemented as shortcut operator (only evaluate the 1st argument if it is sufficient to determine the value) or as logical operator (always evaluate both arguments).

You will need to build a map that records the formal parameter list and body of each function, indexed by function name. This is used by the Eval/M function of function-call expressions/statements to form new function-call states and then to interpret the bodies on the new function-call states. HashMap is a good choice for this purpose too. Incorporate construction of this map into the parser. (I used HashMap<String, FunDef> for this purpose.)

You may assume that the source program obeys normal “semantic rules”, for example, that all functions in any function-call expressions/statements are defined, and the number of actual parameter expressions of each function call matches the number of formal parameters defined in the header.

Your program is to perform the following:

  1. Read any text file that contains (what is intended to be) a string in the category fun def list and build an explicit parse tree as per Project 2.
  2. Send lexical/syntax errors, if any, to an output file.
  3. If the source program has no lexical/syntax errors, run the interpreter starting from the main() function defined in the source program.
  4. Display the results of print statements and runtime error messages on the screen.

To make grading efficient and uniform, observe the following:

  • Your interpreter program must read the input/output file names as external arguments to the main function. The 1st argument must be the input file containing the source program to be interpreted; the 2nd argument must be the output file for lexical/syntax error messages. How to set external arguments to Java main function in Eclipse.
  • Every source program to be interpreted must have the parameterless function main() and execution of the interpreter must start from a call to this function. If Java is used, the main function to be invoked to execute the interpreter must be included in Interpreter.java class. You may use Interpreter.java included in this sample program.

If your Project 2 program is functioning, by all means write a Project 3 program based on it; otherwise, you may use this sample program.

  • sample set #1 of function definitions | output from interpretation of main() function, displayed on the screen
  • sample set #2 of function definitions | output Note that I implemented || and && as logical operator always evaluating both arguments.

You should test your interpreter by additional function definitions.

Submission

Email the following materials with the subject header: CS 316, Project 3, your full name

All the classes comprising your source code, including the lexical analyzer and parser. Since there will be many classes, make sure to double check no classes are missing in your submission.

A list of all class names arranged like this page. This may be in text, html, PDF, or WORD file.

You may email the entire materials in a .zip or .rar compressed file.