# Programming Language Design Assignment \#2
Please hand-in your answers on LMS before 10/23 23:55.
In this assignment, you're asked to implement an AST and operations to interpret boolean expressions.
Please note that you should:
* Implement 1 & 2 (90pt) in Java and 3 in C lang (10pt).
* Use different directory for each answers.
* Zip your all the directories to a single zip, name it by your student id\#, e.g. `107525008.zip`
Please feel free to ask TA if the question is not clear to you. (Check out the [FAQ](#FAQ) below first)
----
~~~~java
public abstract class Exp {
public abstract boolean eval();
}
public class Lit extends Exp {
private boolean val;
public Lit(boolean val) {
this.val = val;
}
public boolean eval() {
return this.val;
}
}
~~~~
### 1. Simple Interpreter
Following the code above, implement `And`/`Or` and `eval` methods using inheritance.
Example Test Cases:
~~~java
(new And(new Lit(true), new Lit(false))).eval() == false;
(new And(new Lit(true), new Lit(true))).eval() == true;
(new Or(new Lit(true), new Lit(false))).eval() == true;
(new Or(new Lit(false), new Lit(false))).eval() == false;
~~~
### 1-1. Add Expression
Add a new expression `Not` to the your AST.
Example Test Cases:
~~~~java
(new Not(new Lit(true))).eval() == false;
(new Not(new Lit(false))).eval() == true;
~~~~
### 1-2. Add Interpretation
Add a new interpretation `toSExp` to the AST,
~~~~java
public abstract class Exp {
public abstract boolean eval();
public abstract String toSExp();
}
~~~~
which return the S-expression of a boolean AST in `String`.
Example Test Cases:
~~~~java
(new Lit(true)).toSExp() == "T";
(new Lit(false)).toSExp() == "F";
(new And(new Lit(true), new Lit(false))).toSExp() == "(and T F)";
(new Or(new Lit(true), new Lit(false))).toSExp() == "(or T F)";
(new Or(new Lit(true), new And(new Lit(true), new Lit(false)))).toSExp()
== "(or T (and T F))";
~~~~
### 2. Simple Interpreter using Visitor pattern
Following the code below, rewrite the simple interpreter in Question 1 using the visitor pattern.
~~~~java
abstract class Exp {
public abstract Object accept(Visitor v);
}
class Lit extends Exp {
public boolean val;
public Lit(boolean val) {
this.val = val;
}
public Object accept(Visitor v) {
return v.visit(this);
}
}
interface Visitor {
public Object visit(Lit e);
}
class Interpreter implements Visitor {
public Object visit(Lit n) {
return n.val;
}
}
~~~~
Example Test Cases:
~~~~java
Interpreter intp = new Interpreter();
(Boolean) (new And(new Lit(true), new Lit(false))).accept(intp) == false;
(Boolean) (new And(new Lit(true), new Lit(true))).accept(intp) == true;
(Boolean) (new Or(new Lit(true), new Lit(false))).accept(intp) == true;
(Boolean) (new Or(new Lit(false), new Lit(false))).accept(intp) == false;
~~~~
:::info
For the sake of simplicity, we make `accept` return an `Object`, which make you need to perform downcasts to extract values.
~~~~java
Interpreter intp = new Interpreter();
(Boolean) (new Lit(true)).accept(intp) == true;
~~~~
There is a better way to do this called "parametric polymorphism" (or "generic" in Java), which will be discussed in future lectures.
:::
### 2-1. Add Interpretation
Like 1-2, add a new interpretation `SExpPrinter` to your Visitor-based AST.
Example:
~~~~java
SExpPrinter printer = new SExpPrinter();
(String) (new Lit(false)).accept(printer) == "F";
~~~~
### 2-2. Add Expression
Like 1-1, add a new expression `Not` to your Visitor-based AST.
:::info
Althouth these exercise is simple, you can still feel that Visitor-style is hard to add expressions and OO-style is hard to add interpretations.
:::
:::info
Furthermore,
The famous "[Open-Closed Principle][ocp]" said "classes should be open for extension, but closed for modification".
As you can see, both OO-style and Visitor-style breaks the principle when you try to add an interpretation(expression),
this phenomenon is called "Expression Problem".
:::
[ocp]: https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle
### 3. (Challenge) Implement AST Without OO-Support (10pt)
The following code is a C implementation and it uses some trick to simulate OO mechanisms.
In this question, you need to complete `And_t`, `and_new`, `and_eval`.
~~~~c
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
/* Exp
* since this is an abstract class with no constructor,
* we don't need to implement a new method for it. */
typedef struct ExpTable ExpTable_t;
typedef struct Exp Exp_t;
struct Exp {
ExpTable_t * table;
};
struct ExpTable {
bool (*eval)(Exp_t * exp);
};
bool exp_eval(Exp_t * e) {
return e->table->eval(e);
}
/* Lit
* the virtual table for Lit is omitted,
* since it don't have any other methods. */
typedef struct Lit {
ExpTable_t * table;
bool val;
} Lit_t;
bool lit_eval(Exp_t * e) {
return ((Lit_t *) e)->val;
}
Exp_t * lit_new(bool val) {
ExpTable_t * table = (ExpTable_t *) malloc(sizeof(ExpTable_t));
table->eval = lit_eval;
Lit_t * obj = (Lit_t*) malloc(sizeof(Lit_t));
obj->table = table;
obj->val = val;
return (Exp_t*) obj;
}
/* And */
typedef struct And {
ExpTable_t * table;
// COMPLETE HERE...
} And_t;
// IMPLEMENT THESE FUNCTIONS
bool and_eval(Exp_t * e);
Exp_t * and_new(Exp_t *e1, Exp_t * e2);
~~~~
Example Test Cases:
~~~~c
exp_eval(lit_new(true)) == true;
exp_eval(lit_new(false)) == false;
exp_eval(and_new(lit_new(true), lit_new(true))) == true;
exp_eval(and_new(lit_new(true), lit_new(false))) == false;
~~~~
# FAQ
* Is there any request about input/output?
No, we don't have any restriction/request on it.
* What is desired folder layout?
As long as you follow the rule - one dir. per one question, it is acceptable.
A possible example is:
~~~~
+ q1
- Exp.java
- And.java
- ...
+ q2
- Exp.java
- And.java
- ...
~~~~