Add web version
This commit is contained in:
parent
0449d9b84e
commit
95f3e0aeed
|
|
@ -1 +1,63 @@
|
||||||
// wip
|
#include "../../libc.h"
|
||||||
|
#include "../../compiler.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <emscripten.h>
|
||||||
|
|
||||||
|
#define MEM_SIZE (1 << 16)
|
||||||
|
|
||||||
|
static size_t List_size(List *list) {
|
||||||
|
size_t total = 0;
|
||||||
|
Node *curr = list->head;
|
||||||
|
while (curr) {
|
||||||
|
total += curr->size;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list2buffer(List *list, char *buffer, size_t *offset) {
|
||||||
|
Node *curr = list->head;
|
||||||
|
while (curr) {
|
||||||
|
char *tmp_str = node_value(curr);
|
||||||
|
memcpy(buffer + *offset, tmp_str, curr->size);
|
||||||
|
*offset += curr->size;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
char *undar_compile(int emitter_type, char *source) {
|
||||||
|
Emitter e;
|
||||||
|
if (emitter_type == 0) {
|
||||||
|
e = rer_emitter();
|
||||||
|
} else if (emitter_type == 1) {
|
||||||
|
e = uxn_emitter();
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 tape[MEM_SIZE];
|
||||||
|
Arena a = {tape, 0, MEM_SIZE};
|
||||||
|
|
||||||
|
List *code = List_init(&a);
|
||||||
|
List *memory = List_init(&a);
|
||||||
|
|
||||||
|
compile(&a, code, memory, e, source);
|
||||||
|
|
||||||
|
size_t code_size = List_size(code);
|
||||||
|
size_t mem_size = List_size(memory);
|
||||||
|
size_t total_size = code_size + mem_size + 1;
|
||||||
|
|
||||||
|
char *result = (char *)malloc(total_size);
|
||||||
|
if (result == NULL) return NULL;
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
list2buffer(code, result, &offset);
|
||||||
|
list2buffer(memory, result, &offset);
|
||||||
|
result[offset] = '\0';
|
||||||
|
|
||||||
|
afree(&a);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
8
build
8
build
|
|
@ -93,7 +93,13 @@ case $ARCH in
|
||||||
BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c emit/rer/emit.c emit/uxn/emit.c $LINK_FLAGS $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/compiler.o $BUILD_DIR/strbuf.o $BUILD_FLAGS $LINK_FLAGS"
|
BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c emit/rer/emit.c emit/uxn/emit.c $LINK_FLAGS $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/compiler.o $BUILD_DIR/strbuf.o $BUILD_FLAGS $LINK_FLAGS"
|
||||||
;;
|
;;
|
||||||
"web")
|
"web")
|
||||||
BUILD_CMD="$CC $SRC_DIR/main.c emit/rer/emit.c emit/uxn/emit.c $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/compiler.o -o $BUILD_DIR/undar.html $BUILD_FLAGS $LINK_FLAGS"
|
WEB_BUILD_FLAGS="-O3 -s STACK_SIZE=1048576"
|
||||||
|
|
||||||
|
WEB_EXPORTS="-s EXPORTED_FUNCTIONS=[\"_undar_compile\",\"_malloc\",\"_free\"] -s EXPORTED_RUNTIME_METHODS=[\"cwrap\"]"
|
||||||
|
|
||||||
|
BUILD_CMD="$CC $SRC_DIR/main.c emit/rer/emit.c emit/uxn/emit.c $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/compiler.o $BUILD_DIR/strbuf.o -o $BUILD_DIR/undar.js $WEB_BUILD_FLAGS $WEB_EXPORTS"
|
||||||
|
|
||||||
|
cp ./tools/index.html $BUILD_DIR/
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
||||||
72
compiler.c
72
compiler.c
|
|
@ -15,7 +15,7 @@ List *memory;
|
||||||
* Scope
|
* Scope
|
||||||
***************************************************/
|
***************************************************/
|
||||||
void
|
void
|
||||||
scopes_init()
|
scopes_init(void)
|
||||||
{
|
{
|
||||||
Scope *current;
|
Scope *current;
|
||||||
Scope child = {0};
|
Scope child = {0};
|
||||||
|
|
@ -27,7 +27,7 @@ scopes_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope *
|
Scope *
|
||||||
scope_new()
|
scope_new(void)
|
||||||
{
|
{
|
||||||
Scope *current;
|
Scope *current;
|
||||||
Scope child = {0};
|
Scope child = {0};
|
||||||
|
|
@ -43,7 +43,7 @@ scope_new()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scope_pop()
|
scope_pop(void)
|
||||||
{
|
{
|
||||||
if(parser.current_scope) {
|
if(parser.current_scope) {
|
||||||
parser.current_scope = parser.current_scope->parent;
|
parser.current_scope = parser.current_scope->parent;
|
||||||
|
|
@ -52,7 +52,7 @@ scope_pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scope_push()
|
scope_push(void)
|
||||||
{
|
{
|
||||||
Scope *scope = List_get(parser.scopes, parser.scope_idx);
|
Scope *scope = List_get(parser.scopes, parser.scope_idx);
|
||||||
parser.current_scope = scope;
|
parser.current_scope = scope;
|
||||||
|
|
@ -109,13 +109,13 @@ scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_global()
|
is_global(void)
|
||||||
{
|
{
|
||||||
return parser.current_scope != nil && parser.current_scope->parent == nil;
|
return parser.current_scope != nil && parser.current_scope->parent == nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_type()
|
is_type(void)
|
||||||
{
|
{
|
||||||
return parser.previous.type >= TOKEN_TYPE_I8 &&
|
return parser.previous.type >= TOKEN_TYPE_I8 &&
|
||||||
parser.previous.type <= TOKEN_TYPE_PTR;
|
parser.previous.type <= TOKEN_TYPE_PTR;
|
||||||
|
|
@ -156,7 +156,7 @@ token_type_to_sym_type(TokenType t)
|
||||||
***************************************************/
|
***************************************************/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
advance()
|
advance(void)
|
||||||
{
|
{
|
||||||
parser.previous = parser.current;
|
parser.previous = parser.current;
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ check(TokenType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
consume_is_type()
|
consume_is_type(void)
|
||||||
{
|
{
|
||||||
if(is_type()) {
|
if(is_type()) {
|
||||||
advance();
|
advance();
|
||||||
|
|
@ -215,17 +215,17 @@ expect(TokenType type)
|
||||||
u32 variable_declaration(Symbol *def);
|
u32 variable_declaration(Symbol *def);
|
||||||
|
|
||||||
void
|
void
|
||||||
define_plex()
|
define_plex(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
define_trait()
|
define_trait(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
define_function()
|
define_function(void)
|
||||||
{
|
{
|
||||||
Symbol *fn;
|
Symbol *fn;
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
|
|
@ -298,7 +298,7 @@ calculate_strides(List *dims, List *strides)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
define_array()
|
define_array(void)
|
||||||
{
|
{
|
||||||
i32 size = 0, n = 0, flat_array_length = 1;
|
i32 size = 0, n = 0, flat_array_length = 1;
|
||||||
TokenType tt = parser.previous.type;
|
TokenType tt = parser.previous.type;
|
||||||
|
|
@ -365,9 +365,9 @@ build_symbol_table(char *source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void expression();
|
void expression(void);
|
||||||
void statement();
|
void statement(void);
|
||||||
void declaration();
|
void declaration(void);
|
||||||
ParseRule *get_rule(TokenType type);
|
ParseRule *get_rule(TokenType type);
|
||||||
void parse_precedence(Precedence precedence);
|
void parse_precedence(Precedence precedence);
|
||||||
|
|
||||||
|
|
@ -459,7 +459,7 @@ variable_declaration(Symbol *def)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
binary()
|
binary(void)
|
||||||
{
|
{
|
||||||
TokenType operatorType = parser.previous.type;
|
TokenType operatorType = parser.previous.type;
|
||||||
ParseRule *rule = get_rule(operatorType);
|
ParseRule *rule = get_rule(operatorType);
|
||||||
|
|
@ -521,7 +521,7 @@ binary()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
literal()
|
literal(void)
|
||||||
{
|
{
|
||||||
switch(parser.previous.type) {
|
switch(parser.previous.type) {
|
||||||
case TOKEN_KEYWORD_FALSE:
|
case TOKEN_KEYWORD_FALSE:
|
||||||
|
|
@ -539,13 +539,13 @@ literal()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
expression()
|
expression(void)
|
||||||
{
|
{
|
||||||
parse_precedence(PREC_ASSIGNMENT);
|
parse_precedence(PREC_ASSIGNMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
variable()
|
variable(void)
|
||||||
{
|
{
|
||||||
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
|
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
|
||||||
parser.previous.length);
|
parser.previous.length);
|
||||||
|
|
@ -594,7 +594,7 @@ variable()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cast_type()
|
cast_type(void)
|
||||||
{
|
{
|
||||||
SymbolType st = parser.current_type;
|
SymbolType st = parser.current_type;
|
||||||
TokenType cast_type;
|
TokenType cast_type;
|
||||||
|
|
@ -691,7 +691,7 @@ cast_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
declaration()
|
declaration(void)
|
||||||
{
|
{
|
||||||
if(is_type() && (parser.current.type == TOKEN_IDENTIFIER || parser.current.type == TOKEN_LBRACKET) )
|
if(is_type() && (parser.current.type == TOKEN_IDENTIFIER || parser.current.type == TOKEN_LBRACKET) )
|
||||||
variable_declaration(nil);
|
variable_declaration(nil);
|
||||||
|
|
@ -700,7 +700,7 @@ declaration()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
print_statement()
|
print_statement(void)
|
||||||
{
|
{
|
||||||
expression();
|
expression();
|
||||||
consume(TOKEN_SEMICOLON);
|
consume(TOKEN_SEMICOLON);
|
||||||
|
|
@ -709,7 +709,7 @@ print_statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
if_statement()
|
if_statement(void)
|
||||||
{
|
{
|
||||||
consume(TOKEN_LPAREN);
|
consume(TOKEN_LPAREN);
|
||||||
expression();
|
expression();
|
||||||
|
|
@ -727,7 +727,7 @@ if_statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
while_statement()
|
while_statement(void)
|
||||||
{
|
{
|
||||||
u32 this_while = emitter.loops++;
|
u32 this_while = emitter.loops++;
|
||||||
emitter.emit_while(arena, code, this_while);
|
emitter.emit_while(arena, code, this_while);
|
||||||
|
|
@ -740,7 +740,7 @@ while_statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
block()
|
block(void)
|
||||||
{
|
{
|
||||||
while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) declaration();
|
while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) declaration();
|
||||||
|
|
||||||
|
|
@ -748,7 +748,7 @@ block()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
function()
|
function(void)
|
||||||
{
|
{
|
||||||
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
|
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
|
||||||
parser.previous.length);
|
parser.previous.length);
|
||||||
|
|
@ -762,7 +762,7 @@ function()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
call()
|
call(void)
|
||||||
{
|
{
|
||||||
if(!check(TOKEN_RPAREN)) {
|
if(!check(TOKEN_RPAREN)) {
|
||||||
do {
|
do {
|
||||||
|
|
@ -777,7 +777,7 @@ call()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
return_statement()
|
return_statement(void)
|
||||||
{
|
{
|
||||||
if(match(TOKEN_SEMICOLON)) {
|
if(match(TOKEN_SEMICOLON)) {
|
||||||
emitter.emit_early_return(arena, code);
|
emitter.emit_early_return(arena, code);
|
||||||
|
|
@ -789,7 +789,7 @@ return_statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
statement()
|
statement(void)
|
||||||
{
|
{
|
||||||
if(match(TOKEN_LBRACE)) {
|
if(match(TOKEN_LBRACE)) {
|
||||||
scope_push();
|
scope_push();
|
||||||
|
|
@ -814,7 +814,7 @@ statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
grouping()
|
grouping(void)
|
||||||
{
|
{
|
||||||
emitter.emit_open_paren(arena, code);
|
emitter.emit_open_paren(arena, code);
|
||||||
|
|
||||||
|
|
@ -825,25 +825,25 @@ grouping()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
number()
|
number(void)
|
||||||
{
|
{
|
||||||
emitter.emit_int(arena, code, parser.previous.start, parser.previous.length);
|
emitter.emit_int(arena, code, parser.previous.start, parser.previous.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
string()
|
string(void)
|
||||||
{
|
{
|
||||||
emitter.emit_str(arena, code, parser.previous.start, parser.previous.length);
|
emitter.emit_str(arena, code, parser.previous.start, parser.previous.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
character()
|
character(void)
|
||||||
{
|
{
|
||||||
emitter.emit_char(arena, code, parser.previous.start, parser.previous.length);
|
emitter.emit_char(arena, code, parser.previous.start, parser.previous.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
unary()
|
unary(void)
|
||||||
{
|
{
|
||||||
TokenType operatorType = parser.previous.type;
|
TokenType operatorType = parser.previous.type;
|
||||||
parse_precedence(PREC_UNARY);
|
parse_precedence(PREC_UNARY);
|
||||||
|
|
@ -861,13 +861,13 @@ unary()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
read()
|
read(void)
|
||||||
{
|
{
|
||||||
emitter.emit_read(arena, code);
|
emitter.emit_read(arena, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
write()
|
write(void)
|
||||||
{
|
{
|
||||||
consume(TOKEN_EQ);
|
consume(TOKEN_EQ);
|
||||||
advance();
|
advance();
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ typedef enum {
|
||||||
PREC_PRIMARY
|
PREC_PRIMARY
|
||||||
} Precedence;
|
} Precedence;
|
||||||
|
|
||||||
typedef void (*ParseFn)();
|
typedef void (*ParseFn)(void);
|
||||||
|
|
||||||
struct parse_rule_s {
|
struct parse_rule_s {
|
||||||
ParseFn prefix;
|
ParseFn prefix;
|
||||||
|
|
|
||||||
4
emit.h
4
emit.h
|
|
@ -109,7 +109,7 @@ struct emitter_s {
|
||||||
StrArgEmit emit_char;
|
StrArgEmit emit_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
Emitter rer_emitter();
|
Emitter rer_emitter(void);
|
||||||
Emitter uxn_emitter();
|
Emitter uxn_emitter(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
22
lexer.c
22
lexer.c
|
|
@ -30,26 +30,26 @@ is_digit(char c)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_at_end()
|
is_at_end(void)
|
||||||
{
|
{
|
||||||
return *lexer.current == '\0';
|
return *lexer.current == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static char
|
static char
|
||||||
advance()
|
advance(void)
|
||||||
{
|
{
|
||||||
lexer.current++;
|
lexer.current++;
|
||||||
return lexer.current[-1];
|
return lexer.current[-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
char
|
char
|
||||||
peek()
|
peek(void)
|
||||||
{
|
{
|
||||||
return *lexer.current;
|
return *lexer.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char
|
static char
|
||||||
peek_next()
|
peek_next(void)
|
||||||
{
|
{
|
||||||
if(is_at_end()) return '\0';
|
if(is_at_end()) return '\0';
|
||||||
return lexer.current[1];
|
return lexer.current[1];
|
||||||
|
|
@ -87,7 +87,7 @@ error_token(const char *message)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
skip_whitespace()
|
skip_whitespace(void)
|
||||||
{
|
{
|
||||||
for(;;) {
|
for(;;) {
|
||||||
char c = peek();
|
char c = peek();
|
||||||
|
|
@ -140,7 +140,7 @@ check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
static TokenType
|
static TokenType
|
||||||
identifierType()
|
identifierType(void)
|
||||||
{
|
{
|
||||||
switch(lexer.start[0]) {
|
switch(lexer.start[0]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
|
|
@ -343,14 +343,14 @@ identifierType()
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token
|
static Token
|
||||||
identifier()
|
identifier(void)
|
||||||
{
|
{
|
||||||
while(is_alpha(peek()) || is_digit(peek())) advance();
|
while(is_alpha(peek()) || is_digit(peek())) advance();
|
||||||
return make_token(identifierType());
|
return make_token(identifierType());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token
|
static Token
|
||||||
number()
|
number(void)
|
||||||
{
|
{
|
||||||
while(is_digit(peek())) advance();
|
while(is_digit(peek())) advance();
|
||||||
|
|
||||||
|
|
@ -368,7 +368,7 @@ number()
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token
|
static Token
|
||||||
string()
|
string(void)
|
||||||
{
|
{
|
||||||
while(peek() != '"' && !is_at_end()) {
|
while(peek() != '"' && !is_at_end()) {
|
||||||
if(peek() == '\n') lexer.line++;
|
if(peek() == '\n') lexer.line++;
|
||||||
|
|
@ -383,7 +383,7 @@ string()
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token
|
static Token
|
||||||
character()
|
character(void)
|
||||||
{
|
{
|
||||||
advance();
|
advance();
|
||||||
if(peek() != '\'' && !is_at_end()) {
|
if(peek() != '\'' && !is_at_end()) {
|
||||||
|
|
@ -398,7 +398,7 @@ character()
|
||||||
}
|
}
|
||||||
|
|
||||||
Token
|
Token
|
||||||
next_token()
|
next_token(void)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
char next;
|
char next;
|
||||||
|
|
|
||||||
4
lexer.h
4
lexer.h
|
|
@ -101,8 +101,8 @@ struct token_s {
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_lexer(const char *source);
|
void init_lexer(const char *source);
|
||||||
Token next_token();
|
Token next_token(void);
|
||||||
const char *token_type_to_string(TokenType type);
|
const char *token_type_to_string(TokenType type);
|
||||||
char peek();
|
char peek(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
4
libc.c
4
libc.c
|
|
@ -367,7 +367,7 @@ stoi(const char *str, u32 length)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (is_digit(*str) && length-- > 0) {
|
while (is_digit(*str) && length-- > 0) {
|
||||||
int digit = *str++ - '0';
|
i32 digit = *str++ - '0';
|
||||||
|
|
||||||
if (neg) {
|
if (neg) {
|
||||||
if (n < (I32_MIN / 10) || (n == (I32_MIN / 10) && digit > -(I32_MIN % 10))) {
|
if (n < (I32_MIN / 10) || (n == (I32_MIN / 10) && digit > -(I32_MIN % 10))) {
|
||||||
|
|
@ -396,7 +396,7 @@ ston(const char *str, u32 length)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (is_digit(*str) && length-- > 0) {
|
while (is_digit(*str) && length-- > 0) {
|
||||||
int digit = *str++ - '0';
|
u32 digit = *str++ - '0';
|
||||||
|
|
||||||
if (n > (U32_MAX / 10) || (n == (U32_MAX / 10) && digit > (U32_MAX % 10))) {
|
if (n > (U32_MAX / 10) || (n == (U32_MAX / 10) && digit > (U32_MAX % 10))) {
|
||||||
return U32_MAX;
|
return U32_MAX;
|
||||||
|
|
|
||||||
9
libc.h
9
libc.h
|
|
@ -5,9 +5,6 @@
|
||||||
#if __has_include(<stdint.h>)
|
#if __has_include(<stdint.h>)
|
||||||
#define HAVE_STDINT 1
|
#define HAVE_STDINT 1
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<stdbool.h>)
|
|
||||||
#define HAVE_STDBOOL 1
|
|
||||||
#endif
|
|
||||||
#if __has_include(<stddef.h>)
|
#if __has_include(<stddef.h>)
|
||||||
#define HAVE_STDDEF 1
|
#define HAVE_STDDEF 1
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -34,13 +31,9 @@ typedef signed int r32;
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STDBOOL
|
|
||||||
#include <stdbool.h>
|
|
||||||
#else
|
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
typedef u8 bool;
|
typedef u8 bool;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_STDDEF
|
#ifdef HAVE_STDDEF
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
@ -59,7 +52,7 @@ typedef u8 bool;
|
||||||
|
|
||||||
#define I32_MIN -2147483647
|
#define I32_MIN -2147483647
|
||||||
#define I32_MAX 2147483647
|
#define I32_MAX 2147483647
|
||||||
#define U32_MAX 4294967295
|
#define U32_MAX 4294967295UL
|
||||||
|
|
||||||
#define FIXED_CONST 65536.0f
|
#define FIXED_CONST 65536.0f
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Undâr Compiler</title>
|
||||||
|
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet" type="text/css" />
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.2/ace.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.2/mode-java.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.2/mode-forth.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.2/theme-one_dark.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-base-100 text-base-content">
|
||||||
|
|
||||||
|
<div class="navbar bg-base-300 shadow-lg">
|
||||||
|
<div class="flex-1">
|
||||||
|
<span class="text-xl font-bold px-4">Undâr Compiler</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex-none gap-2 px-4">
|
||||||
|
<select id="emitter" class="select select-bordered w-full max-w-xs">
|
||||||
|
<option value="1">Uxntal Emitter</option>
|
||||||
|
<option value="0" disabled>Reality Engine Emitter</option>
|
||||||
|
</select>
|
||||||
|
<button id="compile-btn" class="btn btn-primary" disabled>
|
||||||
|
<span id="btn-text">Loading...</span>
|
||||||
|
<span id="btn-loading" class="loading loading-spinner loading-sm hidden"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container mx-auto p-4">
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 h-[calc(100vh-100px)]">
|
||||||
|
<div class="card bg-base-200 shadow-xl flex flex-col">
|
||||||
|
<div class="card-title p-4 pb-0">Source</div>
|
||||||
|
<div class="card-body flex-1 p-4 pt-2">
|
||||||
|
<div id="input" class="w-full h-full rounded-lg overflow-hidden border border-base-300"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card bg-base-200 shadow-xl flex flex-col">
|
||||||
|
<div class="card-title p-4 pb-0">Output</div>
|
||||||
|
<div class="card-body flex-1 p-4 pt-2">
|
||||||
|
<div id="output" class="w-full h-full rounded-lg overflow-hidden border border-base-300"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var inputEditor;
|
||||||
|
var outputEditor;
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
onRuntimeInitialized: function() {
|
||||||
|
const emitterEl = document.getElementById('emitter');
|
||||||
|
const compileBtn = document.getElementById('compile-btn');
|
||||||
|
const btnText = document.getElementById('btn-text');
|
||||||
|
const btnLoading = document.getElementById('btn-loading');
|
||||||
|
|
||||||
|
inputEditor = ace.edit("input");
|
||||||
|
inputEditor.session.setMode("ace/mode/java");
|
||||||
|
inputEditor.setTheme("ace/theme/one_dark");
|
||||||
|
inputEditor.setOptions({ fontSize: "14px" });
|
||||||
|
|
||||||
|
outputEditor = ace.edit("output");
|
||||||
|
outputEditor.session.setMode("ace/mode/forth");
|
||||||
|
outputEditor.setTheme("ace/theme/one_dark");
|
||||||
|
outputEditor.setReadOnly(true);
|
||||||
|
outputEditor.setOptions({ fontSize: "14px" });
|
||||||
|
|
||||||
|
btnText.innerText = "Compile";
|
||||||
|
compileBtn.disabled = false;
|
||||||
|
|
||||||
|
const compile = Module.cwrap('undar_compile', 'string', ['number', 'string']);
|
||||||
|
|
||||||
|
compileBtn.addEventListener('click', function() {
|
||||||
|
const sourceCode = inputEditor.getValue();
|
||||||
|
const emitterType = parseInt(emitterEl.value, 10);
|
||||||
|
|
||||||
|
btnText.classList.add("hidden");
|
||||||
|
btnLoading.classList.remove("hidden");
|
||||||
|
compileBtn.disabled = true;
|
||||||
|
outputEditor.setValue("Compiling...", -1);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
const result = compile(emitterType, sourceCode);
|
||||||
|
outputEditor.setValue((result === null) ? "Compilation Error" : result, -1);
|
||||||
|
} catch (e) {
|
||||||
|
outputEditor.setValue("WASM Runtime Error:\n" + e.message, -1);
|
||||||
|
} finally {
|
||||||
|
btnLoading.classList.add("hidden");
|
||||||
|
btnText.classList.remove("hidden");
|
||||||
|
compileBtn.disabled = false;
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script src="undar.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue