Add new IR language, update docs
This commit is contained in:
parent
5d2aa1ad22
commit
1311659bed
12
Makefile
12
Makefile
|
|
@ -86,17 +86,13 @@ VM_SOURCES := \
|
|||
ifeq ($(BUILD_MODE), release)
|
||||
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
|
||||
$(ARCH_DIR)/devices.c\
|
||||
$(SRC_DIR)/tools/parser.c \
|
||||
$(SRC_DIR)/tools/lexer.c \
|
||||
$(SRC_DIR)/tools/assembler.c\
|
||||
$(SRC_DIR)/tools/compiler.c
|
||||
$(SRC_DIR)/tools/assembler/parser.c \
|
||||
$(SRC_DIR)/tools/assembler/assembler.c
|
||||
else
|
||||
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
|
||||
$(ARCH_DIR)/devices.c \
|
||||
$(SRC_DIR)/tools/parser.c \
|
||||
$(SRC_DIR)/tools/lexer.c \
|
||||
$(SRC_DIR)/tools/assembler.c\
|
||||
$(SRC_DIR)/tools/compiler.c
|
||||
$(SRC_DIR)/tools/assembler/parser.c \
|
||||
$(SRC_DIR)/tools/assembler/assembler.c
|
||||
endif
|
||||
|
||||
# --- OBJECT FILES ---
|
||||
|
|
|
|||
102
README.org
102
README.org
|
|
@ -49,25 +49,35 @@ git clone https://git.alfrescocavern.com/zongor/undar-lang.git
|
|||
cd undar-lang && make
|
||||
#+END_SRC
|
||||
|
||||
=Sċieppan= is a minimal assembler that uses s-expressions.
|
||||
You can view some examples in the =.asm.lisp= files in =/test=
|
||||
The Undâr compiler will be written in Sċieppan, as well as core VM tests.
|
||||
=Sċieppan= is a intermediate representation.
|
||||
You can view some examples in the =.ul.ir= files in =/test=
|
||||
|
||||
**Sample Program: =hello.asm.lisp=**
|
||||
**Sample Program: =hello.ul.ir=**
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
((code
|
||||
(label main
|
||||
(ldi $0 &terminal-namespace) ; get terminal device
|
||||
(ldi $1 0)
|
||||
(syscall OPEN $0 $0 $1)
|
||||
(ldi $1 &hello-str) ; load hello string ptr
|
||||
(strlen $2 $1)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(halt 0)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
(label hello-str "nuqneH 'u'?\n")))
|
||||
#+BEGIN_SRC sh
|
||||
function main ()
|
||||
str hello is $0
|
||||
|
||||
load_heap_immediate "nuqneH 'u'?" -> hello
|
||||
call pln hello
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
int mode is $5
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> ts # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
return
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
|
|
@ -82,33 +92,43 @@ memory is managed via frame based arenas. function scopes defines a memory frame
|
|||
|
||||
heap allocations using the internal malloc opcode push pointers within this frame. when a frame exits, the pointer is reset like stack based gc.
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
((code
|
||||
(label main
|
||||
(ldi $0 &terminal-namespace) ; get terminal device
|
||||
(ldi $11 0)
|
||||
(syscall OPEN $0 $0 $11)
|
||||
#+BEGIN_SRC sh
|
||||
function main ()
|
||||
int mode is $11
|
||||
str term is $10
|
||||
|
||||
(ldi $1 &help) ; print help message
|
||||
(fcall &pln ($0 $1) nil)
|
||||
load_heap_immediate "/dev/term/0" -> term
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN term mode -> term # Terminal term = open("/dev/term/0", 0);
|
||||
|
||||
(ldi $1 32) ; read in a string of max 32 char length
|
||||
(malloc $4 $1) ; allocate memory for the string
|
||||
(syscall READ $0 $4 $1) ; read the string
|
||||
load_heap_immediate "Enter a string:" -> $7
|
||||
string_length $7 -> $8
|
||||
syscall WRITE term $7 $8 # print prompt
|
||||
|
||||
str user_string is $9
|
||||
load_immediate 32 -> $8
|
||||
malloc $8 -> user_string
|
||||
syscall READ term user_string $8 # read in max 32 byte string
|
||||
|
||||
call pln user_string
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int mode is $5
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> ts
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts # get terminal device
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
|
||||
(fcall &pln ($0 $4) nil) ; print the string
|
||||
(halt))
|
||||
(label pln
|
||||
(ldi $3 &new-line)
|
||||
(strlen $2 $1)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(strlen $4 $3)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return nil)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
(label help "Enter a string: ")
|
||||
(label new-line "\n")))
|
||||
#+END_SRC
|
||||
|
||||
values passed to functions must be explicitly returned to propagate. heap values are copy on write, so if a value is modified in a child function it will change the parents value, unless the size of the structure changes then it will copy the parents value and append it to its own frame with the modification. this allows for the low resource usage of a C but the convenience of a Java/Go without the garbage collection.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ function main(int argc, str[] argv) {
|
|||
}
|
||||
}
|
||||
|
||||
exits("Client Closed Successfully");
|
||||
exit(0);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ function main(int argc, str[] argv) {
|
|||
Player[] players = [Player("user", [0.0, 0.0, 0.0], RED)];
|
||||
while (running) {
|
||||
if (Client client = s.accept("players")) {
|
||||
if (Message message = client.get()) {
|
||||
if (Message message = client.read()) {
|
||||
if (message.t == "close") {
|
||||
client.close();
|
||||
running = false;
|
||||
|
|
@ -196,7 +196,7 @@ function main(int argc, str[] argv) {
|
|||
}
|
||||
}
|
||||
}
|
||||
exits(nil);
|
||||
exit(0);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "../../tools/assembler.h"
|
||||
#include "../../tools/compiler.h"
|
||||
#include "../../tools/parser.h"
|
||||
#include "../../tools/assembler/assembler.h"
|
||||
#include "../../tools/assembler/parser.h"
|
||||
#include "../../vm/vm.h"
|
||||
#include "devices.h"
|
||||
#include <SDL2/SDL.h>
|
||||
|
|
@ -146,19 +145,7 @@ bool compileAndSave(const char *source_file, const char *output_file, VM *vm) {
|
|||
source[read] = '\0';
|
||||
fclose(f);
|
||||
|
||||
initLexer(source);
|
||||
Token token;
|
||||
do {
|
||||
token = nextToken();
|
||||
if (token.type == TOKEN_ERROR) {
|
||||
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
|
||||
break; // Stop on error, or continue if you want to see more
|
||||
}
|
||||
if (token.type != TOKEN_EOF) {
|
||||
printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type),
|
||||
token.length, token.start);
|
||||
}
|
||||
} while (token.type != TOKEN_EOF);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef ASSEMBLER_H
|
||||
#define ASSEMBLER_H
|
||||
|
||||
#include "../vm/common.h"
|
||||
#include "../vm/vm.h"
|
||||
#include "../../vm/common.h"
|
||||
#include "../../vm/vm.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <string.h>
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
#include "compiler.h"
|
||||
#include "lexer.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//typedef struct {
|
||||
// Token current;
|
||||
// Token previous;
|
||||
// bool hadError;
|
||||
// bool panicMode;
|
||||
//} Parser;
|
||||
//
|
||||
//typedef enum {
|
||||
// PREC_NONE,
|
||||
// PREC_ASSIGNMENT, /* = */
|
||||
// PREC_OR, /* or */
|
||||
// PREC_AND, /* and */
|
||||
// PREC_EQUALITY, /* == != */
|
||||
// PREC_COMPARISON, /* < > <= >= */
|
||||
// PREC_TERM, /* + - */
|
||||
// PREC_FACTOR, /* * / */
|
||||
// PREC_UNARY, /* not */
|
||||
// PREC_CALL, /* . () */
|
||||
// PREC_PRIMARY
|
||||
//} Precedence;
|
||||
//
|
||||
//typedef void (*ParseFn)(char *program);
|
||||
//
|
||||
//typedef struct {
|
||||
// ParseFn prefix;
|
||||
// ParseFn infix;
|
||||
// Precedence precedence;
|
||||
//} ParseRule;
|
||||
//
|
||||
//typedef struct {
|
||||
// i8 rp; // Next free register
|
||||
//} Compiler;
|
||||
//
|
||||
//Parser parser;
|
||||
//
|
||||
//const char *internalErrorMsg =
|
||||
// "FLAGRANT COMPILER ERROR\n\nCompiler over.\nBug = Very Yes.";
|
||||
//
|
||||
//void errorAt(Token *token, const char *message) {
|
||||
// if (parser.panicMode)
|
||||
// return;
|
||||
// parser.panicMode = true;
|
||||
// fprintf(stderr, "[line %d] Error", token->line);
|
||||
//
|
||||
// if (token->type == TOKEN_EOF) {
|
||||
// fprintf(stderr, " at end");
|
||||
// } else if (token->type == TOKEN_ERROR) {
|
||||
// } else {
|
||||
// fprintf(stderr, " at '%.*s'", token->length, token->start);
|
||||
// }
|
||||
//
|
||||
// fprintf(stderr, ": %s\n", message);
|
||||
// parser.hadError = true;
|
||||
//}
|
||||
//
|
||||
//void error(const char *message) { errorAt(&parser.previous, message); }
|
||||
//
|
||||
//void errorAtCurrent(const char *message) { errorAt(&parser.current, message); }
|
||||
//
|
||||
//void advance() {
|
||||
// parser.previous = parser.current;
|
||||
//
|
||||
// for (;;) {
|
||||
// parser.current = nextToken();
|
||||
// if (parser.current.type != TOKEN_ERROR)
|
||||
// break;
|
||||
//
|
||||
// errorAtCurrent(parser.current.start);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void consume(TokenType type, const char *message) {
|
||||
// if (parser.current.type == type) {
|
||||
// advance();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// errorAtCurrent(message);
|
||||
//}
|
||||
//
|
||||
//static int allocateRegister(Compiler *c) {
|
||||
// char buffer[38];
|
||||
// if (c->rp > 28) {
|
||||
// sprintf(buffer, "Out of registers (used %d, max 28)", c->rp);
|
||||
// error(buffer);
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// return c->rp++;
|
||||
//}
|
||||
|
||||
//static void freeRegister(Compiler *c, u8 reg) {
|
||||
// if (reg == c->rp - 1) {
|
||||
// c->rp--;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
|
||||
//
|
||||
//void emit_u32(VM *vm, u32 value) {
|
||||
// write_u32(vm, code, vm->cp, value);
|
||||
// vm->cp += 4;
|
||||
//}
|
||||
//
|
||||
//void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
|
||||
//
|
||||
//static bool check(TokenType type) { return parser.current.type == type; }
|
||||
//
|
||||
//static bool match(TokenType type) {
|
||||
// if (!check(type))
|
||||
// return false;
|
||||
// advance();
|
||||
// return true;
|
||||
//}
|
||||
//
|
||||
//static void expression(Compiler *c, VM *vm) {
|
||||
// USED(c);
|
||||
// USED(vm);
|
||||
//}
|
||||
//
|
||||
//void number(Compiler *c, VM *vm) {
|
||||
// emit_opcode(vm, OP_LOAD_IMM);
|
||||
// int reg = allocateRegister(c);
|
||||
// if (reg < 0)
|
||||
// return;
|
||||
// emit_byte(vm, reg);
|
||||
//
|
||||
// switch (parser.previous.type) {
|
||||
// case TOKEN_INT_LITERAL: {
|
||||
// char *endptr;
|
||||
// i32 value = (i32)strtol(parser.previous.start, &endptr, 10);
|
||||
// emit_u32(vm, value);
|
||||
// return;
|
||||
// }
|
||||
// case TOKEN_UINT_LITERAL: {
|
||||
// long value = atol(parser.previous.start);
|
||||
// emit_u32(vm, value);
|
||||
// return;
|
||||
// }
|
||||
// case TOKEN_FLOAT_LITERAL: {
|
||||
// float value = atof(parser.previous.start);
|
||||
// fixed_t fvalue = float_to_fixed(value);
|
||||
// emit_u32(vm, fvalue);
|
||||
// return;
|
||||
// }
|
||||
// default:
|
||||
// return; // Unreachable.
|
||||
// }
|
||||
//
|
||||
// errorAtCurrent("Invalid number format");
|
||||
//}
|
||||
//
|
||||
//static void unary(Compiler *c, VM *vm) {
|
||||
// TokenType operatorType = parser.previous.type;
|
||||
//
|
||||
// // Compile the operand.
|
||||
// expression(c, vm);
|
||||
//
|
||||
// // Emit the operator instruction.
|
||||
// switch (operatorType) {
|
||||
// default:
|
||||
// return; // Unreachable.
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//static void emitHalt(Compiler *c, VM *vm) {
|
||||
// emit_opcode(vm, OP_HALT);
|
||||
// advance();
|
||||
// number(c, vm);
|
||||
//}
|
||||
//
|
||||
//static void endCompiler(Compiler *c, VM *vm) { emitHalt(c, vm); }
|
||||
//
|
||||
//static void grouping(Compiler *c, VM *vm) {
|
||||
// expression(c, vm);
|
||||
// consume(TOKEN_RPAREN, "Expect ')' after expression.");
|
||||
//}
|
||||
|
||||
bool compile(const char *source, VM *vm) {
|
||||
USED(source);
|
||||
USED(vm);
|
||||
//initLexer(source);
|
||||
//
|
||||
//parser.hadError = false;
|
||||
//parser.panicMode = false;
|
||||
//
|
||||
//Compiler compiler;
|
||||
//advance();
|
||||
//expression(&compiler, vm);
|
||||
//consume(TOKEN_EOF, "Expect end of expression.");
|
||||
//endCompiler(&compiler, vm);
|
||||
//
|
||||
//return parser.hadError;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef UNDAR_COMPILER_H
|
||||
#define UNDAR_COMPILER_H
|
||||
|
||||
#include "../vm/common.h"
|
||||
#include "../vm/vm.h"
|
||||
#include "../vm/fixed.h"
|
||||
#include "lexer.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct field_s {
|
||||
char* name; // "handle"
|
||||
TokenType type; // TOKEN_TYPE_NAT
|
||||
u32 offset; // 4 (for first field in heap object)
|
||||
u32 size; // 4 (bytes for nat)
|
||||
} Field;
|
||||
|
||||
typedef struct plex_def_s {
|
||||
char* name;
|
||||
u32 field_count;
|
||||
u32 logical_size; // Data size (e.g., 12 for Vec3)
|
||||
u32 physical_size; // Total allocation (logical + 4)
|
||||
Field *fields; // All offsets are PHYSICAL
|
||||
} PlexDef;
|
||||
|
||||
typedef struct array_def_s {
|
||||
TokenType type;
|
||||
u32 length;
|
||||
u32 logical_size; // length * element_size
|
||||
u32 physical_size; // logical_size + 4
|
||||
} ArrayDef;
|
||||
|
||||
bool compile(const char *source, VM *vm);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
global const int x = 1
|
||||
global const int y = 1
|
||||
|
||||
function main ()
|
||||
int a is $0
|
||||
int b is $1
|
||||
int ans is $2
|
||||
str ans_string is $3
|
||||
|
||||
load_absolute_32 &x -> a
|
||||
load_absolute_32 &y -> b
|
||||
call add a b -> ans
|
||||
int_to_string ans -> ans_string
|
||||
call pln ans_string
|
||||
exit 0
|
||||
|
||||
function add (int a is $0, int b is $1)
|
||||
int result is $2
|
||||
add_int a b -> result
|
||||
return result
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int mode is $5
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
|
||||
load_heap_immediate ts "/dev/term/0" # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
return
|
||||
BIN
test/fib.rom
BIN
test/fib.rom
Binary file not shown.
|
|
@ -0,0 +1,44 @@
|
|||
function main ()
|
||||
int n is $0
|
||||
int str_n is $1
|
||||
|
||||
load_immediate 35 -> n
|
||||
call fib n -> n
|
||||
int_to_string n -> str_n
|
||||
call pln str_nn
|
||||
exit 0
|
||||
|
||||
function fib (int n is $0)
|
||||
load_immediate 2 -> $1
|
||||
|
||||
jump_lt_int &base_case n $1
|
||||
|
||||
load_immediate 2 -> $3
|
||||
sub_int n $3 -> $4
|
||||
call fib $4 -> $5
|
||||
|
||||
load_immediate 1 -> $3
|
||||
sub_int n $3 -> $4
|
||||
call fib $4 -> $6
|
||||
|
||||
add_int $6 $5 -> $7
|
||||
return $7
|
||||
&base_case
|
||||
return n
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int mode is $5
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
|
||||
load_heap_immediate ts "/dev/term/0" # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
return
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
function main ()
|
||||
str hello is $0
|
||||
|
||||
load_heap_immediate "nuqneH 'u'?" -> hello
|
||||
call pln hello
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
int mode is $5
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> ts # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
return
|
||||
18
test/loop.ul
18
test/loop.ul
|
|
@ -1,8 +1,3 @@
|
|||
/**
|
||||
* Constants
|
||||
*/
|
||||
const str nl = "\n";
|
||||
|
||||
plex Terminal {
|
||||
nat handle;
|
||||
}
|
||||
|
|
@ -17,17 +12,20 @@ function main() {
|
|||
a = a + 5.0;
|
||||
}
|
||||
nat b = a as nat;
|
||||
pln(term, "Enter a string:");
|
||||
pln("Enter a string:");
|
||||
str user_string = term.read(32);
|
||||
pln(term, a.str);
|
||||
pln(term, b.str);
|
||||
pln(term, user_string);
|
||||
pln(a as str);
|
||||
pln(b as str);
|
||||
pln(user_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print with a newline
|
||||
*/
|
||||
function pln(Terminal term, str message) {
|
||||
function pln(str message) {
|
||||
const str nl = "\n";
|
||||
Terminal term = open("/dev/term/0", 0);
|
||||
write(term, message, message.length);
|
||||
write(term, nl, nl.length);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
function main ()
|
||||
real a is $0
|
||||
int i is $1
|
||||
int mode is $11
|
||||
str term is $10
|
||||
|
||||
load_immediate 5.0 -> a
|
||||
load_immediate 5000 -> i
|
||||
load_immediate 0 -> $2
|
||||
load_immediate -1 -> $3
|
||||
load_immediate 5.0 -> $5
|
||||
&loop_body
|
||||
add_real a $5 -> a
|
||||
add_int i $3 -> i
|
||||
jump_ge_int &loop_body i $2
|
||||
load_heap_immediate "/dev/term/0" -> term
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN term mode -> term # Terminal term = open("/dev/term/0", 0);
|
||||
|
||||
nat b is $1
|
||||
real_to_nat a -> b
|
||||
load_heap_immediate "Enter a string:" -> $7
|
||||
string_length $7 -> $8
|
||||
syscall WRITE term $7 $8 # print prompt
|
||||
|
||||
str user_string is $9
|
||||
load_immediate 32 -> $8
|
||||
malloc $8 -> user_string
|
||||
syscall READ term user_string $8 # read in max 32 byte string
|
||||
|
||||
call pln user_string
|
||||
nat_to_string b -> $4
|
||||
call pln $4
|
||||
real_to_string a -> $3
|
||||
call pln $3
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int mode is $5
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> ts
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts # get terminal device
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
return
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
function main ()
|
||||
int mode is $11
|
||||
str term is $10
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> term
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN term mode -> term # Terminal term = open("/dev/term/0", 0);
|
||||
|
||||
load_heap_immediate "Enter a string:" -> $7
|
||||
string_length $7 -> $8
|
||||
syscall WRITE term $7 $8 # print prompt
|
||||
|
||||
str user_string is $9
|
||||
load_immediate 32 -> $8
|
||||
malloc $8 -> user_string
|
||||
syscall READ term user_string $8 # read in max 32 byte string
|
||||
|
||||
call pln user_string
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str ts is $1
|
||||
int mode is $5
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> ts
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN ts mode -> ts # get terminal device
|
||||
strlen message -> msg_length
|
||||
syscall WRITE ts message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE ts nl nl_length
|
||||
|
|
@ -21,7 +21,7 @@ plex Screen implements Device {
|
|||
|
||||
draw() {
|
||||
unsafe {
|
||||
write(this, this.buffer, this.buffer_size);
|
||||
write(this, this.buffer, this.buffer.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
global const str screen_namespace = "/dev/screen/0"
|
||||
global const str mouse_namespace = "/dev/mouse/0"
|
||||
global const byte BLACK = 0
|
||||
global const byte WHITE = 255
|
||||
global const byte DARK_GRAY = 73
|
||||
global const byte GRAY = 146
|
||||
global const byte LIGHT_GRAY = 182
|
||||
global byte SELECTED_COLOR = 255
|
||||
|
||||
function main ()
|
||||
# Open screen
|
||||
plex screen is $0
|
||||
str screen_name is $18
|
||||
int mode is $11
|
||||
nat screen_buffer is $21
|
||||
|
||||
# use load immediate because it is a pointer to a string, not a value
|
||||
load_address &screen_namespace -> screen_name
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN screen_name mode -> screen # Screen screen = open("/dev/screen/0", 0);
|
||||
|
||||
nat width is $20
|
||||
nat size is $22
|
||||
load_offset_32 screen 8 -> width # load width
|
||||
load_offset_32 screen 12 -> size # load size
|
||||
load_immediate 16 -> $1 # offset for screen buffer
|
||||
add_nat screen $1 -> screen_buffer
|
||||
|
||||
# open mouse
|
||||
plex mouse is $15
|
||||
str mouse_name is $16
|
||||
load_address &mouse_namespace -> mouse_name
|
||||
syscall OPEN mouse_name mode -> mouse # Mouse mouse = open("/dev/mouse/0", 0);
|
||||
|
||||
byte color is $1
|
||||
nat x_pos is $12
|
||||
nat y_pos is $13
|
||||
|
||||
load_absolute_32 &BLACK -> color
|
||||
load_immediate 1 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
|
||||
load_absolute_32 &WHITE -> color
|
||||
load_immediate 21 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
|
||||
# screen.draw#
|
||||
syscall WRITE screen screen_buffer size
|
||||
|
||||
nat zero is $11
|
||||
|
||||
draw_loop:
|
||||
# load mouse click data
|
||||
syscall REFRESH mouse
|
||||
|
||||
byte left_down is $9
|
||||
load_offset_8 mouse 16 -> left_down # load btn1 pressed
|
||||
|
||||
jump_eq_nat &draw_loop left_down zero
|
||||
|
||||
nat mouse_x is $7
|
||||
nat mouse_y is $8
|
||||
load_offset_32 mouse 8 -> mouse_x # load x
|
||||
load_offset_32 mouse 12 -> mouse_y # load y
|
||||
|
||||
nat box_size is $14
|
||||
load_immediate 20 -> box_size
|
||||
|
||||
# first row
|
||||
load_absolute_32 &BLACK -> color
|
||||
load_immediate 1 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
||||
|
||||
|
||||
load_absolute_32 &WHITE -> color
|
||||
load_immediate 21 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
||||
|
||||
syscall WRITE screen screen_buffer size
|
||||
|
||||
byte selected_color is $25
|
||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
||||
|
||||
nat brush_size is $19
|
||||
load_immediate 5 -> brush_size
|
||||
|
||||
call &draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size
|
||||
|
||||
jump &draw_loop
|
||||
|
||||
# Flush and halt
|
||||
exit 0
|
||||
|
||||
function set_color_if_clicked (int click_x is $0, int click_y is $1,
|
||||
int box_x is $2, int box_y is $3, byte color is $4, int box_size is $5)
|
||||
|
||||
# Compute right
|
||||
int right_edge is $6
|
||||
add_int box_x box_size -> right_edge
|
||||
|
||||
# Compute bottom = box_y + box_size
|
||||
int bottom_edge is $7
|
||||
add_int box_y box_size -> bottom_edge
|
||||
|
||||
# Bounds check: x in [box_x, right] and y in [box_y, bottom]
|
||||
jump_lt_int &fail click_x box_x
|
||||
jump_ge_int &fail click_x right_edge
|
||||
jump_lt_int &fail click_y box_y
|
||||
jump_ge_int &fail click_y bottom_edge
|
||||
|
||||
store_absolute_8 &SELECTED_COLOR color
|
||||
|
||||
fail:
|
||||
return
|
||||
|
||||
function draw_outlined_swatch(nat base is $0,
|
||||
byte color is $1, int x is $2, int y is $3, int width is $4)
|
||||
|
||||
# Constants
|
||||
nat background_color is $5
|
||||
load_absolute_32 &GRAY -> background_color
|
||||
|
||||
byte selected_color is $10
|
||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
||||
|
||||
jump_eq_int &set_selected selected_color color
|
||||
jump &end_set_selected
|
||||
set_selected:
|
||||
load_absolute_32 &DARK_GRAY -> background_color
|
||||
end_set_selected:
|
||||
|
||||
nat outline_size is $6
|
||||
load_immediate 20 -> outline_size
|
||||
|
||||
nat fill_size is $7
|
||||
load_immediate 17 -> fill_size
|
||||
|
||||
nat offset is $8
|
||||
load_immediate 2 -> offset
|
||||
|
||||
call &draw_box base width background_color x y outline_size outline_size
|
||||
|
||||
add_int x offset -> $9 # x + 2
|
||||
add_int y offset -> $10 # y + 2
|
||||
|
||||
call &draw_box base width color $9 $10 fill_size fill_size
|
||||
|
||||
return
|
||||
|
||||
function draw_box (nat base is $0, nat screen_width is $1,
|
||||
byte color is $2, nat x_start is $3, nat y_start is $4, nat width is $5, nat height is $6)
|
||||
|
||||
# Compute start address: base + y*640 + x
|
||||
nat offset is $15
|
||||
mul_int y_start screen_width -> offset
|
||||
add_int offset x_start -> offset
|
||||
add_nat offset base -> offset
|
||||
nat fat_ptr_size is $25
|
||||
load_immediate 4 -> fat_ptr_size
|
||||
add_nat offset fat_ptr_size -> offset # need to add offset for fat pointer size
|
||||
|
||||
int i is $30
|
||||
load_immediate 1 -> i
|
||||
|
||||
int zero is $26
|
||||
load_immediate 0 -> zero
|
||||
|
||||
int row_end is $27
|
||||
nat pixel_ptr is $29
|
||||
|
||||
draw_box_outer:
|
||||
add_int offset width -> row_end # current + width
|
||||
register_move offset -> pixel_ptr # set pixel point
|
||||
memset_8 pixel_ptr color width # draw row
|
||||
add_int offset screen_width -> offset # next row += 640
|
||||
sub_int height i -> height # decrement row count
|
||||
jump_gt_int &draw_box_outer height zero
|
||||
return
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
global const str screen_namespace = "/dev/screen/0"
|
||||
global const str mouse_namespace = "/dev/mouse/0"
|
||||
global const byte BLACK = 0
|
||||
global const byte WHITE = 255
|
||||
global const byte DARK_GRAY = 73
|
||||
global const byte GRAY = 146
|
||||
global const byte LIGHT_GRAY = 182
|
||||
global byte SELECTED_COLOR = 255
|
||||
|
||||
function main ()
|
||||
# Open screen
|
||||
plex screen is $0
|
||||
str screen_name is $18
|
||||
int mode is $11
|
||||
nat screen_buffer is $21
|
||||
|
||||
# use load immediate because it is a pointer to a string, not a value
|
||||
load_address &screen_namespace -> screen_name
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN screen_name mode -> screen # Screen screen = open("/dev/screen/0", 0);
|
||||
|
||||
nat width is $20
|
||||
nat size is $22
|
||||
load_offset_32 screen 8 -> width # load width
|
||||
load_offset_32 screen 12 -> size # load size
|
||||
load_immediate 16 -> $1 # offset for screen buffer
|
||||
add_nat screen $1 -> screen_buffer
|
||||
|
||||
# open mouse
|
||||
plex mouse is $15
|
||||
str mouse_name is $16
|
||||
load_address &mouse_namespace -> mouse_name
|
||||
syscall OPEN mouse_name mode -> mouse # Mouse mouse = open("/dev/mouse/0", 0);
|
||||
|
||||
byte color is $1
|
||||
nat x_pos is $12
|
||||
nat y_pos is $13
|
||||
|
||||
load_absolute_32 &BLACK -> color
|
||||
load_immediate 1 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
|
||||
load_absolute_32 &WHITE -> color
|
||||
load_immediate 21 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
|
||||
# screen.draw#
|
||||
syscall WRITE screen screen_buffer size
|
||||
|
||||
nat zero is $11
|
||||
|
||||
draw_loop:
|
||||
# load mouse click data
|
||||
syscall REFRESH mouse
|
||||
|
||||
byte left_down is $9
|
||||
load_offset_8 mouse 16 -> left_down # load btn1 pressed
|
||||
|
||||
jump_eq_nat &draw_loop left_down zero
|
||||
|
||||
nat mouse_x is $7
|
||||
nat mouse_y is $8
|
||||
load_offset_32 mouse 8 -> mouse_x # load x
|
||||
load_offset_32 mouse 12 -> mouse_y # load y
|
||||
|
||||
nat box_size is $14
|
||||
load_immediate 20 -> box_size
|
||||
|
||||
# first row
|
||||
load_absolute_32 &BLACK -> color
|
||||
load_immediate 1 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
||||
|
||||
|
||||
load_absolute_32 &WHITE -> color
|
||||
load_immediate 21 -> x_pos
|
||||
load_immediate 1 -> y_pos
|
||||
call &draw_outlined_swatch screen_buffer color x_pos y_pos width
|
||||
call &set_color_if_clicked mouse_x mouse_y x_pos y_pos color box_size
|
||||
|
||||
syscall WRITE screen screen_buffer size
|
||||
|
||||
byte selected_color is $25
|
||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
||||
|
||||
nat brush_size is $19
|
||||
load_immediate 5 -> brush_size
|
||||
|
||||
call &draw_box screen_buffer width selected_color mouse_x mouse_y brush_size brush_size
|
||||
|
||||
jump &draw_loop
|
||||
|
||||
# Flush and halt
|
||||
exit 0
|
||||
|
||||
function set_color_if_clicked (int click_x is $0, int click_y is $1,
|
||||
int box_x is $2, int box_y is $3, byte color is $4, int box_size is $5)
|
||||
|
||||
# Compute right
|
||||
int right_edge is $6
|
||||
add_int box_x box_size -> right_edge
|
||||
|
||||
# Compute bottom = box_y + box_size
|
||||
int bottom_edge is $7
|
||||
add_int box_y box_size -> bottom_edge
|
||||
|
||||
# Bounds check: x in [box_x, right] and y in [box_y, bottom]
|
||||
jump_lt_int &fail click_x box_x
|
||||
jump_ge_int &fail click_x right_edge
|
||||
jump_lt_int &fail click_y box_y
|
||||
jump_ge_int &fail click_y bottom_edge
|
||||
|
||||
store_absolute_8 &SELECTED_COLOR color
|
||||
|
||||
fail:
|
||||
return
|
||||
|
||||
function draw_outlined_swatch(nat base is $0,
|
||||
byte color is $1, int x is $2, int y is $3, int width is $4)
|
||||
|
||||
# Constants
|
||||
nat background_color is $5
|
||||
load_absolute_32 &GRAY -> background_color
|
||||
|
||||
byte selected_color is $10
|
||||
load_absolute_32 &SELECTED_COLOR -> selected_color
|
||||
|
||||
jump_eq_int &set_selected selected_color color
|
||||
jump &end_set_selected
|
||||
set_selected:
|
||||
load_absolute_32 &DARK_GRAY -> background_color
|
||||
end_set_selected:
|
||||
|
||||
nat outline_size is $6
|
||||
load_immediate 20 -> outline_size
|
||||
|
||||
nat fill_size is $7
|
||||
load_immediate 17 -> fill_size
|
||||
|
||||
nat offset is $8
|
||||
load_immediate 2 -> offset
|
||||
|
||||
call &draw_box base width background_color x y outline_size outline_size
|
||||
|
||||
add_int x offset -> $9 # x + 2
|
||||
add_int y offset -> $10 # y + 2
|
||||
|
||||
call &draw_box base width color $9 $10 fill_size fill_size
|
||||
|
||||
return
|
||||
|
||||
function draw_box (nat base is $0, nat screen_width is $1,
|
||||
byte color is $2, nat x_start is $3, nat y_start is $4, nat width is $5, nat height is $6)
|
||||
|
||||
# Compute start address: base + y*640 + x
|
||||
nat offset is $15
|
||||
mul_int y_start screen_width -> offset
|
||||
add_int offset x_start -> offset
|
||||
add_nat offset base -> offset
|
||||
nat fat_ptr_size is $25
|
||||
load_immediate 4 -> fat_ptr_size
|
||||
add_nat offset fat_ptr_size -> offset # need to add offset for fat pointer size
|
||||
|
||||
int i is $30
|
||||
load_immediate 1 -> i
|
||||
|
||||
int zero is $26
|
||||
load_immediate 0 -> zero
|
||||
|
||||
int row_end is $27
|
||||
nat pixel_ptr is $29
|
||||
|
||||
draw_box_outer:
|
||||
add_int offset width -> row_end # current + width
|
||||
register_move offset -> pixel_ptr # set pixel point
|
||||
memset_8 pixel_ptr color width # draw row
|
||||
add_int offset screen_width -> offset # next row += 640
|
||||
sub_int height i -> height # decrement row count
|
||||
jump_gt_int &draw_box_outer height zero
|
||||
return
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
global const real x = 1.0
|
||||
global const real y = 1.0
|
||||
|
||||
function main ()
|
||||
real x is $0
|
||||
load_absolute_32 &x -> x
|
||||
real y is $1
|
||||
load_absolute_32 &y -> y
|
||||
real result is $2
|
||||
add_real x y -> result
|
||||
str result_str is $3
|
||||
real_to_string result -> result_str
|
||||
call &pln result_str
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str term is $1
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
int mode is $5
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> term # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN term mode -> term
|
||||
strlen message -> msg_length
|
||||
syscall WRITE term message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE term nl nl_length
|
||||
return
|
||||
|
|
@ -49,7 +49,7 @@ function main() {
|
|||
screen.draw();
|
||||
|
||||
loop {
|
||||
if (mouse.btn1) {
|
||||
if (mouse.left) {
|
||||
unsafe {
|
||||
screen.buffer[mouse.y * width + mouse.x +
|
||||
screen.buffer.ptr + 4] = WHITE;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
global const str screen_namespace = "/dev/screen/0"
|
||||
global const str mouse_namespace = "/dev/mouse/0"
|
||||
global const str terminal_namespace = "/dev/term/0"
|
||||
global const str new_line = "\n"
|
||||
global const byte WHITE = 255
|
||||
|
||||
function main ()
|
||||
# Open screen
|
||||
# use load immediate because it is a pointer to a string, not a value
|
||||
plex screen
|
||||
load_address &screen_namespace -> $18
|
||||
int mode is $11
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN $18 mode -> screen # openout Plex screen, in namespace, in flags
|
||||
|
||||
nat_to_string screen -> $5
|
||||
call &pln $5
|
||||
|
||||
nat width is $20
|
||||
load_offset_32 screen 8 -> width # load width
|
||||
nat_to_string width -> $5
|
||||
call &pln $5
|
||||
|
||||
nat buffer_size is $22
|
||||
load_offset_32 screen 12 -> buffer_size # load size
|
||||
nat_to_string buffer_size -> $5
|
||||
call &pln $5
|
||||
|
||||
nat screen_buffer is $21
|
||||
load_immediate $1 16 # offset for screen buffer
|
||||
add_nat screen $1 -> screen_buffer
|
||||
|
||||
nat_to_string screen_buffer -> $5
|
||||
call &pln $5
|
||||
|
||||
# open mouse
|
||||
plex mouse is $15
|
||||
load_address &mouse_namespace -> $16
|
||||
syscall OPEN $16 mode -> mouse # openout Plex mouse, in namespace, in flags
|
||||
|
||||
syscall WRITE screen screen_buffer buffer_size # redraw
|
||||
|
||||
draw_loop:
|
||||
# load mouse click data
|
||||
syscall STAT mouse
|
||||
|
||||
byte left_down is $9
|
||||
load_offset_8 mouse 16 -> left_down # load btn1 pressed
|
||||
|
||||
jump_eq_nat &draw_loop left_down mode # mode is 0 which is an alias for false
|
||||
|
||||
nat x is $7
|
||||
load_offset_32 mouse 8 -> x # load x
|
||||
nat y is $8
|
||||
load_offset_32 mouse 12 -> y # load y
|
||||
|
||||
# Compute start address: y*width + x
|
||||
nat pixel_pos is $30
|
||||
mul_nat y $20 -> pixel_pos # = y * width
|
||||
add_nat x pixel_pos -> pixel_pos # += x
|
||||
add_nat screen_buffer pixel_pos -> pixel_pos # += pixel_offset
|
||||
nat fat_ptr_size is $1
|
||||
load_immediate 4 -> fat_ptr_size # need to add offset for fat pointer size
|
||||
add_nat pixel_pos fat_ptr_size -> pixel_pos
|
||||
|
||||
byte color is $3
|
||||
load_absolute_32 &WHITE -> color
|
||||
store_absolute_8 pixel_pos color # draw color at screen [x,y]
|
||||
syscall WRITE screen screen_buffer buffer_size # redraw
|
||||
|
||||
jump &draw_loop
|
||||
exit 0
|
||||
|
||||
function pln (str message is $0)
|
||||
str term is $1
|
||||
int msg_length is $2
|
||||
str nl is $3
|
||||
int nl_length is $4
|
||||
int mode is $5
|
||||
|
||||
load_heap_immediate "/dev/term/0" -> term # get terminal device
|
||||
load_immediate 0 -> mode
|
||||
syscall OPEN term mode -> term
|
||||
strlen message -> msg_length
|
||||
syscall WRITE term message msg_length
|
||||
load_heap_immediate "\n" -> nl
|
||||
strlen nl -> nl_length
|
||||
syscall WRITE term nl nl_length
|
||||
return
|
||||
Loading…
Reference in New Issue