Merge jackywulf.com:Fcalva/flisp
This commit is contained in:
commit
cb44634016
18 changed files with 289 additions and 113 deletions
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@
|
|||
|
||||
OUTNAME = flisp
|
||||
|
||||
CFLAGS = -std=c99 -O0 -flto -Wall -Wextra -g -pipe -Wno-cast-function-type
|
||||
CFLAGS = -std=c99 -O3 -flto -Wall -Wextra -g -pipe -Wno-cast-function-type
|
||||
|
||||
CC = gcc
|
||||
|
||||
|
|
|
@ -8,16 +8,17 @@ The code in examples/ is public domain
|
|||
## Building
|
||||
|
||||
Pre-requisites:
|
||||
- yacc
|
||||
- Bison
|
||||
- lex
|
||||
- A C99 compiler
|
||||
- GNU Make
|
||||
|
||||
### Unix
|
||||
Running `make` (or `gmake` for BSDs) should work on most Unix systems.
|
||||
Running `make` (or `gmake` for BSDs), maybe twice depending on your version of make,
|
||||
should work on most Unix systems.
|
||||
It produces an executable called `flisp.amd64`
|
||||
|
||||
### Windows
|
||||
To meet the previously mentionned pre-requisites, you need to use mingw.
|
||||
I recommend installing w64devkit, then compiling Bison and Flex from source.
|
||||
Run `make win`
|
||||
Run `make win`, twice
|
||||
|
|
12
TODO.md
12
TODO.md
|
@ -1,15 +1,7 @@
|
|||
tmp:
|
||||
- fix realloc
|
||||
|
||||
- Benchmarks
|
||||
- Tests
|
||||
- Rework assign/call to work better
|
||||
- Finish internal allocator
|
||||
- Strings
|
||||
- String casts
|
||||
- Core functions
|
||||
- Type checks
|
||||
- Scopes
|
||||
|
||||
- Scopes
|
||||
|
||||
- Type propagation
|
||||
- Bytecode gen
|
||||
|
|
3
dump.txt
Normal file
3
dump.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
build/interpreter.o: file format elf64-x86-64
|
||||
|
BIN
perf.data
Normal file
BIN
perf.data
Normal file
Binary file not shown.
|
@ -76,8 +76,9 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
|
||||
uint is_array : 1;
|
||||
uint type : 15;
|
||||
uint is_array : 1;
|
||||
uint is_strong : 1;
|
||||
uint type : 14;
|
||||
|
||||
} PACKED Tag;
|
||||
|
||||
|
@ -140,6 +141,7 @@ typedef Value (bi_fn_t)(void);
|
|||
typedef struct {
|
||||
|
||||
Tag params[8];
|
||||
Tag output;
|
||||
i16 n_param;
|
||||
i16 is_builtin;
|
||||
union {
|
||||
|
|
|
@ -72,7 +72,8 @@ enum BuiltinStatements {
|
|||
struct Statement {
|
||||
|
||||
i32 type;
|
||||
i32 is_const; // Statement is constant, != is a constant - TODO : implem
|
||||
i16 is_const; // Statement is constant, != is a constant - TODO : implem
|
||||
i16 scope;
|
||||
void **children;
|
||||
i32 child_n;
|
||||
void *parent;
|
||||
|
@ -93,16 +94,21 @@ typedef struct Statement Statement;
|
|||
// In practice, this is allocated in parse.c
|
||||
typedef struct {
|
||||
|
||||
// Kept for debug messages
|
||||
// Debug messages
|
||||
// TODO
|
||||
i32 curr_line;
|
||||
i32 curr_column;
|
||||
|
||||
i32 max_statement; // Unused while parsing
|
||||
i32 curr_statement;
|
||||
i32 scope_id;
|
||||
i32 curr_scope;
|
||||
i32 scope_stack[256];
|
||||
|
||||
HashMap symbol_map;
|
||||
|
||||
i32 fn_n;
|
||||
FnSig *funcs;
|
||||
|
||||
i32 stack_size;
|
||||
i32 curr_statement;
|
||||
Statement statements[];
|
||||
|
||||
} ASTStack;
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
// 0 : None (still features runtime debug)
|
||||
// 1 : Some checks
|
||||
// 2 : All checks
|
||||
#define DEBUG 2
|
||||
#define DEBUG 0
|
||||
|
||||
// Debug logs
|
||||
// 0 : None
|
||||
// 1 : All misc debug logs
|
||||
#define LOG 1
|
||||
#define LOG 0
|
||||
|
||||
// TODO : Automate this
|
||||
#define INTERPR
|
||||
|
|
|
@ -58,15 +58,13 @@ int evaluate(Value val){
|
|||
case T_null:
|
||||
return 0;
|
||||
case T_int:
|
||||
return val.v4B.value;
|
||||
case T_fix:
|
||||
return val.v4B.value;
|
||||
return val.v4B.value;
|
||||
case T_float:
|
||||
return FL_EPSILON > fabs((float)val.v4B.value);
|
||||
return FL_EPSILON < fabs(val.v4B.vfl);
|
||||
case T_str:
|
||||
return 0;
|
||||
case T_fn:
|
||||
return 0;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -255,11 +253,13 @@ void print_ast(Statement *base){
|
|||
Value str_to_val(char *str, i32 len){
|
||||
if(len < 0)
|
||||
len = strlen(str);
|
||||
if(len > 65536){
|
||||
fprintf(stderr, "Warning : string is longer than 65k chars"
|
||||
" - will be trunucated\n");
|
||||
len = 65536;
|
||||
}
|
||||
Value retv;
|
||||
retv.tag = (Tag){.is_array = 0, .type = T_str};
|
||||
#if LOG
|
||||
printf("str (%d) : %s\n", len, str);
|
||||
#endif
|
||||
if(len > 4){
|
||||
u32 nstr = flisp_alloc(len);
|
||||
if(!nstr){
|
||||
|
@ -278,15 +278,14 @@ Value str_to_val(char *str, i32 len){
|
|||
}
|
||||
|
||||
void clean_strval(Value str){
|
||||
if(str.vstr.len < 5)
|
||||
return;
|
||||
flisp_free(str.vstr.pos);
|
||||
if(str.vstr.len > 4)
|
||||
flisp_free(str.vstr.pos);
|
||||
}
|
||||
|
||||
// Lesser special functions
|
||||
|
||||
Value is(Tag tag, Value b){
|
||||
Value ret = {.tag = {0,T_int}};
|
||||
Value ret = {.tag = {0,0,T_int}};
|
||||
ret.v4B.value = tag.is_array == b.tag.is_array && tag.type == b.tag.type;
|
||||
return ret;
|
||||
}
|
||||
|
@ -414,7 +413,7 @@ cast_fn_t *cast_table[4][4] = {
|
|||
};
|
||||
|
||||
Value cast(Tag type, Value b){
|
||||
if(type.type == b.tag.type)
|
||||
if(type.type == b.tag.type && type.is_array == b.tag.is_array)
|
||||
return b;
|
||||
if(type.type == T_null || b.tag.type == T_null || type.type == T_fn
|
||||
|| b.tag.type == T_fn || type.is_array || b.tag.is_array){
|
||||
|
@ -573,31 +572,108 @@ Value sml(Value a, Value b){
|
|||
}
|
||||
|
||||
Value sml_eq(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Sml_eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Sml_eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value <= b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl <= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Sml_eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value eq(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value == b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = abs(a.v4B.vfl-b.v4B.vfl) > FL_EPSILON;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value gt_eq(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Gt_eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Gt_eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value >= b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl >= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Gt_eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value gt(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Gt : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Gt : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value > b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl > b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Gt : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value not(Value a){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = !evaluate(a);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value and(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = evaluate(a) && evaluate(b);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value or(Value a, Value b){
|
||||
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = evaluate(a) || evaluate(b);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value len(Value a){
|
||||
|
@ -647,43 +723,43 @@ Value fl_write(Value a){
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return (Value){.tag={0,T_null}};
|
||||
return (Value){.tag={0,0,T_null}};
|
||||
}
|
||||
|
||||
Value nwline(){
|
||||
printf("\n");
|
||||
return (Value){.tag={0,T_null}};
|
||||
return (Value){.tag={0,0,T_null}};
|
||||
}
|
||||
|
||||
const Tag tany = {0,T_null};
|
||||
const Tag tint = {0,T_int};
|
||||
const Tag tfix = {0,T_fix};
|
||||
const Tag tfloat = {0,T_float};
|
||||
const Tag tstr = {0,T_str};
|
||||
const Tag tfn = {0,T_fn};
|
||||
const Tag tvec = {1,T_null};
|
||||
const Tag tany = {0,0,T_any};
|
||||
const Tag tint = {0,0,T_int};
|
||||
const Tag tfix = {0,0,T_fix};
|
||||
const Tag tfloat = {0,0,T_float};
|
||||
const Tag tstr = {0,0,T_str};
|
||||
const Tag tfn = {0,0,T_fn};
|
||||
const Tag tvec = {1,0,T_any};
|
||||
|
||||
#define BICAST(x) ((bi_fn_t*)(x))
|
||||
|
||||
FnSig builtins[] = {
|
||||
{{tany,tany},2,1,{.bi = BICAST(add)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(sub)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(mul)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(divv)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(mod)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(sml)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(sml_eq)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(eq)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(gt_eq)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(gt)}},
|
||||
{{tany} ,1,1,{.bi = BICAST(not)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(and)}},
|
||||
{{tany,tany},2,1,{.bi = BICAST(or)}},
|
||||
{{tvec} ,1,1,{.bi = BICAST(len)}},
|
||||
{{tvec,tany},2,1,{.bi = BICAST(push)}},
|
||||
{{tvec,tint},2,1,{.bi = BICAST(pop)}},
|
||||
{{tany} ,1,1,{.bi = BICAST(fl_write)}},
|
||||
{{0} ,0,1,{.bi = BICAST(nwline)}}
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(add)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(sub)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(mul)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(divv)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(mod)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(sml)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(sml_eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(gt_eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(gt)}},
|
||||
{{tany} ,tint,1,1,{.bi = BICAST(not)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(and)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(or)}},
|
||||
{{tvec} ,tint,1,1,{.bi = BICAST(len)}},
|
||||
{{tvec,tany},tany,2,1,{.bi = BICAST(push)}},
|
||||
{{tvec,tint},tany,2,1,{.bi = BICAST(pop)}},
|
||||
{{tany} ,tany,1,1,{.bi = BICAST(fl_write)}},
|
||||
{{tany} ,tany,0,1,{.bi = BICAST(nwline)}}
|
||||
};
|
||||
|
||||
char *bi_names[] = {
|
||||
|
@ -708,7 +784,7 @@ char *bi_names[] = {
|
|||
};
|
||||
|
||||
void symbol_map_add_bi(HashMap *map){
|
||||
Tag fntag = {0,T_fn};
|
||||
Tag fntag = {0,1,T_fn};
|
||||
for(int i = BI_add; i < BI__end; i++){
|
||||
MapItem *ret = hashmap_insert(map, bi_names[i-BI_add]);
|
||||
ret->type = *((i16*)&fntag);
|
||||
|
|
|
@ -95,7 +95,7 @@ MapItem *hashmap_insert(HashMap *map, char *str){
|
|||
if(!map->bit_free[hsh/32]){
|
||||
map->buffer[hsh].hash = hsh;
|
||||
map->buffer[hsh].id = map->curr_id++;
|
||||
strncpy(map->buffer[hsh].str, str, 32);
|
||||
strncpy(map->buffer[hsh].str, str, 36);
|
||||
set_bit(map->bit_free, hsh);
|
||||
map->item_n++;
|
||||
return &map->buffer[hsh];
|
||||
|
@ -117,7 +117,7 @@ MapItem *hashmap_insert(HashMap *map, char *str){
|
|||
if(!taken){
|
||||
map->buffer[pos].hash = hsh;
|
||||
map->buffer[pos].id = map->curr_id++;
|
||||
strncpy(map->buffer[pos].str, str, 32);
|
||||
strncpy(map->buffer[pos].str, str, 36);
|
||||
set_bit(map->bit_free, hsh);
|
||||
map->item_n++;
|
||||
return &map->buffer[pos];
|
||||
|
@ -134,7 +134,7 @@ MapItem *hashmap_get(HashMap *map, char *str){
|
|||
i32 c_hash = map->buffer[pos].hash;
|
||||
match = c_hash == fhash;
|
||||
if(match)
|
||||
match = !strncmp(str,map->buffer[pos].str,32);
|
||||
match = !strncmp(str,map->buffer[pos].str,36);
|
||||
pos++;
|
||||
} while(!match && pos < map->curr_len && pos-fhash < RELOCATE_TRY_MAX);
|
||||
pos--;
|
||||
|
|
|
@ -31,11 +31,11 @@
|
|||
typedef struct {
|
||||
|
||||
i32 hash;
|
||||
char str[32];
|
||||
char str[36];
|
||||
i32 id;
|
||||
void *fnsig;
|
||||
i32 type;
|
||||
i32 is_const;
|
||||
i16 type;
|
||||
i16 is_const;
|
||||
|
||||
} MapItem;
|
||||
|
||||
|
|
|
@ -37,21 +37,19 @@ void assign(Value *dst, Value src){
|
|||
#if LOG
|
||||
printf("Assign : %d -> %d\n", src.tag.type, dst->tag.type);
|
||||
#endif
|
||||
if((dst->tag.type == src.tag.type || dst->tag.type == T_any)
|
||||
&& dst->tag.is_array == src.tag.is_array){
|
||||
if(dst->tag.type == T_str)
|
||||
clean_strval(*dst);
|
||||
if(dst->tag.is_array != src.tag.is_array)
|
||||
runtime_err("Invalid assignement");
|
||||
if(dst->tag.type == src.tag.type || !dst->tag.is_strong
|
||||
|| dst->tag.type == T_any)
|
||||
*dst = src;
|
||||
}
|
||||
else{
|
||||
fprintf(stderr, "Warning : Possibly incorrect assignement\n"
|
||||
"This may error in the future\n");
|
||||
*dst = src;
|
||||
runtime_err("Invalid assignement");
|
||||
}
|
||||
}
|
||||
|
||||
Value fncall(FnSig *fn, Statement **params){
|
||||
Value returnv = {.tag = {0, T_null}};
|
||||
Value returnv = {.tag = {0,0,T_null}};
|
||||
if(fn->is_builtin){
|
||||
switch(fn->n_param){
|
||||
case 0:
|
||||
|
@ -87,7 +85,7 @@ void init_exec(){
|
|||
}
|
||||
|
||||
Value execute(Statement *stat){
|
||||
Value returnv = {.tag = {0,T_null}};
|
||||
Value returnv = {.tag = {0,0,T_null}};
|
||||
switch(stat->type){
|
||||
case ST_Varuse:
|
||||
if(vars[stat->var_id].tag.type == T_fn){
|
||||
|
|
|
@ -51,7 +51,7 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
else {
|
||||
printf("fLisp interactive env - v0.1\nFcalva 2025\n");
|
||||
printf("Under the terms of the GPL v3.0 license\n");
|
||||
printf("Under the terms of the GPL v2.0 license\n");
|
||||
yyin = stdin;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ ASTStack *stack;
|
|||
|
||||
void yyerror(char *s);
|
||||
|
||||
Tag ntag = {0,T_null};
|
||||
Tag ntag = {0,0,T_null};
|
||||
|
||||
Tag atag = {0,T_any};
|
||||
Tag atag = {0,0,T_any};
|
||||
|
||||
int make_stack(){
|
||||
stack = malloc(sizeof(ASTStack)+sizeof(Statement)*2048);
|
||||
|
@ -45,6 +45,8 @@ int make_stack(){
|
|||
return 1;
|
||||
if(heap_hashmap(&stack->symbol_map, SYMBOL_MAP_S))
|
||||
return 1;
|
||||
stack->funcs = NULL;
|
||||
stack->fn_n = 0;
|
||||
stack->stack_size = 2048;
|
||||
symbol_map_add_bi(&stack->symbol_map);
|
||||
|
||||
|
@ -52,10 +54,26 @@ int make_stack(){
|
|||
}
|
||||
|
||||
void free_stack(){
|
||||
for(int i = 0; i < stack->curr_statement){
|
||||
Statement *stat = &stack->statements[i];
|
||||
if(stat->child_n)
|
||||
free(stat->children);
|
||||
}
|
||||
free(stack->funcs);
|
||||
free_hashmap(&stack->symbol_map);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
Statement *get_statement(){
|
||||
if(stack->curr_statement >= stack->stack_size){
|
||||
stack = realloc(stack, sizeof(ASTStack)+sizeof(Statement)*(stack->stack_size+2048));
|
||||
if(!stack)
|
||||
yyerror("Failed to extend stack");
|
||||
stack->stack_size += 2048;
|
||||
}
|
||||
return &stack->statements[stack->curr_statement++];
|
||||
}
|
||||
|
||||
char *bi_type_names[6] = {
|
||||
"",
|
||||
"int",
|
||||
|
@ -68,22 +86,22 @@ char *bi_type_names[6] = {
|
|||
Tag get_type(char *str){
|
||||
for(int i = 1; i < 6; i++){
|
||||
if(!strcmp(bi_type_names[i], str))
|
||||
return (Tag){0, i};
|
||||
return (Tag){0,1,i};
|
||||
}
|
||||
return (Tag){0, 0};
|
||||
return (Tag){0,0,0};
|
||||
}
|
||||
|
||||
Statement *make_iconst(i32 val){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Const;
|
||||
stat->cons = (Value){{.v4B = {val}},{.is_array = 0, .type = T_int}};
|
||||
stat->cons = (Value){{.v4B = {.value=val}},{.is_array = 0, .type = T_int}};
|
||||
stat->is_const = 1;
|
||||
stat->child_n = 0;
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *make_fconst(float val){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Const;
|
||||
stat->cons = (Value){{.v4B = {.vfl=val}},{.is_array=0,.type=T_float}};
|
||||
stat->is_const = 1;
|
||||
|
@ -92,8 +110,9 @@ Statement *make_fconst(float val){
|
|||
}
|
||||
|
||||
Statement *make_strconst(char *str){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Const;
|
||||
stat->is_const = 1;
|
||||
i32 len = strcspn(str, "\"");
|
||||
stat->cons = str_to_val(str, len);
|
||||
return stat;
|
||||
|
@ -105,7 +124,7 @@ Statement *declare(i32 type, Tag vtype, char *name, Statement *assign){
|
|||
printf("declare : %d\n", vtype.type);
|
||||
#endif
|
||||
name[len] = '\0';
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
stat->type = type;
|
||||
if(hashmap_get(&stack->symbol_map, name)){
|
||||
yyerror("Redeclaring existing identifier");
|
||||
|
@ -129,7 +148,7 @@ Statement *declare(i32 type, Tag vtype, char *name, Statement *assign){
|
|||
}
|
||||
|
||||
Statement *variable_get(char *name){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
MapItem *ret = hashmap_get(&stack->symbol_map, name);
|
||||
if(!ret)
|
||||
yyerror("Undefined identifier");
|
||||
|
@ -141,7 +160,7 @@ Statement *variable_get(char *name){
|
|||
}
|
||||
|
||||
Statement *make_block(Statement *first){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Block;
|
||||
stat->children = malloc(sizeof(void*));
|
||||
stat->children[0] = first;
|
||||
|
@ -160,11 +179,10 @@ Statement *add_block(Statement *block, Statement *add){
|
|||
FnSig assign_sig = {.n_param = 1};
|
||||
|
||||
Statement *make_operation(i32 type, Tag vtype, char *name, i32 nparam, ...){
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
Statement *stat = get_statement();
|
||||
if(nparam)
|
||||
stat->children = malloc(sizeof(void*)*nparam);
|
||||
stat->child_n = 0;
|
||||
FnSig *fnsig = NULL;
|
||||
|
||||
va_list prm;
|
||||
va_start(prm, nparam);
|
||||
|
@ -213,6 +231,53 @@ Statement *make_operation(i32 type, Tag vtype, char *name, i32 nparam, ...){
|
|||
return stat;
|
||||
}
|
||||
|
||||
void push_scope(){
|
||||
if(stack->curr_scope >= 256)
|
||||
yyerror("Scopes are too deep");
|
||||
stack->scope_stack[stack->curr_scope++] = stack->scope_id++;
|
||||
}
|
||||
|
||||
void pop_scope(){
|
||||
if(stack->curr_scope <= 0)
|
||||
yyerror("Weird scope error");
|
||||
stack->curr_scope--;
|
||||
}
|
||||
|
||||
char _mangle_tmp[36];
|
||||
|
||||
// 3 digit "Base64" scope id + { (invalid identifier char) + name
|
||||
char *mangle_name(i32 scope, char *name){
|
||||
// Scope 0 is global so we just return the name
|
||||
if(!scope)
|
||||
return name;
|
||||
for(int i = 0; i < 3; i++){
|
||||
_mangle_tmp[i] = (scope & 63) + ' ';
|
||||
scope >>= 6;
|
||||
}
|
||||
_mangle_tmp[3] = '{';
|
||||
strncpy(&_mangle_tmp[4], name, 32);
|
||||
return _mangle_tmp;
|
||||
}
|
||||
|
||||
FnArgs _fnargs;
|
||||
|
||||
FnArgs *make_fnargs(char *name, Tag type){
|
||||
_fnargs.n_args = 1;
|
||||
_fnargs.names[0] = name;
|
||||
_fnargs.types[0] = type;
|
||||
return &_fnargs;
|
||||
}
|
||||
|
||||
FnArgs *add_fnargs(char *name, Tag type){
|
||||
_fnargs.names[_fnargs.n_args] = name;
|
||||
_fnargs.types[_fnargs.n_args++] = type;
|
||||
return &_fnargs;
|
||||
}
|
||||
|
||||
Statement *make_function(FnArgs *fn_args, Statement *statements){
|
||||
Statement *stat = get_statement();
|
||||
}
|
||||
|
||||
// TODO
|
||||
void set_entry_point(Statement *statement){
|
||||
printf("set_entry_point\n");
|
||||
|
|
18
src/parser.h
18
src/parser.h
|
@ -23,6 +23,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
|
||||
// 0 is function name/output type
|
||||
char *names[9];
|
||||
Tag types[9];
|
||||
i32 n_args;
|
||||
|
||||
} FnArgs;
|
||||
|
||||
void yyerror(char *s);
|
||||
|
||||
int make_stack();
|
||||
|
@ -32,9 +41,7 @@ void free_stack();
|
|||
Tag get_type(char *str);
|
||||
|
||||
Statement *make_iconst(i32 val);
|
||||
|
||||
Statement *make_fconst(float val);
|
||||
//TODO
|
||||
Statement *make_strconst(char *str);
|
||||
|
||||
Statement *declare(i32 type, Tag vtype, char *name, Statement *assign);
|
||||
|
@ -42,9 +49,14 @@ Statement *declare(i32 type, Tag vtype, char *name, Statement *assign);
|
|||
Statement *variable_get(char *name);
|
||||
|
||||
Statement *make_block(Statement *first);
|
||||
|
||||
Statement *add_block(Statement *block, Statement *add);
|
||||
|
||||
Statement *make_operation(i32 type, Tag vtype, char *str, i32 nparam, ...);
|
||||
|
||||
void push_scope();
|
||||
void pop_scope();
|
||||
|
||||
FnArgs *make_fnargs(char *name, Tag type);
|
||||
FnArgs *add_fnargs(char *name, Tag type);
|
||||
|
||||
void set_entry_point(Statement *statement);
|
||||
|
|
|
@ -40,7 +40,10 @@
|
|||
"if" return IF;
|
||||
"else" return ELSE;
|
||||
"while" return WHILE;
|
||||
"fn" return FN;
|
||||
"fn" {
|
||||
push_scope();
|
||||
return FN;
|
||||
}
|
||||
"var" return VAR;
|
||||
"let" return LET;
|
||||
"block" return BLOCK;
|
||||
|
@ -56,7 +59,7 @@
|
|||
return G_IDENT;
|
||||
}
|
||||
|
||||
[0-9]+"."[0-9]+ {
|
||||
[0-9]*"."[0-9]+ {
|
||||
yylval.st = make_fconst(atof(yytext));
|
||||
return CST;
|
||||
}
|
||||
|
|
14
src/parser.y
14
src/parser.y
|
@ -37,6 +37,7 @@
|
|||
char *str;
|
||||
Statement *st;
|
||||
Tag tag;
|
||||
FnArgs *args;
|
||||
}
|
||||
|
||||
%nonassoc <str> G_IDENT
|
||||
|
@ -54,6 +55,7 @@
|
|||
|
||||
%type <st> expr expr_list
|
||||
%type <tag> type
|
||||
%type <args> fn_args
|
||||
|
||||
%%
|
||||
|
||||
|
@ -78,13 +80,13 @@ type:
|
|||
|
||||
fn_args:
|
||||
G_IDENT
|
||||
{}
|
||||
{$$ = make_fnargs($1, atag);}
|
||||
| G_IDENT type
|
||||
{}
|
||||
{$$ = make_fnargs($1, $2);}
|
||||
| fn_args G_IDENT
|
||||
{}
|
||||
{$$ = add_fnargs($2, atag);}
|
||||
| fn_args G_IDENT type
|
||||
{}
|
||||
{$$ = add_fnargs($2, $3);}
|
||||
;
|
||||
|
||||
expr:
|
||||
|
@ -117,7 +119,9 @@ expr:
|
|||
| '(' WHILE expr expr_list ')'
|
||||
{$$ = make_operation(BI_while, ntag, NULL, 2, $3, $4);}
|
||||
| '(' FN '(' fn_args ')' expr_list ')'
|
||||
{}
|
||||
{$$ = make_function($4, $6);
|
||||
pop_scope();
|
||||
}
|
||||
| '(' BLOCK expr_list ')'
|
||||
{$$ = $3;}
|
||||
| '(' G_IDENT expr_list ')'
|
||||
|
|
20
src/tests.c
20
src/tests.c
|
@ -150,9 +150,23 @@ int t_make_fconst(){
|
|||
return err;
|
||||
}
|
||||
|
||||
// TODO
|
||||
int t_make_strconst(){
|
||||
return 0;
|
||||
int err = 0;
|
||||
Statement *st = NULL;
|
||||
st = make_strconst("Hello world");
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.vstr.len != 11 || st->cons.tag.type != T_str;
|
||||
err += strncmp(get_addr(st->cons.vstr.pos), "Hello world", 11);
|
||||
st = make_strconst("Gatt");
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.vstr.len != 4 || st->cons.tag.type != T_str;
|
||||
err += strncmp(st->cons.vstr.str, "Gatt", 4);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_free_stack(){
|
||||
|
@ -191,7 +205,7 @@ char *names[] = {
|
|||
"make_stack",
|
||||
"make_iconst",
|
||||
"make_fconst",
|
||||
"make_strconst (TODO)",
|
||||
"make_strconst",
|
||||
|
||||
"free_stack"
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue