The second F# assignment is to do the following, all based on the parser.fs inline-calculator program. One disadvantage of the F# way of defining the expr datatype is that it is difficult to add a new expr subtype without editing the existing code. One remaining advantage of the object-oriented approach is that classes and interfaces are more "loosely coupled", which make adding something new easier. So F# addresses some of the deficiencies of dynamic dispatch and oop, but not others. You will have to edit the parser.fs file that I gave you. But you should also ask: is there a language that will give us the best of all worlds? 1. The parser allows for disambiguation of shift-reduce conflicts by operator precedence. However, some shift-reduce conflicts can also arise from the associativity of operators. Addition and multiplication are associative, e.g., (a+b)+c = a+(b+c). But subtraction is not: (2-3)-4 <> 2-(3-4). The way that the parser is currently written, 2-3-4 will be interpreted as equivalent to 2-(3-4), but - is usually assumed to associate to the left. Your task is to add an additional functionality to the parser to allow us to specify the associativity of operators. For example, logical implication (a->b) should associate to the right. Hint: in addition to the precedence table/function. you'll have to construct another one for associativity: you can assume that by default, operators associate to the left, but allow the option of declaring them to associate to the right. 2. Add the following operator to your calculator: "=" for boolean equality, and expressions of the form ?a,b,c which represents if (a) b else c. For example, ?(3=2+1),1,0 should evaluate to 1, and ?(2=1),3,4 should return 4. You will have to change all parts of the program, starting with the expr type, the eval function, and the lexical tokenizer. Change your precedence table as well. Your calculator should also evaluate expressions like 2+1=3 directly: return 1.0 for true and 0.0 for false. You will have to decide on what precedence to give to = relative to the other operators. *********** DO EITHER 3a OR 3b: ************ 3a. Write a compiled version of the calculator. If you do not know x86 or some other assembly, then use the following virtual machine: General purpose registers: ax, bx, cx, dx Instructions: add/sub/mult/div : e.g., add bx ax represents ax += bx push x : push x onto stack, x can be value (push 3) or register (push ax) pop r : pop stack contents into register r (e.g., pop ax) You should generate code that would leave the final, computed value on the stack. For example, for "3+4" you can generate the code: push 3 push 4 pop ax pop bx add bx ax push ax This code was generated by performing a post-order traversal on the expr tree: first generate the code to evalute "3", then "4", then "3+4". Each expression should have code that pushes the value on top of the stack. You can also assume that values are always integers. You only need to handle expressions of the form E*E, E+E, E-E, E/E, and -E. If you known real assembly, you may implement the if-else and the exponent (which involves writing a loop in assembly). You can just output to console. UPDATE: See sample program machine.fs for generating intermediate, executable code. 3b. Write the summation [i:0:10:i*i] (you can change syntax if you want). You must respect the scope of bound variables. This is the more meaningful option and will really give you a feel of how to write an interpreter/compiler because it deals with variables and scope. Some hints may be found on my compiler class homepage: www.cs.hofstra.edu/~cscccl/csc124 There is similar code on this webpage written in Java and uses the visitor pattern. ------ EXTRA CREDIT : Do both 3a and 3b AND write a compiled version of both that compiles to a real assembly program (in x86 or something else) that works.