Skip to content

pchedas/Reflang

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reflang Programming Language

An educational programming language designed to teach low-level programming concepts

Reflang is positioned between assembly and C programming. It's designed to help students and developers learn the fundamental mental models they'll need when working with assembly language and C, while providing a more visual and approachable syntax than raw assembly.

Educational Philosophy

Reflang serves as a pedagogical bridge that teaches:

  • Explicit data flow through visual arrow syntax (->)
  • Register-based thinking with direct register manipulation (R1, R2, R3, etc.)
  • Memory management concepts with visible pointer operations (&, *)
  • Low-level control flow with explicit jumps and labels
  • Function calling conventions and parameter passing
  • Assembly-like mindset without assembly's syntactic complexity

Students learn concepts that directly transfer to:

  • Assembly programming (registers, memory addressing, control flow)
  • C programming (pointers, memory layout, function calls)
  • Systems programming (explicit resource management)
  • Computer architecture understanding

Language Overview

Reflang is a low-level programming language designed to be more visual than assembly but less abstract than C. It emphasizes explicit data flow through arrow syntax and treats everything as void* pointers.

Core Design Principles

  • No type system: Everything is treated as void*
  • Visual data flow: -> operator shows explicit data movement
  • Sequential execution: No implicit parallelism, clear execution order
  • Register-oriented: Direct register manipulation with limited register set
  • Memory explicit: All memory operations are visible and controllable

Syntax Specification

1. Data Types and Variables

Registers

  • Syntax: R1, R2, R3, R4, R5 (implementation-defined limit)
  • Default interpretation: RX = data/value stored in register
  • Address interpretation: &RX = treat register contents as memory address

Variables

  • Constraint: Variable name alone is INVALID
  • Address form: &variable = treat variable as address
  • Dereference form: *variable = dereference variable (get value at address)

Operator Precedence

The & and * operators always dominate arithmetic:

&ptr + 4        // (address of ptr) + 4
*base + offset  // (value at base) + offset

2. Data Movement Syntax

Basic Movement

source -> destination

Register Operations

R1 -> R2        // Copy value from R1 to R2
&R1 -> R2       // Load from address in R1 to R2
R2 -> &R1       // Store R2 at address in R1

Variable Operations

&var -> R1      // Load variable address into R1
*var -> R1      // Load value at variable address into R1
R1 -> &var      // Store R1 at variable address
R1 -> *var      // Store R1 at address pointed by variable

Immediate Values

0x1000 -> R1    // Load immediate value
R1 -> &0x1000   // Store at literal address

3. Arithmetic and Logic Operations

R1 + R2 -> R3   // Addition
R1 - R2 -> R3   // Subtraction
R1 * R2 -> R3   // Multiplication
R1 / R2 -> R3   // Division
R1 % R2 -> R3   // Modulo
R1 & R2 -> R3   // Bitwise AND
R1 | R2 -> R3   // Bitwise OR
R1 ^ R2 -> R3   // Bitwise XOR
R1 << R2 -> R3  // Left shift
R1 >> R2 -> R3  // Right shift
R1 == R2 -> R3  // Equality (1 if true, 0 if false)
R1 != R2 -> R3  // Inequality
R1 < R2 -> R3   // Less than
R1 > R2 -> R3   // Greater than
R1 <= R2 -> R3  // Less than or equal
R1 >= R2 -> R3  // Greater than or equal

4. Control Flow

Unconditional Jump

-> label_name

Conditional Jump

RX -> ?label_name   // Jump if RX is non-zero

Conditional Function Call

RX -> ?function_name $arg1 $arg2

5. Routines

Declaration

routine routine_name $param1 $param2:
    // routine body
    -> end

Parameters

  • Parameters are accessed as $1, $2, etc.
  • Parameters are addresses (pointers)

6. Functions

Declaration

function function_name $param1 $param2 -> $return1 $return2:
    // function body
    -> ret

Calling Convention (Haskell-style)

input1 -> input2 -> function_name -> output1 -> output2

7. Memory Management

Heap Operations

&heap -> R1     // Get current heap position
R1 -> *heap     // Store at current heap position

Variable Declaration

&variable = 0x1000      // Direct assignment
0x1000 -> &variable     // Alternative syntax

8. I/O Operations

R1 -> stdout    // Output register contents
stdin -> R1     // Read input to register

Complete Program Examples

Example 1: Basic Arithmetic and Control Flow

routine main:
    // Simple calculator: add two numbers and compare
    10 -> R1            // first number
    20 -> R2            // second number
    R1 + R2 -> R3       // sum
    
    // Check if sum > 25
    25 -> R4
    R3 - R4 -> R5       // R5 = R3 - 25
    R5 -> ?big_number   // jump if positive
    
    // Small number path
    R3 -> stdout
    -> done
    
    big_number:
        999 -> stdout   // output 999 for big numbers
        
    done:
    -> end

Example 2: Memory Management and Pointers

routine memory_demo:
    // Initialize heap
    0x1000 -> &heap     // set heap start
    
    // Allocate space for two variables
    &heap -> &ptr1      // first variable address
    &heap + 1 -> &ptr2  // second variable address
    &heap + 2 -> &heap  // advance heap
    
    // Store values
    42 -> *ptr1         // store 42 at first location
    84 -> *ptr2         // store 84 at second location
    
    // Swap values using registers
    *ptr1 -> R1         // load first value
    *ptr2 -> R2         // load second value
    R2 -> *ptr1         // store second at first location
    R1 -> *ptr2         // store first at second location
    
    // Output swapped values
    *ptr1 -> stdout
    *ptr2 -> stdout
    -> end

Example 3: Function with Multiple Parameters and Returns

function divide_with_remainder $dividend $divisor -> $quotient $remainder:
    // Perform division and return both quotient and remainder
    *dividend -> R1     // load dividend
    *divisor -> R2      // load divisor
    
    // Calculate quotient
    R1 / R2 -> R3
    R3 -> $quotient
    
    // Calculate remainder
    R3 * R2 -> R4       // quotient * divisor
    R1 - R4 -> R5       // dividend - (quotient * divisor)
    R5 -> $remainder
    
    -> ret

routine main:
    // Set up memory for parameters and results
    0x2000 -> &heap
    &heap -> &dividend
    &heap + 1 -> &divisor
    &heap + 2 -> &quotient
    &heap + 3 -> &remainder
    
    // Store input values
    17 -> *dividend     // 17 ÷ 5
    5 -> *divisor
    
    // Call function with chained parameters
    &dividend -> &divisor -> divide_with_remainder -> &quotient -> &remainder
    
    // Output results
    *quotient -> stdout  // should output 3
    *remainder -> stdout // should output 2
    -> end

Example 4: Array Processing with Loops

routine array_sum:
    // Sum an array of 5 numbers
    0x3000 -> &heap
    
    // Initialize array with values
    10 -> *heap
    &heap + 1 -> &heap
    20 -> *heap
    &heap + 1 -> &heap
    30 -> *heap
    &heap + 1 -> &heap
    40 -> *heap
    &heap + 1 -> &heap
    50 -> *heap
    
    // Reset to array start
    0x3000 -> &current
    0 -> R1             // sum accumulator
    0 -> R2             // counter
    5 -> R3             // array length
    
    sum_loop:
        R3 - R2 -> R4   // check if counter < length
        R4 -> ?continue_sum
        -> sum_done
        
    continue_sum:
        *current -> R5  // load current array element
        R1 + R5 -> R1   // add to sum
        &current + 1 -> &current  // advance pointer
        R2 + 1 -> R2    // increment counter
        -> sum_loop
        
    sum_done:
        R1 -> stdout    // output sum (should be 150)
    -> end

Example 5: Recursive Function (Factorial)

function factorial $n -> $result:
    *n -> R1
    1 -> R2
    R1 - R2 -> R3       // n - 1
    R3 -> ?recursive_case
    
    // Base case: n <= 1
    1 -> $result
    -> ret
    
    recursive_case:
        // Allocate space for recursive call
        &heap -> &temp_n
        &heap + 1 -> &temp_result
        &heap + 2 -> &heap
        
        // Store n-1 for recursive call
        R3 -> *temp_n
        
        // Recursive call: factorial(n-1)
        &temp_n -> factorial -> &temp_result
        
        // Multiply n * factorial(n-1)
        R1 -> R2            // n
        *temp_result -> R3  // factorial(n-1)
        R2 * R3 -> $result
        
    -> ret

routine main:
    0x4000 -> &heap
    &heap -> &input
    &heap + 1 -> &output
    &heap + 2 -> &heap
    
    5 -> *input         // calculate 5!
    &input -> factorial -> &output
    *output -> stdout   // should output 120
    -> end

Compiler Implementation Notes

1. Lexical Analysis

  • Keywords: routine, function, ->, end, ret, stdin, stdout, heap
  • Operators: +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=
  • Symbols: &, *, ?, $, :
  • Identifiers: Variables, labels, function names
  • Literals: Decimal and hexadecimal numbers

2. Parsing Considerations

  • Arrow expressions: The -> operator is the core parsing unit
  • Chained expressions: Handle function calls with multiple parameters/returns
  • Address arithmetic: Parse expressions like &ptr + 4 correctly
  • Parameter references: $1, $2, etc. in function/routine contexts

3. Semantic Analysis

  • Register allocation: Track register usage, enforce limits
  • Memory management: Track heap usage, ensure bounds checking
  • Type consistency: While "typeless," ensure pointer/value consistency
  • Control flow: Validate jump targets exist
  • Function signatures: Match parameter counts in calls

4. Code Generation

  • Register mapping: Map R1-R5 to target architecture registers
  • Memory model: Implement heap as linear memory region
  • Jump tables: Handle conditional and unconditional jumps
  • Function calling: Implement parameter passing convention
  • I/O operations: Map stdin/stdout to system calls

5. Runtime Considerations

  • Stack management: For function calls and local variables
  • Heap boundaries: Enforce heap size limits
  • Error handling: Division by zero, memory bounds violations
  • I/O buffering: Efficient stdin/stdout operations

6. Optimization Opportunities

  • Register allocation: Minimize register spills
  • Dead code elimination: Remove unused computations
  • Constant folding: Evaluate constant expressions at compile time
  • Jump optimization: Optimize conditional jump patterns

Standard Library Functions (Proposed)

// Memory allocation with size
function alloc $size -> $address:
    &heap -> $address
    &heap + *size -> &heap
    -> ret

// Memory copy
function memcpy $src $dst $size -> :
    // Implementation for copying memory blocks
    -> ret

// String length
function strlen $str -> $length:
    // Implementation for string length calculation
    -> ret

This guide provides the complete syntax and semantic model needed to implement a Reflang compiler, with comprehensive examples demonstrating all language features.

Reflang Comprehensive Syntax Summary

Core Principles

  • No types: Everything is treated as void*
  • Arrow flow: -> indicates data movement direction
  • Sequential execution: Fully sequential with routines and functions for organization
  • Visual clarity: Data flow is explicit and left-to-right

Registers vs Variables

Registers (R1, R2, etc.):

  • R1 = the value stored in register R1 (data by default)
  • &R1 = treat R1's contents as a memory address

Variables/Pointers (p, myvar, etc.):

  • p alone = NOT VALID - must be explicit
  • &p = treat p as an address
  • *p = dereference p (get value at address stored in p)

Operator Precedence

The & or * symbol always dominates arithmetic:

&add + 1        // (address of add) + 1
*ptr + 5        // (value at ptr) + 5
&($3 + 1)       // address of parameter ($3 + 1)

Data Movement

// Register to register
R1->R2              // move data from R1 to R2

// Register memory access
&R1->R2             // load from address stored in R1 into R2
R2->&R1             // store R2 at address stored in R1

// Variable operations
&p->R1              // load address from variable p into R1
*p->R1              // load value at address p into R1
R1->&p              // store R1 at address in variable p
R1->*p              // store R1 at address pointed to by p

// Immediate values
0x1000->R1          // store immediate value into R1
R2->&0x1000         // store R2 at literal address 0x1000

Arithmetic and Logic

R1+R2->R3           // add R1 and R2, store in R3
R1&R2->R3           // bitwise AND
R1==R2->R3          // comparison (0 or 1 result)
R1<<4->R2           // bit shift

Control Flow

R1->?jump_label     // conditional jump if R1 is non-zero
->jump_label        // unconditional jump
R1->?myroutine $arg // conditional routine call

Routines

routine myroutine $1 $2:
    *$1->R1         // load value at address $1 into R1
    R1+1->R1        // increment R1
    R1->*$2         // store R1 at address $2
    ->end           // end routine

Functions

Functions return values and use Haskell-style parameter passing:

function myfun $1 $2 $3 -> $4 $5:
    &($3 + 1) -> &p     // address of ($3 + 1) goes to address p
    0x01 -> &q          // immediate 0x01 goes to address q
    $1 -> *p            // parameter $1 goes to address pointed by p
    &$2 -> &q           // address of $2 goes to address q
    *p -> *q -> add -> *p   // call add function with chained params/returns
    *p -> $4            // return *p as first output
    *q -> $5            // return *q as second output
    -> ret              // end function

function add $1 $2 -> $3:
    $1 + $2 -> $3       // add parameters, store in return
    -> ret

Function Calling Convention

Multi-parameter functions use chained arrow syntax:

*input1 -> &input2 -> myfunction -> &output1 -> *output2
//  ^         ^          ^            ^          ^
//  param1   param2   function    return1    return2

Memory Management & I/O

// Memory management
&heap->R1           // load heap root/current position into R1
R1->*heap           // store R1 at current heap position
// (No freeing mechanism designed yet)

// I/O
R1->stdout          // output
stdin->R1           // input

Variable Declaration

&p=0x00             // p contains address 0x00 (direct memory assignment)
0x00 -> &heap       // alternative syntax
&heap + 1 -> &a     // address arithmetic in assignment

Complete Example

routine main:
    0x00 -> &heap           // initialize heap pointer
    &heap + 1 -> &a         // set up variable addresses
    &heap + 2 -> &b
    0x10 -> *a              // store values
    0x10 -> *b
    *a -> *b -> &heap -> myfun -> *a -> *b  // call function
    ->end

About

Reflang: A Visual, Register-Oriented Toy Programming Language for Education

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages