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

4.7 KiB

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