wip symbol table, remove malloc_imm, fix docs
This commit is contained in:
parent
4f73339efb
commit
9d2053aef0
30
README.org
30
README.org
|
|
@ -55,33 +55,37 @@ You can view some examples in the =.ul.ir= files in =/test=
|
||||||
**Sample Program: =hello.ul.ir=**
|
**Sample Program: =hello.ul.ir=**
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
function main ()
|
global str terminal_namespace = "/dev/term/0"
|
||||||
str hello is $0
|
global str new_line = "\n"
|
||||||
|
global str message = "nuqneH 'u'?"
|
||||||
|
|
||||||
malloc_immediate "nuqneH 'u'?" -> hello
|
function main ()
|
||||||
call pln hello
|
str hello $0
|
||||||
|
|
||||||
|
load_immediate message -> hello
|
||||||
|
call pln hello -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message is $0)
|
function pln (str message $0)
|
||||||
str ts is $1
|
str ts $1
|
||||||
int msg_length is $2
|
int mode $5
|
||||||
str nl is $3
|
int msg_length $2
|
||||||
int nl_length is $4
|
str nl $3
|
||||||
int mode is $5
|
int nl_length $4
|
||||||
|
|
||||||
malloc_immediate "/dev/term/0" -> ts # get terminal device
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN ts mode -> ts
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE ts message msg_length
|
syscall WRITE ts message msg_length
|
||||||
malloc_immediate "\n" -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE ts nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
./build/linux/undar-linux-debug ./test/hello.asm.lisp
|
./build/linux/undar-linux-debug ./test/hello.ul.ir
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Running the compiler without arguments will put it in "REPL" mode. It will function similar to a LISP repl.
|
Running the compiler without arguments will put it in "REPL" mode. It will function similar to a LISP repl.
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ void emit_u32(VM *vm, u32 value) {
|
||||||
vm->cp += 4;
|
vm->cp += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
|
|
||||||
|
|
||||||
SymbolTable *symbol_table_init() {
|
SymbolTable *symbol_table_init() {
|
||||||
SymbolTable *table = malloc(sizeof(SymbolTable));
|
SymbolTable *table = malloc(sizeof(SymbolTable));
|
||||||
table->symbols = malloc(16 * sizeof(Symbol));
|
table->symbols = malloc(16 * sizeof(Symbol));
|
||||||
|
|
@ -56,8 +54,8 @@ u32 get_ref(VM *vm, SymbolTable *st, const char *name, ScopeType scope) {
|
||||||
return sym->ref;
|
return sym->ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token nextTokenIs(TokenType type) {
|
Token next_token_is(TokenType type) {
|
||||||
Token token = nextToken();
|
Token token = next_token();
|
||||||
if (token.type != type) {
|
if (token.type != type) {
|
||||||
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -71,7 +69,7 @@ Token nextTokenIs(TokenType type) {
|
||||||
bool define_global(VM *vm, SymbolTable *st) {
|
bool define_global(VM *vm, SymbolTable *st) {
|
||||||
Symbol s;
|
Symbol s;
|
||||||
|
|
||||||
Token token_type = nextToken();
|
Token token_type = next_token();
|
||||||
switch (token_type.type) {
|
switch (token_type.type) {
|
||||||
case TOKEN_TYPE_BOOL:
|
case TOKEN_TYPE_BOOL:
|
||||||
s.type = BOOL;
|
s.type = BOOL;
|
||||||
|
|
@ -114,8 +112,8 @@ bool define_global(VM *vm, SymbolTable *st) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token eq = nextTokenIs(TOKEN_EQ);
|
Token eq = next_token_is(TOKEN_EQ);
|
||||||
Token name = nextTokenIs(TOKEN_IDENTIFIER);
|
Token name = next_token_is(TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -127,21 +125,21 @@ bool define_global(VM *vm, SymbolTable *st) {
|
||||||
s.ref = addr;
|
s.ref = addr;
|
||||||
s.scope = GLOBAL;
|
s.scope = GLOBAL;
|
||||||
|
|
||||||
Token value = nextToken();
|
Token value = next_token();
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case TOKEN_KEYWORD_TRUE: {
|
case TOKEN_KEYWORD_TRUE: {
|
||||||
u32 addr = vm->mp;
|
u32 addr = vm->mp;
|
||||||
write_u8(vm, memory, addr, 1);
|
write_u8(vm, memory, addr, 1);
|
||||||
|
|
||||||
vm->mp += 1;
|
vm->mp += s.size;
|
||||||
vm->frames[vm->fp].end += 1;
|
vm->frames[vm->fp].end += s.size;
|
||||||
}
|
}
|
||||||
case TOKEN_KEYWORD_FALSE: {
|
case TOKEN_KEYWORD_FALSE: {
|
||||||
u32 addr = vm->mp;
|
u32 addr = vm->mp;
|
||||||
write_u8(vm, memory, addr, 0);
|
write_u8(vm, memory, addr, 0);
|
||||||
|
|
||||||
vm->mp += 1;
|
vm->mp += s.size;
|
||||||
vm->frames[vm->fp].end += 1;
|
vm->frames[vm->fp].end += s.size;
|
||||||
}
|
}
|
||||||
case TOKEN_LITERAL_INT: {
|
case TOKEN_LITERAL_INT: {
|
||||||
i32 out = atoi(value.start);
|
i32 out = atoi(value.start);
|
||||||
|
|
@ -266,7 +264,7 @@ void define_var(VM *vm, SymbolTable *st, Token regType) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKEN_TYPE_REAL: {
|
case TOKEN_TYPE_REAL: {
|
||||||
s.type = REAL;
|
s.type = F32;
|
||||||
s.size = 4;
|
s.size = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +284,7 @@ void define_var(VM *vm, SymbolTable *st, Token regType) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token name = nextTokenIs(TOKEN_IDENTIFIER);
|
Token name = next_token_is(TOKEN_IDENTIFIER);
|
||||||
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
||||||
printf("VARIABLE NAME TOO LONG at line %d: %.*s\n", regType.line,
|
printf("VARIABLE NAME TOO LONG at line %d: %.*s\n", regType.line,
|
||||||
regType.length, regType.start);
|
regType.length, regType.start);
|
||||||
|
|
@ -295,9 +293,9 @@ void define_var(VM *vm, SymbolTable *st, Token regType) {
|
||||||
|
|
||||||
memcpy(s.name, name.start, name.length);
|
memcpy(s.name, name.start, name.length);
|
||||||
|
|
||||||
nextTokenIs(TOKEN_BIG_MONEY);
|
next_token_is(TOKEN_BIG_MONEY);
|
||||||
|
|
||||||
Token reg_num = nextTokenIs(TOKEN_LITERAL_INT);
|
Token reg_num = next_token_is(TOKEN_LITERAL_INT);
|
||||||
s.ref = atoi(reg_num.start);
|
s.ref = atoi(reg_num.start);
|
||||||
symbol_table_add(st, s);
|
symbol_table_add(st, s);
|
||||||
}
|
}
|
||||||
|
|
@ -305,33 +303,33 @@ void define_var(VM *vm, SymbolTable *st, Token regType) {
|
||||||
/**
|
/**
|
||||||
* function .
|
* function .
|
||||||
*/
|
*/
|
||||||
void define_function(vm *vm, SymbolTable *st) {
|
void define_function(VM *vm, SymbolTable *st) {
|
||||||
Symbol s;
|
Symbol s;
|
||||||
s.scope = LOCAL;
|
s.scope = LOCAL;
|
||||||
s.type = FUNCTION;
|
s.type = FUNCTION;
|
||||||
|
|
||||||
Token name = nextTokenIs(TOKEN_IDENTIFIER);
|
Token name = next_token_is(TOKEN_IDENTIFIER);
|
||||||
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
||||||
printf("FUNCITON NAME TOO LONG at line %d: %.*s\n", regType.line,
|
printf("FUNCITON NAME TOO LONG at line %d: %.*s\n", name.line,
|
||||||
regType.length, regType.start);
|
name.length, name.start);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memcpy(s.name, name.start, name.length);
|
memcpy(s.name, name.start, name.length);
|
||||||
|
|
||||||
nextTokenIs(TOKEN_LPAREN);
|
next_token_is(TOKEN_LPAREN);
|
||||||
|
|
||||||
Token next = nextToken();
|
Token next = next_token();
|
||||||
while (next.type != TOKEN_RPAREN) {
|
while (next.type != TOKEN_RPAREN) {
|
||||||
Token regType = nextToken();
|
Token regType = next_token();
|
||||||
define_var(vm, st, regType);
|
define_var(vm, st, regType);
|
||||||
|
|
||||||
Token comma = nextToken();
|
Token next = next_token();
|
||||||
if (comma.type == TOKEN_COMMA) {
|
if (next.type == TOKEN_COMMA) {
|
||||||
continue;
|
continue;
|
||||||
} else if (comma.type == TOKEN_RPAREN) {
|
} else if (next.type == TOKEN_RPAREN) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
printf("ERROR at line %d: %.*s\n", comma.line, comma.length, comma.start);
|
printf("ERROR at line %d: %.*s\n", next.line, next.length, next.start);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -347,10 +345,10 @@ void define_branch(VM *vm, SymbolTable *st) {
|
||||||
s.scope = LOCAL;
|
s.scope = LOCAL;
|
||||||
s.type = VOID;
|
s.type = VOID;
|
||||||
|
|
||||||
token name = nextTokenIs(TOKEN_IDENTIFIER);
|
Token name = next_token_is(TOKEN_IDENTIFIER);
|
||||||
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
if (name.length > MAX_SYMBOL_NAME_LENGTH) {
|
||||||
printf("BRANCH NAME TOO LONG at line %d: %.*s\n", regType.line,
|
printf("BRANCH NAME TOO LONG at line %d: %.*s\n", name.line,
|
||||||
regType.length, regType.start);
|
name.length, name.start);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memcpy(s.name, name.start, name.length);
|
memcpy(s.name, name.start, name.length);
|
||||||
|
|
@ -364,136 +362,150 @@ void define_branch(VM *vm, SymbolTable *st) {
|
||||||
*/
|
*/
|
||||||
void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
||||||
Token token;
|
Token token;
|
||||||
initLexer(source);
|
init_lexer(source);
|
||||||
do {
|
do {
|
||||||
token = nextToken();
|
token = next_token();
|
||||||
if (token.type == TOKEN_ERROR) {
|
if (token.type == TOKEN_ERROR) {
|
||||||
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (token.type != TOKEN_EOF) {
|
|
||||||
printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type),
|
|
||||||
token.length, token.start);
|
|
||||||
|
|
||||||
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
||||||
define_global(vm, st);
|
define_global(vm, st);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == TOKEN_KEYWORD_FN) {
|
if (token.type == TOKEN_KEYWORD_FN) {
|
||||||
define_function(vm, st);
|
define_function(vm, st);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == TOKEN_KEYWORD_PLEX || token.type == TOKEN_TYPE_I8 ||
|
if (token.type == TOKEN_KEYWORD_PLEX || token.type == TOKEN_TYPE_I8 ||
|
||||||
token.type == TOKEN_TYPE_I16 || token.type == TOKEN_TYPE_INT ||
|
token.type == TOKEN_TYPE_I16 || token.type == TOKEN_TYPE_INT ||
|
||||||
token.type == TOKEN_TYPE_U8 || token.type == TOKEN_TYPE_U16 ||
|
token.type == TOKEN_TYPE_U8 || token.type == TOKEN_TYPE_U16 ||
|
||||||
token.type == TOKEN_TYPE_NAT || token.type == TOKEN_TYPE_REAL ||
|
token.type == TOKEN_TYPE_NAT || token.type == TOKEN_TYPE_REAL ||
|
||||||
token.type == TOKEN_TYPE_STR || token.type == TOKEN_TYPE_BOOL) {
|
token.type == TOKEN_TYPE_STR || token.type == TOKEN_TYPE_BOOL) {
|
||||||
define_var(vm, st, token);
|
define_var(vm, st, token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == TOKEN_KEYWORD_LOOP || token.type == TOKEN_KEYWORD_IF ||
|
if (token.type == TOKEN_KEYWORD_LOOP || token.type == TOKEN_KEYWORD_IF ||
|
||||||
token.type == TOKEN_KEYWORD_ELSE || token.type == TOKEN_KEYWORD_DO ||
|
token.type == TOKEN_KEYWORD_ELSE || token.type == TOKEN_KEYWORD_DO ||
|
||||||
token.type == TOKEN_KEYWORD_FOR) {
|
token.type == TOKEN_KEYWORD_FOR) {
|
||||||
define_branch(vm, st);
|
define_branch(vm, st);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type == TOKEN_IDENTIFIER) {
|
if (token.type == TOKEN_IDENTIFIER) {
|
||||||
// check to see if it is an opcode first
|
// check to see if it is an opcode first
|
||||||
if (streq(token.start, "exit")) {
|
if (streq(token.start, "exit")) {
|
||||||
} else if (streq(token.start, "call")) {
|
vm->pc++;
|
||||||
} else if (streq(token.start, "syscall")) {
|
|
||||||
} else if (streq(token.start, "load_immediate")) {
|
next_token_is(TOKEN_LITERAL_NAT);
|
||||||
} else if (streq(token.start, "load_indirect_8")) {
|
vm->pc+=4;
|
||||||
} else if (streq(token.start, "load_indirect_16")) {
|
} else if (streq(token.start, "call")) {
|
||||||
} else if (streq(token.start, "load_indirect_32")) {
|
vm->pc++;
|
||||||
} else if (streq(token.start, "load_absolute_8")) {
|
|
||||||
} else if (streq(token.start, "load_absolute_16")) {
|
next_token_is(TOKEN_IDENTIFIER);
|
||||||
} else if (streq(token.start, "load_absolute_32")) {
|
vm->pc+=4;
|
||||||
} else if (streq(token.start, "load_offset_8")) {
|
|
||||||
} else if (streq(token.start, "load_offset_16")) {
|
vm->pc++; /* number of args (implied) */
|
||||||
} else if (streq(token.start, "load_offset_32")) {
|
|
||||||
} else if (streq(token.start, "store_absolute_8")) {
|
Token next = next_token();
|
||||||
} else if (streq(token.start, "store_absolute_16")) {
|
while (next.type != TOKEN_ARROW_LEFT) {
|
||||||
} else if (streq(token.start, "store_absolute_32")) {
|
vm->pc++;
|
||||||
} else if (streq(token.start, "store_indirect_8")) {
|
Token next = next_token();
|
||||||
} else if (streq(token.start, "store_indirect_16")) {
|
|
||||||
} else if (streq(token.start, "store_indirect_32")) {
|
|
||||||
} else if (streq(token.start, "store_offset_8")) {
|
|
||||||
} else if (streq(token.start, "store_offset_16")) {
|
|
||||||
} else if (streq(token.start, "store_offset_32")) {
|
|
||||||
} else if (streq(token.start, "malloc")) {
|
|
||||||
} else if (streq(token.start, "malloc_immediate")) {
|
|
||||||
} else if (streq(token.start, "memset_8")) {
|
|
||||||
} else if (streq(token.start, "memset_16")) {
|
|
||||||
} else if (streq(token.start, "memset_32")) {
|
|
||||||
} else if (streq(token.start, "register_move")) {
|
|
||||||
} else if (streq(token.start, "add_int")) {
|
|
||||||
} else if (streq(token.start, "sub_int")) {
|
|
||||||
} else if (streq(token.start, "mul_int")) {
|
|
||||||
} else if (streq(token.start, "div_int")) {
|
|
||||||
} else if (streq(token.start, "abs_int")) {
|
|
||||||
} else if (streq(token.start, "neg_int")) {
|
|
||||||
} else if (streq(token.start, "add_nat")) {
|
|
||||||
} else if (streq(token.start, "sub_nat")) {
|
|
||||||
} else if (streq(token.start, "mul_nat")) {
|
|
||||||
} else if (streq(token.start, "div_nat")) {
|
|
||||||
} else if (streq(token.start, "abs_nat")) {
|
|
||||||
} else if (streq(token.start, "neg_nat")) {
|
|
||||||
} else if (streq(token.start, "add_real")) {
|
|
||||||
} else if (streq(token.start, "sub_real")) {
|
|
||||||
} else if (streq(token.start, "mul_real")) {
|
|
||||||
} else if (streq(token.start, "div_real")) {
|
|
||||||
} else if (streq(token.start, "abs_real")) {
|
|
||||||
} else if (streq(token.start, "neg_real")) {
|
|
||||||
} else if (streq(token.start, "int_to_real")) {
|
|
||||||
} else if (streq(token.start, "nat_to_real")) {
|
|
||||||
} else if (streq(token.start, "real_to_int")) {
|
|
||||||
} else if (streq(token.start, "real_to_nat")) {
|
|
||||||
} else if (streq(token.start, "bit_shift_left")) {
|
|
||||||
} else if (streq(token.start, "bit_shift_right")) {
|
|
||||||
} else if (streq(token.start, "bit_shift_r_ext")) {
|
|
||||||
} else if (streq(token.start, "bit_and")) {
|
|
||||||
} else if (streq(token.start, "bit_or")) {
|
|
||||||
} else if (streq(token.start, "bit_xor")) {
|
|
||||||
} else if (streq(token.start, "jump")) {
|
|
||||||
} else if (streq(token.start, "jump_if_flag")) {
|
|
||||||
} else if (streq(token.start, "jump_eq_int")) {
|
|
||||||
} else if (streq(token.start, "jump_neq_int")) {
|
|
||||||
} else if (streq(token.start, "jump_gt_int")) {
|
|
||||||
} else if (streq(token.start, "jump_lt_int")) {
|
|
||||||
} else if (streq(token.start, "jump_le_int")) {
|
|
||||||
} else if (streq(token.start, "jump_ge_int")) {
|
|
||||||
} else if (streq(token.start, "jump_eq_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_neq_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_gt_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_lt_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_le_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_ge_nat")) {
|
|
||||||
} else if (streq(token.start, "jump_eq_real")) {
|
|
||||||
} else if (streq(token.start, "jump_neq_real")) {
|
|
||||||
} else if (streq(token.start, "jump_ge_real")) {
|
|
||||||
} else if (streq(token.start, "jump_gt_real")) {
|
|
||||||
} else if (streq(token.start, "jump_lt_real")) {
|
|
||||||
} else if (streq(token.start, "jump_le_real")) {
|
|
||||||
} else if (streq(token.start, "string_length")) {
|
|
||||||
} else if (streq(token.start, "string_eq")) {
|
|
||||||
} else if (streq(token.start, "string_concat")) {
|
|
||||||
} else if (streq(token.start, "string_get_char")) {
|
|
||||||
} else if (streq(token.start, "string_find_char")) {
|
|
||||||
} else if (streq(token.start, "string_slice")) {
|
|
||||||
} else if (streq(token.start, "int_to_string")) {
|
|
||||||
} else if (streq(token.start, "nat_to_string")) {
|
|
||||||
} else if (streq(token.start, "real_to_string")) {
|
|
||||||
} else if (streq(token.start, "string_to_int")) {
|
|
||||||
} else if (streq(token.start, "string_to_nat")) {
|
|
||||||
} else if (streq(token.start, "string_to_real")) {
|
|
||||||
} else {
|
|
||||||
// some other identifier
|
|
||||||
}
|
}
|
||||||
|
/* return type */
|
||||||
|
next = next_token();
|
||||||
|
vm->pc++;
|
||||||
|
} else if (streq(token.start, "syscall")) {
|
||||||
|
} else if (streq(token.start, "load_immediate")) {
|
||||||
|
} else if (streq(token.start, "load_indirect_8")) {
|
||||||
|
} else if (streq(token.start, "load_indirect_16")) {
|
||||||
|
} else if (streq(token.start, "load_indirect_32")) {
|
||||||
|
} else if (streq(token.start, "load_absolute_8")) {
|
||||||
|
} else if (streq(token.start, "load_absolute_16")) {
|
||||||
|
} else if (streq(token.start, "load_absolute_32")) {
|
||||||
|
} else if (streq(token.start, "load_offset_8")) {
|
||||||
|
} else if (streq(token.start, "load_offset_16")) {
|
||||||
|
} else if (streq(token.start, "load_offset_32")) {
|
||||||
|
} else if (streq(token.start, "store_absolute_8")) {
|
||||||
|
} else if (streq(token.start, "store_absolute_16")) {
|
||||||
|
} else if (streq(token.start, "store_absolute_32")) {
|
||||||
|
} else if (streq(token.start, "store_indirect_8")) {
|
||||||
|
} else if (streq(token.start, "store_indirect_16")) {
|
||||||
|
} else if (streq(token.start, "store_indirect_32")) {
|
||||||
|
} else if (streq(token.start, "store_offset_8")) {
|
||||||
|
} else if (streq(token.start, "store_offset_16")) {
|
||||||
|
} else if (streq(token.start, "store_offset_32")) {
|
||||||
|
} else if (streq(token.start, "malloc")) {
|
||||||
|
} else if (streq(token.start, "memset_8")) {
|
||||||
|
} else if (streq(token.start, "memset_16")) {
|
||||||
|
} else if (streq(token.start, "memset_32")) {
|
||||||
|
} else if (streq(token.start, "register_move")) {
|
||||||
|
} else if (streq(token.start, "add_int")) {
|
||||||
|
} else if (streq(token.start, "sub_int")) {
|
||||||
|
} else if (streq(token.start, "mul_int")) {
|
||||||
|
} else if (streq(token.start, "div_int")) {
|
||||||
|
} else if (streq(token.start, "abs_int")) {
|
||||||
|
} else if (streq(token.start, "neg_int")) {
|
||||||
|
} else if (streq(token.start, "add_nat")) {
|
||||||
|
} else if (streq(token.start, "sub_nat")) {
|
||||||
|
} else if (streq(token.start, "mul_nat")) {
|
||||||
|
} else if (streq(token.start, "div_nat")) {
|
||||||
|
} else if (streq(token.start, "abs_nat")) {
|
||||||
|
} else if (streq(token.start, "neg_nat")) {
|
||||||
|
} else if (streq(token.start, "add_real")) {
|
||||||
|
} else if (streq(token.start, "sub_real")) {
|
||||||
|
} else if (streq(token.start, "mul_real")) {
|
||||||
|
} else if (streq(token.start, "div_real")) {
|
||||||
|
} else if (streq(token.start, "abs_real")) {
|
||||||
|
} else if (streq(token.start, "neg_real")) {
|
||||||
|
} else if (streq(token.start, "int_to_real")) {
|
||||||
|
} else if (streq(token.start, "nat_to_real")) {
|
||||||
|
} else if (streq(token.start, "real_to_int")) {
|
||||||
|
} else if (streq(token.start, "real_to_nat")) {
|
||||||
|
} else if (streq(token.start, "bit_shift_left")) {
|
||||||
|
} else if (streq(token.start, "bit_shift_right")) {
|
||||||
|
} else if (streq(token.start, "bit_shift_r_ext")) {
|
||||||
|
} else if (streq(token.start, "bit_and")) {
|
||||||
|
} else if (streq(token.start, "bit_or")) {
|
||||||
|
} else if (streq(token.start, "bit_xor")) {
|
||||||
|
} else if (streq(token.start, "jump")) {
|
||||||
|
} else if (streq(token.start, "jump_if_flag")) {
|
||||||
|
} else if (streq(token.start, "jump_eq_int")) {
|
||||||
|
} else if (streq(token.start, "jump_neq_int")) {
|
||||||
|
} else if (streq(token.start, "jump_gt_int")) {
|
||||||
|
} else if (streq(token.start, "jump_lt_int")) {
|
||||||
|
} else if (streq(token.start, "jump_le_int")) {
|
||||||
|
} else if (streq(token.start, "jump_ge_int")) {
|
||||||
|
} else if (streq(token.start, "jump_eq_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_neq_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_gt_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_lt_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_le_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_ge_nat")) {
|
||||||
|
} else if (streq(token.start, "jump_eq_real")) {
|
||||||
|
} else if (streq(token.start, "jump_neq_real")) {
|
||||||
|
} else if (streq(token.start, "jump_ge_real")) {
|
||||||
|
} else if (streq(token.start, "jump_gt_real")) {
|
||||||
|
} else if (streq(token.start, "jump_lt_real")) {
|
||||||
|
} else if (streq(token.start, "jump_le_real")) {
|
||||||
|
} else if (streq(token.start, "string_length")) {
|
||||||
|
} else if (streq(token.start, "string_eq")) {
|
||||||
|
} else if (streq(token.start, "string_concat")) {
|
||||||
|
} else if (streq(token.start, "string_get_char")) {
|
||||||
|
} else if (streq(token.start, "string_find_char")) {
|
||||||
|
} else if (streq(token.start, "string_slice")) {
|
||||||
|
} else if (streq(token.start, "int_to_string")) {
|
||||||
|
} else if (streq(token.start, "nat_to_string")) {
|
||||||
|
} else if (streq(token.start, "real_to_string")) {
|
||||||
|
} else if (streq(token.start, "string_to_int")) {
|
||||||
|
} else if (streq(token.start, "string_to_nat")) {
|
||||||
|
} else if (streq(token.start, "string_to_real")) {
|
||||||
|
} else {
|
||||||
|
// some other identifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (token.type != TOKEN_EOF);
|
} while (token.type != TOKEN_EOF);
|
||||||
|
|
@ -504,15 +516,15 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
||||||
*/
|
*/
|
||||||
void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
||||||
Token token;
|
Token token;
|
||||||
initLexer(source);
|
init_lexer(source);
|
||||||
do {
|
do {
|
||||||
token = nextToken();
|
token = next_token();
|
||||||
if (token.type == TOKEN_ERROR) {
|
if (token.type == TOKEN_ERROR) {
|
||||||
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (token.type != TOKEN_EOF) {
|
if (token.type != TOKEN_EOF) {
|
||||||
printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type),
|
printf("Line %d [%s]: %.*s\n", token.line, token_type_to_string(token.type),
|
||||||
token.length, token.start);
|
token.length, token.start);
|
||||||
|
|
||||||
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
||||||
|
|
@ -561,7 +573,6 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
||||||
} else if (streq(token.start, "store_offset_16")) {
|
} else if (streq(token.start, "store_offset_16")) {
|
||||||
} else if (streq(token.start, "store_offset_32")) {
|
} else if (streq(token.start, "store_offset_32")) {
|
||||||
} else if (streq(token.start, "malloc")) {
|
} else if (streq(token.start, "malloc")) {
|
||||||
} else if (streq(token.start, "malloc_immediate")) {
|
|
||||||
} else if (streq(token.start, "memset_8")) {
|
} else if (streq(token.start, "memset_8")) {
|
||||||
} else if (streq(token.start, "memset_16")) {
|
} else if (streq(token.start, "memset_16")) {
|
||||||
} else if (streq(token.start, "memset_32")) {
|
} else if (streq(token.start, "memset_32")) {
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,24 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *start;
|
const char *start;
|
||||||
const char *current;
|
const char *current;
|
||||||
int line;
|
i32 line;
|
||||||
} Lexer;
|
} Lexer;
|
||||||
|
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
|
|
||||||
void initLexer(const char *source) {
|
void init_lexer(const char *source) {
|
||||||
lexer.start = source;
|
lexer.start = source;
|
||||||
lexer.current = source;
|
lexer.current = source;
|
||||||
lexer.line = 1;
|
lexer.line = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAlpha(char c) {
|
static bool is_alpha(char c) {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDigit(char c) { return c >= '0' && c <= '9'; }
|
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||||
|
|
||||||
static bool isAtEnd() { return *lexer.current == '\0'; }
|
static bool is_at_end() { return *lexer.current == '\0'; }
|
||||||
|
|
||||||
static char advance() {
|
static char advance() {
|
||||||
lexer.current++;
|
lexer.current++;
|
||||||
|
|
@ -32,14 +32,14 @@ static char advance() {
|
||||||
|
|
||||||
static char peek() { return *lexer.current; }
|
static char peek() { return *lexer.current; }
|
||||||
|
|
||||||
static char peekNext() {
|
static char peek_next() {
|
||||||
if (isAtEnd())
|
if (is_at_end())
|
||||||
return '\0';
|
return '\0';
|
||||||
return lexer.current[1];
|
return lexer.current[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool match(char expected) {
|
static bool match(char expected) {
|
||||||
if (isAtEnd())
|
if (is_at_end())
|
||||||
return false;
|
return false;
|
||||||
if (*lexer.current != expected)
|
if (*lexer.current != expected)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -47,25 +47,25 @@ static bool match(char expected) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token makeToken(TokenType type) {
|
static Token make_token(TokenType type) {
|
||||||
Token token;
|
Token token;
|
||||||
token.type = type;
|
token.type = type;
|
||||||
token.start = lexer.start;
|
token.start = lexer.start;
|
||||||
token.length = (int)(lexer.current - lexer.start);
|
token.length = (i32)(lexer.current - lexer.start);
|
||||||
token.line = lexer.line;
|
token.line = lexer.line;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token errorToken(const char *message) {
|
static Token error_token(const char *message) {
|
||||||
Token token;
|
Token token;
|
||||||
token.type = TOKEN_ERROR;
|
token.type = TOKEN_ERROR;
|
||||||
token.start = message;
|
token.start = message;
|
||||||
token.length = (int)strlen(message);
|
token.length = (i32)strlen(message);
|
||||||
token.line = lexer.line;
|
token.line = lexer.line;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skipWhitespace() {
|
static void skip_whitespace() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c = peek();
|
char c = peek();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -79,19 +79,19 @@ static void skipWhitespace() {
|
||||||
advance();
|
advance();
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (peekNext() == '/') {
|
if (peek_next() == '/') {
|
||||||
// Single-line comment: skip until newline or end of file
|
// Single-line comment: skip until newline or end of file
|
||||||
advance();
|
advance();
|
||||||
while (peek() != '\n' && !isAtEnd())
|
while (peek() != '\n' && !is_at_end())
|
||||||
advance();
|
advance();
|
||||||
} else if (peekNext() == '*') {
|
} else if (peek_next() == '*') {
|
||||||
// Multi-line comment: skip until '*/' or end of file
|
// Multi-line comment: skip until '*/' or end of file
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
while (!isAtEnd()) {
|
while (!is_at_end()) {
|
||||||
if (peek() == '\n')
|
if (peek() == '\n')
|
||||||
lexer.line++;
|
lexer.line++;
|
||||||
if (peek() == '*' && peekNext() == '/') {
|
if (peek() == '*' && peek_next() == '/') {
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
break; // Exit loop, comment ended
|
break; // Exit loop, comment ended
|
||||||
|
|
@ -108,7 +108,7 @@ static void skipWhitespace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static TokenType checkKeyword(int start, int length, const char *rest,
|
static TokenType check_keyword(i32 start, i32 length, const char *rest,
|
||||||
TokenType type) {
|
TokenType type) {
|
||||||
if (lexer.current - lexer.start == start + length &&
|
if (lexer.current - lexer.start == start + length &&
|
||||||
memcmp(lexer.start + start, rest, length) == 0) {
|
memcmp(lexer.start + start, rest, length) == 0) {
|
||||||
|
|
@ -124,9 +124,9 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'n':
|
case 'n':
|
||||||
return checkKeyword(2, 1, "d", TOKEN_OPERATOR_AND);
|
return check_keyword(2, 1, "d", TOKEN_OPERATOR_AND);
|
||||||
case 's':
|
case 's':
|
||||||
return checkKeyword(2, 0, "", TOKEN_KEYWORD_AS);
|
return check_keyword(2, 0, "", TOKEN_KEYWORD_AS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -134,47 +134,47 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'l':
|
case 'l':
|
||||||
return checkKeyword(2, 3, "ose", TOKEN_KEYWORD_CLOSE);
|
return check_keyword(2, 3, "ose", TOKEN_KEYWORD_CLOSE);
|
||||||
case 'o':
|
case 'o':
|
||||||
return checkKeyword(2, 3, "nst", TOKEN_KEYWORD_CONST);
|
return check_keyword(2, 3, "nst", TOKEN_KEYWORD_CONST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
|
return check_keyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
|
||||||
case 'f':
|
case 'f':
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
return checkKeyword(2, 3, "lse", TOKEN_KEYWORD_FALSE);
|
return check_keyword(2, 3, "lse", TOKEN_KEYWORD_FALSE);
|
||||||
case 'o':
|
case 'o':
|
||||||
return checkKeyword(2, 1, "r", TOKEN_KEYWORD_FOR);
|
return check_keyword(2, 1, "r", TOKEN_KEYWORD_FOR);
|
||||||
case '3':
|
case '3':
|
||||||
return checkKeyword(1, 1, "2", TOKEN_TYPE_REAL);
|
return check_keyword(1, 1, "2", TOKEN_TYPE_REAL);
|
||||||
}
|
}
|
||||||
return checkKeyword(1, 7, "unction", TOKEN_KEYWORD_FN);
|
return check_keyword(1, 7, "unction", TOKEN_KEYWORD_FN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
return checkKeyword(2, 0, "", TOKEN_KEYWORD_IF);
|
return check_keyword(2, 0, "", TOKEN_KEYWORD_IF);
|
||||||
case 's':
|
case 's':
|
||||||
return checkKeyword(2, 0, "", TOKEN_KEYWORD_IS);
|
return check_keyword(2, 0, "", TOKEN_KEYWORD_IS);
|
||||||
case '8':
|
case '8':
|
||||||
return checkKeyword(2, 0, "", TOKEN_TYPE_I8);
|
return check_keyword(2, 0, "", TOKEN_TYPE_I8);
|
||||||
case '1':
|
case '1':
|
||||||
return checkKeyword(2, 1, "6", TOKEN_TYPE_I16);
|
return check_keyword(2, 1, "6", TOKEN_TYPE_I16);
|
||||||
case '3':
|
case '3':
|
||||||
return checkKeyword(2, 1, "2", TOKEN_TYPE_INT);
|
return check_keyword(2, 1, "2", TOKEN_TYPE_INT);
|
||||||
case 'n':
|
case 'n':
|
||||||
if (lexer.current - lexer.start > 2) {
|
if (lexer.current - lexer.start > 2) {
|
||||||
switch (lexer.start[2]) {
|
switch (lexer.start[2]) {
|
||||||
case 'i':
|
case 'i':
|
||||||
return checkKeyword(3, 2, "t", TOKEN_KEYWORD_INIT);
|
return check_keyword(3, 2, "t", TOKEN_KEYWORD_INIT);
|
||||||
case 't':
|
case 't':
|
||||||
return checkKeyword(3, 0, "", TOKEN_TYPE_INT);
|
return check_keyword(3, 0, "", TOKEN_TYPE_INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -185,9 +185,9 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
return checkKeyword(2, 1, "t", TOKEN_TYPE_NAT);
|
return check_keyword(2, 1, "t", TOKEN_TYPE_NAT);
|
||||||
case 'i':
|
case 'i':
|
||||||
return checkKeyword(2, 1, "l", TOKEN_KEYWORD_NIL);
|
return check_keyword(2, 1, "l", TOKEN_KEYWORD_NIL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -195,9 +195,9 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'p':
|
case 'p':
|
||||||
return checkKeyword(2, 2, "en", TOKEN_KEYWORD_OPEN);
|
return check_keyword(2, 2, "en", TOKEN_KEYWORD_OPEN);
|
||||||
case 'r':
|
case 'r':
|
||||||
return checkKeyword(2, 0, "", TOKEN_OPERATOR_OR);
|
return check_keyword(2, 0, "", TOKEN_OPERATOR_OR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -205,7 +205,7 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'l':
|
case 'l':
|
||||||
return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
return check_keyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -216,11 +216,11 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 2) {
|
if (lexer.current - lexer.start > 2) {
|
||||||
switch (lexer.start[2]) {
|
switch (lexer.start[2]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
return checkKeyword(3, 1, "d", TOKEN_KEYWORD_READ);
|
return check_keyword(3, 1, "d", TOKEN_KEYWORD_READ);
|
||||||
case 'f':
|
case 'f':
|
||||||
return checkKeyword(3, 4, "resh", TOKEN_KEYWORD_REFRESH);
|
return check_keyword(3, 4, "resh", TOKEN_KEYWORD_REFRESH);
|
||||||
case 't':
|
case 't':
|
||||||
return checkKeyword(3, 3, "urn", TOKEN_KEYWORD_RETURN);
|
return check_keyword(3, 3, "urn", TOKEN_KEYWORD_RETURN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -231,7 +231,7 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 't':
|
case 't':
|
||||||
return checkKeyword(2, 1, "r", TOKEN_TYPE_STR);
|
return check_keyword(2, 1, "r", TOKEN_TYPE_STR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -239,9 +239,9 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'h':
|
case 'h':
|
||||||
return checkKeyword(2, 2, "is", TOKEN_KEYWORD_THIS);
|
return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS);
|
||||||
case 'r':
|
case 'r':
|
||||||
return checkKeyword(2, 2, "ue", TOKEN_KEYWORD_TRUE);
|
return check_keyword(2, 2, "ue", TOKEN_KEYWORD_TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -249,13 +249,13 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 's':
|
case 's':
|
||||||
return checkKeyword(2, 1, "e", TOKEN_KEYWORD_USE);
|
return check_keyword(2, 1, "e", TOKEN_KEYWORD_USE);
|
||||||
case '8':
|
case '8':
|
||||||
return checkKeyword(2, 0, "", TOKEN_TYPE_U8);
|
return check_keyword(2, 0, "", TOKEN_TYPE_U8);
|
||||||
case '1':
|
case '1':
|
||||||
return checkKeyword(2, 1, "6", TOKEN_TYPE_U16);
|
return check_keyword(2, 1, "6", TOKEN_TYPE_U16);
|
||||||
case '3':
|
case '3':
|
||||||
return checkKeyword(2, 1, "2", TOKEN_TYPE_NAT);
|
return check_keyword(2, 1, "2", TOKEN_TYPE_NAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -263,129 +263,133 @@ static TokenType identifierType() {
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'h':
|
case 'h':
|
||||||
return checkKeyword(2, 3, "ile", TOKEN_KEYWORD_WHILE);
|
return check_keyword(2, 3, "ile", TOKEN_KEYWORD_WHILE);
|
||||||
case 'r':
|
case 'r':
|
||||||
return checkKeyword(2, 3, "ite", TOKEN_KEYWORD_WRITE);
|
return check_keyword(2, 3, "ite", TOKEN_KEYWORD_WRITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
return checkKeyword(1, 5, "lobal", TOKEN_KEYWORD_GLOBAL);
|
return check_keyword(1, 5, "lobal", TOKEN_KEYWORD_GLOBAL);
|
||||||
case 'l':
|
case 'l':
|
||||||
return checkKeyword(1, 4, "oop", TOKEN_KEYWORD_LOOP);
|
return check_keyword(1, 4, "oop", TOKEN_KEYWORD_LOOP);
|
||||||
|
case 'd':
|
||||||
|
return check_keyword(1, 1, "o", TOKEN_KEYWORD_DO);
|
||||||
|
case 'v':
|
||||||
|
return check_keyword(1, 3, "oid", TOKEN_TYPE_VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TOKEN_IDENTIFIER;
|
return TOKEN_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token identifier() {
|
static Token identifier() {
|
||||||
while (isAlpha(peek()) || isDigit(peek()))
|
while (is_alpha(peek()) || is_digit(peek()))
|
||||||
advance();
|
advance();
|
||||||
return makeToken(identifierType());
|
return make_token(identifierType());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token number() {
|
static Token number() {
|
||||||
while (isDigit(peek()))
|
while (is_digit(peek()))
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
/* Look for a fractional part. */
|
/* Look for a fractional part. */
|
||||||
if (peek() == '.' && isDigit(peekNext())) {
|
if (peek() == '.' && is_digit(peek_next())) {
|
||||||
/* Consume the ".". */
|
/* Consume the ".". */
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
while (isDigit(peek()))
|
while (is_digit(peek()))
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
return makeToken(TOKEN_LITERAL_REAL);
|
return make_token(TOKEN_LITERAL_REAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeToken(TOKEN_LITERAL_INT);
|
return make_token(TOKEN_LITERAL_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token string() {
|
static Token string() {
|
||||||
while (peek() != '"' && !isAtEnd()) {
|
while (peek() != '"' && !is_at_end()) {
|
||||||
if (peek() == '\n')
|
if (peek() == '\n')
|
||||||
lexer.line++;
|
lexer.line++;
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAtEnd())
|
if (is_at_end())
|
||||||
return errorToken("Unterminated string.");
|
return error_token("Unterminated string.");
|
||||||
|
|
||||||
/* The closing quote. */
|
/* The closing quote. */
|
||||||
advance();
|
advance();
|
||||||
return makeToken(TOKEN_LITERAL_STR);
|
return make_token(TOKEN_LITERAL_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token nextToken() {
|
Token next_token() {
|
||||||
skipWhitespace();
|
skip_whitespace();
|
||||||
lexer.start = lexer.current;
|
lexer.start = lexer.current;
|
||||||
|
|
||||||
if (isAtEnd())
|
if (is_at_end())
|
||||||
return makeToken(TOKEN_EOF);
|
return make_token(TOKEN_EOF);
|
||||||
|
|
||||||
char c = advance();
|
char c = advance();
|
||||||
if (isAlpha(c))
|
if (is_alpha(c))
|
||||||
return identifier();
|
return identifier();
|
||||||
if (isDigit(c))
|
if (is_digit(c))
|
||||||
return number();
|
return number();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '(':
|
case '(':
|
||||||
return makeToken(TOKEN_LPAREN);
|
return make_token(TOKEN_LPAREN);
|
||||||
case ')':
|
case ')':
|
||||||
return makeToken(TOKEN_RPAREN);
|
return make_token(TOKEN_RPAREN);
|
||||||
case '{':
|
case '{':
|
||||||
return makeToken(TOKEN_LBRACE);
|
return make_token(TOKEN_LBRACE);
|
||||||
case '}':
|
case '}':
|
||||||
return makeToken(TOKEN_RBRACE);
|
return make_token(TOKEN_RBRACE);
|
||||||
case '[':
|
case '[':
|
||||||
return makeToken(TOKEN_LBRACKET);
|
return make_token(TOKEN_LBRACKET);
|
||||||
case ']':
|
case ']':
|
||||||
return makeToken(TOKEN_RBRACKET);
|
return make_token(TOKEN_RBRACKET);
|
||||||
case ';':
|
case ';':
|
||||||
return makeToken(TOKEN_SEMICOLON);
|
return make_token(TOKEN_SEMICOLON);
|
||||||
case ',':
|
case ',':
|
||||||
return makeToken(TOKEN_COMMA);
|
return make_token(TOKEN_COMMA);
|
||||||
case '.':
|
case '.':
|
||||||
return makeToken(TOKEN_DOT);
|
return make_token(TOKEN_DOT);
|
||||||
case '-':
|
case '-':
|
||||||
return makeToken(match('>') ? TOKEN_ARROW_LEFT : TOKEN_MINUS);
|
return make_token(match('>') ? TOKEN_ARROW_LEFT : TOKEN_MINUS);
|
||||||
case '+':
|
case '+':
|
||||||
return makeToken(TOKEN_PLUS);
|
return make_token(TOKEN_PLUS);
|
||||||
case '/':
|
case '/':
|
||||||
return makeToken(TOKEN_SLASH);
|
return make_token(TOKEN_SLASH);
|
||||||
case '&':
|
case '&':
|
||||||
return makeToken(match('&') ? TOKEN_AND_AND : TOKEN_AND);
|
return make_token(match('&') ? TOKEN_AND_AND : TOKEN_AND);
|
||||||
case '#':
|
case '#':
|
||||||
return makeToken(TOKEN_MESH);
|
return make_token(TOKEN_MESH);
|
||||||
case '$':
|
case '$':
|
||||||
return makeToken(TOKEN_BIG_MONEY);
|
return make_token(TOKEN_BIG_MONEY);
|
||||||
case '*':
|
case '*':
|
||||||
return makeToken(TOKEN_STAR);
|
return make_token(TOKEN_STAR);
|
||||||
case '!':
|
case '!':
|
||||||
return makeToken(match('=') ? TOKEN_BANG_EQ : TOKEN_BANG);
|
return make_token(match('=') ? TOKEN_BANG_EQ : TOKEN_BANG);
|
||||||
case '=':
|
case '=':
|
||||||
return makeToken(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
|
return make_token(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
|
||||||
case '<':
|
case '<':
|
||||||
return makeToken(match('=') ? TOKEN_LTE : TOKEN_LT);
|
return make_token(match('=') ? TOKEN_LTE : TOKEN_LT);
|
||||||
case '>':
|
case '>':
|
||||||
return makeToken(match('=') ? TOKEN_GTE : TOKEN_GT);
|
return make_token(match('=') ? TOKEN_GTE : TOKEN_GT);
|
||||||
case '"':
|
case '"':
|
||||||
return string();
|
return string();
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorToken("Unexpected character.");
|
return error_token("Unexpected character.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *tokenTypeToString(TokenType type) {
|
const char *token_type_to_string(TokenType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TOKEN_EOF:
|
case TOKEN_EOF:
|
||||||
return "EOF";
|
return "EOF";
|
||||||
case TOKEN_IDENTIFIER:
|
case TOKEN_IDENTIFIER:
|
||||||
return "IDENTIFIER";
|
return "IDENTIFIER";
|
||||||
case TOKEN_LITERAL_INT:
|
case TOKEN_LITERAL_INT:
|
||||||
return "LITERAL_INT";
|
return "LITERAL_i32";
|
||||||
case TOKEN_LITERAL_NAT:
|
case TOKEN_LITERAL_NAT:
|
||||||
return "LITERAL_NAT";
|
return "LITERAL_NAT";
|
||||||
case TOKEN_LITERAL_REAL:
|
case TOKEN_LITERAL_REAL:
|
||||||
|
|
@ -393,7 +397,7 @@ const char *tokenTypeToString(TokenType type) {
|
||||||
case TOKEN_LITERAL_STR:
|
case TOKEN_LITERAL_STR:
|
||||||
return "LITERAL_STR";
|
return "LITERAL_STR";
|
||||||
case TOKEN_TYPE_INT:
|
case TOKEN_TYPE_INT:
|
||||||
return "TYPE_INT";
|
return "TYPE_i32";
|
||||||
case TOKEN_TYPE_NAT:
|
case TOKEN_TYPE_NAT:
|
||||||
return "TYPE_NAT";
|
return "TYPE_NAT";
|
||||||
case TOKEN_TYPE_REAL:
|
case TOKEN_TYPE_REAL:
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ typedef enum {
|
||||||
TOKEN_TYPE_NAT,
|
TOKEN_TYPE_NAT,
|
||||||
TOKEN_TYPE_REAL,
|
TOKEN_TYPE_REAL,
|
||||||
TOKEN_TYPE_STR,
|
TOKEN_TYPE_STR,
|
||||||
|
TOKEN_TYPE_BOOL,
|
||||||
|
TOKEN_TYPE_VOID,
|
||||||
TOKEN_KEYWORD_PLEX,
|
TOKEN_KEYWORD_PLEX,
|
||||||
TOKEN_KEYWORD_FN,
|
TOKEN_KEYWORD_FN,
|
||||||
TOKEN_KEYWORD_CONST,
|
TOKEN_KEYWORD_CONST,
|
||||||
|
|
@ -36,6 +38,7 @@ typedef enum {
|
||||||
TOKEN_KEYWORD_REFRESH,
|
TOKEN_KEYWORD_REFRESH,
|
||||||
TOKEN_KEYWORD_CLOSE,
|
TOKEN_KEYWORD_CLOSE,
|
||||||
TOKEN_KEYWORD_LOOP,
|
TOKEN_KEYWORD_LOOP,
|
||||||
|
TOKEN_KEYWORD_DO,
|
||||||
TOKEN_KEYWORD_NIL,
|
TOKEN_KEYWORD_NIL,
|
||||||
TOKEN_KEYWORD_TRUE,
|
TOKEN_KEYWORD_TRUE,
|
||||||
TOKEN_KEYWORD_FALSE,
|
TOKEN_KEYWORD_FALSE,
|
||||||
|
|
@ -79,8 +82,8 @@ typedef struct {
|
||||||
int line;
|
int line;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
void initLexer(const char *source);
|
void init_lexer(const char *source);
|
||||||
Token nextToken();
|
Token next_token();
|
||||||
const char* tokenTypeToString(TokenType type);
|
const char* token_type_to_string(TokenType type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -184,14 +184,14 @@ Symbol *global(VM *vm) {
|
||||||
|
|
||||||
s.ref.global = vm->mp;
|
s.ref.global = vm->mp;
|
||||||
|
|
||||||
Token token_type = nextToken();
|
Token token_type = next_token();
|
||||||
Token array_or_eq = nextToken();
|
Token array_or_eq = next_token();
|
||||||
if (array_or_eq.type == TOKEN_LBRACKET) {
|
if (array_or_eq.type == TOKEN_LBRACKET) {
|
||||||
Token rb = nextToken();
|
Token rb = next_token();
|
||||||
if (rb.type != TOKEN_RBRACKET)
|
if (rb.type != TOKEN_RBRACKET)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
Token eq = nextToken();
|
Token eq = next_token();
|
||||||
if (eq.type != TOKEN_EQ)
|
if (eq.type != TOKEN_EQ)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
|
|
@ -268,7 +268,7 @@ Symbol *global(VM *vm) {
|
||||||
|
|
||||||
s.type = t;
|
s.type = t;
|
||||||
|
|
||||||
Token value = nextToken();
|
Token value = next_token();
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +345,7 @@ void advance() {
|
||||||
parser.previous = parser.current;
|
parser.previous = parser.current;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
parser.current = nextToken();
|
parser.current = next_token();
|
||||||
if (parser.current.type != TOKEN_ERROR)
|
if (parser.current.type != TOKEN_ERROR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,7 @@ static Token string() {
|
||||||
return makeToken(TOKEN_LITERAL_STR);
|
return makeToken(TOKEN_LITERAL_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token nextToken() {
|
Token next_token() {
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
lexer.start = lexer.current;
|
lexer.start = lexer.current;
|
||||||
|
|
||||||
|
|
@ -376,7 +376,7 @@ Token nextToken() {
|
||||||
return errorToken("Unexpected character.");
|
return errorToken("Unexpected character.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *tokenTypeToString(TokenType type) {
|
const char *token_type_to_string(TokenType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TOKEN_EOF:
|
case TOKEN_EOF:
|
||||||
return "EOF";
|
return "EOF";
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ typedef struct {
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
void initLexer(const char *source);
|
void initLexer(const char *source);
|
||||||
Token nextToken();
|
Token next_token();
|
||||||
const char* tokenTypeToString(TokenType type);
|
const char* token_type_to_string(TokenType type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ typedef enum {
|
||||||
OP_STORE_OFF_16, /* store_offset_16 : memory[locals[dest] + offset] = locals[src1] && 0xFFFF */
|
OP_STORE_OFF_16, /* store_offset_16 : memory[locals[dest] + offset] = locals[src1] && 0xFFFF */
|
||||||
OP_STORE_OFF_32, /* store_offset_32 : memory[locals[dest] + offset] = locals[src1] */
|
OP_STORE_OFF_32, /* store_offset_32 : memory[locals[dest] + offset] = locals[src1] */
|
||||||
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
|
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
|
||||||
OP_MALLOC_IMM, /* malloc_immediate : dest = fat ptr to memory of raw <str or array or plex>*/
|
|
||||||
OP_MEMSET_8, /* memset_8 : dest <-> dest+count = src1 as u8 */
|
OP_MEMSET_8, /* memset_8 : dest <-> dest+count = src1 as u8 */
|
||||||
OP_MEMSET_16, /* memset_16 : dest <-> dest+count = src1 as u8 */
|
OP_MEMSET_16, /* memset_16 : dest <-> dest+count = src1 as u8 */
|
||||||
OP_MEMSET_32, /* memset_32 : dest <-> dest+count = src1 as u32 */
|
OP_MEMSET_32, /* memset_32 : dest <-> dest+count = src1 as u32 */
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ function main ()
|
||||||
load_absolute_32 y -> $1
|
load_absolute_32 y -> $1
|
||||||
call add $0 $1 -> ans
|
call add $0 $1 -> ans
|
||||||
int_to_string ans -> ans_string
|
int_to_string ans -> ans_string
|
||||||
call pln ans_string
|
call pln ans_string -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function add (int a $0, int b $1)
|
function add (int a $0, int b $1)
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,23 @@ function main ()
|
||||||
int str_n $1
|
int str_n $1
|
||||||
|
|
||||||
load_immediate 35 -> n
|
load_immediate 35 -> n
|
||||||
call &fib n -> n
|
call fib n -> n
|
||||||
int_to_string n -> str_n
|
int_to_string n -> str_n
|
||||||
call &pln str_n
|
call pln str_n -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function fib (int n $0)
|
function fib (int n $0)
|
||||||
load_immediate 2 -> $1
|
load_immediate 2 -> $1
|
||||||
|
|
||||||
jump_lt_int &base_case n $1
|
jump_lt_int base_case n $1
|
||||||
|
|
||||||
load_immediate 2 -> $3
|
load_immediate 2 -> $3
|
||||||
sub_int n $3 -> $4
|
sub_int n $3 -> $4
|
||||||
call &fib $4 -> $5
|
call fib $4 -> $5
|
||||||
|
|
||||||
load_immediate 1 -> $3
|
load_immediate 1 -> $3
|
||||||
sub_int n $3 -> $4
|
sub_int n $3 -> $4
|
||||||
call &fib $4 -> $6
|
call fib $4 -> $6
|
||||||
|
|
||||||
add_int $6 $5 -> $7
|
add_int $6 $5 -> $7
|
||||||
return $7
|
return $7
|
||||||
|
|
@ -37,12 +37,12 @@ function pln (str message $0)
|
||||||
str nl $3
|
str nl $3
|
||||||
int nl_length $4
|
int nl_length $4
|
||||||
|
|
||||||
load_immediate &terminal_namespace -> ts
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN ts mode -> ts
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE ts message msg_length
|
syscall WRITE ts message msg_length
|
||||||
load_immediate &new_line -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE ts nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ global str message = "nuqneH 'u'?"
|
||||||
function main ()
|
function main ()
|
||||||
str hello $0
|
str hello $0
|
||||||
|
|
||||||
load_immediate &message -> hello
|
load_immediate message -> hello
|
||||||
call pln hello
|
call pln hello -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message $0)
|
function pln (str message $0)
|
||||||
|
|
@ -16,13 +16,12 @@ function pln (str message $0)
|
||||||
str nl $3
|
str nl $3
|
||||||
int nl_length $4
|
int nl_length $4
|
||||||
|
|
||||||
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate &terminal_namespace -> ts
|
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN ts mode -> ts
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE ts message msg_length
|
syscall WRITE ts message msg_length
|
||||||
load_immediate &new_line -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE ts nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
global str terminal_namespace = "/dev/term/0"
|
||||||
|
global str prompt = "Enter a string:"
|
||||||
|
global str new_line = "\n"
|
||||||
|
|
||||||
function main ()
|
function main ()
|
||||||
real a is $0
|
real a $0
|
||||||
int i is $1
|
int i $1
|
||||||
int mode is $11
|
int mode $11
|
||||||
str term is $10
|
str term $10
|
||||||
|
|
||||||
load_immediate 5.0 -> a
|
load_immediate 5.0 -> a
|
||||||
load_immediate 5000 -> i
|
load_immediate 5000 -> i
|
||||||
|
|
@ -15,41 +18,41 @@ function main ()
|
||||||
add_int i $3 -> i
|
add_int i $3 -> i
|
||||||
jump_ge_int loop_body i $2
|
jump_ge_int loop_body i $2
|
||||||
|
|
||||||
malloc_immediate "/dev/term/0" -> term
|
load_immediate terminal_namespace -> term
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN term mode -> term # Terminal term = open("/dev/term/0", 0);
|
syscall OPEN term mode -> term // Terminal term = open("/dev/term/0", 0);
|
||||||
|
|
||||||
nat b is $1
|
nat b $1
|
||||||
real_to_nat a -> b
|
real_to_nat a -> b
|
||||||
malloc_immediate "Enter a string:" -> $7
|
load_immediate prompt -> $7
|
||||||
string_length $7 -> $8
|
string_length $7 -> $8
|
||||||
syscall WRITE term $7 $8 # print prompt
|
syscall WRITE term $7 $8 // print prompt
|
||||||
|
|
||||||
str user_string is $9
|
str user_string $9
|
||||||
load_immediate 32 -> $8
|
load_immediate 32 -> $8
|
||||||
malloc $8 -> user_string
|
malloc $8 -> user_string
|
||||||
syscall READ term user_string $8 # read in max 32 byte string
|
syscall READ term user_string $8 // read in max 32 byte string
|
||||||
|
|
||||||
call pln user_string
|
call pln user_string -> void
|
||||||
nat_to_string b -> $4
|
nat_to_string b -> $4
|
||||||
call pln $4
|
call pln $4 -> void
|
||||||
real_to_string a -> $3
|
real_to_string a -> $3
|
||||||
call pln $3
|
call pln $3 -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message is $0)
|
function pln (str message $0)
|
||||||
str ts is $1
|
str ts $1
|
||||||
int mode is $5
|
int mode $5
|
||||||
int msg_length is $2
|
int msg_length $2
|
||||||
str nl is $3
|
str nl $3
|
||||||
int nl_length is $4
|
int nl_length $4
|
||||||
|
|
||||||
malloc_immediate "/dev/term/0" -> ts
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN ts mode -> ts # get terminal device
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE ts message msg_length
|
syscall WRITE ts message msg_length
|
||||||
malloc_immediate "\n" -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE ts nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
|
global str terminal_namespace = "/dev/term/0"
|
||||||
|
global str prompt = "Enter a string:"
|
||||||
|
global str new_line = "\n"
|
||||||
|
|
||||||
function main ()
|
function main ()
|
||||||
int mode $11;
|
int mode $11;
|
||||||
str term $10;
|
str term $10;
|
||||||
|
|
||||||
malloc_immediate "/dev/term/0" -> term
|
load_immediate terminal_namespace -> term
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN term mode -> term # Terminal term = open("/dev/term/0", 0);
|
syscall OPEN term mode -> term // Terminal term = open("/dev/term/0", 0);
|
||||||
|
|
||||||
malloc_immediate "Enter a string:" -> $7
|
load_immediate prompt -> $7
|
||||||
string_length $7 -> $8
|
string_length $7 -> $8
|
||||||
syscall WRITE term $7 $8 # print prompt
|
syscall WRITE term $7 $8 // print prompt
|
||||||
|
|
||||||
str user_string $9
|
str user_string $9
|
||||||
load_immediate 32 -> $8
|
load_immediate 32 -> $8
|
||||||
malloc $8 -> user_string
|
malloc $8 -> user_string
|
||||||
syscall READ term user_string $8 # read in max 32 byte string
|
syscall READ term user_string $8 // read in max 32 byte string
|
||||||
|
|
||||||
call pln user_string;
|
call pln user_string -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message $0)
|
function pln (str message $0)
|
||||||
|
|
@ -24,14 +27,14 @@ function pln (str message $0)
|
||||||
int mode $5
|
int mode $5
|
||||||
int msg_length $2
|
int msg_length $2
|
||||||
str nl $3
|
str nl $3
|
||||||
int nl_length $4
|
int nl_length $4
|
||||||
|
|
||||||
malloc_immediate "/dev/term/0" -> ts
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN ts mode -> ts # get terminal device
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE ts message msg_length
|
syscall WRITE ts message msg_length
|
||||||
malloc_immediate "\n" -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE ts nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -8,177 +8,178 @@ global const byte LIGHT_GRAY = 182
|
||||||
global byte SELECTED_COLOR = 255
|
global byte SELECTED_COLOR = 255
|
||||||
|
|
||||||
function main ()
|
function main ()
|
||||||
# Open screen
|
// Open screen
|
||||||
plex screen is $0
|
plex screen $0
|
||||||
str screen_name is $18
|
str screen_name $18
|
||||||
int mode is $11
|
int mode $11
|
||||||
nat screen_buffer is $21
|
nat screen_buffer $21
|
||||||
|
|
||||||
# use load immediate because it is a pointer to a string, not a value
|
// use load immediate because it a pointer to a string, not a value
|
||||||
load_address &screen_namespace -> screen_name
|
load_address screen_namespace -> screen_name
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN screen_name mode -> screen # Screen screen = open("/dev/screen/0", 0);
|
syscall OPEN screen_name mode -> screen // Screen screen = open("/dev/screen/0", 0);
|
||||||
|
|
||||||
nat width is $20
|
nat width $20
|
||||||
nat size is $22
|
nat size $22
|
||||||
load_offset_32 screen 8 -> width # load width
|
load_offset_32 screen 8 -> width // load width
|
||||||
load_offset_32 screen 12 -> size # load size
|
load_offset_32 screen 12 -> size // load size
|
||||||
load_immediate 16 -> $1 # offset for screen buffer
|
load_immediate 16 -> $1 // offset for screen buffer
|
||||||
add_nat screen $1 -> screen_buffer
|
add_nat screen $1 -> screen_buffer
|
||||||
|
|
||||||
# open mouse
|
// open mouse
|
||||||
plex mouse is $15
|
plex mouse $15
|
||||||
str mouse_name is $16
|
str mouse_name $16
|
||||||
load_address &mouse_namespace -> mouse_name
|
load_address mouse_namespace -> mouse_name
|
||||||
syscall OPEN mouse_name mode -> mouse # Mouse mouse = open("/dev/mouse/0", 0);
|
syscall OPEN mouse_name mode -> mouse // Mouse mouse = open("/dev/mouse/0", 0);
|
||||||
|
|
||||||
byte color is $1
|
byte color $1
|
||||||
nat x_pos is $12
|
nat x_pos $12
|
||||||
nat y_pos is $13
|
nat y_pos $13
|
||||||
|
|
||||||
load_absolute_32 &BLACK -> color
|
load_absolute_32 BLACK -> color
|
||||||
load_immediate 1 -> x_pos
|
load_immediate 1 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
|
|
||||||
load_absolute_32 &WHITE -> color
|
load_absolute_32 WHITE -> color
|
||||||
load_immediate 21 -> x_pos
|
load_immediate 21 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
|
|
||||||
# screen.draw#
|
// screen.draw
|
||||||
syscall WRITE screen screen_buffer size
|
syscall WRITE screen screen_buffer size
|
||||||
|
|
||||||
nat zero is $11
|
nat zero $11
|
||||||
|
|
||||||
draw_loop:
|
loop draw_loop
|
||||||
# load mouse click data
|
// load mouse click data
|
||||||
syscall REFRESH mouse
|
syscall REFRESH mouse
|
||||||
|
|
||||||
byte left_down is $9
|
byte left_down $9
|
||||||
load_offset_8 mouse 16 -> left_down # load btn1 pressed
|
load_offset_8 mouse 16 -> left_down // load btn1 pressed
|
||||||
|
|
||||||
jump_eq_nat &draw_loop left_down zero
|
jump_eq_nat draw_loop left_down zero
|
||||||
|
|
||||||
nat mouse_x is $7
|
nat mouse_x $7
|
||||||
nat mouse_y is $8
|
nat mouse_y $8
|
||||||
load_offset_32 mouse 8 -> mouse_x # load x
|
load_offset_32 mouse 8 -> mouse_x // load x
|
||||||
load_offset_32 mouse 12 -> mouse_y # load y
|
load_offset_32 mouse 12 -> mouse_y // load y
|
||||||
|
|
||||||
nat box_size is $14
|
nat box_size $14
|
||||||
load_immediate 20 -> box_size
|
load_immediate 20 -> box_size
|
||||||
|
|
||||||
# first row
|
// first row
|
||||||
load_absolute_32 &BLACK -> color
|
load_absolute_32 BLACK -> color
|
||||||
load_immediate 1 -> x_pos
|
load_immediate 1 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size -> void
|
||||||
|
|
||||||
|
|
||||||
load_absolute_32 &WHITE -> color
|
load_absolute_32 WHITE -> color
|
||||||
load_immediate 21 -> x_pos
|
load_immediate 21 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size -> void
|
||||||
|
|
||||||
syscall WRITE screen screen_buffer size
|
syscall WRITE screen screen_buffer size
|
||||||
|
|
||||||
byte selected_color is $25
|
byte selected_color $25
|
||||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
load_absolute_32 SELECTED_COLOR -> selected_color
|
||||||
|
|
||||||
nat brush_size is $19
|
nat brush_size $19
|
||||||
load_immediate 5 -> brush_size
|
load_immediate 5 -> brush_size
|
||||||
|
|
||||||
call &draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size
|
call draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size -> void
|
||||||
|
|
||||||
jump &draw_loop
|
jump draw_loop
|
||||||
|
|
||||||
# Flush and exit
|
// Flush and exit
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function set_color_if_clicked (int click_x is $0, int click_y is $1,
|
function set_color_if_clicked (int click_x $0, int click_y $1,
|
||||||
int box_x is $2, int box_y is $3, byte color is $4, int box_size is $5)
|
int box_x $2, int box_y $3, byte color $4, int box_size $5)
|
||||||
|
|
||||||
# Compute right
|
// Compute right
|
||||||
int right_edge is $6
|
int right_edge $6
|
||||||
add_int box_x box_size -> right_edge
|
add_int box_x box_size -> right_edge
|
||||||
|
|
||||||
# Compute bottom = box_y + box_size
|
// Compute bottom = box_y + box_size
|
||||||
int bottom_edge is $7
|
int bottom_edge $7
|
||||||
add_int box_y box_size -> bottom_edge
|
add_int box_y box_size -> bottom_edge
|
||||||
|
|
||||||
# Bounds check: x in [box_x, right] and y in [box_y, bottom]
|
// Bounds check: x in [box_x, right] and y in [box_y, bottom]
|
||||||
jump_lt_int &fail click_x box_x
|
jump_lt_int fail click_x box_x
|
||||||
jump_ge_int &fail click_x right_edge
|
jump_ge_int fail click_x right_edge
|
||||||
jump_lt_int &fail click_y box_y
|
jump_lt_int fail click_y box_y
|
||||||
jump_ge_int &fail click_y bottom_edge
|
jump_ge_int fail click_y bottom_edge
|
||||||
|
|
||||||
store_absolute_8 &SELECTED_COLOR color
|
store_absolute_8 SELECTED_COLOR color
|
||||||
|
|
||||||
fail:
|
else fail
|
||||||
return
|
return
|
||||||
|
|
||||||
function draw_outlined_swatch(nat base is $0,
|
function draw_outlined_swatch(nat base $0,
|
||||||
byte color is $1, int x is $2, int y is $3, int width is $4)
|
byte color $1, int x $2, int y $3, int width $4)
|
||||||
|
|
||||||
# Constants
|
// Constants
|
||||||
nat background_color is $5
|
nat background_color $5
|
||||||
load_absolute_32 &GRAY -> background_color
|
load_absolute_32 GRAY -> background_color
|
||||||
|
|
||||||
byte selected_color is $10
|
byte selected_color $10
|
||||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
load_absolute_32 SELECTED_COLOR -> selected_color
|
||||||
|
|
||||||
jump_eq_int &set_selected selected_color color
|
jump_eq_int set_selected selected_color color
|
||||||
jump &end_set_selected
|
jump end_set_selected
|
||||||
set_selected:
|
set_selected:
|
||||||
load_absolute_32 &DARK_GRAY -> background_color
|
load_absolute_32 DARK_GRAY -> background_color
|
||||||
end_set_selected:
|
end_set_selected:
|
||||||
|
|
||||||
nat outline_size is $6
|
nat outline_size $6
|
||||||
load_immediate 20 -> outline_size
|
load_immediate 20 -> outline_size
|
||||||
|
|
||||||
nat fill_size is $7
|
nat fill_size $7
|
||||||
load_immediate 17 -> fill_size
|
load_immediate 17 -> fill_size
|
||||||
|
|
||||||
nat offset is $8
|
nat offset $8
|
||||||
load_immediate 2 -> offset
|
load_immediate 2 -> offset
|
||||||
|
|
||||||
call &draw_box base width background_color x y outline_size outline_size
|
call draw_box base width background_color x y outline_size outline_size -> void
|
||||||
|
|
||||||
add_int x offset -> $9 # x + 2
|
add_int x offset -> $9 // x + 2
|
||||||
add_int y offset -> $10 # y + 2
|
add_int y offset -> $10 // y + 2
|
||||||
|
|
||||||
call &draw_box base width color $9 $10 fill_size fill_size
|
call draw_box base width color $9 $10 fill_size fill_size -> void
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
function draw_box (nat base is $0, nat screen_width is $1,
|
function draw_box (nat base $0, nat screen_width $1,
|
||||||
byte color is $2, nat x_start is $3, nat y_start is $4, nat width is $5, nat height is $6)
|
byte color $2, nat x_start $3, nat y_start $4,
|
||||||
|
nat width $5, nat height $6)
|
||||||
|
|
||||||
# Compute start address: base + y*640 + x
|
// Compute start address: base + y*640 + x
|
||||||
nat offset is $15
|
nat offset $15
|
||||||
mul_int y_start screen_width -> offset
|
mul_int y_start screen_width -> offset
|
||||||
add_int offset x_start -> offset
|
add_int offset x_start -> offset
|
||||||
add_nat offset base -> offset
|
add_nat offset base -> offset
|
||||||
nat fat_ptr_size is $25
|
nat fat_ptr_size $25
|
||||||
load_immediate 4 -> fat_ptr_size
|
load_immediate 4 -> fat_ptr_size
|
||||||
add_nat offset fat_ptr_size -> offset # need to add offset for fat pointer size
|
add_nat offset fat_ptr_size -> offset // need to add offset for fat pointer size
|
||||||
|
|
||||||
int i is $30
|
int i $30
|
||||||
load_immediate 1 -> i
|
load_immediate 1 -> i
|
||||||
|
|
||||||
int zero is $26
|
int zero $26
|
||||||
load_immediate 0 -> zero
|
load_immediate 0 -> zero
|
||||||
|
|
||||||
int row_end is $27
|
int row_end $27
|
||||||
nat pixel_ptr is $29
|
nat pixel_ptr $29
|
||||||
|
|
||||||
draw_box_outer:
|
loop draw_box_outer
|
||||||
add_int offset width -> row_end # current + width
|
add_int offset width -> row_end // current + width
|
||||||
register_move offset -> pixel_ptr # set pixel point
|
register_move offset -> pixel_ptr // set pixel point
|
||||||
memset_8 pixel_ptr color width # draw row
|
memset_8 pixel_ptr color width // draw row
|
||||||
add_int offset screen_width -> offset # next row += 640
|
add_int offset screen_width -> offset // next row += 640
|
||||||
sub_int height i -> height # decrement row count
|
sub_int height i -> height // decrement row count
|
||||||
jump_gt_int &draw_box_outer height zero
|
jump_gt_int draw_box_outer height zero
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,12 @@ function main ()
|
||||||
load_absolute_32 BLACK -> color
|
load_absolute_32 BLACK -> color
|
||||||
load_immediate 1 -> x_pos
|
load_immediate 1 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch [screen_buffer color x_pos y_pos width] -> void
|
||||||
|
|
||||||
load_absolute_32 WHITE -> color
|
load_absolute_32 WHITE -> color
|
||||||
load_immediate 21 -> x_pos
|
load_immediate 21 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
|
|
||||||
// screen.draw//
|
// screen.draw//
|
||||||
syscall WRITE screen screen_buffer size
|
syscall WRITE screen screen_buffer size
|
||||||
|
|
@ -72,15 +72,15 @@ function main ()
|
||||||
load_absolute_32 BLACK -> color
|
load_absolute_32 BLACK -> color
|
||||||
load_immediate 1 -> x_pos
|
load_immediate 1 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size -> void
|
||||||
|
|
||||||
|
|
||||||
load_absolute_32 WHITE -> color
|
load_absolute_32 WHITE -> color
|
||||||
load_immediate 21 -> x_pos
|
load_immediate 21 -> x_pos
|
||||||
load_immediate 1 -> y_pos
|
load_immediate 1 -> y_pos
|
||||||
call draw_outlined_swatch screen_buffer color x_pos y_pos width
|
call draw_outlined_swatch screen_buffer color x_pos y_pos width -> void
|
||||||
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
call set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size -> void
|
||||||
|
|
||||||
syscall WRITE screen screen_buffer size
|
syscall WRITE screen screen_buffer size
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ function main ()
|
||||||
nat brush_size $19
|
nat brush_size $19
|
||||||
load_immediate 5 -> brush_size
|
load_immediate 5 -> brush_size
|
||||||
|
|
||||||
call draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size
|
call draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size -> void
|
||||||
|
|
||||||
jump draw_loop
|
jump draw_loop
|
||||||
|
|
||||||
|
|
@ -144,12 +144,12 @@ function draw_outlined_swatch(nat base $0,
|
||||||
nat offset $8
|
nat offset $8
|
||||||
load_immediate 2 -> offset
|
load_immediate 2 -> offset
|
||||||
|
|
||||||
call draw_box base width background_color x y outline_size outline_size
|
call draw_box base width background_color x y outline_size outline_size -> void
|
||||||
|
|
||||||
add_int x offset -> $9 // x + 2
|
add_int x offset -> $9 // x + 2
|
||||||
add_int y offset -> $10 // y + 2
|
add_int y offset -> $10 // y + 2
|
||||||
|
|
||||||
call draw_box base width color $9 $10 fill_size fill_size
|
call draw_box base width color $9 $10 fill_size fill_size -> void
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -180,5 +180,5 @@ function draw_box (nat base $0, nat screen_width $1,
|
||||||
memset_8 pixel_ptr color width // draw row
|
memset_8 pixel_ptr color width // draw row
|
||||||
add_int offset screen_width -> offset // next row += 640
|
add_int offset screen_width -> offset // next row += 640
|
||||||
sub_int height i -> height // decrement row count
|
sub_int height i -> height // decrement row count
|
||||||
jump_gt_int draw_box_outer height zero
|
jump_gt_int draw_box_outer height zero
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ function main ()
|
||||||
add_real x y -> result
|
add_real x y -> result
|
||||||
str result_str $3
|
str result_str $3
|
||||||
real_to_string result -> result_str
|
real_to_string result -> result_str
|
||||||
call &pln result_str
|
call &pln result_str -> void
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message $0)
|
function pln (str message $0)
|
||||||
|
|
|
||||||
|
|
@ -24,21 +24,21 @@ function main ()
|
||||||
syscall OPEN screen mode -> screen
|
syscall OPEN screen mode -> screen
|
||||||
|
|
||||||
nat_to_string screen -> tmp_str
|
nat_to_string screen -> tmp_str
|
||||||
call pln tmp_str
|
call pln tmp_str -> void
|
||||||
|
|
||||||
load_offset_32 screen 8 -> width
|
load_offset_32 screen 8 -> width
|
||||||
nat_to_string width -> tmp_str
|
nat_to_string width -> tmp_str
|
||||||
call pln tmp_str
|
call pln tmp_str -> void
|
||||||
|
|
||||||
load_offset_32 screen 12 -> buffer_size
|
load_offset_32 screen 12 -> buffer_size
|
||||||
nat_to_string buffer_size -> tmp_str
|
nat_to_string buffer_size -> tmp_str
|
||||||
call pln tmp_str
|
call pln tmp_str -> void
|
||||||
|
|
||||||
load_immediate 16 -> offset_temp
|
load_immediate 16 -> offset_temp
|
||||||
add_nat screen offset_temp -> screen_buffer
|
add_nat screen offset_temp -> screen_buffer
|
||||||
|
|
||||||
nat_to_string screen_buffer -> tmp_str
|
nat_to_string screen_buffer -> tmp_str
|
||||||
call pln tmp_str
|
call pln tmp_str -> void
|
||||||
|
|
||||||
// open mouse
|
// open mouse
|
||||||
load_immediate mouse_namespace -> mouse
|
load_immediate mouse_namespace -> mouse
|
||||||
|
|
@ -72,17 +72,18 @@ function main ()
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
function pln (str message $0)
|
function pln (str message $0)
|
||||||
str term $1
|
str ts $1
|
||||||
int msg_length $2
|
|
||||||
str nl $3
|
|
||||||
int nl_length $4
|
|
||||||
int mode $5
|
int mode $5
|
||||||
|
int msg_length $2
|
||||||
|
str nl $3
|
||||||
|
int nl_length $4
|
||||||
|
|
||||||
|
load_immediate terminal_namespace -> ts
|
||||||
load_immediate 0 -> mode
|
load_immediate 0 -> mode
|
||||||
syscall OPEN terminal_namespace mode -> term
|
syscall OPEN ts mode -> ts
|
||||||
strlen message -> msg_length
|
strlen message -> msg_length
|
||||||
syscall WRITE term message msg_length
|
syscall WRITE ts message msg_length
|
||||||
load_address new_line -> nl
|
load_immediate new_line -> nl
|
||||||
strlen nl -> nl_length
|
strlen nl -> nl_length
|
||||||
syscall WRITE term nl nl_length
|
syscall WRITE ts nl nl_length
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue