Files
2026-08-07 15:58:44 +01:00

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`