feat: initial commit
This commit is contained in:
commit
4399f5bae9
6 changed files with 353 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
build/
|
||||||
|
build-win/
|
||||||
|
build-tmp/
|
||||||
|
*.amd64
|
||||||
|
*.exe
|
||||||
|
*.swp
|
63
Makefile
Normal file
63
Makefile
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# /!\ Warning /!\
|
||||||
|
# Parallel build doesn't work with w64devkit
|
||||||
|
|
||||||
|
OUTNAME = flisp
|
||||||
|
|
||||||
|
CFLAGS = -O0 -Wall -Wextra -g -pipe
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
LDFLAGS_UNIX = -lm
|
||||||
|
LDFLAGS_WIN = -lm
|
||||||
|
|
||||||
|
# ===== End of what should be edited =====
|
||||||
|
|
||||||
|
OUTPUT = "${OUTNAME}.amd64"
|
||||||
|
|
||||||
|
LDFLAGS = $(LDFLAGS_UNIX)
|
||||||
|
|
||||||
|
BUILD_DIR = build
|
||||||
|
SRC_DIR = src
|
||||||
|
|
||||||
|
OBJS = $(patsubst $(SRC_DIR)/%.c,build-tmp/%.o,$(wildcard $(SRC_DIR)/*.c))
|
||||||
|
|
||||||
|
all: | builddir build builddir2
|
||||||
|
|
||||||
|
windef:
|
||||||
|
$(eval OUTPUT = "$(OUTNAME).exe")
|
||||||
|
$(eval BUILD_DIR = build-win)
|
||||||
|
$(eval LDFLAGS = $(LDFLAGS_WIN))
|
||||||
|
|
||||||
|
builddir:
|
||||||
|
- mkdir $(BUILD_DIR)
|
||||||
|
- mkdir build-tmp
|
||||||
|
- rm -rf $(wildcard build-tmp/*)
|
||||||
|
- mv $(wildcard $(BUILD_DIR)/*.o) build-tmp/
|
||||||
|
|
||||||
|
build-tmp/%.o : $(SRC_DIR)/%.c
|
||||||
|
${CC} -c $< -o $@ ${CFLAGS}
|
||||||
|
|
||||||
|
build: $(OBJS)
|
||||||
|
${CC} ${CFLAGS} -o ${OUTPUT} $(OBJS) ${LDFLAGS}
|
||||||
|
|
||||||
|
builddir2:
|
||||||
|
mv $(OBJS) $(BUILD_DIR)
|
||||||
|
rm -rf build-tmp
|
||||||
|
|
||||||
|
win: | windef all
|
||||||
|
|
||||||
|
testwin: win
|
||||||
|
./$(OUTPUT)
|
||||||
|
|
||||||
|
test: all
|
||||||
|
@echo "===== Program output ====="
|
||||||
|
@./${OUTPUT}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
- rm -rf ${BUILD_DIR}
|
||||||
|
- rm -rf build-win
|
||||||
|
- rm -rf build-tmp
|
||||||
|
- rm "$(OUTNAME).amd64" "$(OUTNAME).exe"
|
||||||
|
|
||||||
|
.NOTPARALLEL: builddir builddir2
|
||||||
|
.PHONY: all test clean win windef builddir builddir2 testwin
|
175
spec.md
Normal file
175
spec.md
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
# fLisp
|
||||||
|
|
||||||
|
- S-expressions:
|
||||||
|
`(<function> [arg0 ... argN])`
|
||||||
|
Will call function with optional args arg0-argN
|
||||||
|
`([*]<variable> [arg | *arg] [arg2])`
|
||||||
|
If arg is given, it will assign arg to variable, then return variable
|
||||||
|
If assigning to a vector or string :
|
||||||
|
- If `*` is specified before variable, it will replace the vector
|
||||||
|
- Otherwise, if only arg is given, it will return the element at position
|
||||||
|
arg of variable. If arg2 is given, it will set the element at position
|
||||||
|
arg of variable to arg2.
|
||||||
|
Examples:
|
||||||
|
```
|
||||||
|
fLisp : (let:vec:int a 5)
|
||||||
|
C : int a[5];
|
||||||
|
fLisp : (a 0 69)
|
||||||
|
C : a[0] = 69;
|
||||||
|
fLisp : (let:int x)(x (a 0))
|
||||||
|
C : int x = a[0];
|
||||||
|
```
|
||||||
|
For vectors and strings, it's a shallow copy (data is the same) unless a `*`
|
||||||
|
is specified before [arg]
|
||||||
|
|
||||||
|
- Compiled to bytecode
|
||||||
|
|
||||||
|
In this document :
|
||||||
|
- <...> :
|
||||||
|
Mandatory argument
|
||||||
|
- [...] :
|
||||||
|
Optional argument
|
||||||
|
- | :
|
||||||
|
Or
|
||||||
|
## Core types
|
||||||
|
|
||||||
|
- null :
|
||||||
|
Represents a null value - always evaluates to false
|
||||||
|
- int :
|
||||||
|
32 bit signed integer, evaluates to false if zero and true otherwise
|
||||||
|
- fix :
|
||||||
|
16:16 bit fixed point signed integer, same evaluation rules as ints
|
||||||
|
- float :
|
||||||
|
32bit IEEE floating point value, same evaluation as ints (within
|
||||||
|
`FL_ESPILOǸ̀`)
|
||||||
|
- str:
|
||||||
|
ASCII character string - always evaluates to false
|
||||||
|
- fn:
|
||||||
|
Function, function "variables" are inherently of type fn - handle with care !
|
||||||
|
- vec :
|
||||||
|
Vectors of any type,
|
||||||
|
|
||||||
|
## Core functions
|
||||||
|
|
||||||
|
- `(var[:type] <name> [size])` :
|
||||||
|
Declares a global variable of optional type type and name name
|
||||||
|
if type is of format `:vec:<type>`, the variable will be a vector
|
||||||
|
of type type, and optional size size (otherwise size 0)
|
||||||
|
(if type isn't specified it is inferred)
|
||||||
|
|
||||||
|
- `(let[:type] <name>)`:
|
||||||
|
Same as var, but variable is of local scope (recommended)
|
||||||
|
|
||||||
|
- `(if <cond> [expressions])`:
|
||||||
|
If cond evaluates to true, will execute optional expressions
|
||||||
|
|
||||||
|
- `(else [expressions])`:
|
||||||
|
Must follow a if, will execute if the if's cond evaluates to false
|
||||||
|
|
||||||
|
- `(while <cond> [expressions])`:
|
||||||
|
while cond evalutates to true, will execute optional expressions
|
||||||
|
|
||||||
|
- `(fn (<name> [arg0[:type] ... argN[:type]]) [expressions])` :
|
||||||
|
Declares a function of name name, optional args arg0-argN with optional
|
||||||
|
types (recommended to explicit them), that executes optional expressions
|
||||||
|
The name cannot be a variable
|
||||||
|
|
||||||
|
- `(import <lib0> [... libN])` :
|
||||||
|
Import the functions and variables from lib0-libN
|
||||||
|
|
||||||
|
For the following numerical functions, values must be scalars (except + and =,
|
||||||
|
where they may be strings), and of the same type
|
||||||
|
- `(+ <a> <b>)`:
|
||||||
|
Returns a+b, if they are both strings they will be concatenated
|
||||||
|
|
||||||
|
- `(- <a> <b>)`:
|
||||||
|
Returns a-b
|
||||||
|
|
||||||
|
- `(* <a> <b>)`:
|
||||||
|
Returns a×b
|
||||||
|
|
||||||
|
- `(/ <a> <b>)`:
|
||||||
|
Returns a/b
|
||||||
|
|
||||||
|
- `(% <a> <b>)`:
|
||||||
|
Returns a%b
|
||||||
|
|
||||||
|
- `(< <a> <b>)`:
|
||||||
|
Returns 1 if a < b, else 0
|
||||||
|
|
||||||
|
- ̀`(<= <a> <b>)`:
|
||||||
|
Returns 1 if a <= b, else 0
|
||||||
|
|
||||||
|
- `(= <a> <b>)̀̀`:
|
||||||
|
Returns 1 if a == b, else 0
|
||||||
|
|
||||||
|
- `(>= <a> <b>)`:
|
||||||
|
Returns 1 if a >= b, else 0
|
||||||
|
|
||||||
|
- `(> <a> <b>)`:
|
||||||
|
Returns 1 if a > b, else 0
|
||||||
|
|
||||||
|
## console functions
|
||||||
|
- `(input)`:
|
||||||
|
Will try to get input from the user, returns it as a string
|
||||||
|
- `(write <var>)`:
|
||||||
|
Will try to cast var to string then print it to the console
|
||||||
|
- `(newline)`:
|
||||||
|
Will print a newline to the console (newline characters aren't escaped with
|
||||||
|
write)
|
||||||
|
|
||||||
|
## gint functions
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
# Bytecode
|
||||||
|
|
||||||
|
- 8 byte Value :
|
||||||
|
2 bytes tag, 6 bytes value itself
|
||||||
|
- 4 byte bytecode ops:
|
||||||
|
1 byte op, 3 byte args (named 1-3)
|
||||||
|
|
||||||
|
## Bytecode types
|
||||||
|
|
||||||
|
- `T_Null̀̀` -> null
|
||||||
|
- `T_Int` -> int
|
||||||
|
- `T_Fix` -> fix
|
||||||
|
- `T_Float` -> float
|
||||||
|
- `T_Str` -> string :
|
||||||
|
- If shorter than 4 chars (+ `\0`), is a "compact string"
|
||||||
|
- Otherwise, gets converted to a vector, inherently of chars
|
||||||
|
- `T_Fn` -> fn / function
|
||||||
|
|
||||||
|
## Bytecode operations :
|
||||||
|
|
||||||
|
if just 1, 2 or 3, means the value at pos 1,2,3 of the stack
|
||||||
|
if #1,#2,#3, the immediate value of 1,2,3
|
||||||
|
if 1:2 / 1:2:3, means stitching 1,2,3 together as a 2 or 3 byte value
|
||||||
|
- `add` : 1+2 -> stack
|
||||||
|
- `sub` : 1-2 -> stack
|
||||||
|
- `mul` : 1×2 -> stack
|
||||||
|
- `div` : 1/2 -> stack
|
||||||
|
- `mod` : 1%2 -> stack
|
||||||
|
- `call` : calls 1
|
||||||
|
- `ret` : returns to caller
|
||||||
|
- `mov` : 1 -> 2
|
||||||
|
- `copy` : deepcopy of 1 -> 2
|
||||||
|
- `get` : value at pos 2 of vector 1 -> stack
|
||||||
|
- `set` : set value at pos 2 of vector 1 to 3
|
||||||
|
- `gt` : 1>2 -> stack
|
||||||
|
- `ge` : 1>=2 -> stack
|
||||||
|
- `eq` : 1==2 -> stack
|
||||||
|
- `jmp` : Jumps to bytecode at relative 2:3
|
||||||
|
- `brt` : Jumps to bytecode at relative 2:3 if 1
|
||||||
|
- `cast` : Casts 1 to the type of 2 -> 1
|
||||||
|
- `fcast` : Casts 1 to the type of 2:3 -> 1
|
||||||
|
- `init` : value of type 2:3 and size 1 -> stack
|
||||||
|
- `fcall` : calls function of hash 1:2:3
|
||||||
|
- `pop` : pop value 1
|
||||||
|
- `popl` : pops the last #2 values on stack, starting from #1
|
||||||
|
- `cst0` : 2:3 -> LSW of 3
|
||||||
|
- `cst1` : 2:3 -> MSW of 3
|
||||||
|
- `iter` : Iterates on vector 1, keeping track with int value at 2, and sets
|
||||||
|
int value at 3 to 1 when done
|
||||||
|
to 1
|
||||||
|
|
81
src/byte_defs.h
Normal file
81
src/byte_defs.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum OpTypes {
|
||||||
|
OP_add = 0,
|
||||||
|
OP_sub = 1,
|
||||||
|
OP_mul = 2,
|
||||||
|
OP_div = 3,
|
||||||
|
OP_mod = 4,
|
||||||
|
OP_call = 5,
|
||||||
|
OP_ret = 6,
|
||||||
|
OP_mov = 7,
|
||||||
|
OP_copy = 8,
|
||||||
|
OP_get = 9,
|
||||||
|
OP_set = 10,
|
||||||
|
OP_gt = 11,
|
||||||
|
OP_ge = 12,
|
||||||
|
OP_eq = 13,
|
||||||
|
OP_jmp = 14,
|
||||||
|
OP_brt = 15,
|
||||||
|
OP_cast = 16,
|
||||||
|
OP_fcast = 17,
|
||||||
|
OP_init = 18,
|
||||||
|
OP_fcall = 19,
|
||||||
|
OP_pop = 20,
|
||||||
|
OP_popl = 21,
|
||||||
|
OP_cst0 = 22,
|
||||||
|
OP_cst1 = 23,
|
||||||
|
OP_iter = 24
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
u8 type; // OpTypes
|
||||||
|
u8 o1;
|
||||||
|
u8 o2;
|
||||||
|
u8 o3;
|
||||||
|
|
||||||
|
} PACKED Opcode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
u8 __padding[2];
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
} PACKED Value4B;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
u16 len;
|
||||||
|
u32 pos; // Offset from stack allocator
|
||||||
|
|
||||||
|
} PACKED ValueArray;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
u8 len;
|
||||||
|
union {
|
||||||
|
char str[5];
|
||||||
|
struct {
|
||||||
|
u8 __padding;
|
||||||
|
u32 pos;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} PACKED ValueStr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
uint is_array : 1;
|
||||||
|
uint type : 15;
|
||||||
|
|
||||||
|
PACKED union {
|
||||||
|
Value4B v4B;
|
||||||
|
ValueArray varray;
|
||||||
|
};
|
||||||
|
|
||||||
|
} PACKED Value;
|
||||||
|
|
||||||
|
_Static_assert(sizeof(Value) == 8);
|
11
src/main.c
Normal file
11
src/main.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
17
src/types.h
Normal file
17
src/types.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef int8_t i8;
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef int16_t i16;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef int32_t i32;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef int64_t i64;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
#define PACKED __attribute__((__packed__))
|
||||||
|
|
Loading…
Add table
Reference in a new issue