Read Exercise 5.5.9 in EOPL. Get a good document on Java and try to understand the precise semantics of statements and expressions.
You are to write a Scheme interpreter for the core of Java. At this point, we are only concerned with statements and expressions. We completely ignore objects, classes, and exceptions for the time being. Furthermore, I made a simplifying assumption to avoid dealing with the semantics of I/O. All our programs in this assignment will have one class with one static method that returns an integer. For example, we can write things like:
// silly test class Test { static int main () { return 42; } }and
// factorial of 5 class Test { static int main () { int x = 1; int y = 5; while (y > 0) { x = x*y; y = y-1; } return x; } }The beginnings of the interpreter follow:
(define main (lambda (file) (let* ((ast (java-file-parser file)) (block (findMainBody ast)) (env emptyEnv) (store emptyStore)) (call-with-values (call/cc (lambda (return) (lambda () (interpBlock block env store return)))) (lambda (value newStore) value))))) (define findMainBody (lambda (ast) (variant-case ast [ast-comp-unit (package imports types) (if (= (length types) 1) (variant-case (car types) [ast-class-decl (modifiers name super implements body) (if (= (length body) 1) (variant-case (car body) [ast-method-decl (modifiers type id formal-args throws body) body] [else (error 'interp "~s not method definition" (car body))]) (error 'interp "Can only handle one method definition"))] [else (error 'interp "~s not a class definition" body)]) (error 'interp "Can only handle one class definition"))] [else (error 'interp "~s not a compilation unit" ast)]))) (define interpBlock ...)To run this code use the version of Chez Scheme that includes the Java parser. It is called /local/apps/chez-5.0a/bin/jscheme. The Java parser reads a file and produces an abstract syntax tree defined as follows: (the lines starting with *** are my comments)
block ::= ast-block (statements) statements ::= () | (cons statement statements) statement ::= ast-null-statement () | ast-var-decl (type declarators) | ast-binary-op (op lhs rhs) | ast-if-then-else (condition true-stmt false-stmt) *** condition is an expr | ast-block (statements) | ast-return (expr) | ast-break (identifier) *** if actual statement is break; then identifier is #f | ast-continue (identifier) *** if actual statement is continue; then identifier is #f | ast-labeled-statement (label statement) *** label is an identifier | ast-while (condition body) *** condition is an expr declarators ::= () | (cons declarator declarators) declarator ::= ast-var-declarator (id ndims init) *** ignore ndims as we don't deal with arrays *** init is #f if declaration is not initialized else is an expr expr ::= ast-literal (type value) | ast-name (ids) *** use (car ids) to get the name of the identifier as we don't *** have qualified names | ast-binary-op (op lhs rhs) *** both lhs and rhs are expr op ::= add | sub | mult | div | eq | gt | assign *** there are more ops but these are the ones I implementedScheme tip: Use variant-case and call-with-values. Explain and document your decisions: you must tell me what you think the semantics of Java statements and expressions is. This is one case where documentation, comments, and examples are a must.