F# Assignment 3 The next F# assignment is to do the following, all based on the parserm.fs inline-calculator program. This assignment asks you to modify parserm.fs without editing it in the same manner as the previous assignment. See the sample file parserext.fs for how this is done. 1. Add the % operator to the language recognized. In the base program, I show in comments what you would need to do to add the "^" operator: you can call newoperator, which will automatically update the precedence table. You will then also need to add clauses to eval and to parse. You shouldn't have to touch the lexical analysis code. Choose a reasonable precedence for %, or research online for the correct precedence of % relative to the other operators. 2. Write a compiled version of the calculator by generating AM7B assembly code, which can then be executed by your assembler. For this part, I will leave it OPTIONAL as to wether you can compile let-expressions (x=2+2:x*x) because that will entail you to allocate memory to variables (see hint at end as to how to do this). 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 only need to handle expressions of the form E*E, E+E, E-E, E/E, -E, and E%E (if you have completed assignment 2 and modified the idiv instruction). You can just output to Console (stdout): parser.exe > out.7b You can then use your AM7B simulator to run your compiled program. 3 (maybe made optional). The let-expression in the base program is actually not correct: (x=3:(x=4:x+x)+x) returns 12, but it should return 11! Please fix the eval function to respect the SCOPE of let. Hint: Given a env of type Dictionary, env.["x"] will try to retrieve the value of associated with key "x", but will throw an exception if there's no such key, so you need to do: try (env.[key]) with | except -> ... what do you want to do if there's no such key? ... Alternatively, env.ContainsKey("x") will return boolean to indicate if there's a binding for "x" in the dictionary. Now, if you want to COMPILE the let-expression as extra credit, I suggest you use the upper portion of RAM to store the values of variables, because the lower portion is reserved for the stack. You need to create what's called a "symbol table" that maps variables to memory addresses where they're stored. Now to really respect the scope of variables, your symbol table must form a tree, which reflects the static structure of your expression. Do not use stack of dictionaries: that will lead you into making the biggest mistake you could possibly make when you implement a programming language, which is to make it dynamically instead of statically scoped. This option is hard, but worth doing because it will really give you a taste of what writing a compiler entails. ------ 4. EXTRA EXTRA CREDIT: Modify the parser/evaluator to implement a simple scripting language. Utilize the 'Seq' option for contructing expressions. You can write an interpreter by extending the eval function. As a further challenge, you can compile the following into AM7B, once you have enhanced it appropriately (invent a instruction call print...) that invokes OS services. n = 65 while n<65+26 begin printnum n // should print number printchr n // should print ascii char for n n = n+1 end