Skip to content

ananthvk/cpp-lox

Repository files navigation

cpp-lox

My implementation of second part of Lox programming language from Crafting interpreters in C++. This implementation uses a bytecode VM to execute the programs.

How to run?

Install meson, ninja and a C++ 20 capable compiler

$ meson setup builddir
$ cd builddir
$ ninja -j8

If you are on linux, run

$ ./src/cpplox

On windows, run

.\src\cpplox.exe

To run tests

To run tests, you need to have Python 3

First install pytest, a test automation library used to test programs.

Create a virtual environment

$ python -m venv .venv

Install dependencies

$ pip install -r requirements.txt

Run tests

$ meson setup builddir -Denable-tests=true
$ cd builddir
$ ninja -j8
$ meson test -v

Development build

Have Clang installed along with asan. You also need to follow the steps in the above section, pytest must be installed and available on the PATH

Then run the following command,

$ ./development.sh

Help

$ cpplox --help
Lox compiler and interpreter in C++
Usage:
  cpplox [OPTION...] positional parameters

      --print-tokens         Show all tokens generated by the lexer along 
                             with line position
      --compile-only         Compiles the source code to bytecode but does 
                             not execute it
      --dump-bytecode        Dumps the bytecode generated by the compiler 
                             before execution
      --trace-execution      Used for debugging: Prints the bytecode 
                             instruction before executing it
      --trace-eval-stack     Used for debugginig: Prints the internal 
                             evaluation stack before the instruction is 
                             executed
      --enable-step-mode     Used for debugging: Enables step mode and 
                             waits for input before an instruction is 
                             executed
      --eval-stack-size arg  Maximum evaluation stack size allowed 
                             (default: 1024)
  -c, --command arg          Execute the given command and exit
  -h, --help                 Prints this help message
  -v, --version              Prints program version

Changes from the book

  1. The compiler de-duplicates both strings and integers (but not real numbers)

  2. Supports 65k constants, and 65k global variables (accessed with 2 byte unsigned index)

  3. const variables

In global scope,

If a constant of the same name has already been declared, do not allow
redeclaration with var Example:
>> const x = 32;
>> var x = 50; // Not allowed

>> const x = 80;
>> const x = 90; // Not Allowed

>> var x = 95;
>> var x = 100; // Allowed

One difference is that redeclaration with const is not allowed since it helps make the vm simpler, otherwise an extra flag/byte needs to be maintained to identify if it's a const declaration or a var declaration.

  1. switch statement

Supports C-style switch statements with cases and default:

switch (value) {
    case 1:
        print "one";
        break;
    case 2:
        var foo = "hello";
        print foo;
        break;
    default:
        print "other";
}
  • Both the selector and the case value can be expressions
  • Each arm of the switch statement defines a local scope, so variables can be declared within it
  • There is no break statement, there is no fallthrough
  • Cases cannot appear after the default statement

In local scope redeclaration of any form is disallowed

TODO

  • Fix division by zero error
  • Implement break statements