Skip to content

davidbits/notplusplus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NotPlusPlus

NotPlusPlus is a small interpreter for a strict subset of real C++. It accepts ordinary .cpp source files, parses and type-checks supported constructs, lowers them to an internal IR, and executes int main() directly without producing native code.

The project is intentionally narrow. Supported C++ works with predictable semantics; unsupported C++ is rejected with targeted diagnostics instead of being silently reinterpreted.

Current Status

This repository already includes:

  • A Rust library crate plus the npp CLI binary
  • A front-end pipeline for lexing, parsing, semantic analysis, IR lowering, and interpretation
  • Built-in output functions print(int) and print(bool)
  • Debug modes for dumping tokens, AST, semantic analysis, IR, and execution traces
  • Integration and snapshot tests covering lexer, parser, semantics, runtime, diagnostics, and CLI behavior

The authoritative design lives in docs/design.md. The test workflow and layering policy live in docs/tdd.md.

Supported C++ Subset

NotPlusPlus currently supports a deliberately small, explicit subset:

  • Single-file programs with function declarations and definitions
  • Exactly one entry point with the signature int main()
  • Scalar types int, bool, and void
  • Fixed-size one-dimensional arrays
  • Integer and boolean literals
  • Identifier references, parenthesized expressions, function calls, and array indexing
  • Unary operators +, -, !
  • Binary arithmetic +, -, *, /, %
  • Comparisons <, <=, >, >=, ==, !=
  • Logical operators &&, || with short-circuit behavior
  • Assignment = and compound assignment +=, -=, *=, /=, %=
  • Statements: declaration, expression, block, if, if/else, while, for, return, break, continue
  • Implicit return 0; at the end of main

Runtime checks currently report errors for:

  • Division by zero
  • Integer overflow
  • Uninitialized reads
  • Missing return values from non-void functions
  • Exceeded call-depth limits
  • Array bounds violations

Explicitly Unsupported

Examples of constructs that are intentionally rejected today:

  • Preprocessor directives such as #include
  • std::cout and stream insertion
  • Namespaces
  • Pointers and references
  • Classes, structs, templates, and dynamic allocation
  • String literals and floating-point types
  • const and other storage/type qualifiers
  • ++ and --
  • Complex declarators such as multi-declarator statements

If a feature is not listed as supported, assume it is outside the current subset.

Quick Start

Build and run the interpreter with Cargo:

cargo run -- tests/fixtures/integration/for_loop_end_to_end.cpp

That fixture program is:

int main() {
    int sum = 0;
    for (int i = 1; i <= 4; i += 1) {
        sum += i;
    }
    print(sum);
    return 0;
}

Expected output:

10

You can also run one of the curated examples in examples:

CLI

usage: npp [--dump-tokens|--dump-ast|--dump-sema|--dump-ir|--trace-exec] [--no-color] [--max-call-depth=N] <file>

Options:

  • --dump-tokens: lex and print the token stream
  • --dump-ast: parse and print the AST
  • --dump-sema: run semantic analysis and print the analyzed program
  • --dump-ir: lower to IR and print the executable representation
  • --trace-exec: execute the program and emit a statement-level trace to stderr
  • --no-color: render diagnostics without ANSI color codes
  • --max-call-depth=N: override the runtime recursion/call-depth limit; default is 256

Only one debug mode can be selected at a time.

Example:

cargo run -- --trace-exec tests/fixtures/cli/basic.cpp

That prints program output to stdout and a trace like this to stderr:

trace:
  enter main
  stmt main at tests/fixtures/cli/basic.cpp:6:5
  enter add at tests/fixtures/cli/basic.cpp:6:17
  stmt add at tests/fixtures/cli/basic.cpp:2:5
  return add => 5
  stmt main at tests/fixtures/cli/basic.cpp:7:5
  stmt main at tests/fixtures/cli/basic.cpp:8:5
  return main => 0

Diagnostics and Exit Codes

The interpreter distinguishes between compile-time failures and runtime failures:

  • 0: successful execution
  • 2: compile failure
  • 3: runtime failure
  • 4: CLI or internal failure

Diagnostics include source locations, stable project-specific error codes, and stack traces for runtime failures when available.

Development

Common commands:

cargo test --all-targets
cargo test runtime_allows_implicit_zero_return_from_main
cargo run -- --dump-ir tests/fixtures/runtime/arithmetic.cpp
cargo fmt
cargo fmt --check

Repository layout:

  • src: implementation
  • tests: integration and snapshot tests
  • examples: small standalone example programs
  • docs: design and workflow notes

License

See LICENSE.

About

Interpreting C++ because compiling it was apparently too reasonable

Resources

License

Stars

Watchers

Forks

Contributors

Languages