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
|
set -e
|
||||||
|
|
||||||
|
if [ -z $ARCH ]; then
|
||||||
|
ARCH='linux'
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z $MODE ]; then
|
if [ -z $MODE ]; then
|
||||||
MODE='debug'
|
MODE='debug'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z $EMIT ]; then
|
||||||
|
EMIT='c'
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $ARCH in
|
||||||
|
"linux")
|
||||||
if [ -z $CC ]; then
|
if [ -z $CC ]; then
|
||||||
CC='gcc'
|
CC='gcc'
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
"web")
|
||||||
|
CC=emcc
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
# setup dirs
|
# setup dirs
|
||||||
BUILD_DIR=./out
|
SRC_DIR=./arch/$ARCH
|
||||||
|
BUILD_DIR=./out/$EMIT/$ARCH
|
||||||
GEN_DIR=$BUILD_DIR/gen
|
GEN_DIR=$BUILD_DIR/gen
|
||||||
TOOL_SRC=tools/file2header.c
|
TOOL_SRC=tools/file2header.c
|
||||||
TOOL_EXE=$BUILD_DIR/file2header
|
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
|
$CC $TOOL_SRC -o $TOOL_EXE
|
||||||
fi
|
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
|
# setup the build flags based on the build mode
|
||||||
case $MODE in
|
case $MODE in
|
||||||
"debug")
|
"debug")
|
||||||
|
|
@ -71,7 +73,24 @@ case $MODE in
|
||||||
;;
|
;;
|
||||||
esac
|
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"
|
echo "$BUILD_CMD"
|
||||||
${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"
|
#include "lexer.h"
|
||||||
|
|
||||||
typedef struct lexer_s Lexer;
|
typedef struct lexer_s Lexer;
|
||||||
|
|
@ -83,7 +81,7 @@ error_token(const char *message)
|
||||||
Token token;
|
Token token;
|
||||||
token.type = TOKEN_ERROR;
|
token.type = TOKEN_ERROR;
|
||||||
token.start = message;
|
token.start = message;
|
||||||
token.length = (i32)strlen(message);
|
token.length = (i32)slen(message);
|
||||||
token.line = lexer.line;
|
token.line = lexer.line;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
@ -105,11 +103,11 @@ skip_whitespace()
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if(peek_next() == '/') {
|
if(peek_next() == '/') {
|
||||||
// Single-line comment: skip until newline or end of file
|
/* Single-line comment: skip until newline or end of file */
|
||||||
advance();
|
advance();
|
||||||
while(peek() != '\n' && !is_at_end()) advance();
|
while(peek() != '\n' && !is_at_end()) advance();
|
||||||
} else if(peek_next() == '*') {
|
} else if(peek_next() == '*') {
|
||||||
// Multi-line comment: skip until '*/' or end of file
|
/* Multi-line comment: skip until '* /' or end of file */
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
while(!is_at_end()) {
|
while(!is_at_end()) {
|
||||||
|
|
@ -117,12 +115,12 @@ skip_whitespace()
|
||||||
if(peek() == '*' && peek_next() == '/') {
|
if(peek() == '*' && peek_next() == '/') {
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
break; // Exit loop, comment ended
|
break; /* Exit loop, comment ended */
|
||||||
}
|
}
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return; // Not a comment, let tokenization handle it
|
return; /* Not a comment, let tokenization handle it */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -135,7 +133,7 @@ static TokenType
|
||||||
check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
||||||
{
|
{
|
||||||
if(lexer.current - lexer.start == start + length &&
|
if(lexer.current - lexer.start == start + length &&
|
||||||
memcmp(lexer.start + start, rest, length) == 0) {
|
sleq(lexer.start + start, rest, length) == 0) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,9 +230,10 @@ identifierType()
|
||||||
switch(lexer.start[1]) {
|
switch(lexer.start[1]) {
|
||||||
case 't':
|
case 't':
|
||||||
return check_keyword(2, 1, "r", TOKEN_TYPE_PTR);
|
return check_keyword(2, 1, "r", TOKEN_TYPE_PTR);
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
return check_keyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
return check_keyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
||||||
|
case 'r':
|
||||||
|
return check_keyword(2, 3, "int", TOKEN_KEYWORD_PRINT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -376,14 +375,16 @@ string()
|
||||||
Token
|
Token
|
||||||
next_token()
|
next_token()
|
||||||
{
|
{
|
||||||
|
char c;
|
||||||
|
char next;
|
||||||
skip_whitespace();
|
skip_whitespace();
|
||||||
lexer.start = lexer.current;
|
lexer.start = lexer.current;
|
||||||
|
|
||||||
if(is_at_end()) return make_token(TOKEN_EOF);
|
if(is_at_end()) return make_token(TOKEN_EOF);
|
||||||
|
|
||||||
char c = advance();
|
c = advance();
|
||||||
if(is_alpha(c)) return identifier();
|
if(is_alpha(c)) return identifier();
|
||||||
char next = peek();
|
next = peek();
|
||||||
if((c == '-' && is_digit(next)) || is_digit(c)) return number();
|
if((c == '-' && is_digit(next)) || is_digit(c)) return number();
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
|
|
||||||
2
lexer.h
2
lexer.h
|
|
@ -20,6 +20,7 @@ typedef enum {
|
||||||
TOKEN_TYPE_REAL,
|
TOKEN_TYPE_REAL,
|
||||||
TOKEN_TYPE_STR,
|
TOKEN_TYPE_STR,
|
||||||
TOKEN_TYPE_BOOL,
|
TOKEN_TYPE_BOOL,
|
||||||
|
TOKEN_TYPE_BYTE,
|
||||||
TOKEN_TYPE_VOID,
|
TOKEN_TYPE_VOID,
|
||||||
TOKEN_TYPE_PTR,
|
TOKEN_TYPE_PTR,
|
||||||
TOKEN_KEYWORD_PLEX,
|
TOKEN_KEYWORD_PLEX,
|
||||||
|
|
@ -46,6 +47,7 @@ typedef enum {
|
||||||
TOKEN_KEYWORD_NIL,
|
TOKEN_KEYWORD_NIL,
|
||||||
TOKEN_KEYWORD_TRUE,
|
TOKEN_KEYWORD_TRUE,
|
||||||
TOKEN_KEYWORD_FALSE,
|
TOKEN_KEYWORD_FALSE,
|
||||||
|
TOKEN_KEYWORD_PRINT,
|
||||||
TOKEN_OPERATOR_NOT,
|
TOKEN_OPERATOR_NOT,
|
||||||
TOKEN_OPERATOR_AND,
|
TOKEN_OPERATOR_AND,
|
||||||
TOKEN_OPERATOR_OR,
|
TOKEN_OPERATOR_OR,
|
||||||
|
|
|
||||||
2
libc.c
2
libc.c
|
|
@ -76,7 +76,7 @@ snlen(const char *str, u32 max_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
aaloc(Arena *arena, u32 size)
|
aalloc(Arena *arena, u32 size)
|
||||||
{
|
{
|
||||||
u32 pos;
|
u32 pos;
|
||||||
if(arena == nil) return nil;
|
if(arena == nil) return nil;
|
||||||
|
|
|
||||||
24
list.c
24
list.c
|
|
@ -22,6 +22,7 @@ node_value(Node *n)
|
||||||
void *
|
void *
|
||||||
list_push(Arena *arena, List *list, void *data, u32 data_size)
|
list_push(Arena *arena, List *list, void *data, u32 data_size)
|
||||||
{
|
{
|
||||||
|
void *dest;
|
||||||
void *ptr = aalloc(arena, sizeof(Node) + data_size);
|
void *ptr = aalloc(arena, sizeof(Node) + data_size);
|
||||||
Node *node = (Node *)ptr;
|
Node *node = (Node *)ptr;
|
||||||
|
|
||||||
|
|
@ -38,7 +39,7 @@ list_push(Arena *arena, List *list, void *data, u32 data_size)
|
||||||
|
|
||||||
list->count++;
|
list->count++;
|
||||||
|
|
||||||
void *dest = node_value(node);
|
dest = node_value(node);
|
||||||
if (data && data_size > 0) {
|
if (data && data_size > 0) {
|
||||||
mcpy(dest, data, data_size);
|
mcpy(dest, data, data_size);
|
||||||
}
|
}
|
||||||
|
|
@ -49,9 +50,10 @@ list_push(Arena *arena, List *list, void *data, u32 data_size)
|
||||||
void
|
void
|
||||||
list_foreach(List *list, list_iter_fn func)
|
list_foreach(List *list, list_iter_fn func)
|
||||||
{
|
{
|
||||||
|
Node *curr;
|
||||||
if (!list || !func) return;
|
if (!list || !func) return;
|
||||||
|
|
||||||
Node *curr = list->head;
|
curr = list->head;
|
||||||
while (curr) {
|
while (curr) {
|
||||||
func(node_value(curr));
|
func(node_value(curr));
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
|
|
@ -61,11 +63,12 @@ list_foreach(List *list, list_iter_fn func)
|
||||||
void *
|
void *
|
||||||
list_get(List *list, u32 index)
|
list_get(List *list, u32 index)
|
||||||
{
|
{
|
||||||
|
u32 i;
|
||||||
|
Node *curr;
|
||||||
if (!list || index >= list->count) return nil;
|
if (!list || index >= list->count) return nil;
|
||||||
|
|
||||||
Node *curr = list->head;
|
curr = list->head;
|
||||||
// Walk to the desired index
|
for (i = 0; i < index; i++) {
|
||||||
for (u32 i = 0; i < index; i++) {
|
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +76,7 @@ list_get(List *list, u32 index)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
void *target = list_get(list, index);
|
||||||
if (target) {
|
if (target) {
|
||||||
|
|
@ -82,13 +85,16 @@ list_set(List *list, u32 index, const void *data, u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
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;
|
if (!list || !compare) return nil;
|
||||||
|
|
||||||
Node *curr = list->head;
|
curr = list->head;
|
||||||
while (curr) {
|
while (curr) {
|
||||||
void *data = node_value(curr);
|
data = node_value(curr);
|
||||||
if (compare(data, target)) {
|
if (compare(data, target)) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
list.h
6
list.h
|
|
@ -15,15 +15,15 @@ struct list_s {
|
||||||
u32 count;
|
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);
|
typedef void (*list_iter_fn)(void *data);
|
||||||
|
|
||||||
List *new_list(Arena *arena);
|
List *new_list(Arena *arena);
|
||||||
void *node_value(Node *n);
|
void *node_value(Node *n);
|
||||||
void *list_push(Arena *arena, List *list, void *data, u32 data_size);
|
void *list_push(Arena *arena, List *list, void *data, u32 data_size);
|
||||||
void list_foreach(List *list, list_iter_fn func);
|
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_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
|
#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 "parser.h"
|
||||||
|
#include "emit.h"
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
|
|
||||||
bool
|
|
||||||
advance()
|
|
||||||
{
|
|
||||||
parser.previous = parser.current;
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
parser.current = next_token();
|
|
||||||
if(parser.current.type != TOKEN_ERROR) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* Scope
|
* Scope
|
||||||
***************************************************/
|
***************************************************/
|
||||||
|
|
@ -30,7 +18,7 @@ scope_push(Arena *arena)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scope_pop(Arena *arena)
|
scope_pop()
|
||||||
{
|
{
|
||||||
Scope *prev = parser.current_scope->parent;
|
Scope *prev = parser.current_scope->parent;
|
||||||
parser.current_scope = prev;
|
parser.current_scope = prev;
|
||||||
|
|
@ -39,21 +27,21 @@ scope_pop(Arena *arena)
|
||||||
Symbol *
|
Symbol *
|
||||||
scope_get_symbol(Scope *scope, const char *name, u32 name_length)
|
scope_get_symbol(Scope *scope, const char *name, u32 name_length)
|
||||||
{
|
{
|
||||||
|
u32 count, i;
|
||||||
if(!scope) return nil;
|
if(!scope) return nil;
|
||||||
|
|
||||||
u32 count = scope->symbols->count;
|
count = scope->symbols->count;
|
||||||
for (u32 i = 0; i < count; i++) {
|
for(i = 0; i < count; i++) {
|
||||||
Symbol *sym = list_get(scope->symbols, i);
|
Symbol *sym = list_get(scope->symbols, i);
|
||||||
if (sleq(sym->name, name, name_length)) {
|
if(sleq(sym->name, name, name_length)) return sym;
|
||||||
return sym;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope_get_symbol(scope->parent, name, name_length);
|
return scope_get_symbol(scope->parent, name, name_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *
|
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);
|
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
|
||||||
if(sym != nil) return sym;
|
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));
|
scpy(sym->name, name, slen(name));
|
||||||
sym->name_length = slen(name);
|
sym->name_length = slen(name);
|
||||||
sym->type = type;
|
sym->type = type;
|
||||||
sym->secondary_type = VOID; // Default
|
sym->secondary_type = VOID;
|
||||||
sym->size = size;
|
sym->size = size;
|
||||||
sym->ref = 0;
|
sym->ref = 0;
|
||||||
if(type == PLEX || type == METHOD || type == TRAIT) {
|
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
|
* Parser
|
||||||
***************************************************/
|
***************************************************/
|
||||||
|
|
||||||
bool
|
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
|
bool
|
||||||
parse_plex()
|
consume(TokenType type)
|
||||||
{
|
{
|
||||||
|
if(check(type)) {
|
||||||
|
advance();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
return false;
|
||||||
parse_function()
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
match(TokenType type)
|
||||||
{
|
{
|
||||||
|
if(!check(type)) return false;
|
||||||
|
advance();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void expression();
|
||||||
parse_if()
|
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
|
/* Move to above switch statement for postfix */
|
||||||
parse_loop()
|
parse_precedence((Precedence)(rule->precedence + 1));
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void
|
||||||
parse_while()
|
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
|
static void
|
||||||
parse_for()
|
expression()
|
||||||
{
|
{
|
||||||
return true;
|
parse_precedence(PREC_ASSIGNMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void
|
||||||
parse_return()
|
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
|
statement();
|
||||||
parse_assignment()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void
|
||||||
parse_expression()
|
statement()
|
||||||
{
|
{
|
||||||
return true;
|
if(match(TOKEN_KEYWORD_PRINT))
|
||||||
|
emit_print();
|
||||||
|
else
|
||||||
|
expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void
|
||||||
parse_statement()
|
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
|
bool
|
||||||
compile(char *source)
|
compile(char *source)
|
||||||
{
|
{
|
||||||
|
init_lexer(source);
|
||||||
|
advance();
|
||||||
|
|
||||||
|
prolog();
|
||||||
|
|
||||||
|
while(!match(TOKEN_EOF)) declaration();
|
||||||
|
|
||||||
|
epilogue();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
29
parser.h
29
parser.h
|
|
@ -4,6 +4,7 @@
|
||||||
#include "libc.h"
|
#include "libc.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
#include "emit.h"
|
||||||
|
|
||||||
typedef enum symbol_type_e {
|
typedef enum symbol_type_e {
|
||||||
VOID,
|
VOID,
|
||||||
|
|
@ -25,12 +26,13 @@ typedef enum symbol_type_e {
|
||||||
PLEX,
|
PLEX,
|
||||||
METHOD,
|
METHOD,
|
||||||
TRAIT,
|
TRAIT,
|
||||||
CONST,
|
CONST
|
||||||
} SymbolType;
|
} SymbolType;
|
||||||
|
|
||||||
typedef struct symbol_s Symbol;
|
typedef struct symbol_s Symbol;
|
||||||
typedef struct scope_s Scope;
|
typedef struct scope_s Scope;
|
||||||
typedef struct parser_s Parser;
|
typedef struct parser_s Parser;
|
||||||
|
typedef struct parse_rule_s ParseRule;
|
||||||
|
|
||||||
#define MAX_SYMBOL_NAME_LENGTH 64
|
#define MAX_SYMBOL_NAME_LENGTH 64
|
||||||
struct symbol_s {
|
struct symbol_s {
|
||||||
|
|
@ -49,6 +51,28 @@ struct scope_s {
|
||||||
List *symbols; /* list of symbols that live in this scope */
|
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 {
|
struct parser_s {
|
||||||
Scope *current_scope;
|
Scope *current_scope;
|
||||||
Token current;
|
Token current;
|
||||||
|
|
@ -57,4 +81,7 @@ struct parser_s {
|
||||||
|
|
||||||
bool compile(char *source);
|
bool compile(char *source);
|
||||||
|
|
||||||
|
extern void emit_return();
|
||||||
|
extern void emit_constant();
|
||||||
|
|
||||||
#endif
|
#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