Skip to content

alainrk/nrk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NRK Programming Language

nrk (/ˈanɑːrki/) is a small programming language with a bytecode interpreter implementation written entirely in C99. The language is inspired by Bob Nystrom's "Crafting Interpreters" with modifications and enhancements.

Doc

Features

  • Bytecode Virtual Machine: Executes instructions efficiently with a stack-based architecture
  • C99 Implementation: Written in standard C99 for maximum portability
  • REPL: Interactive Read-Eval-Print Loop with history persistence and line editing
  • File Execution: Run nrk script files directly
  • Expression Evaluation: Supports arithmetic expressions, string operations, and variables
  • Type System: Dynamic typing with runtime type checking
  • Operators: Arithmetic, comparison, logical, bitwise, and postfix operations
  • String Handling: String literals, concatenation, interning, and template strings
  • Memory Management: Efficient memory allocation with garbage collection foundations
  • Variable Scoping: Support for both global and local variables with lexical scoping

Getting Started

Prerequisites

  • C compiler (clang recommended)
  • Make

Building

# Standard build
make all

# Debug build with all debugging flags enabled
make debug

# Release build (no debug flags)
make release

Running

REPL Mode:

./bin/nrk

File Execution:

./bin/nrk path/to/script.nrk

Debugging:

# Run with GDB
make gdb-debug

# Run tests
make test

Language Guide

Basic Syntax

NRK uses semicolons to terminate statements:

print "Hello, world!";
var x = 10;

Data Types

NRK currently supports the following primitive types:

  • Numbers: 42, 3.14159
  • Strings: "Hello, world!"
  • Booleans: true, false
  • Nil: nil (represents absence of a value)

Template strings are also supported for more dynamic string creation:

`This is a ${1+1} in a template string`  // "This is a 2 in a template string"
`Nested templates: ${`inner ${42}`}`     // "Nested templates: inner 42"

Operators

Arithmetic Operators

1 + 2         // Addition: 3
10 - 5        // Subtraction: 5
3 * 4         // Multiplication: 12
10 / 2        // Division: 5

Bitwise Operators

~5            // Bitwise NOT: -6
8 >> 2        // Bitwise right shift: 2
2 << 3        // Bitwise left shift: 16
12 & 5        // Bitwise AND: 4
12 | 5        // Bitwise OR: 13
12 ^ 5        // Bitwise XOR: 9

Comparison Operators

1 == 1        // Equal: true
2 != 2        // Not equal: false
3 > 2         // Greater than: true
4 < 3         // Less than: false
5 >= 5        // Greater than or equal: true
6 <= 7        // Less than or equal: true

Logical Operators

!true         // Logical NOT: false
!!0           // Double NOT: false (0 converts to false first)
!nil          // NOT nil: true (nil is falsey)

Postfix Operators

var a = 5;
a++           // Increment: a becomes 6
a--           // Decrement: a becomes 5

String Operations

"Hello, " + "world!"  // Concatenation: "Hello, world!"

Variables

Variables are declared using the var keyword:

var a = 5;
var name = "Alice";
var isActive = true;

Variables can be modified after declaration:

var counter = 0;
counter = 10;
counter++;           // Now 11

Compound assignment is also supported:

var x = 5;
x += 3;              // x = x + 3: x becomes 8
x -= 2;              // x = x - 2: x becomes 6
x *= 2;              // x = x * 2: x becomes 12
x /= 4;              // x = x / 4: x becomes 3

Expressions

NRK supports complex expressions with operator precedence:

1 + 2 * (3 + 4) / 5  // 3.8

Statements

Print Statement

print "Hello, world!";
print 2 + 2;         // 4
print a + b;         // Prints the sum of variables a and b

Blocks and Scopes

NRK supports lexical scoping with blocks:

{
  var x = 10;
  print x;           // 10
  {
    var y = 20;
    print x + y;     // 30
  }
  // y is not accessible here
}
// x is not accessible here

Implementation Details

Architecture

NRK is implemented as a bytecode virtual machine with a stack-based architecture:

  1. Scanner: Tokenizes source code into a stream of tokens
  2. Compiler: Parses tokens and generates bytecode instructions
  3. Virtual Machine: Executes bytecode instructions

Grammar Notes

Grammar:

program        → declaration* EOF ;

declaration    → varDecl
               | statement ;

varDecl        → "var" IDENTIFIER ( "=" expression )? ";" ;

statement      → exprStmt
               | printStmt
               | block ;

block          → "{" declaration* "}" ;

exprStmt       → expression ";" ;
printStmt      → "print" expression ";" ;

Variable declaration:

varDeclaration() -> parseVariable() --Constant--> Compile Initializer -> defineVariable()

Project Structure

  • VM: Stack-based virtual machine that executes bytecode
  • Compiler: Turns source code into bytecode
  • Scanner: Tokenizes source code for the compiler
  • Chunk: Represents bytecode and related metadata
  • Value: Represents runtime values (numbers, booleans, nil, strings)
  • Object: Manages heap-allocated objects like strings
  • Memory: Handles memory allocation, reallocation, and garbage collection
  • Debug: Tools for inspecting bytecode and execution
  • REPL: Interactive environment with history, line editing, and history persistence
  • Table: Hash table implementation for string interning and variable lookup

Development Status

NRK is currently in early development (v0.0.1) and implements:

  • Basic arithmetic operations
  • Comparison operations
  • Boolean logic
  • Bitwise operations
  • Variables and assignment (global and local)
  • Print statements
  • Postfix operators (++, --)
  • String operations and template strings
  • String interning with hash tables
  • Memory management foundations with garbage collection
  • Lexical scoping with blocks

Debugging

The interpreter includes powerful debugging features that can be enabled via the Makefile:

# Enable all debug flags
make debug

Individual debugging options can also be controlled in common.h:

  • DEBUG_PRINT_CODE: Disassembles and prints bytecode after compilation
  • DEBUG_TRACE_EXECUTION: Traces VM execution step by step, showing stack state
  • DEBUG_SCAN_EXECUTION: Shows detailed scanning process information
  • DEBUG_COMPILE_EXECUTION: Provides detailed compilation process logs

All debug flags can be simultaneously enabled by defining NRK_DEBUG_ALL.

The new build system also supports:

  • Cleaner directory structure (src, obj, bin)
  • Better dependency tracking
  • GDB integration
  • Test running capabilities

Roadmap

Future plans include:

  • Control flow (if/else, loops)
  • Functions and closures
  • Classes and inheritance
  • Full implementation of compound assignment operators

Development Notes

  • String interning is implemented using a hash table for efficient string comparison
  • Extended constant pool via OP_CONSTANT_LONG allows for more than 256 constants
  • Memory management uses Flexible Array Members (FAM) for efficient string storage
  • Local variable handling uses direct stack slot access for performance
  • Planned improvements:
    • Extend table support to other immutable objects besides strings as keys
    • Optimize compiler pointer indirections in critical paths
    • Complete implementation of compound assignment operators

About

The nrk programming language

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published