Skip to content

Dcoumentation v3.1

Ujjwal Kumar edited this page May 27, 2023 · 4 revisions

Documentation

Official documentation for the RAM programming language. Please open an issue if you find any bugs, or want some features to be changed or added.

Program Structure

A program should always start with a main: label, defining a block. Blocks are like functions where you can jump anytime using jmp or conditional jumps (see jump reference to learn how to use them). Each label contains a block which is executed when the label is called. The program has a stack which stores integers and there exists some commands to manipulate it.

Variable Reference

The language has 4 general purpose variables or registers (as in x86/arm). And rest of all are dynamic user defined variables of certain types.

NOTE: The registers are local to a function, they cannot be modified independently unless you perform a jump to another function. On the other hand, user defined variables are globally mutable, they can be modified independently.

General purpose vars

  • lx and rv store i32 integers.
  • string and lxstring stores strings.

Dynamic Global vars

They exist in the form of following types-

  • :int (i32 integer)
  • :string (string literal)
  • :vec :string/:int (vector of string or ints)
  • todo: u32, i64, u64, i128, u128.
  • structs?
  • multi dimensional vectors?

NOTE: These variables are truly global. They can change from a block without calling any jump statements.

Contents

todo: make a contents table using https://www.tablesgenerator.com/markdown_tables

General Commands

comments

// this is a one line comment

print

  • print hello world
  • print var [can be a register]

Variable Based Commands

ram

The ram command is used to assign variables and store a i32 on the stack. You can push an i32 on the stack using ram <number>

For registers:

ram lx/rv 10
ram string/lxstring = 'hello world'

For variables: ram <var_name> :<type_of_var> = <value_of_var>

- ram test :int = 10
- ram test :string = 'hello'
- ram test :vec :int = [1, 2, 4]
- ram test :vec :string = ['hello', 'world']

You can push register values to the stack by using ram lx/rv

ram lx 10
ram lx

You can assign the last value on the stack using ram lx/rv prev

ram 10
ram lx prev
print var lx
// prints 10

halt

halt exits the program

Drop

Drops the value of the variable from the memory, including dependencies in case of a map. Useful in cleaning stuff, or save memory leaks in a loop.

drop <var>

std commands

stdin

Takes in user input. Print message is optional.

stdin string = "input something: "
print var string

OR

ram x :str = ''
stdin x
print var x

stdfs

Opens a file with the given path and store the contents as string.

ram lxstring = './readme.txt'
stdfs open lxstring = string
print var string
// string has the contents of the file

rand

rand [1,10]
// sets a random number between 1 to 10 excluding 10 on the stack

rand lx [1,10]
// sets the random number to lx

rand lx [rv, lx]
// generate random number between rv & lx into lx

parse

Parses variables into the given type and stores them into the string or lx register.

ram lx 5
parse lx :str
// now string = "5"
ram x :str = '10'
parse x :int
// now lx = 10

pop

  • pop Removes the last i32 from the stack
  • Be careful, you might not want to always use it.

reset

Empties the entire stack.

string operations

split

split lxstring > " " = var
// splits lxstring using spaces and stores the data in a string vector named var
split string > "\n" = var
// splits string using a new line and stores the data in a string vector named var

concat

concats two strings and stores the values (registers and vars) in the string register

main:
    ram string = 'hello '
    ram lxstring = 'world'
    concat string lxstring
    print var string
    halt

join

Joins vector of strings into the given string var:

ram x :vec :str = ['hello', 'world']
join x > " " = string
print var string
// hello world

copy

Copy is used to copy the value of one variable/register to another variable/register.

ram x :int = 1
ram y :int = 10
copy x = y
print var x
// prints 10

Vector operations

pop

ram x :vec :int = [1, 2]
vec x pop
print var x
// prints [1]

push

ram lx 100
ram x :vec :int = [1, 2]
vec x push lx
print var x
// [1, 2, 100] 

(works for registers and vars)

return by index

ram x :vec :str = ['hello', 'world']
vec string = x[0]
print var string
// hello

modify by index

ram lx 100
ram x :vec :int = [2, 3, 4]
vec x[1] = lx
print var x
// [1, 100, 4]

length

ram :vec :str x = ['a', 'b', 'c']
vec x len
// pushes 3 to the stack 

Shift

Deletes the first item , reducing length of vector

ram :vec :int x = [1, 2, 4]
vec x shift
// x = [2, 4]

Maps

Maps are like dicts in python, or objects in JavaScript. They hold key value pairs.

main:
    ram lx 100
    ram :str x = "test"
    ram var :map
    insert var { 10: "temst" }
    insert var { x: 12 }
    delete var 10
    ram t :str = ""
    get var 10 = t
    dbg

This does not yet work with registers so you might have to use copy to perform operations to it. This also supports nested maps which is pretty cool. Butterflies and vectors as keys are not yet implemented due to issues in deep comparisons.

Drop

Drops a variable. Use with caution.

ram x :str = "helloworld"
drop x
// cant access x, cleared from heap

Operation Commands

add

  • adds two numbers and pushes the result to the stack
ram 10
ram 20
add 
// pushes 30 to the stack, removing the last 2 values
var x :int = 20
ram 10
add x 
// adds x to 10 and pops 10 from the stack; pushing result on the stack
var x :int = 10
var y :int = 20
add x y
// pushes 30 to the stack

sub

Works as same as add; subtracts the latest item of the stack from the previous.

ram 20
ram 5
add 
// pushes 15 to the stack, removing the last 2 values
var x :int = 10
var y :int = 20
sub x y
// pushes -10 to the stack

mul

multiplies two latest numbers on the stack and pushes the value back to it;

ram 5
ram 2
mul
// pushes 10 to the stack, removing the last 2 values
var x :int = 10
var y :int = 20
mul x y
// pushes 200 to the stack

div

the number added prior to the last number / last number and pushes to stack.

ram 10
ram 5
mul
// pushes 2 to the stack, removing the last 2 values
var x :int = 25
var y :int = 5
div x y
// pushes 5 to the stack

cmp and Jump statements

The program is devided into labels and we can jump on any label to execute the code block below it.

main:
    ram 100
    ram 300
    cmp
    jne not_equal:
    cmp
    je equal:
 
 not_equal:
    print Not Equal
    
equal:
    print Equal

The main: label is considered compulsory at the beginning of the program.

  • jmp <label:> - jumps to the label
  • cmp pushes -1, 0, 1 to the stack if the previous number smaller, equal or greater than the number after it in the stack.
main:
    ram 10
    ram 20
    cmp
    print
    // this will print -1 as 10 < 20
  • cmp can also be used to compare two variables or registers:
main:
    ram x :int = 100
    ram y :int = 200
    cmp x y
    print
    // prints -1
    cmp y x
    print
    // prints 1
  • jne <label:> - jumps to the label if the previous cmp statement is not 0 (not equal)

  • je <label:> - jumps to the label if the previous cmp statement is 0 (equal)

  • jgr <label:> - jumps to the label if the prev cmp statement is 1 (greater)

  • jsm <label:> - jumps to the label if the prev cmp statement is -1 (smaller)

Imports

Imports are restricted only to the main file. You can import as many files you want using include <filepath> and then you shall be able to call all the codeblocks associated with the file.

// main.ram

include "ok.ram"
main:
    print hello from main
    jmp test:
// ok.ram
test:
    print hello from ok.ram