Skip to content

karolzmijewski/calculator

Repository files navigation

Overview

ci  Tests  Release

This implementation of the Calculator App uses a Context-Free Grammar (CFG) to define the structure of valid expressions and instructions. CFG is a formal set of production rules that describe how expressions in a language can be formed.

The grammar is based on BNF (Backus-Naur Form) — a notation used to formally specify the syntax of programming languages and other structured formats. BNF is considered a meta-syntax, meaning it provides a systematic way to describe the rules that govern the structure of a language. It is commonly used for defining document formats, instruction sets, and communication protocols.

There are several variations of BNF, including:

  • EBNF (Extended Backus-Naur Form) – introduces additional syntactic sugar for readability.
  • ABNF (Augmented Backus-Naur Form) – often used in internet protocol specifications.

BNF-based grammars consist of three fundamental components:

  • Non-terminal symbols – These represent abstract language constructs and are typically enclosed in angle brackets (e.g., , ). They can be replaced by other non-terminals or terminals according to the grammar rules.
  • Terminal symbols – These are the actual symbols or keywords used in the language (e.g., +, -, numbers, parentheses).
  • Production rules (derivations) – These define how non-terminal symbols can be rewritten as a combination of terminals and/or non-terminals.

Simplified BNF Grammar of the Calculator:

<expression> ::= <term>
              | <expression> + <term>
              | <expression> - <term>

<term>       ::= <power>
              | <term> * <power>
              | <term> / <power>

<power>      ::= <postfix>
              | <postfix> ^ <power>

<postfix>    ::= <primary>
              | <postfix> !

<primary>    ::= <number>
              | ( <expression> )
              | - <primary>
              | sqrt <primary>

This grammar allows for arithmetic expressions using addition, subtraction, multiplication, division, parentheses, and unary negation. Parsing is done recursively, reflecting the hierarchical structure defined by these grammar rules.

Build

To build this project, a few prerequisites are required:

  • Qt 6.9.1 (used for the GUI)
  • g++ compiler
  • CMake build tools
  • CXXOPTS library (header), SPDLOG library (static lib)

To simplify the build process and ensure consistency, the entire build environment is isolated within a Docker container. The Dockerfile is structured into multiple stages to enable layer caching. This means that only the first build may take a while; subsequent builds will be much faster — as long as there are no changes to the build environment.

Note: Building the project requires access to the Qt Essentials libraries, which are available to registered Qt users.

To obtain access, please create a free Qt account at:

👉 https://login.qt.io/register

You will need to provide your Qt credentials as build arguments.

Steps to Build

  1. Install Docker following the official instructions. Example for Ubuntu: Docker Installation Guide for Ubuntu
  2. Run the following command, replacing the placeholder values with your Qt account credentials:
sudo docker build \
    -f Dockerfile.build \
    --build-arg QT_USERNAME=<email-used-for-qt-registration> \
    --build-arg QT_PASSWORD=<password-used-for-qt-registration> \
    --output type=local,dest=./ .

The build output will be available in the ./artifacts directory.

Run

To run the application, essential OpenGL-related libraries are required. These libraries will be installed automatically during the installation of the Calculator .deb package:

apt install -y ./artifacts/calculator_*.deb

Once installed, you can launch the application by running:

cd /opt/calculator/usr/bin/
./calculator -u

Alternatively, the application can be containerized with Docker:

docker build -t calculator .

To run the application from within the Docker container:

xhost +local:docker
docker run \
    --rm -it \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    calculator

The application supports multiple run modes, as described in the sections below. For usage details and available options, execute the binary with the --help flag:

./calculator --help

To pass arguments to the application when running in Docker, use the APP_ARGS environment variable:

-e APP_ARGS="--help"

GUI mode

To launch the graphical user interface, run:

./calculator -u

This will display the GUI:

execution mode

To directly evaluate an expression, use the -e flag:

./calculator -e <expression>;

Example:

./calculator -e "(1+2)*3;"

Note: Don’t forget the semicolon (;) at the end of the expression. It is required to signal the end of the input. If omitted, the calculator will continue to wait for additional tokens.

interactive mode

To enter interactive mode, run:

./calculator -i

This mode displays a prompt and allows you to enter expressions one at a time, confirming each with the <ENTER> key:

Launching calculator in interactive mode.
Enter expression (or q to quit):
> (1+2)*3;
= 9
> q
Exiting calculator.

Logging

Two logging destinations are available: console and file. By default, console logging is set to the warn level, and file logging is set to the trace level. To change the logging level for both loggers, set the CALC_LOG_LEVEL environment variable:

export CALC_LOG_LEVEL="main=warn"

To change the logging level for the console logger only:

export CALC_CONSOLE_LOG_LEVEL="warn"

To change the logging level for the file logger only:

export CALC_FILE_LOG_LEVEL="warn"

Supported logging levels (from most to least verbose): trace > debug > info > warn > err > critical > off

Development

If you prefer to set up the development environment directly on your host machine for greater control during development, follow the tips below.

Prerequisites

This project requires the following external dependencies:

  • CXXOPTS: Header-only library
  • SPDLOG: Static library
  • Qt 6 Framework: Essential modules

Ensure that the following environment variables are set to the appropriate paths where these dependencies are located. For example:

export Qt6_DIR="/opt/Qt/6.9.1/gcc_64/lib/cmake/Qt6"
export SPDLOG_DIR="/opt/spdlog/lib"
export SPDLOG_H_DIR="/opt/spdlog/include"
export CXXOPTS_H_DIR="/opt/cxxops/include"

Visual Studio Code

Recommended configuration files are provided in the ./.vscode directory. These allow you to:

  • Configure the project (this generates the appropriate Makefile):
Ctrl + Shift + P
> Type: "Run Task"
> Select: "CMake Configure [<Type of build>]
  • Build the project (this compiles the executable binary):
Ctrl + Shift + P
> Type: "Run Task"
> Select: "CMake Build [<Type of build>]

By default, the build type is set to Debug, so pressing Ctrl + Shift + B will rebuild the project in Debug mode.

CMake

Alternatively, you can configure and build the project directly using the CMake command-line tools:

cmake -S . -B "./build/Debug" -DCMAKE_BUILD_TYPE="Debug"
cmake --build "./build/Debug" --config "Debug"

To create .deb package:

cpack -G DEB -B "./build/deb" --config "./build/Debug/CPackConfig.cmake"

Tests

Basic unit tests are currently provided in the tests folder, utilizing the gtest framework. The appropriate test binary should be built using CMake. You can run the tests with the following command:

./build/Debug/bin/test_calculator

Optionally, you can generate a JUnit-compliant report:

./build/Debug/bin/test_calculator --gtest_output=xml:test-results.xml

To convert the report into a human-readable HTML format, use the provided script:

python3 ./scripts/gtest_to_html.py --input test-results.xml --output test-results.html

You can also use the run-tests.yaml GitHub Actions workflow to execute tests on a selected branch.

Release

To release a new version of the Calculator application, first tag the source code you wish to use for the release using semantic versioning. Then, push the tag to the repository. For example:

git tag v1.0.0
git push origin v1.0.0

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published