114 lines
4.7 KiB
Markdown
114 lines
4.7 KiB
Markdown
# CMP-7009A Reassessment 001 - Interpreter + Maths Visualiser
|
|
|
|
## How to open and run
|
|
|
|
1. Open **CMP7009A.sln** in Visual Studio 2022 (with the ".NET desktop
|
|
development" and "F# desktop language support" workloads installed).
|
|
2. Set **GUI** as the startup project (right-click GUI project -> "Set as
|
|
Startup Project").
|
|
3. Press F5 to build and run. The `GUI` project references `Interpreter`
|
|
directly (project reference), so both build together.
|
|
|
|
If you prefer the command line (with the .NET SDK installed):
|
|
|
|
```
|
|
dotnet build CMP7009A.sln
|
|
dotnet run --project GUI
|
|
```
|
|
|
|
## Project layout
|
|
|
|
```
|
|
CMP7009A.sln
|
|
Interpreter/
|
|
Interpreter.fsproj F# class library
|
|
Interpreter.fs Tokenizer, parser, evaluator, public Engine class
|
|
GUI/
|
|
GUI.csproj C# WPF application (references Interpreter)
|
|
App.xaml / App.xaml.cs
|
|
MainWindow.xaml Input box, output box, drawing canvas
|
|
MainWindow.xaml.cs Wires the UI to Engine; draws axes and lines
|
|
```
|
|
|
|
## Using the app
|
|
|
|
Type into the input box and press Enter or click Run:
|
|
|
|
- `3 + 4 x 2` -> expression evaluation (`x` is multiplication) -> `11`
|
|
- `a = 5` -> assignment, output shows `a = 5`; `a` is remembered
|
|
- `a x 2 + 1` -> uses the stored variable `a` -> `11`
|
|
- `y = 2x + 1` -> parsed as a line equation and drawn on the canvas
|
|
- `y = x + 5` -> coefficient defaults to 1
|
|
- `y = -2x - 3` -> negative coefficient/intercept supported
|
|
- `y = ax + b` (after `a` and `b` have been assigned) -> uses their values
|
|
|
|
## BNF grammar (for the report's Implementation section)
|
|
|
|
```
|
|
<statement> ::= <ident> "=" <expr> | <expr>
|
|
|
|
<expr> ::= <term> { ("+" | "-") <term> }
|
|
<term> ::= <factor> { ("x" | "/") <factor> }
|
|
<factor> ::= <number> | <ident> | "(" <expr> ")" | "-" <factor>
|
|
|
|
<number> ::= <integer> | <float>
|
|
<integer> ::= <digit> [<digit> [<digit>]] (1 to 3 digits)
|
|
<float> ::= <digit> [<digit>] "." <digit> [<digit>] (1-2 digits . 1-2 digits)
|
|
|
|
<ident> ::= <letter> [<alnum> [<alnum> [<alnum>]]] (max 4 characters)
|
|
|
|
<digit> ::= "0" | "1" | ... | "9"
|
|
<letter> ::= "a" | ... | "z" | "A" | ... | "Z"
|
|
<alnum> ::= <digit> | <letter>
|
|
```
|
|
|
|
Separate line-drawing syntax (parsed directly from raw characters in
|
|
`Engine.ParseLine`, since `x` is already the multiplication operator token
|
|
in the grammar above):
|
|
|
|
```
|
|
<line> ::= "y" "=" [ "-" ] [ <coefValue> ] ("x"|"X") ("+"|"-") <interceptValue>
|
|
<coefValue> ::= <number> | <ident>
|
|
<interceptValue> ::= <number> | <ident>
|
|
```
|
|
|
|
## Design notes (for the report)
|
|
|
|
- **No library parsing functions are used.** The tokenizer builds integer
|
|
and float values digit-by-digit using manual accumulator recursion
|
|
(see `buildIntValue` / `buildFracValue` in `Interpreter.fs`); it does not
|
|
call `Int32.Parse`, `Double.Parse`, `TryParse`, `String.Split`, or any
|
|
regular expression. Identifiers are built character-by-character with a
|
|
recursive `buildStr` helper instead of `Substring`.
|
|
- **No collection-library functions are used.** List reversal
|
|
(`reverseAcc`) and the variable environment lookup/update
|
|
(`lookupVar` / `updateEnv`) are hand-written recursive functions over a
|
|
plain association list, rather than `List.rev`, `Map`, or `Dictionary`.
|
|
- **The only library/framework usage is the WPF `Canvas` and shape classes**
|
|
(`Line`, `TextBlock`) in `MainWindow.xaml.cs`, which the assignment brief
|
|
explicitly permits.
|
|
- **Class diagram / sequence diagram**: the report should show
|
|
`MainWindow` -> `Engine.Evaluate` / `Engine.ParseLine` -> internal
|
|
`tokenize` -> `parseTokens` -> `evalExpr` pipeline for the class diagram,
|
|
and a sequence diagram for the line-drawing path:
|
|
`User -> MainWindow.RunInput -> Engine.ParseLine -> MainWindow.DrawLine -> Canvas`.
|
|
- **Line-drawing algorithm**: the line is drawn using two endpoint
|
|
coordinates computed analytically from `y = ax + b` at the left and right
|
|
edges of the visible canvas, converted from maths coordinates to pixel
|
|
coordinates via a fixed `Scale` (pixels per unit) and the canvas centre as
|
|
the origin, then rendered with WPF's built-in `Line` shape (this is the
|
|
permitted library use for the canvas itself - no custom rasterisation
|
|
algorithm like Bresenham is needed because WPF's vector `Line` element
|
|
handles anti-aliased rendering).
|
|
|
|
## Testing suggestions (for the report's Testing section)
|
|
|
|
Arithmetic:
|
|
- `1 + 2`, `10 - 4`, `6 x 7`, `20 / 4`, `(1 + 2) x 3`, `10 / (5 - 5)` (division by zero error)
|
|
- `999` (max 3-digit int, valid), `1000` (should error - exceeds 3 digits)
|
|
- `99.99` (max digits, valid), `100.5` (should error - integer part too long)
|
|
- `ab1` = `5` (valid 3-char identifier), `abcde` (should error - exceeds 4 chars)
|
|
|
|
Line drawing:
|
|
- `y = 2x + 1`, `y = -x + 3`, `y = 0.5x - 2`, `y = ax + b` after assigning `a` and `b`
|