https://github.com/blagojeblagojevic/blang
Fort like lang
https://github.com/blagojeblagojevic/blang
bytecode bytecode-interpreter c concatenative-language concatenative-programming-language esoteric-language esoteric-programming-language forth forth-like lexer parser programming-language std vm
Last synced: 2 months ago
JSON representation
Fort like lang
- Host: GitHub
- URL: https://github.com/blagojeblagojevic/blang
- Owner: BlagojeBlagojevic
- Created: 2024-11-05T21:09:12.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-02-06T20:54:31.000Z (3 months ago)
- Last Synced: 2025-02-06T21:34:32.985Z (3 months ago)
- Topics: bytecode, bytecode-interpreter, c, concatenative-language, concatenative-programming-language, esoteric-language, esoteric-programming-language, forth, forth-like, lexer, parser, programming-language, std, vm
- Language: C
- Homepage:
- Size: 416 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Blang
**EXTREMELY IMPORTANT! THIS LANGUAGE IS A WORK IN PROGRESS! ANYTHING CAN CHANGE AT ANY MOMENT WITHOUT ANY NOTICE! USE THIS LANGUAGE AT YOUR OWN RISK!**
Blang is a **[Concatenative](https://en.wikipedia.org/wiki/Concatenative_programming_language)**, **[Stack-Oriented](https://en.wikipedia.org/wiki/Stack-oriented_programming)** **[Programming Language](https://en.wikipedia.org/wiki/Programming_language)** for **[Computers](https://en.wikipedia.org/wiki/Computer)**.
*(If you've never heard about this kind of language before, check out [https://concatenative.org/](https://concatenative.org/))*
---
## Development Milestones
- [x] Compiled to a custom instruction set (BVM bytecode)
- [x] Conditional/selection statements
- [x] Loops
- [x] [Turing-complete](./examples/celluarautomata/rule110.blang)
- [x] Cross-platform
- [x] Strings support
- [x] Functions
- [ ] Self-hosted
- [ ] Statically typed
- [ ] Optimized
- [ ] Implement a VM as a custom CPU for FPGA---
## Examples
### Hello, World:
```forth
0 "HelloWorld" printstring
endscript .
```### Simple program that prints all uppercase letters:
```forth
65 ? a
while
a charprint
89 < if
breakloop
end
1 a + ? a
endloop
endscript .
```---
## Quick Start
### Compile the project:
```bash
gcc -O3 lex.c parser.c main.c -o main.out
```OR
```bash
make all
```### Compile to bytecode:
```bash
./main.out -c
```### Run the bytecode:
```bash
./main.out -r
```### Usage:
```bash
Usage: Compile -c
Run -r
```---
## Language Reference
This section describes the features supported by the language so far. **Since the language is a work in progress, everything in this section is subject to change.**
### Literals
#### Integer
An integer is a sequence of decimal digits. When an integer is encountered, it is pushed onto the data stack for processing by the relevant operations.
Example:
```forth
10 20 +
```The code above pushes `10` and `20` onto the data stack and sums them up with the `+` operation.
#### String
TBD
#### Character
A character is currently used as a variable on the heap. For printing a character, there is a function called `charprint`. For working with strings, there is a function called `printstring`. You must provide an end token, which is `0`.
Example:
```forth
35 ? taraba
32 ? space
10 ? newLine
```---
### Intrinsics (Built-in Words)
### Stack Manipulation
| Name | Signature | Description |
| --- | --- | --- |
| `dup` | `a -- a a` | Duplicate an element on top of the stack. |
| `swap` | `a b -- b a` | Swap 2 elements on the top of the stack. |
| `drop` | `a --` | Remove the top element from the stack. |
| `print` | `a --` | Print the element on top of the stack and remove it. |
| `over` | `a b -- a b a` | Copy the element below the top of the stack. |
| `rot` | `a b c -- b c a` | Rotate the top three stack elements. |### Arithmetic
| Name | Signature | Description |
| --- | --- | --- |
| `+` | `[a: int] [b: int] -- [a + b: int]` | Sum up two elements on the top of the stack. |
| `-` | `[a: int] [b: int] -- [a - b: int]` | Subtract two elements on the top of the stack. |
| `*` | `[a: int] [b: int] -- [a * b: int]` | Multiply two elements on top of the stack. |
| `/` | `[a: int] [b: int] -- [a / b: int]` | Divide two elements on top of the stack. |
| `%` | `[a: int] [b: int] -- [a % b: int]` | Modulo two elements on top of the stack. |
#### Bitwise
| Name | Signature | Description |
| --- | --- | --- |
| `shr` | `[a: int] [b: int] -- [a >> b: int]` | Right **unsigned** bit shift. |
| `shl` | `[a: int] [b: int] -- [a << b: int]` | Left bit shift. |
| `or` | `[a: int] [b: int] -- [a \| b: int]` | Bitwise `OR`. |
| `and` | `[a: int] [b: int] -- [a & b: int]` | Bitwise `AND`. |
| `not` | `[a: int] -- [~a: int]` | Bitwise `NOT`. |#### Memory
| Name | Signature | Description |
| --- | --- | --- |
| `?` | ` let ` | Store a value from `` at the var address. If the var is not declared, create the var on ``. |
| `arr` | `arr ` | Create an array at the first free address on `stacksize - numofvars - 1`. |
| `&` | `ptr ` | Push a memory address of a var onto the top of the stack. |
| `@` | ` ptrval` | Push a value from the memory address on top of the stack onto the top of the stack. |
| `??` | ` ptrval` | Store a value from `` to the memory address on ``. |#### System
- `syscall`:
| Name | Signature | Description |
|------------|----------------------------------|-----------------------------------------------------------------------------|
| `write` | `fd ptr len -- result` | Write `len` bytes from `ptr` to file descriptor `fd`. |
| `close` | `fd -- result` | Close file descriptor `fd`. |
| `exit` | `status --` | Terminate the program with exit `status`. |
| `truncate` | `fd length -- result` | Truncate file descriptor `fd` to `length` bytes. |
| `isatty` | `fd -- result` | Check if `fd` refers to a terminal. Returns 1 if true, 0 otherwise. |
| `read` | `fd ptr len -- bytes_read` | Read up to `len` bytes from `fd` into `ptr`. Returns number of bytes read. |
| `sleep` | `seconds --` | Sleep for `seconds` seconds. |
| `system` | `command_ptr -- exit_code` | Execute shell command specified by `command_ptr`. |
| `dupF` | `fd -- new_fd` | Duplicate file descriptor `fd`. |
| `dup2` | `old_fd new_fd -- new_fd` | Duplicate `old_fd` to `new_fd`, closing `new_fd` first if open. |
| `halt` | `--` | Immediately halt the program execution. |- `c functions` - TBD
---
### Control Flow
#### If-Condition
Simple `if`:
```html
if
end
````If/else`:
```html
dup if
end
else
end
```Example:
```forth
0 10
= dup
if
20 print
30 40 = dup
if
30 print
end
else
50 print
end
end
else
30 print
end
40 print
endscript .
```#### While-Loop
Infinite loop:
```html
while
endloop
```Conditional loop (use `breakloop` to exit):
```html
while
if
breakloop
end
endloop
```---
### Procedures and Functions
The `word` keyword declares a procedure or function. Values can be passed through the stack or the heap.
Example:
```forth
word printString
while
dup @ charprint
0 = if
breakloop
end
1 +
endloop
drop
endword& H printString
```#### Procedure Pointers
TBD
---
### Constants
Constants are declared like this:
```forth
word pi 3.1415 endword
```---
### Memory
The heap is built on top of the stack. Variables are global for the entire duration of the program.
---
### Type Checking
There are 4 types: `int64`, `float64`, `uint64`, and `ch` (basically `uint64`, but used in strings). The type is inferred for math operations based on the last element on the stack. For example, if we have `10 10.2` on the stack and we perform the `+` operation, the `+` operation will use the `float` type as the operand.
---
## Example Programs
### Memory Copy Example
```forth
0
arr toCopyInto 50word memcpy
? memcpySize
drop
? memcpySrc
drop
? memcpyDest
drop
SP ? memcpySP
drop
while
memcpySrc @ memcpyDest ??
memcpySrc 1 + ? memcpySrc
memcpyDest 1 + ? memcpyDest
memcpySize 0 = if
breakloop
end
memcpySize -1 + ? memcpySize
endloop
memcpySP SET
endwordword memmove memcpy endword
SP ? temp
drop0 "HelloWorld" 10
& toCopyInto0 temp 12 memcpy1 & toCopyInto0 12 write
0 & toCopyInto0 12 read
1 & toCopyInto0 6 write
10 sleep
1 & toCopyInto0 6 write
endscript .
```### Game of Life Implementation
```forth
050 ? MAX_X_POS
35 ? MAX_Y_POS
word BACKGROUND_CHAR 32 endword
word CELL_CHAR 35 endword
word SLEEP_TIME 1 endwordarr checkCoords 100
arr mainMatrix 1800
arr neighborCountBuffer 1800
word increment 1 + endword
word matrixIndex MAX_X_POS updateCell_y * updateCell_x + endword
word matrixIndexP MAX_X_POS printCells_y * printCells_x + endword
word matrixIndexC MAX_X_POS tempY * tempX + endwordword matrixInit
0 ? printCells_x
0 ? printCells_y
SP ? printCells_SP
while MAX_Y_POS printCells_y loopBreak
printCells_y 1 + ? printCells_y
0 ? printCells_x
while printCells_x MAX_X_POS loopBreak
printCells_x 1 + ? printCells_x
BACKGROUND_CHAR
& mainMatrix0 matrixIndexP + ??
endloop
endloop
0 SET
endwordword loopBreak
= if
breakloop
end
endwordword updateCell
0 ? updateCell_x
MAX_Y_POS ? updateCell_y
SP ? upadteCell_SP
while 0 updateCell_y loopBreak
updateCell_y -1 + ? updateCell_y
0 ? updateCell_x
while updateCell_x MAX_X_POS loopBreak
updateCell_x 1 + ? updateCell_x
3 & neighborCountBuffer0 matrixIndex + @
= if
CELL_CHAR
& mainMatrix0 matrixIndex + ??
end
3 & neighborCountBuffer0 matrixIndex + @ >
2 & neighborCountBuffer0 matrixIndex + @ <
or
1 = if
BACKGROUND_CHAR
& mainMatrix0 matrixIndex + ??
end
endloop
endloop
upadteCell_SP SET
endwordword countNeighbors
? posY
drop
? posX
drop
SP ? countNeighbors_SP
1 posY + ? checkCoords0
-1 posX + ? checkCoords1
1 posY + ? checkCoords2
0 posX + ? checkCoords3
1 posY + ? checkCoords4
1 posX + ? checkCoords50 posY + ? checkCoords6
1 posX + ? checkCoords7-1 posY + ? checkCoords8
1 posX + ? checkCoords9
-1 posY + ? checkCoords10
0 posX + ? checkCoords11
-1 posY + ? checkCoords12
-1 posX + ? checkCoords13
0 posY + ? checkCoords14
-1 posX + ? checkCoords15
0 ? i
0 ? neighbors
while
& checkCoords0 i + @ ? tempY
& checkCoords1 i + @ ? tempX
0 tempX < if
MAX_X_POS -1 + ? tempX
end
MAX_X_POS -1 + tempX > if
0 ? tempX
end
0 tempY < if
MAX_Y_POS -1 + ? tempY
end
MAX_Y_POS -1 + tempY > if
0 ? tempY
end
& mainMatrix0 matrixIndexC + @ CELL_CHAR = if
neighbors 1 + ? neighbors
end
i 2 + ? i
i 16 = if
neighbors
breakloop
end
endloopcountNeighbors_SP SET
neighbors
endwordword printCells
0 ? printCells_x
MAX_Y_POS ? printCells_y
SP ? printCells_SP
while printCells_y 0 loopBreak
printCells_y -1 + ? printCells_y
-1 ? printCells_x
while printCells_x MAX_X_POS loopBreak
printCells_x 1 + ? printCells_x
& mainMatrix0 matrixIndexP + @
charprint 0
printCells_x printCells_y countNeighbors
& neighborCountBuffer0 matrixIndexP + ??
endloop
10 charprint
endloop
printCells_SP SET
endwordword convayLoop
SP print
while
0 SET
0 "cls" system
0 10 10 9 9 "GameOfLife" 10 9 9 9 9 "By:" 32 "B.B." printstring
printCells
updateCell
SLEEP_TIME sleep
endloop
endword0 SET
matrixInit
0 "color" 32 "3" system
CELL_CHAR ? mainMatrix925
CELL_CHAR ? mainMatrix926
CELL_CHAR ? mainMatrix927CELL_CHAR ? mainMatrix120
CELL_CHAR ? mainMatrix170
CELL_CHAR ? mainMatrix220CELL_CHAR ? mainMatrix1025
CELL_CHAR ? mainMatrix1026
CELL_CHAR ? mainMatrix1075
CELL_CHAR ? mainMatrix1076convayLoop
endscript .
```---
## Contributing
Contributions are welcome! If you'd like to contribute, please follow these steps:
1. Fork the repository.
2. Create a new branch for your feature or bugfix.
3. Commit your changes.
4. Push your branch to your fork.
5. Submit a pull request.---
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
---
## Acknowledgments
- Inspired by concatenative and stack-oriented languages like Forth and Factor.
- Special thanks to the [concatenative.org](https://concatenative.org/) community for their resources and inspiration.---