WIP functions def
This commit is contained in:
parent
490b869919
commit
e968cb6725
238
compiler.c
238
compiler.c
|
|
@ -79,6 +79,36 @@ is_type()
|
|||
parser.previous.type <= TOKEN_TYPE_PTR;
|
||||
}
|
||||
|
||||
SymbolType
|
||||
tokt_to_symt(TokenType t)
|
||||
{
|
||||
switch(t) {
|
||||
case TOKEN_TYPE_BOOL:
|
||||
return SYMBOL_BOOL;
|
||||
case TOKEN_TYPE_BYTE:
|
||||
return SYMBOL_BYTE;
|
||||
case TOKEN_TYPE_INT:
|
||||
return SYMBOL_INT;
|
||||
case TOKEN_TYPE_NAT:
|
||||
return SYMBOL_NAT;
|
||||
case TOKEN_TYPE_REAL:
|
||||
return SYMBOL_REAL;
|
||||
case TOKEN_TYPE_STR:
|
||||
return SYMBOL_STR;
|
||||
case TOKEN_TYPE_U8:
|
||||
return SYMBOL_U8;
|
||||
case TOKEN_TYPE_I8:
|
||||
return SYMBOL_I8;
|
||||
case TOKEN_TYPE_I16:
|
||||
return SYMBOL_I16;
|
||||
case TOKEN_TYPE_U16:
|
||||
return SYMBOL_U16;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SYMBOL_UNDEFINED;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Parser
|
||||
***************************************************/
|
||||
|
|
@ -120,6 +150,84 @@ match(TokenType type)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
expect(TokenType type)
|
||||
{
|
||||
if(!match(type)) {
|
||||
emitter.error(parser.previous.start, parser.previous.length,
|
||||
parser.previous.line);
|
||||
}
|
||||
}
|
||||
|
||||
u32 variable_declaration(Symbol *def);
|
||||
|
||||
void
|
||||
define_plex()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
define_trait()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
define_function()
|
||||
{
|
||||
Symbol *fn;
|
||||
u32 size = 0;
|
||||
advance();
|
||||
fn = scope_add_symbol(parser.previous.start, parser.previous.length,
|
||||
SYMBOL_FUNCTION, 0);
|
||||
|
||||
/* need to push scope early because the variables need to be a part of the fn
|
||||
* scope */
|
||||
scope_push();
|
||||
|
||||
expect(TOKEN_LPAREN);
|
||||
|
||||
/* parse the args */
|
||||
while(!match(TOKEN_RPAREN)) size += variable_declaration(fn);
|
||||
|
||||
if(!match(TOKEN_LBRACE)) {
|
||||
fn->secondary_type = tokt_to_symt(parser.previous.type);
|
||||
/* now parse the fn body */
|
||||
expect(TOKEN_LBRACE);
|
||||
}
|
||||
|
||||
/* get the size of all the locals for the function in the body */
|
||||
while(!match(TOKEN_RBRACE))
|
||||
if(is_type()) size += variable_declaration(fn);
|
||||
|
||||
fn->size = size;
|
||||
}
|
||||
|
||||
void
|
||||
build_symbol_table(char *source)
|
||||
{
|
||||
init_lexer(source);
|
||||
advance();
|
||||
scope_push();
|
||||
|
||||
while(!match(TOKEN_EOF)) {
|
||||
|
||||
if(match(TOKEN_LBRACE)) {
|
||||
scope_push();
|
||||
} else if(match(TOKEN_RBRACE)) {
|
||||
scope_pop();
|
||||
} else if(match(TOKEN_KEYWORD_FN)) {
|
||||
define_function();
|
||||
} else if(match(TOKEN_KEYWORD_PLEX)) {
|
||||
define_plex();
|
||||
} else if(match(TOKEN_KEYWORD_TRAIT)) {
|
||||
define_trait();
|
||||
} else {
|
||||
/* in binary bytecode output mode we need to count the bytes here */
|
||||
/* otherwise ignore everything */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expression();
|
||||
void statement();
|
||||
void declaration();
|
||||
|
|
@ -321,103 +429,38 @@ cast_type()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
variable_declaration()
|
||||
u32
|
||||
variable_declaration(Symbol *def)
|
||||
{
|
||||
|
||||
i32 size = 0;
|
||||
TokenType tt = parser.previous.type;
|
||||
Token var = parser.current;
|
||||
SymbolType st = tokt_to_symt(tt);
|
||||
Symbol *arg;
|
||||
|
||||
if (st != SYMBOL_UNDEFINED) {
|
||||
size = emitter.get_size(st);
|
||||
arg = scope_add_symbol(parser.current.start, parser.current.length,
|
||||
st, size);
|
||||
if(def) {
|
||||
List_push(arena, def->args, arg, sizeof(Symbol));
|
||||
} else {
|
||||
emitter.emit_type(st, parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
parser.current_type = st;
|
||||
}
|
||||
} else {
|
||||
/* we need to look up the type */
|
||||
|
||||
switch(tt) {
|
||||
case TOKEN_TYPE_INT: {
|
||||
size = emitter.emit_int_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_INT,
|
||||
size);
|
||||
parser.current_type = SYMBOL_INT;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_NAT: {
|
||||
size = emitter.emit_nat_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_NAT,
|
||||
size);
|
||||
parser.current_type = SYMBOL_NAT;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_REAL: {
|
||||
size = emitter.emit_real_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_REAL,
|
||||
size);
|
||||
parser.current_type = SYMBOL_REAL;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_STR: {
|
||||
size = emitter.emit_str_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_STR,
|
||||
size);
|
||||
parser.current_type = SYMBOL_STR;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_BOOL: {
|
||||
size = emitter.emit_bool_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_BOOL,
|
||||
size);
|
||||
parser.current_type = SYMBOL_BOOL;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_BYTE: {
|
||||
size = emitter.emit_byte_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8,
|
||||
size);
|
||||
parser.current_type = SYMBOL_BYTE;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_U8: {
|
||||
size = emitter.emit_u8_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8,
|
||||
size);
|
||||
parser.current_type = SYMBOL_U8;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_I8: {
|
||||
size = emitter.emit_i8_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I8,
|
||||
size);
|
||||
parser.current_type = SYMBOL_I8;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_U16: {
|
||||
size = emitter.emit_u16_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U16,
|
||||
size);
|
||||
parser.current_type = SYMBOL_U16;
|
||||
break;
|
||||
}
|
||||
case TOKEN_TYPE_I16: {
|
||||
size = emitter.emit_i16_type(parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I16,
|
||||
size);
|
||||
parser.current_type = SYMBOL_I16;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* probably a plex */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
advance();
|
||||
|
||||
if(def && (check(TOKEN_COMMA) || check(TOKEN_RPAREN))) return size;
|
||||
if(def)
|
||||
emitter.error(parser.previous.start, parser.previous.length,
|
||||
parser.previous.line);
|
||||
|
||||
if(match(TOKEN_EQ)) {
|
||||
emitter.emit_set_value();
|
||||
expression();
|
||||
|
|
@ -427,6 +470,7 @@ variable_declaration()
|
|||
consume(TOKEN_SEMICOLON);
|
||||
emitter.emit_end_statement();
|
||||
parser.current_type = SYMBOL_UNDEFINED;
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -438,7 +482,7 @@ declaration()
|
|||
* if not then
|
||||
*/
|
||||
if(is_type())
|
||||
variable_declaration();
|
||||
variable_declaration(nil);
|
||||
else
|
||||
statement();
|
||||
}
|
||||
|
|
@ -681,11 +725,9 @@ get_rule(TokenType type)
|
|||
return &rules[type];
|
||||
}
|
||||
|
||||
bool
|
||||
compile(Arena *a, Emitter e, char *source)
|
||||
void
|
||||
emit_program(char *source)
|
||||
{
|
||||
arena = a;
|
||||
emitter = e;
|
||||
init_lexer(source);
|
||||
advance();
|
||||
scope_push();
|
||||
|
|
@ -695,6 +737,16 @@ compile(Arena *a, Emitter e, char *source)
|
|||
while(!match(TOKEN_EOF)) declaration();
|
||||
|
||||
emitter.epilogue();
|
||||
}
|
||||
|
||||
bool
|
||||
compile(Arena *a, Emitter e, char *source)
|
||||
{
|
||||
arena = a;
|
||||
emitter = e;
|
||||
|
||||
build_symbol_table(source);
|
||||
emit_program(source);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,29 +8,54 @@ This is similar to Java's "build once run anywhere" but even more flexable, a Un
|
|||
|
||||
Memory Management
|
||||
|
||||
Memory is handled deterministically by the compiler following RAII style rules. Unless the devloper is doing some fine grained optimization they will need to think about memory as much as any GC language developer would.
|
||||
System Specification: Frame-Scoped Region Allocator with Handle References
|
||||
** Overview
|
||||
|
||||
Memory is partitioned into a C style "heap" and "stack". the difference is the behavior of the heap matches that of the stack which are laid out as a "region per call frame". A frame is made up of N many "locals" in the stack (bottom up) and a handle to the beginning of that frames allocated memory in the heap (top down).
|
||||
A single-threaded, deterministic memory model where each call frame owns a dedicated memory region. References are strictly scoped to the call tree, complex types use length-prefixed handles, and memory is reclaimed immediately on frame teardown. Designed for fixed-size actors communicating via serialized message passing.
|
||||
** Memory Layout
|
||||
|
||||
When a function gets called, it creates a new region in heap memory starting at the end of the previous frame. (or at the beginning of memory if no function has been called). And a new static region for "locals" on the stack.
|
||||
Logical Heap: Partitioned into one region per call frame, laid out top-down from the previous frame's end (or memory start for the first call).
|
||||
Stack: Holds frame locals (bottom-up).
|
||||
Frame Metadata: Stores a handle/pointer to its heap region base, plus frame state.
|
||||
Allocation: Bump-style allocation within the region. No free-lists or fragmentation tracking within a live frame.
|
||||
|
||||
Variables allocated in the frame's region are owned by default by the frame they are allocated in.
|
||||
** Ownership & Lifecycle
|
||||
|
||||
When variables get modified within the current frame they will get updated in that frame in their current location in memory.
|
||||
All allocations are owned by the frame that created them.
|
||||
Variables are modified in-place within their frame's region.
|
||||
On function return, the frame's region is immediately deallocated, deterministically freeing all owned memory.
|
||||
|
||||
All complex types (Plex, arrays, strings) use reference handles. Allocations prepend the length to the allocation, its to make sure that its impossible to have the kind of buffer overflow bugs common in C like languages. It also optimizes copy speed since you do not have to do a O(n) search for the size of the block.
|
||||
** References, Handles & Complex Types
|
||||
|
||||
If the size of the variable changes (like adding a value to the end of a array), a new block is allocated at the end of the region of the size of that value + the old value.
|
||||
Complex types (structs, arrays, strings) use reference handles instead of raw pointers.
|
||||
Every dynamic allocation prepends a length field to prevent buffer overflows and enable O(1) size queries.
|
||||
Handles are strictly scoped: they can be passed down to child frames but cannot outlive their frame. If a value must escape, it must be explicitly returned.
|
||||
No sharing or aliasing exists between frames. The structure is a strict tree (parent → child). Handles become invalid upon frame return.
|
||||
|
||||
When a variable is passed to a child function primitive types are pass by value, complex types (Arrays, Plexes, Strings) are pass by reference.
|
||||
** Resizing & Fragmentation Strategy
|
||||
|
||||
Variables passed as arguments to the child follow the same rules except when the size of a complex type changes, the new value is allocated at the end of the childs frame and the owner is now the child. This is the same as C++/Rust "move".
|
||||
When a complex type grows, a new block is allocated at the end of the region, and ownership transfers to the new allocation. The old block becomes dead space.
|
||||
Fragmentation is mitigated by design: the system encourages short-lived frames and compositional patterns (building up via smaller, focused functions) to ensure dead space is reclaimed quickly.
|
||||
Static-size complex types are pre-allocated upfront, so they never need to move on return.
|
||||
|
||||
When a function "returns" the frame is deallocated and all values allocated by it is freed; thus freeing memory deterministically.
|
||||
** Parameter Passing & Returns
|
||||
|
||||
When a variable is returned if it is primitive it is just passed back to the parent. If it is complex the value it is copied back to the parent.
|
||||
Primitives: Passed by value.
|
||||
Complex types: Passed by handle/reference.
|
||||
If a passed complex type is modified/grown in a child frame, the new allocation occurs in the child's region, and ownership moves to the child (move semantics).
|
||||
Returns: Primitives are copied back. Complex types are returned via handle. Since return space is pre-allocated in the caller, the callee writes directly into it, making "move" and "copy" functionally identical for returns.
|
||||
|
||||
This allows for the low resource usage of a C but the convenience of a garbage collected language like C# or Go but without the GC pauses.
|
||||
** Concurrency Model
|
||||
|
||||
Not thread-safe. Designed for a single-threaded actor model where fixed-size actors communicate via serialized message passing. Each actor maintains its own isolated call-tree region.
|
||||
|
||||
** Key Constraints & Guarantees
|
||||
|
||||
References cannot outlive their frame.
|
||||
No cross-frame sharing; strict parent→child data flow.
|
||||
Deterministic, O(1) deallocation on frame exit.
|
||||
Prepend length on all dynamic allocations for safety & performance.
|
||||
Region reuse encouraged via short-lived frames and compositional design.
|
||||
|
||||
Built in Types
|
||||
Type Description
|
||||
|
|
|
|||
18
emit.h
18
emit.h
|
|
@ -4,11 +4,12 @@
|
|||
#include "common.h"
|
||||
#include "libc.h"
|
||||
|
||||
typedef u32 (*SymbolSize)(SymbolType t);
|
||||
typedef void (*SymbolEmit)(Symbol *sym);
|
||||
typedef void (*ErrorMsg)(const char *str, i32 length, i32 line);
|
||||
typedef void (*VoidArgEmit)();
|
||||
typedef void (*StrArgEmit)(const char *str, i32 length);
|
||||
typedef i32 (*TypeVariableEmit)(const char *str, i32 length, bool local);
|
||||
typedef void (*TypeVariableEmit)(SymbolType t, const char *str, i32 length, bool local);
|
||||
typedef void (*ConstEmit)(const char *str, i32 length, bool local);
|
||||
typedef void (*VarEmit)(Symbol *sym, bool local);
|
||||
typedef void (*I32ArgEmit)(i32 val);
|
||||
|
|
@ -20,6 +21,7 @@ struct emitter_s {
|
|||
i32 loops;
|
||||
i32 loop_depth;
|
||||
ErrorMsg error;
|
||||
SymbolSize get_size;
|
||||
VoidArgEmit prolog;
|
||||
VoidArgEmit epilogue;
|
||||
VoidArgEmit emit_add;
|
||||
|
|
@ -41,19 +43,7 @@ struct emitter_s {
|
|||
StrArgEmit emit_real;
|
||||
StrArgEmit emit_byte;
|
||||
StrArgEmit emit_str;
|
||||
TypeVariableEmit emit_bool_type;
|
||||
TypeVariableEmit emit_byte_type;
|
||||
TypeVariableEmit emit_int_type;
|
||||
TypeVariableEmit emit_nat_type;
|
||||
TypeVariableEmit emit_real_type;
|
||||
TypeVariableEmit emit_str_type;
|
||||
TypeVariableEmit emit_u8_type;
|
||||
TypeVariableEmit emit_i8_type;
|
||||
TypeVariableEmit emit_i16_type;
|
||||
TypeVariableEmit emit_u16_type;
|
||||
TypeVariableEmit emit_i32_type;
|
||||
TypeVariableEmit emit_u32_type;
|
||||
TypeVariableEmit emit_f32_type;
|
||||
TypeVariableEmit emit_type;
|
||||
VoidArgEmit emit_array;
|
||||
VoidArgEmit emit_function;
|
||||
VoidArgEmit emit_plex;
|
||||
|
|
|
|||
274
emit/rer/emit.c
274
emit/rer/emit.c
|
|
@ -28,6 +28,7 @@ rer_epilogue()
|
|||
printf("BRK\n\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rer_emit_add()
|
||||
{
|
||||
|
|
@ -123,137 +124,127 @@ rer_emit_void()
|
|||
{
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_bool_type(const char *str, i32 length, bool local)
|
||||
u32
|
||||
rer_get_size(SymbolType t)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: return 1;
|
||||
case SYMBOL_BYTE: return 1;
|
||||
case SYMBOL_INT: return 2;
|
||||
case SYMBOL_NAT: return 2;
|
||||
case SYMBOL_REAL: return 2;
|
||||
case SYMBOL_STR: return 2;
|
||||
case SYMBOL_U8: return 1;
|
||||
case SYMBOL_I8: return 1;
|
||||
case SYMBOL_I16: return 2;
|
||||
case SYMBOL_U16: return 2;
|
||||
case SYMBOL_I32: return 4;
|
||||
case SYMBOL_U32: return 4;
|
||||
case SYMBOL_F32: return 4;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_byte_type(const char *str, i32 length, bool local)
|
||||
void
|
||||
rer_emit_primitive_type(SymbolType t, const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_BYTE: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_INT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_NAT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_REAL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_STR: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_F32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_int_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_nat_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_real_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_str_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_u8_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_i8_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_i16_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_u16_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_i32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_u32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
i32
|
||||
rer_emit_f32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_int(const char *str, i32 length)
|
||||
{
|
||||
|
|
@ -376,7 +367,6 @@ rer_emit_set_variable(Symbol *sym, bool local)
|
|||
printf(";%.*s STA2 ", sym->name_length, sym->name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rer_emit_write()
|
||||
{
|
||||
|
|
@ -564,42 +554,41 @@ rer_emit_print()
|
|||
void
|
||||
rer_emit_if()
|
||||
{
|
||||
printf("#03 JCN !{ ");
|
||||
printf("#03 JCN !{ \n");
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_patch_if(i32 local_ifs)
|
||||
{
|
||||
printf("!&if_end.%d } ", local_ifs);
|
||||
printf("!&if_end.%d } ", local_ifs);
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_patch_if_done(i32 local_ifs)
|
||||
{
|
||||
printf("&if_end.%d ", local_ifs);
|
||||
printf("&if_end.%d \n", local_ifs);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rer_emit_while(i32 local_whiles)
|
||||
{
|
||||
printf("&while.%d ", local_whiles);
|
||||
printf("&while.%d ", local_whiles);
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_while_postfix()
|
||||
{
|
||||
printf("#03 JCN !{ ");
|
||||
printf("#03 JCN !{ \n");
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_patch_while(i32 local_whiles)
|
||||
{
|
||||
printf("!&while.%d } ", local_whiles);
|
||||
printf("!&while.%d } \n", local_whiles);
|
||||
}
|
||||
|
||||
|
||||
Emitter rer_emitter()
|
||||
Emitter
|
||||
rer_emitter()
|
||||
{
|
||||
return (Emitter){
|
||||
0,
|
||||
|
|
@ -607,6 +596,7 @@ Emitter rer_emitter()
|
|||
0,
|
||||
0,
|
||||
rer_emit_error,
|
||||
rer_get_size,
|
||||
rer_prolog,
|
||||
rer_epilogue,
|
||||
rer_emit_add,
|
||||
|
|
@ -628,19 +618,7 @@ Emitter rer_emitter()
|
|||
rer_emit_real,
|
||||
rer_emit_byte,
|
||||
rer_emit_str,
|
||||
rer_emit_bool_type,
|
||||
rer_emit_byte_type,
|
||||
rer_emit_int_type,
|
||||
rer_emit_nat_type,
|
||||
rer_emit_real_type,
|
||||
rer_emit_str_type,
|
||||
rer_emit_u8_type,
|
||||
rer_emit_i8_type,
|
||||
rer_emit_i16_type,
|
||||
rer_emit_u16_type,
|
||||
rer_emit_i32_type,
|
||||
rer_emit_u32_type,
|
||||
rer_emit_f32_type,
|
||||
rer_emit_primitive_type,
|
||||
rer_emit_array,
|
||||
rer_emit_function,
|
||||
rer_emit_plex,
|
||||
|
|
|
|||
275
emit/uxn/emit.c
275
emit/uxn/emit.c
|
|
@ -145,7 +145,6 @@ unsigned char __lib_undar[] = {
|
|||
};
|
||||
unsigned int __lib_undar_len = 1433;
|
||||
|
||||
|
||||
void
|
||||
uxn_emit_error(const char *str, i32 length, i32 line)
|
||||
{
|
||||
|
|
@ -169,9 +168,7 @@ void
|
|||
uxn_epilogue()
|
||||
{
|
||||
printf("BRK\n\n");
|
||||
for (u32 i = 0; i < __lib_undar_len; i++) {
|
||||
putchar(__lib_undar[i]);
|
||||
}
|
||||
for(u32 i = 0; i < __lib_undar_len; i++) putchar(__lib_undar[i]);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -269,137 +266,127 @@ uxn_emit_void()
|
|||
{
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_bool_type(const char *str, i32 length, bool local)
|
||||
u32
|
||||
uxn_get_size(SymbolType t)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: return 1;
|
||||
case SYMBOL_BYTE: return 1;
|
||||
case SYMBOL_INT: return 2;
|
||||
case SYMBOL_NAT: return 2;
|
||||
case SYMBOL_REAL: return 2;
|
||||
case SYMBOL_STR: return 2;
|
||||
case SYMBOL_U8: return 1;
|
||||
case SYMBOL_I8: return 1;
|
||||
case SYMBOL_I16: return 2;
|
||||
case SYMBOL_U16: return 2;
|
||||
case SYMBOL_I32: return 4;
|
||||
case SYMBOL_U32: return 4;
|
||||
case SYMBOL_F32: return 4;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_byte_type(const char *str, i32 length, bool local)
|
||||
void
|
||||
uxn_emit_primitive_type(SymbolType t, const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_BYTE: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_INT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_NAT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_REAL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_STR: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_F32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_int_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_nat_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_real_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_str_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_u8_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_i8_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_i16_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_u16_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
return 2;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_i32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_u32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
i32
|
||||
uxn_emit_f32_type(const char *str, i32 length, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
return 4;
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_int(const char *str, i32 length)
|
||||
{
|
||||
|
|
@ -715,36 +702,35 @@ uxn_emit_if()
|
|||
void
|
||||
uxn_emit_patch_if(i32 local_ifs)
|
||||
{
|
||||
printf("!&if_end.%d } ", local_ifs);
|
||||
printf("!&if_end.%d } ", local_ifs);
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_patch_if_done(i32 local_ifs)
|
||||
{
|
||||
printf("&if_end.%d \n", local_ifs);
|
||||
printf("&if_end.%d \n", local_ifs);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uxn_emit_while(i32 local_whiles)
|
||||
{
|
||||
printf("&while.%d ", local_whiles);
|
||||
printf("&while.%d ", local_whiles);
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_while_postfix()
|
||||
{
|
||||
printf("#03 JCN !{ \n");
|
||||
printf("#03 JCN !{ \n");
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_patch_while(i32 local_whiles)
|
||||
{
|
||||
printf("!&while.%d } \n", local_whiles);
|
||||
printf("!&while.%d } \n", local_whiles);
|
||||
}
|
||||
|
||||
|
||||
Emitter uxn_emitter()
|
||||
Emitter
|
||||
uxn_emitter()
|
||||
{
|
||||
return (Emitter){
|
||||
0,
|
||||
|
|
@ -752,6 +738,7 @@ Emitter uxn_emitter()
|
|||
0,
|
||||
0,
|
||||
uxn_emit_error,
|
||||
uxn_get_size,
|
||||
uxn_prolog,
|
||||
uxn_epilogue,
|
||||
uxn_emit_add,
|
||||
|
|
@ -773,19 +760,7 @@ Emitter uxn_emitter()
|
|||
uxn_emit_real,
|
||||
uxn_emit_byte,
|
||||
uxn_emit_str,
|
||||
uxn_emit_bool_type,
|
||||
uxn_emit_byte_type,
|
||||
uxn_emit_int_type,
|
||||
uxn_emit_nat_type,
|
||||
uxn_emit_real_type,
|
||||
uxn_emit_str_type,
|
||||
uxn_emit_u8_type,
|
||||
uxn_emit_i8_type,
|
||||
uxn_emit_i16_type,
|
||||
uxn_emit_u16_type,
|
||||
uxn_emit_i32_type,
|
||||
uxn_emit_u32_type,
|
||||
uxn_emit_f32_type,
|
||||
uxn_emit_primitive_type,
|
||||
uxn_emit_array,
|
||||
uxn_emit_function,
|
||||
uxn_emit_plex,
|
||||
|
|
|
|||
21
lexer.c
21
lexer.c
|
|
@ -134,9 +134,7 @@ check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
|||
{
|
||||
i32 s1 = lexer.current - lexer.start;
|
||||
i32 s2 = start + length;
|
||||
if(s1 == s2 && sleq(lexer.start + start, rest, length)) {
|
||||
return type;
|
||||
}
|
||||
if(s1 == s2 && sleq(lexer.start + start, rest, length)) return type;
|
||||
|
||||
return TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
|
@ -284,7 +282,14 @@ identifierType()
|
|||
case 'h':
|
||||
return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS);
|
||||
case 'r':
|
||||
return check_keyword(2, 2, "ue", TOKEN_KEYWORD_TRUE);
|
||||
if(lexer.current - lexer.start > 2) {
|
||||
switch(lexer.start[2]) {
|
||||
case 'u':
|
||||
return check_keyword(3, 1, "e", TOKEN_KEYWORD_TRUE);
|
||||
case 'a':
|
||||
return check_keyword(3, 2, "it", TOKEN_KEYWORD_TRAIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -432,9 +437,13 @@ next_token()
|
|||
case '=':
|
||||
return make_token(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
|
||||
case '<':
|
||||
return make_token(match('=') ? TOKEN_LTE : match('<') ? TOKEN_SLL : TOKEN_LT);
|
||||
return make_token(match('=') ? TOKEN_LTE
|
||||
: match('<') ? TOKEN_SLL
|
||||
: TOKEN_LT);
|
||||
case '>':
|
||||
return make_token(match('=') ? TOKEN_GTE : match('>') ? TOKEN_SRL : TOKEN_GT);
|
||||
return make_token(match('=') ? TOKEN_GTE
|
||||
: match('>') ? TOKEN_SRL
|
||||
: TOKEN_GT);
|
||||
case '"':
|
||||
return string();
|
||||
}
|
||||
|
|
|
|||
3
lexer.h
3
lexer.h
|
|
@ -86,7 +86,8 @@ typedef enum {
|
|||
TOKEN_ARROW_RIGHT,
|
||||
TOKEN_SLL,
|
||||
TOKEN_SRL,
|
||||
TOKEN_KEYWORD_PRINT
|
||||
TOKEN_KEYWORD_PRINT,
|
||||
TOKEN_KEYWORD_TRAIT
|
||||
} TokenType;
|
||||
|
||||
typedef struct token_s Token;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
nat[3,3,3] matrix = [1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1];
|
||||
|
||||
nat xSize = 3;
|
||||
nat ySize = 3;
|
||||
nat zSize = 3;
|
||||
|
||||
bool found = false;
|
||||
for (nat x = 0; x < xSize; x++) {
|
||||
for (nat y = 0; y < ySize; y++) {
|
||||
for (nat z = 0; z < zSize; z++) {
|
||||
if (matrix[x][y][z] == 0) {
|
||||
print("found: [");
|
||||
print(x as str);
|
||||
print(",");
|
||||
print(y as str);
|
||||
print(",");
|
||||
print(z as str);
|
||||
print("]\n");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue