WIP: c emitter, uxn emitter, parser, compiler, examples, cleanup
This commit is contained in:
parent
8fd281e463
commit
b332ecf06d
|
|
@ -0,0 +1,53 @@
|
|||
#include "../../parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define EMBED_FILE(name) \
|
||||
void emit_##name(const char *filename) \
|
||||
{ \
|
||||
FILE *f = fopen(filename, "wb"); \
|
||||
if(f) { \
|
||||
fwrite(name, 1, name##_len, f); \
|
||||
fclose(f); \
|
||||
} \
|
||||
}
|
||||
|
||||
static char* readFile(const char* path) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Could not open file \"%s\".\n", path);
|
||||
exit(74);
|
||||
}
|
||||
|
||||
fseek(file, 0L, SEEK_END);
|
||||
size_t fileSize = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = (char*)malloc(fileSize + 1);
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, "Not enough memory to read \"%s\".\n", path);
|
||||
exit(74);
|
||||
}
|
||||
size_t bytesRead = fread(buffer, sizeof(char), fileSize, file);
|
||||
if (bytesRead < fileSize) {
|
||||
fprintf(stderr, "Could not read file \"%s\".\n", path);
|
||||
exit(74);
|
||||
}
|
||||
|
||||
buffer[bytesRead] = '\0';
|
||||
|
||||
fclose(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if(argc != 2) return EXIT_FAILURE;
|
||||
|
||||
char* source = readFile(argv[1]);
|
||||
compile(source);
|
||||
free(source);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
// wip
|
||||
51
build
51
build
|
|
@ -2,16 +2,32 @@
|
|||
|
||||
set -e
|
||||
|
||||
if [ -z $ARCH ]; then
|
||||
ARCH='linux'
|
||||
fi
|
||||
|
||||
if [ -z $MODE ]; then
|
||||
MODE='debug'
|
||||
fi
|
||||
|
||||
if [ -z $EMIT ]; then
|
||||
EMIT='c'
|
||||
fi
|
||||
|
||||
case $ARCH in
|
||||
"linux")
|
||||
if [ -z $CC ]; then
|
||||
CC='gcc'
|
||||
fi
|
||||
;;
|
||||
"web")
|
||||
CC=emcc
|
||||
;;
|
||||
esac
|
||||
|
||||
# setup dirs
|
||||
BUILD_DIR=./out
|
||||
SRC_DIR=./arch/$ARCH
|
||||
BUILD_DIR=./out/$EMIT/$ARCH
|
||||
GEN_DIR=$BUILD_DIR/gen
|
||||
TOOL_SRC=tools/file2header.c
|
||||
TOOL_EXE=$BUILD_DIR/file2header
|
||||
|
|
@ -47,20 +63,6 @@ if [ ! -f $TOOL_EXE ] || [ $TOOL_SRC -nt $TOOL_EXE ]; then
|
|||
$CC $TOOL_SRC -o $TOOL_EXE
|
||||
fi
|
||||
|
||||
if [ -d "arch" ]; then
|
||||
for file in arch/*.c; do
|
||||
name=$(basename "$file" .c)
|
||||
out_header="$GEN_DIR/${name}.h"
|
||||
|
||||
if [ ! -f "$out_header" ] || [ "$file" -nt "$out_header" ]; then
|
||||
echo "Packing $file -> $out_header"
|
||||
$TOOL_EXE "$file" > "$out_header"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Warning: 'arch' directory not found."
|
||||
fi
|
||||
|
||||
# setup the build flags based on the build mode
|
||||
case $MODE in
|
||||
"debug")
|
||||
|
|
@ -71,7 +73,24 @@ case $MODE in
|
|||
;;
|
||||
esac
|
||||
|
||||
BUILD_CMD="$CC -o $BUILD_DIR/undar main.c -I$GEN_DIR $BUILD_FLAGS"
|
||||
# build the core VM
|
||||
VM_BUILD_FLAGS="$BUILD_FLAGS -std=c89 -ffreestanding -nostdlib -fno-builtin"
|
||||
${CC} -c libc.c -o $BUILD_DIR/libc.o $VM_BUILD_FLAGS
|
||||
${CC} -c list.c -o $BUILD_DIR/list.o $VM_BUILD_FLAGS
|
||||
${CC} -c lexer.c -o $BUILD_DIR/lexer.o $VM_BUILD_FLAGS
|
||||
${CC} -c parser.c -o $BUILD_DIR/parser.o $VM_BUILD_FLAGS
|
||||
|
||||
#BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c libc.c list.c lexer.c parser.c -I$GEN_DIR $BUILD_FLAGS"
|
||||
|
||||
# Set up the final build command
|
||||
case $ARCH in
|
||||
"linux")
|
||||
BUILD_CMD="$CC -o $BUILD_DIR/undar $SRC_DIR/main.c emit/$EMIT/emit.c $LINK_FLAGS $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o $BUILD_FLAGS $LINK_FLAGS"
|
||||
;;
|
||||
"web")
|
||||
BUILD_CMD="$CC $SRC_DIR/main.c emit/$EMIT/emit.c $BUILD_DIR/libc.o $BUILD_DIR/list.o $BUILD_DIR/lexer.o $BUILD_DIR/parser.o -o $BUILD_DIR/undar.html $BUILD_FLAGS $LINK_FLAGS"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$BUILD_CMD"
|
||||
${BUILD_CMD}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef UNDAR_EMIT_H
|
||||
#define UNDAR_EMIT_H
|
||||
|
||||
#include "libc.h"
|
||||
|
||||
typedef enum expression_config_e {
|
||||
PREFIX,
|
||||
INFIX,
|
||||
POSTFIX
|
||||
} ExpressionConfig;
|
||||
|
||||
typedef enum output_config_e {
|
||||
BINARY,
|
||||
TEXT
|
||||
} OutputConfig;
|
||||
|
||||
ExpressionConfig expression_config();
|
||||
OutputConfig output_config();
|
||||
|
||||
/**
|
||||
* Prolog is for all of the "setup" boilerplate
|
||||
*/
|
||||
void prolog();
|
||||
|
||||
/**
|
||||
* Prolog is for all of the "cleanup" boilerplate
|
||||
*/
|
||||
void epilogue();
|
||||
|
||||
/**
|
||||
* Emitters
|
||||
*/
|
||||
void emit_add();
|
||||
void emit_sub();
|
||||
void emit_mul();
|
||||
void emit_div();
|
||||
void emit_lt();
|
||||
void emit_le();
|
||||
void emit_gt();
|
||||
void emit_ge();
|
||||
void emit_ne();
|
||||
void emit_eq();
|
||||
void emit_false();
|
||||
void emit_true();
|
||||
void emit_nil();
|
||||
void emit_void();
|
||||
void emit_int(const char *str, i32 length);
|
||||
void emit_nat(const char *str, i32 length);
|
||||
void emit_real(const char *str, i32 length);
|
||||
void emit_str(const char *str, i32 length);
|
||||
void emit_bool_type();
|
||||
void emit_byte_type();
|
||||
void emit_int_type();
|
||||
void emit_nat_type();
|
||||
void emit_real_type();
|
||||
void emit_str_type();
|
||||
void emit_u8_type();
|
||||
void emit_i8_type();
|
||||
void emit_i16_type();
|
||||
void emit_u16_type();
|
||||
void emit_i32_type();
|
||||
void emit_u32_type();
|
||||
void emit_f32_type();
|
||||
void emit_array();
|
||||
void emit_function();
|
||||
void emit_plex();
|
||||
void emit_method();
|
||||
void emit_trait();
|
||||
void emit_const();
|
||||
void emit_print();
|
||||
void emit_neg();
|
||||
void emit_not();
|
||||
void emit_open_paren();
|
||||
void emit_close_paren();
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
#include "../../emit.h"
|
||||
#include <stdio.h>
|
||||
|
||||
ExpressionConfig
|
||||
expression_config()
|
||||
{
|
||||
return INFIX;
|
||||
}
|
||||
|
||||
OutputConfig
|
||||
output_config()
|
||||
{
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
void
|
||||
prolog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
epilogue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
emit_add()
|
||||
{
|
||||
printf("+ ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_sub()
|
||||
{
|
||||
printf("- ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_mul()
|
||||
{
|
||||
printf("* ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_div()
|
||||
{
|
||||
printf("/ ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_lt()
|
||||
{
|
||||
printf("< ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_le()
|
||||
{
|
||||
printf("<= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_gt()
|
||||
{
|
||||
printf("> ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_ge()
|
||||
{
|
||||
printf(">= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_ne()
|
||||
{
|
||||
printf("!= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_eq()
|
||||
{
|
||||
printf("== ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_false()
|
||||
{
|
||||
printf("false ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_true()
|
||||
{
|
||||
printf("true ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_nil()
|
||||
{
|
||||
printf("NULL ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_neg()
|
||||
{
|
||||
printf("-");
|
||||
}
|
||||
|
||||
void
|
||||
emit_not()
|
||||
{
|
||||
printf("!");
|
||||
}
|
||||
|
||||
void
|
||||
emit_void()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_bool_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_byte_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_int_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_nat_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_real_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_str_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u8_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i8_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i16_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u16_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_f32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_int(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_nat(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_real(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_str(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_array()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_function()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_plex()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_method()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_trait()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_const()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_print()
|
||||
{
|
||||
printf("printf(\"%%s\", ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_open_paren()
|
||||
{
|
||||
printf("(");
|
||||
}
|
||||
|
||||
void
|
||||
emit_close_paren()
|
||||
{
|
||||
printf(")");
|
||||
}
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
#include "../../emit.h"
|
||||
#include <stdio.h>
|
||||
|
||||
ExpressionConfig
|
||||
expression_config()
|
||||
{
|
||||
return POSTFIX;
|
||||
}
|
||||
|
||||
OutputConfig
|
||||
output_config()
|
||||
{
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
void
|
||||
prolog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
epilogue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
emit_add()
|
||||
{
|
||||
printf("+ ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_sub()
|
||||
{
|
||||
printf("- ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_mul()
|
||||
{
|
||||
printf("* ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_div()
|
||||
{
|
||||
printf("/ ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_lt()
|
||||
{
|
||||
printf("< ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_le()
|
||||
{
|
||||
printf("<= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_gt()
|
||||
{
|
||||
printf("> ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_ge()
|
||||
{
|
||||
printf(">= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_ne()
|
||||
{
|
||||
printf("!= ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_eq()
|
||||
{
|
||||
printf("== ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_false()
|
||||
{
|
||||
printf("false ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_true()
|
||||
{
|
||||
printf("true ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_nil()
|
||||
{
|
||||
printf("NULL ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_neg()
|
||||
{
|
||||
printf("-");
|
||||
}
|
||||
|
||||
void
|
||||
emit_not()
|
||||
{
|
||||
printf("!");
|
||||
}
|
||||
|
||||
void
|
||||
emit_void()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_bool_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_byte_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_int_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_nat_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_real_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_str_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u8_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i8_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i16_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u16_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_i32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_u32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_f32_type()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_int(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_nat(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_real(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_str(const char *str, i32 length)
|
||||
{
|
||||
printf("%.*s ", length, str);
|
||||
}
|
||||
|
||||
void
|
||||
emit_array()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_function()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_plex()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_method()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_trait()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_const()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
emit_print()
|
||||
{
|
||||
printf("printf(\"%%s\", ");
|
||||
}
|
||||
|
||||
void
|
||||
emit_open_paren()
|
||||
{
|
||||
printf("(");
|
||||
}
|
||||
void
|
||||
emit_close_paren()
|
||||
{
|
||||
printf(")");
|
||||
}
|
||||
23
lexer.c
23
lexer.c
|
|
@ -1,5 +1,3 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct lexer_s Lexer;
|
||||
|
|
@ -83,7 +81,7 @@ error_token(const char *message)
|
|||
Token token;
|
||||
token.type = TOKEN_ERROR;
|
||||
token.start = message;
|
||||
token.length = (i32)strlen(message);
|
||||
token.length = (i32)slen(message);
|
||||
token.line = lexer.line;
|
||||
return token;
|
||||
}
|
||||
|
|
@ -105,11 +103,11 @@ skip_whitespace()
|
|||
break;
|
||||
case '/':
|
||||
if(peek_next() == '/') {
|
||||
// Single-line comment: skip until newline or end of file
|
||||
/* Single-line comment: skip until newline or end of file */
|
||||
advance();
|
||||
while(peek() != '\n' && !is_at_end()) advance();
|
||||
} else if(peek_next() == '*') {
|
||||
// Multi-line comment: skip until '*/' or end of file
|
||||
/* Multi-line comment: skip until '* /' or end of file */
|
||||
advance();
|
||||
advance();
|
||||
while(!is_at_end()) {
|
||||
|
|
@ -117,12 +115,12 @@ skip_whitespace()
|
|||
if(peek() == '*' && peek_next() == '/') {
|
||||
advance();
|
||||
advance();
|
||||
break; // Exit loop, comment ended
|
||||
break; /* Exit loop, comment ended */
|
||||
}
|
||||
advance();
|
||||
}
|
||||
} else {
|
||||
return; // Not a comment, let tokenization handle it
|
||||
return; /* Not a comment, let tokenization handle it */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -135,7 +133,7 @@ static TokenType
|
|||
check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
||||
{
|
||||
if(lexer.current - lexer.start == start + length &&
|
||||
memcmp(lexer.start + start, rest, length) == 0) {
|
||||
sleq(lexer.start + start, rest, length) == 0) {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
@ -232,9 +230,10 @@ identifierType()
|
|||
switch(lexer.start[1]) {
|
||||
case 't':
|
||||
return check_keyword(2, 1, "r", TOKEN_TYPE_PTR);
|
||||
|
||||
case 'l':
|
||||
return check_keyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
||||
case 'r':
|
||||
return check_keyword(2, 3, "int", TOKEN_KEYWORD_PRINT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -376,14 +375,16 @@ string()
|
|||
Token
|
||||
next_token()
|
||||
{
|
||||
char c;
|
||||
char next;
|
||||
skip_whitespace();
|
||||
lexer.start = lexer.current;
|
||||
|
||||
if(is_at_end()) return make_token(TOKEN_EOF);
|
||||
|
||||
char c = advance();
|
||||
c = advance();
|
||||
if(is_alpha(c)) return identifier();
|
||||
char next = peek();
|
||||
next = peek();
|
||||
if((c == '-' && is_digit(next)) || is_digit(c)) return number();
|
||||
|
||||
switch(c) {
|
||||
|
|
|
|||
2
lexer.h
2
lexer.h
|
|
@ -20,6 +20,7 @@ typedef enum {
|
|||
TOKEN_TYPE_REAL,
|
||||
TOKEN_TYPE_STR,
|
||||
TOKEN_TYPE_BOOL,
|
||||
TOKEN_TYPE_BYTE,
|
||||
TOKEN_TYPE_VOID,
|
||||
TOKEN_TYPE_PTR,
|
||||
TOKEN_KEYWORD_PLEX,
|
||||
|
|
@ -46,6 +47,7 @@ typedef enum {
|
|||
TOKEN_KEYWORD_NIL,
|
||||
TOKEN_KEYWORD_TRUE,
|
||||
TOKEN_KEYWORD_FALSE,
|
||||
TOKEN_KEYWORD_PRINT,
|
||||
TOKEN_OPERATOR_NOT,
|
||||
TOKEN_OPERATOR_AND,
|
||||
TOKEN_OPERATOR_OR,
|
||||
|
|
|
|||
2
libc.c
2
libc.c
|
|
@ -76,7 +76,7 @@ snlen(const char *str, u32 max_len)
|
|||
}
|
||||
|
||||
void *
|
||||
aaloc(Arena *arena, u32 size)
|
||||
aalloc(Arena *arena, u32 size)
|
||||
{
|
||||
u32 pos;
|
||||
if(arena == nil) return nil;
|
||||
|
|
|
|||
24
list.c
24
list.c
|
|
@ -22,6 +22,7 @@ node_value(Node *n)
|
|||
void *
|
||||
list_push(Arena *arena, List *list, void *data, u32 data_size)
|
||||
{
|
||||
void *dest;
|
||||
void *ptr = aalloc(arena, sizeof(Node) + data_size);
|
||||
Node *node = (Node *)ptr;
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ list_push(Arena *arena, List *list, void *data, u32 data_size)
|
|||
|
||||
list->count++;
|
||||
|
||||
void *dest = node_value(node);
|
||||
dest = node_value(node);
|
||||
if (data && data_size > 0) {
|
||||
mcpy(dest, data, data_size);
|
||||
}
|
||||
|
|
@ -49,9 +50,10 @@ list_push(Arena *arena, List *list, void *data, u32 data_size)
|
|||
void
|
||||
list_foreach(List *list, list_iter_fn func)
|
||||
{
|
||||
Node *curr;
|
||||
if (!list || !func) return;
|
||||
|
||||
Node *curr = list->head;
|
||||
curr = list->head;
|
||||
while (curr) {
|
||||
func(node_value(curr));
|
||||
curr = curr->next;
|
||||
|
|
@ -61,11 +63,12 @@ list_foreach(List *list, list_iter_fn func)
|
|||
void *
|
||||
list_get(List *list, u32 index)
|
||||
{
|
||||
u32 i;
|
||||
Node *curr;
|
||||
if (!list || index >= list->count) return nil;
|
||||
|
||||
Node *curr = list->head;
|
||||
// Walk to the desired index
|
||||
for (u32 i = 0; i < index; i++) {
|
||||
curr = list->head;
|
||||
for (i = 0; i < index; i++) {
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +76,7 @@ list_get(List *list, u32 index)
|
|||
}
|
||||
|
||||
void
|
||||
list_set(List *list, u32 index, const void *data, u32 size)
|
||||
list_set(List *list, u32 index, void *data, u32 size)
|
||||
{
|
||||
void *target = list_get(list, index);
|
||||
if (target) {
|
||||
|
|
@ -82,13 +85,16 @@ list_set(List *list, u32 index, const void *data, u32 size)
|
|||
}
|
||||
|
||||
void *
|
||||
list_find(List *list, compare_fn compare, const void *target)
|
||||
list_find(List *list, compare_fn compare, void *target)
|
||||
{
|
||||
Node *curr;
|
||||
void *data;
|
||||
|
||||
if (!list || !compare) return nil;
|
||||
|
||||
Node *curr = list->head;
|
||||
curr = list->head;
|
||||
while (curr) {
|
||||
void *data = node_value(curr);
|
||||
data = node_value(curr);
|
||||
if (compare(data, target)) {
|
||||
return data;
|
||||
}
|
||||
|
|
|
|||
6
list.h
6
list.h
|
|
@ -15,15 +15,15 @@ struct list_s {
|
|||
u32 count;
|
||||
};
|
||||
|
||||
typedef bool (*compare_fn)(const void *data, const void *target);
|
||||
typedef bool (*compare_fn)(void *data, void *target);
|
||||
typedef void (*list_iter_fn)(void *data);
|
||||
|
||||
List *new_list(Arena *arena);
|
||||
void *node_value(Node *n);
|
||||
void *list_push(Arena *arena, List *list, void *data, u32 data_size);
|
||||
void list_foreach(List *list, list_iter_fn func);
|
||||
void *list_find(List *list, compare_fn compare, const void *target);
|
||||
void *list_find(List *list, compare_fn compare, void *target);
|
||||
void *list_get(List *list, u32 index);
|
||||
void list_set(List *list, u32 index, const void *data, u32 size);
|
||||
void list_set(List *list, u32 index, void *data, u32 size);
|
||||
|
||||
#endif
|
||||
26
main.c
26
main.c
|
|
@ -1,26 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define EMBED_FILE(name) \
|
||||
void emit_##name(const char *filename) \
|
||||
{ \
|
||||
FILE *f = fopen(filename, "wb"); \
|
||||
if(f) { \
|
||||
fwrite(name, 1, name##_len, f); \
|
||||
fclose(f); \
|
||||
} \
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if(argc > 1)
|
||||
name = argv[1];
|
||||
else
|
||||
name = "'u'";
|
||||
|
||||
printf("nuqneH %s?\n", name);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
343
parser.c
343
parser.c
|
|
@ -1,20 +1,8 @@
|
|||
#include "parser.h"
|
||||
#include "emit.h"
|
||||
|
||||
Parser parser;
|
||||
|
||||
bool
|
||||
advance()
|
||||
{
|
||||
parser.previous = parser.current;
|
||||
|
||||
for(;;) {
|
||||
parser.current = next_token();
|
||||
if(parser.current.type != TOKEN_ERROR) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Scope
|
||||
***************************************************/
|
||||
|
|
@ -30,7 +18,7 @@ scope_push(Arena *arena)
|
|||
}
|
||||
|
||||
void
|
||||
scope_pop(Arena *arena)
|
||||
scope_pop()
|
||||
{
|
||||
Scope *prev = parser.current_scope->parent;
|
||||
parser.current_scope = prev;
|
||||
|
|
@ -39,21 +27,21 @@ scope_pop(Arena *arena)
|
|||
Symbol *
|
||||
scope_get_symbol(Scope *scope, const char *name, u32 name_length)
|
||||
{
|
||||
u32 count, i;
|
||||
if(!scope) return nil;
|
||||
|
||||
u32 count = scope->symbols->count;
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
count = scope->symbols->count;
|
||||
for(i = 0; i < count; i++) {
|
||||
Symbol *sym = list_get(scope->symbols, i);
|
||||
if (sleq(sym->name, name, name_length)) {
|
||||
return sym;
|
||||
}
|
||||
if(sleq(sym->name, name, name_length)) return sym;
|
||||
}
|
||||
|
||||
return scope_get_symbol(scope->parent, name, name_length);
|
||||
}
|
||||
|
||||
Symbol *
|
||||
scope_add_symbol(Arena *arena, const char *name, u32 name_length, SymbolType type, u32 size)
|
||||
scope_add_symbol(Arena *arena, const char *name, u32 name_length,
|
||||
SymbolType type, u32 size)
|
||||
{
|
||||
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
|
||||
if(sym != nil) return sym;
|
||||
|
|
@ -62,7 +50,7 @@ scope_add_symbol(Arena *arena, const char *name, u32 name_length, SymbolType typ
|
|||
scpy(sym->name, name, slen(name));
|
||||
sym->name_length = slen(name);
|
||||
sym->type = type;
|
||||
sym->secondary_type = VOID; // Default
|
||||
sym->secondary_type = VOID;
|
||||
sym->size = size;
|
||||
sym->ref = 0;
|
||||
if(type == PLEX || type == METHOD || type == TRAIT) {
|
||||
|
|
@ -78,74 +66,325 @@ scope_add_symbol(Arena *arena, const char *name, u32 name_length, SymbolType typ
|
|||
/****************************************************
|
||||
* Parser
|
||||
***************************************************/
|
||||
|
||||
bool
|
||||
parse_trait()
|
||||
advance()
|
||||
{
|
||||
return true;
|
||||
parser.previous = parser.current;
|
||||
|
||||
for(;;) {
|
||||
parser.current = next_token();
|
||||
if(parser.current.type != TOKEN_ERROR) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool
|
||||
check(TokenType type)
|
||||
{
|
||||
return parser.current.type == type;
|
||||
}
|
||||
|
||||
bool
|
||||
parse_plex()
|
||||
consume(TokenType type)
|
||||
{
|
||||
if(check(type)) {
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
parse_function()
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
match(TokenType type)
|
||||
{
|
||||
if(!check(type)) return false;
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
parse_if()
|
||||
static void expression();
|
||||
static void statement();
|
||||
static void declaration();
|
||||
static ParseRule *get_rule(TokenType type);
|
||||
static void parse_precedence(Precedence precedence);
|
||||
|
||||
static void
|
||||
binary()
|
||||
{
|
||||
return true;
|
||||
TokenType operatorType = parser.previous.type;
|
||||
ParseRule *rule = get_rule(operatorType);
|
||||
|
||||
switch(operatorType) {
|
||||
case TOKEN_BANG_EQ:
|
||||
emit_ne();
|
||||
break;
|
||||
case TOKEN_EQ_EQ:
|
||||
emit_eq();
|
||||
break;
|
||||
case TOKEN_GT:
|
||||
emit_ge();
|
||||
break;
|
||||
case TOKEN_GTE:
|
||||
emit_ge();
|
||||
break;
|
||||
case TOKEN_LT:
|
||||
emit_lt();
|
||||
break;
|
||||
case TOKEN_LTE:
|
||||
emit_le();
|
||||
break;
|
||||
case TOKEN_PLUS:
|
||||
emit_add();
|
||||
break;
|
||||
case TOKEN_MINUS:
|
||||
emit_sub();
|
||||
break;
|
||||
case TOKEN_STAR:
|
||||
emit_mul();
|
||||
break;
|
||||
case TOKEN_SLASH:
|
||||
emit_div();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
parse_loop()
|
||||
{
|
||||
return true;
|
||||
/* Move to above switch statement for postfix */
|
||||
parse_precedence((Precedence)(rule->precedence + 1));
|
||||
}
|
||||
|
||||
bool
|
||||
parse_while()
|
||||
static void
|
||||
literal()
|
||||
{
|
||||
return true;
|
||||
switch(parser.previous.type) {
|
||||
case TOKEN_KEYWORD_FALSE:
|
||||
emit_false();
|
||||
break;
|
||||
case TOKEN_KEYWORD_TRUE:
|
||||
emit_true();
|
||||
break;
|
||||
case TOKEN_KEYWORD_NIL:
|
||||
emit_nil();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
parse_for()
|
||||
static void
|
||||
expression()
|
||||
{
|
||||
return true;
|
||||
parse_precedence(PREC_ASSIGNMENT);
|
||||
}
|
||||
|
||||
bool
|
||||
parse_return()
|
||||
static void
|
||||
declaration()
|
||||
{
|
||||
return true;
|
||||
if(match(TOKEN_TYPE_INT)) {
|
||||
emit_int_type();
|
||||
} else if(match(TOKEN_TYPE_NAT)) {
|
||||
emit_nat_type();
|
||||
} else if(match(TOKEN_TYPE_REAL)) {
|
||||
emit_real_type();
|
||||
} else if(match(TOKEN_TYPE_STR)) {
|
||||
emit_str_type();
|
||||
} else if(match(TOKEN_TYPE_BOOL)) {
|
||||
emit_bool_type();
|
||||
} else if(match(TOKEN_TYPE_BYTE)) {
|
||||
emit_byte_type();
|
||||
} else if(match(TOKEN_TYPE_U8)) {
|
||||
emit_u8_type();
|
||||
} else if(match(TOKEN_TYPE_I8)) {
|
||||
emit_i8_type();
|
||||
} else if(match(TOKEN_TYPE_U16)) {
|
||||
emit_u16_type();
|
||||
} else if(match(TOKEN_TYPE_I16)) {
|
||||
emit_i16_type();
|
||||
} else if(match(TOKEN_IDENTIFIER)) {
|
||||
/**
|
||||
* maybe a Plex?
|
||||
* lookup plex defs
|
||||
* if not then
|
||||
*/
|
||||
}
|
||||
|
||||
bool
|
||||
parse_assignment()
|
||||
{
|
||||
return true;
|
||||
statement();
|
||||
}
|
||||
|
||||
bool
|
||||
parse_expression()
|
||||
static void
|
||||
statement()
|
||||
{
|
||||
return true;
|
||||
if(match(TOKEN_KEYWORD_PRINT))
|
||||
emit_print();
|
||||
else
|
||||
expression();
|
||||
}
|
||||
|
||||
bool
|
||||
parse_statement()
|
||||
static void
|
||||
grouping()
|
||||
{
|
||||
return true;
|
||||
emit_open_paren();
|
||||
|
||||
expression();
|
||||
|
||||
emit_close_paren();
|
||||
consume(TOKEN_RPAREN);
|
||||
}
|
||||
|
||||
static void
|
||||
number()
|
||||
{
|
||||
emit_int(parser.previous.start, parser.previous.length);
|
||||
}
|
||||
|
||||
static void
|
||||
string()
|
||||
{
|
||||
emit_str(parser.previous.start, parser.previous.length);
|
||||
}
|
||||
|
||||
static void
|
||||
unary()
|
||||
{
|
||||
TokenType operatorType = parser.previous.type;
|
||||
|
||||
switch(operatorType) {
|
||||
case TOKEN_MINUS:
|
||||
emit_neg();
|
||||
break;
|
||||
case TOKEN_BANG:
|
||||
emit_not();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move to above switch statement for postfix */
|
||||
parse_precedence(PREC_UNARY);
|
||||
}
|
||||
|
||||
ParseRule rules[] = {
|
||||
/* 0 */ {NULL, NULL, PREC_NONE},
|
||||
/* 1 */ {NULL, NULL, PREC_NONE},
|
||||
/* 2 */ {NULL, NULL, PREC_NONE},
|
||||
/* 3 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_INT */
|
||||
/* 4 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_NAT */
|
||||
/* 5 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_REAL */
|
||||
/* 6 */ {string, NULL, PREC_NONE}, /* TOKEN_LITERAL_STR */
|
||||
/* 7 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_I8 */
|
||||
/* 8 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_I16 */
|
||||
/* 9 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_INT */
|
||||
/*10 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_U8 */
|
||||
/*11 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_U16 */
|
||||
/*12 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_NAT */
|
||||
/*13 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_REAL */
|
||||
/*14 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_STR */
|
||||
/*15 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_BOOL */
|
||||
/*16 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_BYTE */
|
||||
/*17 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_VOID */
|
||||
/*18 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_PTR */
|
||||
/*19 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_PLEX */
|
||||
/*20 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FN */
|
||||
/*21 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_CONST */
|
||||
/*22 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_IF */
|
||||
/*23 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_IS */
|
||||
/*24 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_AS */
|
||||
/*25 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_ELSE */
|
||||
/*26 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_WHILE */
|
||||
/*27 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FOR */
|
||||
/*28 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_RETURN */
|
||||
/*29 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_USE */
|
||||
/*30 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_INIT */
|
||||
/*31 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_THIS */
|
||||
/*32 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_GLOBAL */
|
||||
/*33 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_OPEN */
|
||||
/*34 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_READ */
|
||||
/*35 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_WRITE */
|
||||
/*36 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_STAT */
|
||||
/*37 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_CLOSE */
|
||||
/*38 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_LOOP */
|
||||
/*39 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_DO */
|
||||
/*40 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_NIL */
|
||||
/*41 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_TRUE */
|
||||
/*42 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FALSE */
|
||||
/*43 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_PRINT */
|
||||
/*44 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_NOT */
|
||||
/*45 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_AND */
|
||||
/*46 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_OR */
|
||||
/*47 */ {unary, NULL, PREC_NONE}, /* TOKEN_BANG */
|
||||
/*48 */ {NULL, binary, PREC_EQUALITY}, /* TOKEN_BANG_EQ */
|
||||
/*49 */ {NULL, NULL, PREC_NONE}, /* TOKEN_EQ */
|
||||
/*50 */ {NULL, binary, PREC_EQUALITY}, /* TOKEN_EQ_EQ */
|
||||
/*51 */ {NULL, NULL, PREC_NONE}, /* TOKEN_AND */
|
||||
/*52 */ {NULL, NULL, PREC_NONE}, /* TOKEN_AND_AND */
|
||||
/*53 */ {NULL, NULL, PREC_NONE}, /* TOKEN_PIPE */
|
||||
/*54 */ {NULL, NULL, PREC_NONE}, /* TOKEN_PIPE_PIPE */
|
||||
/*55 */ {NULL, NULL, PREC_NONE}, /* TOKEN_QUESTION */
|
||||
/*56 */ {NULL, NULL, PREC_NONE}, /* TOKEN_QUESTION_DOT */
|
||||
/*57 */ {NULL, binary, PREC_TERM}, /* TOKEN_PLUS */
|
||||
/*58 */ {unary, binary, PREC_TERM}, /* TOKEN_MINUS */
|
||||
/*59 */ {NULL, binary, PREC_FACTOR}, /* TOKEN_STAR */
|
||||
/*60 */ {NULL, binary, PREC_FACTOR}, /* TOKEN_SLASH */
|
||||
/*61 */ {NULL, NULL, PREC_NONE}, /* TOKEN_MESH */
|
||||
/*62 */ {NULL, NULL, PREC_NONE}, /* TOKEN_BIG_MONEY */
|
||||
/*63 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_GT */
|
||||
/*64 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_LT */
|
||||
/*65 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_GTE */
|
||||
/*66 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_LTE */
|
||||
/*67 */ {NULL, NULL, PREC_NONE}, /* TOKEN_DOT */
|
||||
/*68 */ {NULL, NULL, PREC_NONE}, /* TOKEN_COMMA */
|
||||
/*69 */ {NULL, NULL, PREC_NONE}, /* TOKEN_COLON */
|
||||
/*70 */ {NULL, NULL, PREC_NONE}, /* TOKEN_CARET */
|
||||
/*71 */ {NULL, NULL, PREC_NONE}, /* TOKEN_SEMICOLON */
|
||||
/*72 */ {grouping, NULL, PREC_NONE}, /* TOKEN_LPAREN */
|
||||
/*73 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RPAREN */
|
||||
/*74 */ {NULL, NULL, PREC_NONE}, /* TOKEN_LBRACE */
|
||||
/*75 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RBRACE */
|
||||
/*76 */ {NULL, NULL, PREC_NONE}, /* TOKEN_LBRACKET */
|
||||
/*77 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RBRACKET */
|
||||
/*78 */ {NULL, NULL, PREC_NONE} /* TOKEN_ARROW_RIGHT */
|
||||
};
|
||||
|
||||
static void
|
||||
parse_precedence(Precedence precedence)
|
||||
{
|
||||
ParseFn prefixRule;
|
||||
ParseFn infixRule;
|
||||
|
||||
advance();
|
||||
prefixRule = get_rule(parser.previous.type)->prefix;
|
||||
if(prefixRule == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
prefixRule();
|
||||
|
||||
while(precedence <= get_rule(parser.current.type)->precedence) {
|
||||
advance();
|
||||
infixRule = get_rule(parser.previous.type)->infix;
|
||||
infixRule();
|
||||
}
|
||||
}
|
||||
|
||||
static ParseRule *
|
||||
get_rule(TokenType type)
|
||||
{
|
||||
return &rules[type];
|
||||
}
|
||||
|
||||
bool
|
||||
compile(char *source)
|
||||
{
|
||||
init_lexer(source);
|
||||
advance();
|
||||
|
||||
prolog();
|
||||
|
||||
while(!match(TOKEN_EOF)) declaration();
|
||||
|
||||
epilogue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
29
parser.h
29
parser.h
|
|
@ -4,6 +4,7 @@
|
|||
#include "libc.h"
|
||||
#include "list.h"
|
||||
#include "lexer.h"
|
||||
#include "emit.h"
|
||||
|
||||
typedef enum symbol_type_e {
|
||||
VOID,
|
||||
|
|
@ -25,12 +26,13 @@ typedef enum symbol_type_e {
|
|||
PLEX,
|
||||
METHOD,
|
||||
TRAIT,
|
||||
CONST,
|
||||
CONST
|
||||
} SymbolType;
|
||||
|
||||
typedef struct symbol_s Symbol;
|
||||
typedef struct scope_s Scope;
|
||||
typedef struct parser_s Parser;
|
||||
typedef struct parse_rule_s ParseRule;
|
||||
|
||||
#define MAX_SYMBOL_NAME_LENGTH 64
|
||||
struct symbol_s {
|
||||
|
|
@ -49,6 +51,28 @@ struct scope_s {
|
|||
List *symbols; /* list of symbols that live in this scope */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PREC_NONE,
|
||||
PREC_ASSIGNMENT, /* = */
|
||||
PREC_OR, /* or */
|
||||
PREC_AND, /* and */
|
||||
PREC_EQUALITY, /* == != */
|
||||
PREC_COMPARISON, /* < > <= >= */
|
||||
PREC_TERM, /* + - */
|
||||
PREC_FACTOR, /* * / */
|
||||
PREC_UNARY, /* ! - */
|
||||
PREC_CALL, /* . () */
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
||||
typedef void (*ParseFn)();
|
||||
|
||||
struct parse_rule_s {
|
||||
ParseFn prefix;
|
||||
ParseFn infix;
|
||||
Precedence precedence;
|
||||
};
|
||||
|
||||
struct parser_s {
|
||||
Scope *current_scope;
|
||||
Token current;
|
||||
|
|
@ -57,4 +81,7 @@ struct parser_s {
|
|||
|
||||
bool compile(char *source);
|
||||
|
||||
extern void emit_return();
|
||||
extern void emit_constant();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Add two numbers together
|
||||
*/
|
||||
function add(int a, int b) int {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
print(add(1, 1) as str);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
bool flag = false;
|
||||
|
||||
if (!flag) {
|
||||
print("flag is false");
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
!(5 - 4 > 3 * 2 == false)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Recursively calculate fibonacci
|
||||
*/
|
||||
function fib(int n) int {
|
||||
if (n < 2) { return n; }
|
||||
return fib(n - 2) + fib(n - 1);
|
||||
}
|
||||
|
||||
print(fib(35) as str);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
nat i = 0;
|
||||
|
||||
for (nat x in 10) {
|
||||
print(x as str);
|
||||
}
|
||||
|
||||
for (nat j = 0; j < 10; j = j + 1) {
|
||||
print(j as str);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
print("nuqneH 'u'?");
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
nat x = 10;
|
||||
|
||||
if (x == 10) {
|
||||
print("x is 10");
|
||||
} else if (x == 20) {
|
||||
print("x is 20");
|
||||
} else {
|
||||
print("x is something else");
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Main function
|
||||
*/
|
||||
function main() {
|
||||
print("Enter a string: ");
|
||||
str msg = read(32);
|
||||
print(msg);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* Constants
|
||||
*/
|
||||
const byte BLACK = 0;
|
||||
const byte WHITE = 255;
|
||||
const byte DARK_GRAY = 73;
|
||||
const byte GRAY = 146;
|
||||
const byte LIGHT_GRAY = 182;
|
||||
|
||||
byte selected_color = 255;
|
||||
|
||||
trait Device {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
plex Screen implements Device {
|
||||
nat handle;
|
||||
nat width;
|
||||
nat height;
|
||||
byte[] buffer;
|
||||
|
||||
draw() {
|
||||
write(this, this.buffer, this.buffer.length);
|
||||
}
|
||||
}
|
||||
|
||||
plex Mouse implements Device {
|
||||
nat handle;
|
||||
nat x;
|
||||
nat y;
|
||||
bool left;
|
||||
bool right;
|
||||
bool middle;
|
||||
bool btn4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
function main() {
|
||||
Screen screen = open("/dev/screen/0", 0);
|
||||
Mouse mouse = open("/dev/mouse/0", 0);
|
||||
|
||||
outline_swatch(screen, BLACK, 1, 1);
|
||||
outline_swatch(screen, WHITE, 21, 1);
|
||||
screen.draw();
|
||||
|
||||
loop {
|
||||
mouse.refresh();
|
||||
if (!mouse.left) continue;
|
||||
|
||||
int box_size = 20;
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
byte color = BLACK;
|
||||
outlined_swatch(screen, color, x, y);
|
||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||
|
||||
color = WHITE;
|
||||
x = 21;
|
||||
outlined_swatch(screen, color, x, y);
|
||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||
screen.draw();
|
||||
|
||||
rectangle(screen, selected_color, x, y, 5, 5);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the click is within the bound and update the selected color if so.
|
||||
*/
|
||||
function set_color(int box_size, int bx, int by, int mx, int my, byte color) {
|
||||
int right = bx + box_size;
|
||||
int bottom = by + box_size;
|
||||
|
||||
if (mx < bx) return;
|
||||
if (mx > right) return;
|
||||
if (my < by) return;
|
||||
if (my > bottom) return;
|
||||
|
||||
selected_color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a color box with a grey outline, if selected use a darker color
|
||||
*/
|
||||
function outline_swatch(Device screen, byte color, int x, int y) {
|
||||
byte bg_color = GRAY;
|
||||
if (selected_color == color) {
|
||||
bg_color = DARK_GRAY;
|
||||
}
|
||||
|
||||
rectangle(screen, bg_color, x, y, 20, 20);
|
||||
rectangle(screen, color, x + 2, y + 2, 17, 17);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a rectangle
|
||||
*/
|
||||
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
|
||||
int base = y * screen.width + x + screen.buffer.ptr + 4;
|
||||
|
||||
for (int i = height; i > 0; i--) {
|
||||
int row = base + width;
|
||||
memset(screen.buffer, row, color, width);
|
||||
base += screen.width;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct arena_s Arena;
|
||||
struct arena_s {
|
||||
unsigned char *tape;
|
||||
unsigned int count;
|
||||
unsigned int capacity;
|
||||
};
|
||||
|
||||
void *aalloc(Arena *arena, unsigned int size){
|
||||
unsigned int pos;
|
||||
if(arena == NULL) return NULL;
|
||||
if(arena->count + size > arena->capacity) return NULL;
|
||||
|
||||
pos = arena->count;
|
||||
arena->count += size;
|
||||
return (void *)&arena->tape[pos];
|
||||
}
|
||||
|
||||
unsigned int
|
||||
scpy(char *to, const char *from, unsigned int length)
|
||||
{
|
||||
unsigned int i;
|
||||
if(to == NULL || from == NULL) return -1;
|
||||
if(length == 0) return 0;
|
||||
for(i = 0; i < length - 1 && from[i] != '\0'; i++) to[i] = from[i];
|
||||
to[i] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
ascpy(Arena *arena, const char *start, unsigned int length)
|
||||
{
|
||||
char *str;
|
||||
if(!start) return NULL;
|
||||
str = (char *)aalloc(arena, length + 1);
|
||||
if(!str) return NULL;
|
||||
scpy(str, start, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
void *
|
||||
areturn(Arena *arena, unsigned int checkpoint, const void *src, unsigned int size)
|
||||
{
|
||||
void *dest;
|
||||
if(arena == NULL || src == NULL) return NULL;
|
||||
|
||||
dest = (void *)&arena->tape[checkpoint];
|
||||
if (src == dest) return dest;
|
||||
|
||||
memmove(dest, src, size);
|
||||
arena->count = checkpoint + size;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define ARENA_RETURN(arena, ckpt, src_ptr, type) \
|
||||
return (type *)areturn((arena), (ckpt), (src_ptr), sizeof(type))
|
||||
|
||||
#define ARENA_RETURN_ARRAY(arena, ckpt, src_ptr, type, count) \
|
||||
return (type *)areturn((arena), (ckpt), (src_ptr), sizeof(type) * (count))
|
||||
|
||||
typedef struct Point Point;
|
||||
struct Point {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
};
|
||||
|
||||
Point *
|
||||
Point_new(Arena *a, unsigned int x, unsigned int y)
|
||||
{
|
||||
Point *this = (Point *)aalloc(a, sizeof(Point));
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
char*
|
||||
Point_toS(Arena *a, Point *this)
|
||||
{
|
||||
unsigned int ckpt = a->count;
|
||||
char *s = (char*)&a->tape[a->count];
|
||||
int len = sprintf(s, "[x:%d, y:%d]",
|
||||
this->x,
|
||||
this->y);
|
||||
s[len] = '\0';
|
||||
a->count += len + 1;
|
||||
ARENA_RETURN_ARRAY(a, ckpt, s, char, len + 1);
|
||||
}
|
||||
|
||||
typedef struct Rect Rect;
|
||||
struct Rect {
|
||||
Point top_left;
|
||||
Point bottom_right;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
};
|
||||
|
||||
Rect *
|
||||
Rect_new(Arena *a, Point *tl, Point *br, unsigned int width, unsigned int height)
|
||||
{
|
||||
Rect *this = (Rect *)aalloc(a, sizeof(Rect));
|
||||
memcpy(&this->top_left, tl, sizeof(Point));
|
||||
memcpy(&this->bottom_right, br, sizeof(Point));
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
char*
|
||||
Rect_toS(Arena *a, Rect *this)
|
||||
{
|
||||
unsigned int ckpt = a->count;
|
||||
char *s1 = Point_toS(a, &this->top_left);
|
||||
char *s2 = Point_toS(a, &this->bottom_right);
|
||||
|
||||
char *s = (char*)&a->tape[a->count];
|
||||
int len = sprintf(s, "[top_left: %s, bottom_right: %s, width:%d, height:%d]",
|
||||
s1,
|
||||
s2,
|
||||
this->width,
|
||||
this->height);
|
||||
s[len] = '\0';
|
||||
a->count += len + 1;
|
||||
ARENA_RETURN_ARRAY(a, ckpt, s, char, len + 1);
|
||||
}
|
||||
|
||||
Rect *
|
||||
create_geometry(Arena *a)
|
||||
{
|
||||
unsigned int ckpt = a->count;
|
||||
Rect *final_rect;
|
||||
Point *temp_tl;
|
||||
Point *temp_br;
|
||||
|
||||
temp_tl = Point_new(a, 10, 20);
|
||||
temp_br = Point_new(a, 100, 200);
|
||||
|
||||
final_rect = Rect_new(a, temp_tl, temp_br, 90, 180);
|
||||
|
||||
ARENA_RETURN(a, ckpt, final_rect, Rect);
|
||||
}
|
||||
|
||||
int main() {
|
||||
unsigned char tape[64000];
|
||||
Arena a = {tape, 0, 64000};
|
||||
Rect *r = create_geometry(&a);
|
||||
printf("%s\n", Rect_toS(&a, r));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
plex Point {
|
||||
nat x;
|
||||
nat y;
|
||||
|
||||
init(nat x, nat y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
toS() {
|
||||
pln("[x:%d, y:%d]",
|
||||
this.x,
|
||||
this.y);
|
||||
}
|
||||
}
|
||||
|
||||
plex Rect {
|
||||
Point top_left;
|
||||
Point bottom_right;
|
||||
nat width;
|
||||
nat height;
|
||||
|
||||
init(Point tl, Point br, nat width, nat height) {
|
||||
this.top_left = tl;
|
||||
this.bottom_right = br;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
toS() {
|
||||
pln("[top_left: [x:%d, y:%d], bottom_right: [x:%d, y:%d], width:%d, height:%d]]",
|
||||
this.top_left.x,
|
||||
this.top_left.y,
|
||||
this.bottom_right.x,
|
||||
this.bottom_right.y,
|
||||
this.width,
|
||||
this.height);
|
||||
}
|
||||
}
|
||||
|
||||
function create_geometry() Rect {
|
||||
Point tl(10, 20);
|
||||
Point br(100, 50);
|
||||
Rect final_rect(tl, br, 90, 180);
|
||||
return final_rect;
|
||||
}
|
||||
|
||||
function main() int {
|
||||
Rect r = create_geometry();
|
||||
print(r.toS());
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
print((1.0 + 1.0) as str);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
trait Device {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
trait Printable {
|
||||
print();
|
||||
}
|
||||
|
||||
plex Screen implements Device {
|
||||
nat handle;
|
||||
nat width;
|
||||
}
|
||||
|
||||
plex Monitor implements Device, Printable {
|
||||
nat handle;
|
||||
nat width;
|
||||
nat height;
|
||||
|
||||
print() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
nat i = 0;
|
||||
|
||||
while (i < 10) {
|
||||
print(i as str);
|
||||
i = i + 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Constants
|
||||
*/
|
||||
const str screen_namespace = "/dev/screen/0";
|
||||
const str mouse_namespace = "/dev/mouse/0";
|
||||
const str terminal_namespace = "/dev/term/0";
|
||||
const str new_line = "\n";
|
||||
const byte WHITE = 255;
|
||||
|
||||
/**
|
||||
* Devices
|
||||
*/
|
||||
plex Terminal {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
plex Screen {
|
||||
nat handle;
|
||||
nat width;
|
||||
nat height;
|
||||
byte[] buffer;
|
||||
|
||||
draw() {
|
||||
write(this, this.buffer, this.buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
plex Mouse {
|
||||
nat handle;
|
||||
nat x;
|
||||
nat y;
|
||||
bool left;
|
||||
bool right;
|
||||
bool middle;
|
||||
bool btn4;
|
||||
nat size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
function main() {
|
||||
Screen screen = open(screen_namespace, 0);
|
||||
print(screen.handle as str);
|
||||
print(screen.width as str);
|
||||
print(screen.size as str);
|
||||
unsafe {
|
||||
print(screen.buffer.ptr as str);
|
||||
}
|
||||
|
||||
Mouse mouse = open(mouse_namespace, 0);
|
||||
screen.draw();
|
||||
|
||||
loop {
|
||||
if (mouse.left) {
|
||||
unsafe {
|
||||
screen.buffer[mouse.y * width + mouse.x +
|
||||
screen.buffer.ptr + 4] = WHITE;
|
||||
screen.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print with a newline
|
||||
*/
|
||||
function print(str message) {
|
||||
Terminal term = open(terminal_namespace, 0);
|
||||
write(term, message, message.length);
|
||||
write(term, nl, nl.length);
|
||||
}
|
||||
Loading…
Reference in New Issue