Compare commits
7
Commits
v1.1
..
bbdaa4a9b9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbdaa4a9b9 | ||
|
|
7c04d8b7ec | ||
|
|
567bf49d27 | ||
|
|
d93c315359 | ||
|
|
e11089c90f | ||
|
|
ea28c470d2 | ||
|
|
70bf63e2ea |
@@ -5,6 +5,7 @@ skip is
|
|||||||
skip -rfunction fzl_mk*
|
skip -rfunction fzl_mk*
|
||||||
skip -rfunction fzl_free*
|
skip -rfunction fzl_free*
|
||||||
skip -rfunction fzl_symt*
|
skip -rfunction fzl_symt*
|
||||||
|
skip -rfunction fzl_linked*
|
||||||
skip add_const
|
skip add_const
|
||||||
skip push_op
|
skip push_op
|
||||||
skip push_word
|
skip push_word
|
||||||
|
|||||||
+14
-1
@@ -11,6 +11,13 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(ffi
|
||||||
|
GIT_REPOSITORY "https://git.samsonium.dev/samsonium/libffi.git"
|
||||||
|
GIT_TAG "main"
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(ffi)
|
||||||
|
|
||||||
# Compiler
|
# Compiler
|
||||||
add_executable(fzc
|
add_executable(fzc
|
||||||
@@ -19,7 +26,6 @@ add_executable(fzc
|
|||||||
src/compiler/utils/fzl_linked.c
|
src/compiler/utils/fzl_linked.c
|
||||||
src/compiler/utils/fzl_options.c
|
src/compiler/utils/fzl_options.c
|
||||||
src/compiler/utils/fzl_ctable.c
|
src/compiler/utils/fzl_ctable.c
|
||||||
src/compiler/checkers/fzl_loop_check.c
|
|
||||||
src/compiler/analyzer/utility.c
|
src/compiler/analyzer/utility.c
|
||||||
src/compiler/analyzer/context.c
|
src/compiler/analyzer/context.c
|
||||||
src/compiler/analyzer/an_assign.c
|
src/compiler/analyzer/an_assign.c
|
||||||
@@ -40,6 +46,11 @@ add_executable(fzc
|
|||||||
src/compiler/analyzer/an_return.c
|
src/compiler/analyzer/an_return.c
|
||||||
src/compiler/analyzer/an_unarycond.c
|
src/compiler/analyzer/an_unarycond.c
|
||||||
src/compiler/analyzer/an_unarymath.c
|
src/compiler/analyzer/an_unarymath.c
|
||||||
|
src/compiler/reader/rd_fmtstr.c
|
||||||
|
src/compiler/reader/rd_name.c
|
||||||
|
src/compiler/reader/rd_number.c
|
||||||
|
src/compiler/reader/rd_string_literal.c
|
||||||
|
src/compiler/reader/utility.c
|
||||||
src/compiler/fzl_analyzer.c
|
src/compiler/fzl_analyzer.c
|
||||||
src/compiler/fzl_debug.c
|
src/compiler/fzl_debug.c
|
||||||
src/compiler/fzl_parser.c
|
src/compiler/fzl_parser.c
|
||||||
@@ -56,6 +67,8 @@ add_executable(fz
|
|||||||
src/vm/fzl_vm_debug.c
|
src/vm/fzl_vm_debug.c
|
||||||
src/vm/main.c)
|
src/vm/main.c)
|
||||||
|
|
||||||
|
target_link_libraries(fz PRIVATE ffi_static dl)
|
||||||
|
|
||||||
#
|
#
|
||||||
# ========== Tests ==========
|
# ========== Tests ==========
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
extern "libglfw" {
|
||||||
|
type GLFWwindow = handle;
|
||||||
|
type GLFWmonitor = handle;
|
||||||
|
|
||||||
|
struct GLFWvidmode {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int redBits;
|
||||||
|
int greenBits;
|
||||||
|
int blueBits;
|
||||||
|
int refreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// GLFWvidmode*
|
||||||
|
type GLFWvidmodeRef = ref GLFWvidmode;
|
||||||
|
|
||||||
|
/// Create window with specified [width], [height] and [title]
|
||||||
|
fn glfw_mkWindow(
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
str title,
|
||||||
|
GLFWmonitor mon,
|
||||||
|
GLFWwindow shr
|
||||||
|
) GLFWwindow = "glfwCreateWindow";
|
||||||
|
|
||||||
|
/// Get videomode from monitor [mon]
|
||||||
|
fn glfw_getVideoMode(
|
||||||
|
GLFWmonitor mon
|
||||||
|
) GLFWvidmodeRef = "glfwGetVideoMode";
|
||||||
|
|
||||||
|
/// Get framebuffer [width] and [height]
|
||||||
|
fn glfw_getFrameBufferSize(
|
||||||
|
GLFWwindow win,
|
||||||
|
out int width,
|
||||||
|
out int height
|
||||||
|
) = "glfwGetFramebufferSize";
|
||||||
|
}
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ typedef enum
|
|||||||
FZL_OPCODE_MOD = 0xA00006, // Get module of two numbers in dstack
|
FZL_OPCODE_MOD = 0xA00006, // Get module of two numbers in dstack
|
||||||
FZL_OPCODE_NEG = 0xA00007, // Negotiate number in dstack
|
FZL_OPCODE_NEG = 0xA00007, // Negotiate number in dstack
|
||||||
|
|
||||||
|
FZL_OPCODE_BUILD_STR = 0xA10001, // Build a string from N values in dstack
|
||||||
|
|
||||||
FZL_OPCODE_CMP_EQ = 0xB00001, // Equal
|
FZL_OPCODE_CMP_EQ = 0xB00001, // Equal
|
||||||
FZL_OPCODE_CMP_NEQ = 0xB00002, // Not equal
|
FZL_OPCODE_CMP_NEQ = 0xB00002, // Not equal
|
||||||
FZL_OPCODE_CMP_LT = 0xB00003, // Less than
|
FZL_OPCODE_CMP_LT = 0xB00003, // Less than
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ typedef enum
|
|||||||
FZL_TYPE_NULL,
|
FZL_TYPE_NULL,
|
||||||
FZL_TYPE_OBJECT,
|
FZL_TYPE_OBJECT,
|
||||||
|
|
||||||
|
FZL_TYPE_EXTERN_FN,
|
||||||
|
|
||||||
FZL_TYPE_STRING,
|
FZL_TYPE_STRING,
|
||||||
FZL_TYPE_CHAR,
|
FZL_TYPE_CHAR,
|
||||||
FZL_TYPE_BOOL,
|
FZL_TYPE_BOOL,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef enum
|
|||||||
FZL_NODETYPE_BLOCK,
|
FZL_NODETYPE_BLOCK,
|
||||||
FZL_NODETYPE_CALL,
|
FZL_NODETYPE_CALL,
|
||||||
FZL_NODETYPE_LITERAL,
|
FZL_NODETYPE_LITERAL,
|
||||||
|
FZL_NODETYPE_FMT_STRING,
|
||||||
FZL_NODETYPE_IDENTIFIER,
|
FZL_NODETYPE_IDENTIFIER,
|
||||||
FZL_NODETYPE_CONDITIONAL,
|
FZL_NODETYPE_CONDITIONAL,
|
||||||
FZL_NODETYPE_FUNCTION,
|
FZL_NODETYPE_FUNCTION,
|
||||||
|
|||||||
@@ -8,57 +8,68 @@
|
|||||||
// Token type
|
// Token type
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
FZL_TOKTYPE_CLASS, // class
|
FZL_TOKTYPE_IMPORT, // `import`
|
||||||
FZL_TOKTYPE_NEW, // new
|
FZL_TOKTYPE_EXTERN, // `extern`
|
||||||
|
FZL_TOKTYPE_TYPEDEF, // `type`
|
||||||
|
FZL_TOKTYPE_HANDLE, // `handle`
|
||||||
|
FZL_TOKTYPE_STRUCT, // `struct`
|
||||||
|
FZL_TOKTYPE_REFERENCE, // `ref`
|
||||||
|
FZL_TOKTYPE_OUT, // `out`
|
||||||
|
|
||||||
FZL_TOKTYPE_FUNCTION, // fn
|
FZL_TOKTYPE_CLASS, // `class`
|
||||||
FZL_TOKTYPE_RETURN, // return
|
FZL_TOKTYPE_NEW, // `new`
|
||||||
|
|
||||||
FZL_TOKTYPE_FOR, // for
|
FZL_TOKTYPE_FUNCTION, // `fn`
|
||||||
FZL_TOKTYPE_WHILE, // while
|
FZL_TOKTYPE_RETURN, // `return`
|
||||||
FZL_TOKTYPE_BREAK, // break
|
|
||||||
|
|
||||||
FZL_TOKTYPE_IF, // if
|
FZL_TOKTYPE_FOR, // `for`
|
||||||
FZL_TOKTYPE_ELSE, // else
|
FZL_TOKTYPE_WHILE, // `while`
|
||||||
|
FZL_TOKTYPE_BREAK, // `break`
|
||||||
|
|
||||||
|
FZL_TOKTYPE_IF, // `if`
|
||||||
|
FZL_TOKTYPE_ELSE, // `else`
|
||||||
|
|
||||||
FZL_TOKTYPE_NAME, // abc
|
FZL_TOKTYPE_NAME, // abc
|
||||||
FZL_TOKTYPE_TYPE, // i16
|
FZL_TOKTYPE_TYPE, // i16
|
||||||
|
|
||||||
FZL_TOKTYPE_DDASH, // // :D
|
FZL_TOKTYPE_DDASH, // `//` :D
|
||||||
|
|
||||||
FZL_TOKTYPE_LPAREN, // (
|
FZL_TOKTYPE_LPAREN, // `(`
|
||||||
FZL_TOKTYPE_RPAREN, // )
|
FZL_TOKTYPE_RPAREN, // `)`
|
||||||
FZL_TOKTYPE_LBRACE, // {
|
FZL_TOKTYPE_LBRACE, // `{`
|
||||||
FZL_TOKTYPE_RBRACE, // }
|
FZL_TOKTYPE_RBRACE, // `}`
|
||||||
|
|
||||||
FZL_TOKTYPE_COMMA, // ,
|
FZL_TOKTYPE_COMMA, // `,`
|
||||||
FZL_TOKTYPE_DOT, // .
|
FZL_TOKTYPE_DOT, // `.`
|
||||||
FZL_TOKTYPE_SEMICOLON, // ;
|
FZL_TOKTYPE_SEMICOLON, // `;`
|
||||||
|
|
||||||
FZL_TOKTYPE_STR_LITERAL, // ""
|
FZL_TOKTYPE_STR_LITERAL, // ""
|
||||||
FZL_TOKTYPE_NUM_LITERAL, // 123
|
FZL_TOKTYPE_NUM_LITERAL, // 123
|
||||||
FZL_TOKTYPE_BOOL_LITERAL, // true
|
FZL_TOKTYPE_BOOL_LITERAL, // true
|
||||||
FZL_TOKTYPE_NULL_LITERAL, // null
|
FZL_TOKTYPE_NULL_LITERAL, // null
|
||||||
|
|
||||||
FZL_TOKTYPE_DAMPERSAND, // &&
|
FZL_TOKTYPE_STR_FORMAT_START, // `$` before `"`
|
||||||
FZL_TOKTYPE_DVBAR, // ||
|
FZL_TOKTYPE_STR_FORMAT_END, // end of string formatting sequence
|
||||||
|
|
||||||
FZL_TOKTYPE_EQEQ, // ==
|
FZL_TOKTYPE_DAMPERSAND, // `&&`
|
||||||
FZL_TOKTYPE_REQ, // >=
|
FZL_TOKTYPE_DVBAR, // `||`
|
||||||
FZL_TOKTYPE_LEQ, // <=
|
|
||||||
FZL_TOKTYPE_NEQ, // !=
|
|
||||||
FZL_TOKTYPE_LANGLE, // <
|
|
||||||
FZL_TOKTYPE_RANGLE, // >
|
|
||||||
FZL_TOKTYPE_NOT, // !
|
|
||||||
|
|
||||||
FZL_TOKTYPE_STAR, // *
|
FZL_TOKTYPE_EQEQ, // `==`
|
||||||
FZL_TOKTYPE_SLASH, // /
|
FZL_TOKTYPE_REQ, // `>=`
|
||||||
FZL_TOKTYPE_PLUS, // +
|
FZL_TOKTYPE_LEQ, // `<=`
|
||||||
FZL_TOKTYPE_MINUS, // -
|
FZL_TOKTYPE_NEQ, // `!=`
|
||||||
FZL_TOKTYPE_CARET, // ^
|
FZL_TOKTYPE_LANGLE, // `<`
|
||||||
FZL_TOKTYPE_PERCENT, // %
|
FZL_TOKTYPE_RANGLE, // `>`
|
||||||
|
FZL_TOKTYPE_NOT, // `!`
|
||||||
|
|
||||||
FZL_TOKTYPE_EQ // =
|
FZL_TOKTYPE_STAR, // `*`
|
||||||
|
FZL_TOKTYPE_SLASH, // `/`
|
||||||
|
FZL_TOKTYPE_PLUS, // `+`
|
||||||
|
FZL_TOKTYPE_MINUS, // `-`
|
||||||
|
FZL_TOKTYPE_CARET, // `^`
|
||||||
|
FZL_TOKTYPE_PERCENT, // `%`
|
||||||
|
|
||||||
|
FZL_TOKTYPE_EQ // `=`
|
||||||
} fzl_toktype_t;
|
} fzl_toktype_t;
|
||||||
|
|
||||||
// Token descriptor
|
// Token descriptor
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef INTERNALS_READER_H
|
||||||
|
#define INTERNALS_READER_H
|
||||||
|
|
||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
extern char last_err[256];
|
||||||
|
|
||||||
|
size_t move(fzl_reader_t *reader, size_t len);
|
||||||
|
void rd_comment(fzl_reader_t *reader);
|
||||||
|
|
||||||
|
fzl_token_t *rd_name(fzl_reader_t *reader);
|
||||||
|
fzl_token_t *rd_string_literal(fzl_reader_t *reader);
|
||||||
|
fzl_token_t *rd_number(fzl_reader_t *reader);
|
||||||
|
fzl_token_t *rd_single(fzl_reader_t *reader, fzl_toktype_t type);
|
||||||
|
fzl_token_t *rd_double(fzl_reader_t *reader, fzl_toktype_t type);
|
||||||
|
fzl_token_t *rd_fmtstr(fzl_reader_t *reader);
|
||||||
|
|
||||||
|
#endif // INTERNALS_READER_H
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vm/fzl_vm_env.h>
|
#include <vm/fzl_vm_env.h>
|
||||||
|
#include <vm/fzl_vm_extern.h>
|
||||||
#include <vm/fzl_vm_object.h>
|
#include <vm/fzl_vm_object.h>
|
||||||
|
|
||||||
// VM descriptor
|
// VM descriptor
|
||||||
@@ -14,6 +15,9 @@ typedef struct
|
|||||||
fzl_const_t *consts;
|
fzl_const_t *consts;
|
||||||
size_t consts_count;
|
size_t consts_count;
|
||||||
|
|
||||||
|
fzl_vm_extern_t *externs;
|
||||||
|
size_t externs_count;
|
||||||
|
|
||||||
uint64_t *ops;
|
uint64_t *ops;
|
||||||
size_t ops_count;
|
size_t ops_count;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef FZL_VM_EXTERN_H
|
||||||
|
#define FZL_VM_EXTERN_H
|
||||||
|
|
||||||
|
#include <ffi.h>
|
||||||
|
|
||||||
|
// Loaded extern function definition
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void *func_ptr;
|
||||||
|
ffi_cif cif;
|
||||||
|
ffi_type **arg_types;
|
||||||
|
} fzl_vm_extern_t;
|
||||||
|
|
||||||
|
#endif // FZL_VM_EXTERN_H
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
#include <common/fzl_opcodes.h>
|
|
||||||
#include <common/fzl_types.h>
|
|
||||||
#include <compiler/fzl_parser.h>
|
|
||||||
#include <compiler/fzl_walker.h>
|
|
||||||
#include <compiler/utils/fzl_const_pool.h>
|
|
||||||
#include <compiler/utils/fzl_symtable.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
ssize_t check_top;
|
|
||||||
fzl_nodetype_t check_tree[256];
|
|
||||||
|
|
||||||
// Ghost walk AST tree (w/o adding opcodes) to check if
|
|
||||||
// variable used in condition is changed
|
|
||||||
void ghost_walk_changed(fzl_node_t *node, bool *changed, fzl_sym_t *sym)
|
|
||||||
{
|
|
||||||
if (!node || !changed || *changed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
check_tree[check_top++] = node->type;
|
|
||||||
|
|
||||||
switch (node->type)
|
|
||||||
{
|
|
||||||
case FZL_NODETYPE_BREAK:
|
|
||||||
case FZL_NODETYPE_DECLARATION:
|
|
||||||
case FZL_NODETYPE_CONSTRUCT:
|
|
||||||
case FZL_NODETYPE_CLASS:
|
|
||||||
case FZL_NODETYPE_FUNCTION:
|
|
||||||
case FZL_NODETYPE_LITERAL:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_UNARY_PLUS:
|
|
||||||
case FZL_NODETYPE_UNARY_MINUS:
|
|
||||||
case FZL_NODETYPE_NOT:
|
|
||||||
ghost_walk_changed(node->unary_op.operand, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_ADD:
|
|
||||||
case FZL_NODETYPE_SUB:
|
|
||||||
case FZL_NODETYPE_MUL:
|
|
||||||
case FZL_NODETYPE_DIV:
|
|
||||||
case FZL_NODETYPE_POW:
|
|
||||||
case FZL_NODETYPE_MOD:
|
|
||||||
case FZL_NODETYPE_OR:
|
|
||||||
case FZL_NODETYPE_AND:
|
|
||||||
case FZL_NODETYPE_EQUAL:
|
|
||||||
case FZL_NODETYPE_NEQUAL:
|
|
||||||
case FZL_NODETYPE_LESS:
|
|
||||||
case FZL_NODETYPE_LESS_EQUAL:
|
|
||||||
case FZL_NODETYPE_GREATER:
|
|
||||||
case FZL_NODETYPE_GREATER_EQUAL:
|
|
||||||
case FZL_NODETYPE_ASSIGN:
|
|
||||||
ghost_walk_changed(node->binary_op.left, changed, sym);
|
|
||||||
ghost_walk_changed(node->binary_op.right, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_FIELD:
|
|
||||||
ghost_walk_changed(node->memb.parent, changed, sym);
|
|
||||||
ghost_walk_changed(node->memb.field, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_RETURN:
|
|
||||||
ghost_walk_changed(node->ret.value, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_CONDITIONAL:
|
|
||||||
ghost_walk_changed(node->cond.condition, changed, sym);
|
|
||||||
ghost_walk_changed(node->cond.true_block, changed, sym);
|
|
||||||
ghost_walk_changed(node->cond.else_block, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_LOOP:
|
|
||||||
ghost_walk_changed(node->loop.cond, changed, sym);
|
|
||||||
ghost_walk_changed(node->loop.step, changed, sym);
|
|
||||||
ghost_walk_changed(node->loop.body, changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_BLOCK:
|
|
||||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
|
||||||
ghost_walk_changed(node->list.entries[i], changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_CALL:
|
|
||||||
ghost_walk_changed(node->call.callee, changed, sym);
|
|
||||||
for (size_t i = 0; i < node->call.args_count; i++)
|
|
||||||
ghost_walk_changed(node->call.args[i], changed, sym);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_IDENTIFIER:
|
|
||||||
if (strcmp(node->token->value, sym->name) == 0)
|
|
||||||
{
|
|
||||||
*changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*changed)
|
|
||||||
{
|
|
||||||
*changed = false;
|
|
||||||
for (ssize_t i = check_top - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
fzl_nodetype_t cur_t = check_tree[i];
|
|
||||||
if (cur_t == FZL_NODETYPE_ADD || cur_t == FZL_NODETYPE_SUB ||
|
|
||||||
cur_t == FZL_NODETYPE_MUL || cur_t == FZL_NODETYPE_DIV ||
|
|
||||||
cur_t == FZL_NODETYPE_POW || cur_t == FZL_NODETYPE_MOD ||
|
|
||||||
cur_t == FZL_NODETYPE_UNARY_MINUS)
|
|
||||||
{
|
|
||||||
*changed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_tree[--check_top] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether value changed in loop body
|
|
||||||
bool value_is_changed(fzl_node_t *node, fzl_sym_t *sym)
|
|
||||||
{
|
|
||||||
if (!node || !sym)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
check_top = 0;
|
|
||||||
memset(check_tree, 0, sizeof(check_tree));
|
|
||||||
ghost_walk_changed(node, &changed, sym);
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find symbol in loop condition node
|
|
||||||
bool retrieve_cond_sym(fzl_walker_t *walker, fzl_node_t *node, fzl_sym_t *sym)
|
|
||||||
{
|
|
||||||
if (!walker || !node)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (node->type)
|
|
||||||
{
|
|
||||||
case FZL_NODETYPE_BREAK:
|
|
||||||
case FZL_NODETYPE_BLOCK:
|
|
||||||
case FZL_NODETYPE_CALL:
|
|
||||||
case FZL_NODETYPE_LITERAL:
|
|
||||||
case FZL_NODETYPE_CONDITIONAL:
|
|
||||||
case FZL_NODETYPE_FUNCTION:
|
|
||||||
case FZL_NODETYPE_RETURN:
|
|
||||||
case FZL_NODETYPE_CLASS:
|
|
||||||
case FZL_NODETYPE_FIELD:
|
|
||||||
case FZL_NODETYPE_CONSTRUCT:
|
|
||||||
case FZL_NODETYPE_LOOP:
|
|
||||||
case FZL_NODETYPE_ASSIGN:
|
|
||||||
case FZL_NODETYPE_DECLARATION:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_UNARY_MINUS:
|
|
||||||
case FZL_NODETYPE_UNARY_PLUS:
|
|
||||||
case FZL_NODETYPE_NOT:
|
|
||||||
return retrieve_cond_sym(walker, node->unary_op.operand, sym);
|
|
||||||
|
|
||||||
case FZL_NODETYPE_ADD:
|
|
||||||
case FZL_NODETYPE_SUB:
|
|
||||||
case FZL_NODETYPE_MUL:
|
|
||||||
case FZL_NODETYPE_DIV:
|
|
||||||
case FZL_NODETYPE_POW:
|
|
||||||
case FZL_NODETYPE_MOD:
|
|
||||||
case FZL_NODETYPE_AND:
|
|
||||||
case FZL_NODETYPE_OR:
|
|
||||||
case FZL_NODETYPE_LESS:
|
|
||||||
case FZL_NODETYPE_LESS_EQUAL:
|
|
||||||
case FZL_NODETYPE_GREATER:
|
|
||||||
case FZL_NODETYPE_GREATER_EQUAL:
|
|
||||||
case FZL_NODETYPE_EQUAL:
|
|
||||||
case FZL_NODETYPE_NEQUAL:
|
|
||||||
if (retrieve_cond_sym(walker, node->binary_op.left, sym))
|
|
||||||
return true;
|
|
||||||
if (retrieve_cond_sym(walker, node->binary_op.right, sym))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case FZL_NODETYPE_IDENTIFIER:
|
|
||||||
{
|
|
||||||
bool exists;
|
|
||||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if ((exists = fzl_symt_get(walker->syms[i], (char *)node->token->value,
|
|
||||||
sym)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for infinite loop
|
|
||||||
bool is_infinite_loop(fzl_walker_t *walker, fzl_node_t *node, size_t start_ip,
|
|
||||||
size_t end_ip)
|
|
||||||
{
|
|
||||||
if (!walker)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
end_ip = (end_ip >= walker->op_count) ? (walker->op_count - 1) : end_ip;
|
|
||||||
|
|
||||||
fzl_sym_t sym;
|
|
||||||
bool sym_exists = retrieve_cond_sym(walker, node->loop.cond, &sym);
|
|
||||||
if (sym_exists)
|
|
||||||
{
|
|
||||||
if (sym.type >= FZL_TYPE_INT8)
|
|
||||||
{
|
|
||||||
bool value_changed = value_is_changed(node, &sym);
|
|
||||||
if (value_changed)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// At least has jump outside
|
|
||||||
for (size_t i = start_ip; i <= end_ip; i++)
|
|
||||||
{
|
|
||||||
if (walker->ops[i] != FZL_OPCODE_JMP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t jump_ip = walker->ops[++i];
|
|
||||||
if (jump_ip >= end_ip)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -31,6 +31,26 @@ void print_node(fzl_node_t *node, int level)
|
|||||||
|
|
||||||
switch (node->type)
|
switch (node->type)
|
||||||
{
|
{
|
||||||
|
case FZL_NODETYPE_UNARY_MINUS:
|
||||||
|
printf("%s Unary '-':\n", levelbuf);
|
||||||
|
print_node(node->unary_op.operand, level + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_UNARY_PLUS:
|
||||||
|
printf("%s Unary '+':\n", levelbuf);
|
||||||
|
print_node(node->unary_op.operand, level + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_BREAK:
|
||||||
|
printf("%s Break\n", levelbuf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_FMT_STRING:
|
||||||
|
printf("%s Format string:\n", levelbuf);
|
||||||
|
for (size_t i = 0; i < node->list.entry_count; i++)
|
||||||
|
print_node(node->list.entries[i], level + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_LOOP:
|
case FZL_NODETYPE_LOOP:
|
||||||
printf("%s Loop:\n", levelbuf);
|
printf("%s Loop:\n", levelbuf);
|
||||||
printf("-%s Init:\n", levelbuf);
|
printf("-%s Init:\n", levelbuf);
|
||||||
@@ -172,9 +192,6 @@ void print_node(fzl_node_t *node, int level)
|
|||||||
case FZL_NODETYPE_IDENTIFIER:
|
case FZL_NODETYPE_IDENTIFIER:
|
||||||
printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value);
|
printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
printf("%s Secure node\n", levelbuf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+115
-38
@@ -1,5 +1,5 @@
|
|||||||
#include "compiler/fzl_token.h"
|
|
||||||
#include <compiler/fzl_parser.h>
|
#include <compiler/fzl_parser.h>
|
||||||
|
#include <compiler/fzl_token.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -151,6 +151,99 @@ fzl_node_t *parse_primary(fzl_parser_t *parser)
|
|||||||
fzl_token_t *tok = consume(parser);
|
fzl_token_t *tok = consume(parser);
|
||||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||||
}
|
}
|
||||||
|
else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START))
|
||||||
|
{
|
||||||
|
consume(parser);
|
||||||
|
|
||||||
|
size_t remainder = 2;
|
||||||
|
size_t count = 0;
|
||||||
|
fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *));
|
||||||
|
if (!entries)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END)
|
||||||
|
{
|
||||||
|
if (is(parser, FZL_TOKTYPE_STR_FORMAT_END))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (remainder <= count)
|
||||||
|
{
|
||||||
|
remainder *= 2;
|
||||||
|
fzl_node_t **newentries =
|
||||||
|
realloc(entries, remainder * sizeof(fzl_node_t *));
|
||||||
|
if (!newentries)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
fzl_freeast(entries[i]);
|
||||||
|
|
||||||
|
free(entries);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries = newentries;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzl_node_t *expr = parse_expression(parser);
|
||||||
|
if (expr == NULL)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
fzl_freeast(entries[i]);
|
||||||
|
|
||||||
|
free(entries);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries[count++] = expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzl_token_t *end = consume(parser);
|
||||||
|
if (end->type != FZL_TOKTYPE_STR_FORMAT_END)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err),
|
||||||
|
"'%s':%zu:%zu => unterminated format string",
|
||||||
|
last_known_tok->filename, last_known_tok->ln,
|
||||||
|
last_known_tok->cn);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
fzl_freeast(entries[i]);
|
||||||
|
|
||||||
|
free(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 1)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err),
|
||||||
|
"'%s':%zu:%zu => do you really need empty format string?",
|
||||||
|
last_known_tok->filename, last_known_tok->ln,
|
||||||
|
last_known_tok->cn);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
fzl_freeast(entries[i]);
|
||||||
|
|
||||||
|
free(entries);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token);
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
fzl_freeast(entries[i]);
|
||||||
|
|
||||||
|
free(entries);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->list.entries = entries;
|
||||||
|
node->list.entry_count = count;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
else if (is(parser, FZL_TOKTYPE_LPAREN))
|
else if (is(parser, FZL_TOKTYPE_LPAREN))
|
||||||
{
|
{
|
||||||
consume(parser);
|
consume(parser);
|
||||||
@@ -559,8 +652,8 @@ fzl_node_t *parse_new(fzl_parser_t *parser)
|
|||||||
|
|
||||||
fzl_token_t *new = consume(parser);
|
fzl_token_t *new = consume(parser);
|
||||||
fzl_node_t *objname = parse_or(parser);
|
fzl_node_t *objname = parse_or(parser);
|
||||||
if (objname->type != FZL_NODETYPE_IDENTIFIER &&
|
if (!objname || (objname->type != FZL_NODETYPE_IDENTIFIER &&
|
||||||
objname->type != FZL_NODETYPE_FIELD)
|
objname->type != FZL_NODETYPE_FIELD))
|
||||||
{
|
{
|
||||||
fzl_freeast(objname);
|
fzl_freeast(objname);
|
||||||
snprintf(plast_err, sizeof(plast_err),
|
snprintf(plast_err, sizeof(plast_err),
|
||||||
@@ -1247,7 +1340,10 @@ fzl_node_t *parse_program(fzl_parser_t *parser)
|
|||||||
{
|
{
|
||||||
node = parse_statement(parser);
|
node = parse_statement(parser);
|
||||||
if (!node)
|
if (!node)
|
||||||
|
{
|
||||||
|
fzl_freeast(first);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!last)
|
if (!last)
|
||||||
{
|
{
|
||||||
@@ -1308,54 +1404,40 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
case FZL_NODETYPE_LITERAL:
|
case FZL_NODETYPE_LITERAL:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_FMT_STRING:
|
||||||
case FZL_NODETYPE_BLOCK:
|
case FZL_NODETYPE_BLOCK:
|
||||||
if (root->list.entries)
|
if (root->list.entries)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < root->list.entry_count; i++)
|
for (size_t i = 0; i < root->list.entry_count; i++)
|
||||||
if (root->list.entries[i])
|
fzl_freeast(root->list.entries[i]);
|
||||||
fzl_freeast(root->list.entries[i]);
|
|
||||||
|
|
||||||
free(root->list.entries);
|
free(root->list.entries);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_CALL:
|
case FZL_NODETYPE_CALL:
|
||||||
if (root->call.callee)
|
fzl_freeast(root->call.callee);
|
||||||
fzl_freeast(root->call.callee);
|
|
||||||
|
|
||||||
if (root->call.args_count)
|
if (root->call.args_count)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < root->call.args_count; i++)
|
for (size_t i = 0; i < root->call.args_count; i++)
|
||||||
if (root->call.args[i])
|
fzl_freeast(root->call.args[i]);
|
||||||
fzl_freeast(root->call.args[i]);
|
|
||||||
}
|
}
|
||||||
if (root->call.args)
|
if (root->call.args)
|
||||||
free(root->call.args);
|
free(root->call.args);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_CONDITIONAL:
|
case FZL_NODETYPE_CONDITIONAL:
|
||||||
if (root->cond.condition)
|
fzl_freeast(root->cond.condition);
|
||||||
fzl_freeast(root->cond.condition);
|
fzl_freeast(root->cond.true_block);
|
||||||
|
fzl_freeast(root->cond.else_block);
|
||||||
if (root->cond.true_block)
|
|
||||||
fzl_freeast(root->cond.true_block);
|
|
||||||
|
|
||||||
if (root->cond.else_block)
|
|
||||||
fzl_freeast(root->cond.else_block);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_LOOP:
|
case FZL_NODETYPE_LOOP:
|
||||||
if (root->loop.init)
|
fzl_freeast(root->loop.init);
|
||||||
fzl_freeast(root->loop.init);
|
fzl_freeast(root->loop.cond);
|
||||||
|
fzl_freeast(root->loop.step);
|
||||||
if (root->loop.cond)
|
fzl_freeast(root->loop.body);
|
||||||
fzl_freeast(root->loop.cond);
|
|
||||||
|
|
||||||
if (root->loop.step)
|
|
||||||
fzl_freeast(root->loop.step);
|
|
||||||
|
|
||||||
if (root->loop.body)
|
|
||||||
fzl_freeast(root->loop.body);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_ADD:
|
case FZL_NODETYPE_ADD:
|
||||||
@@ -1373,17 +1455,14 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
case FZL_NODETYPE_GREATER:
|
case FZL_NODETYPE_GREATER:
|
||||||
case FZL_NODETYPE_GREATER_EQUAL:
|
case FZL_NODETYPE_GREATER_EQUAL:
|
||||||
case FZL_NODETYPE_ASSIGN:
|
case FZL_NODETYPE_ASSIGN:
|
||||||
if (root->binary_op.left)
|
fzl_freeast(root->binary_op.left);
|
||||||
fzl_freeast(root->binary_op.left);
|
fzl_freeast(root->binary_op.right);
|
||||||
if (root->binary_op.right)
|
|
||||||
fzl_freeast(root->binary_op.right);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_UNARY_PLUS:
|
case FZL_NODETYPE_UNARY_PLUS:
|
||||||
case FZL_NODETYPE_UNARY_MINUS:
|
case FZL_NODETYPE_UNARY_MINUS:
|
||||||
case FZL_NODETYPE_NOT:
|
case FZL_NODETYPE_NOT:
|
||||||
if (root->unary_op.operand)
|
fzl_freeast(root->unary_op.operand);
|
||||||
fzl_freeast(root->unary_op.operand);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_FUNCTION:
|
case FZL_NODETYPE_FUNCTION:
|
||||||
@@ -1395,8 +1474,7 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_RETURN:
|
case FZL_NODETYPE_RETURN:
|
||||||
if (root->ret.value)
|
fzl_freeast(root->ret.value);
|
||||||
fzl_freeast(root->ret.value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_CLASS:
|
case FZL_NODETYPE_CLASS:
|
||||||
@@ -1421,8 +1499,7 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_DECLARATION:
|
case FZL_NODETYPE_DECLARATION:
|
||||||
if (root->var.identifier)
|
fzl_freeast(root->var.identifier);
|
||||||
fzl_freeast(root->var.identifier);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-257
@@ -1,6 +1,7 @@
|
|||||||
#include "compiler/fzl_token.h"
|
|
||||||
#include "compiler/utils/fzl_linked.h"
|
|
||||||
#include <compiler/fzl_reader.h>
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/fzl_token.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <compiler/utils/fzl_linked.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -8,7 +9,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// Last error from reader
|
// Last error from reader
|
||||||
static char last_err[256] = {0};
|
char last_err[256];
|
||||||
|
|
||||||
fzl_reader_t *fzl_mkreader(fzl_linked_t *linked)
|
fzl_reader_t *fzl_mkreader(fzl_linked_t *linked)
|
||||||
{
|
{
|
||||||
@@ -24,238 +25,18 @@ fzl_reader_t *fzl_mkreader(fzl_linked_t *linked)
|
|||||||
reader->size = linked->total_sz;
|
reader->size = linked->total_sz;
|
||||||
reader->position = 0;
|
reader->position = 0;
|
||||||
|
|
||||||
|
memset(last_err, 0, sizeof(last_err));
|
||||||
|
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Read zone ---
|
|
||||||
|
|
||||||
// Move cursor forward
|
|
||||||
// @deprecated
|
|
||||||
static size_t move(fzl_reader_t *reader, size_t len)
|
|
||||||
{
|
|
||||||
if (!reader)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return reader->position += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try parse name
|
|
||||||
fzl_token_t *parse_name(fzl_reader_t *reader)
|
|
||||||
{
|
|
||||||
size_t lpos = reader->position;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lpos++;
|
|
||||||
size++;
|
|
||||||
} while ((reader->source[lpos] >= 'A' && reader->source[lpos] <= 'Z') ||
|
|
||||||
(reader->source[lpos] >= 'a' && reader->source[lpos] <= 'z') ||
|
|
||||||
(reader->source[lpos] >= '0' && reader->source[lpos] <= '9') ||
|
|
||||||
(reader->source[lpos] == '_'));
|
|
||||||
|
|
||||||
char *value = malloc(size + 1);
|
|
||||||
memcpy(value, reader->source + reader->position, size);
|
|
||||||
value[size] = '\0';
|
|
||||||
|
|
||||||
size_t start = reader->position;
|
|
||||||
move(reader, size);
|
|
||||||
|
|
||||||
fzl_token_t *tok;
|
|
||||||
fzl_file_loc l;
|
|
||||||
bool ok = fzl_linked_getpos(reader->linked, start, &l);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(value, "class") == 0)
|
|
||||||
tok =
|
|
||||||
fzl_mktoken(FZL_TOKTYPE_CLASS, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "for") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_FOR, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "while") == 0)
|
|
||||||
tok =
|
|
||||||
fzl_mktoken(FZL_TOKTYPE_WHILE, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "break") == 0)
|
|
||||||
tok =
|
|
||||||
fzl_mktoken(FZL_TOKTYPE_BREAK, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "new") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_NEW, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "fn") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_FUNCTION, l.line, l.col, value, size,
|
|
||||||
l.filename);
|
|
||||||
else if (strcmp(value, "return") == 0)
|
|
||||||
tok =
|
|
||||||
fzl_mktoken(FZL_TOKTYPE_RETURN, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "if") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_IF, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "else") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_ELSE, l.line, l.col, value, size, l.filename);
|
|
||||||
else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_BOOL_LITERAL, l.line, l.col, value, size,
|
|
||||||
l.filename);
|
|
||||||
else if (strcmp(value, "null") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_NULL_LITERAL, l.line, l.col, value, size,
|
|
||||||
l.filename);
|
|
||||||
else if (strcmp(value, "str") == 0 || strcmp(value, "char") == 0 ||
|
|
||||||
strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 ||
|
|
||||||
strcmp(value, "int") == 0 || strcmp(value, "i8") == 0 ||
|
|
||||||
strcmp(value, "i16") == 0 || strcmp(value, "i32") == 0 ||
|
|
||||||
strcmp(value, "i64") == 0 || strcmp(value, "u8") == 0 ||
|
|
||||||
strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 ||
|
|
||||||
strcmp(value, "u64") == 0)
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_TYPE, l.line, l.col, value, size, l.filename);
|
|
||||||
else
|
|
||||||
tok = fzl_mktoken(FZL_TOKTYPE_NAME, l.line, l.col, value, size, l.filename);
|
|
||||||
free(value);
|
|
||||||
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try parse string literal
|
|
||||||
fzl_token_t *parse_string_literal(fzl_reader_t *reader)
|
|
||||||
{
|
|
||||||
size_t lpos = reader->position;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
if (reader->source[lpos] != '\'' && reader->source[lpos] != '"')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char open_symbol = reader->source[lpos];
|
|
||||||
char close_symbol = '\0';
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lpos++;
|
|
||||||
size++;
|
|
||||||
|
|
||||||
if (reader->source[lpos] == open_symbol)
|
|
||||||
close_symbol = open_symbol;
|
|
||||||
|
|
||||||
} while (reader->source[lpos] != open_symbol && lpos < reader->size);
|
|
||||||
size++;
|
|
||||||
|
|
||||||
fzl_file_loc l;
|
|
||||||
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close_symbol != open_symbol)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "'%s': unterminated string at %ld:%ld",
|
|
||||||
l.filename, l.line, l.col);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 2)
|
|
||||||
{
|
|
||||||
fzl_token_t *tok =
|
|
||||||
fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, "", 0, l.filename);
|
|
||||||
move(reader, 2);
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *value = malloc(size - 2);
|
|
||||||
memcpy(value, reader->source + reader->position + 1, size - 2);
|
|
||||||
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value,
|
|
||||||
size - 2, l.filename);
|
|
||||||
free(value);
|
|
||||||
move(reader, size);
|
|
||||||
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse numeric literal
|
|
||||||
fzl_token_t *parse_number(fzl_reader_t *reader)
|
|
||||||
{
|
|
||||||
if (!reader)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
size_t size = 0;
|
|
||||||
size_t lpos = reader->position;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
size++;
|
|
||||||
lpos++;
|
|
||||||
} while ((reader->source[lpos] >= '0' && reader->source[lpos] <= '9') &&
|
|
||||||
lpos < reader->size);
|
|
||||||
|
|
||||||
char *value = malloc(size * sizeof(char) + 1);
|
|
||||||
memcpy(value, reader->source + reader->position, size);
|
|
||||||
value[size] = '\0';
|
|
||||||
|
|
||||||
fzl_file_loc l;
|
|
||||||
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, l.line, l.col, value,
|
|
||||||
size, l.filename);
|
|
||||||
free(value);
|
|
||||||
|
|
||||||
if (!tok)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
move(reader, size);
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add single-char token
|
|
||||||
fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type)
|
|
||||||
{
|
|
||||||
fzl_file_loc l;
|
|
||||||
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
move(reader, 1);
|
|
||||||
return fzl_mktoken(type, l.line, l.col, "", 0, l.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add double-char token
|
|
||||||
fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type)
|
|
||||||
{
|
|
||||||
fzl_file_loc l;
|
|
||||||
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
move(reader, 2);
|
|
||||||
return fzl_mktoken(type, l.line, l.col, "", 0, l.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip symbols until '\n' or EOF
|
|
||||||
void skip_comment(fzl_reader_t *reader)
|
|
||||||
{
|
|
||||||
move(reader, 2);
|
|
||||||
|
|
||||||
while (reader->position < reader->size)
|
|
||||||
{
|
|
||||||
if (reader->source[reader->position++] == '\n')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fzl_read(fzl_reader_t *reader)
|
int fzl_read(fzl_reader_t *reader)
|
||||||
{
|
{
|
||||||
if (reader->position >= reader->size)
|
if (reader->position >= reader->size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bool is_format_str = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
size_t p = reader->position;
|
size_t p = reader->position;
|
||||||
@@ -268,64 +49,76 @@ int fzl_read(fzl_reader_t *reader)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr == '\'' || curr == '"')
|
if (is_format_str)
|
||||||
token = parse_string_literal(reader);
|
{
|
||||||
|
token = rd_fmtstr(reader);
|
||||||
|
if (token && token->type == FZL_TOKTYPE_STR_FORMAT_END)
|
||||||
|
is_format_str = false;
|
||||||
|
}
|
||||||
|
else if (curr == '\'' || curr == '"')
|
||||||
|
token = rd_string_literal(reader);
|
||||||
else if (curr == '/' && reader->source[p + 1] == '/')
|
else if (curr == '/' && reader->source[p + 1] == '/')
|
||||||
{
|
{
|
||||||
skip_comment(reader);
|
rd_comment(reader);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (curr == '=' && reader->source[p + 1] == '=')
|
else if (curr == '=' && reader->source[p + 1] == '=')
|
||||||
token = add_double(reader, FZL_TOKTYPE_EQEQ);
|
token = rd_double(reader, FZL_TOKTYPE_EQEQ);
|
||||||
else if (curr == '>' && reader->source[p + 1] == '=')
|
else if (curr == '>' && reader->source[p + 1] == '=')
|
||||||
token = add_double(reader, FZL_TOKTYPE_REQ);
|
token = rd_double(reader, FZL_TOKTYPE_REQ);
|
||||||
else if (curr == '<' && reader->source[p + 1] == '=')
|
else if (curr == '<' && reader->source[p + 1] == '=')
|
||||||
token = add_double(reader, FZL_TOKTYPE_LEQ);
|
token = rd_double(reader, FZL_TOKTYPE_LEQ);
|
||||||
else if (curr == '!' && reader->source[p + 1] == '=')
|
else if (curr == '!' && reader->source[p + 1] == '=')
|
||||||
token = add_double(reader, FZL_TOKTYPE_NEQ);
|
token = rd_double(reader, FZL_TOKTYPE_NEQ);
|
||||||
else if (curr == '|' && reader->source[p + 1] == '|')
|
else if (curr == '|' && reader->source[p + 1] == '|')
|
||||||
token = add_double(reader, FZL_TOKTYPE_DVBAR);
|
token = rd_double(reader, FZL_TOKTYPE_DVBAR);
|
||||||
else if (curr == '&' && reader->source[p + 1] == '&')
|
else if (curr == '&' && reader->source[p + 1] == '&')
|
||||||
token = add_double(reader, FZL_TOKTYPE_DAMPERSAND);
|
token = rd_double(reader, FZL_TOKTYPE_DAMPERSAND);
|
||||||
else if (curr == '>')
|
else if (curr == '>')
|
||||||
token = add_single(reader, FZL_TOKTYPE_RANGLE);
|
token = rd_single(reader, FZL_TOKTYPE_RANGLE);
|
||||||
else if (curr == '<')
|
else if (curr == '<')
|
||||||
token = add_single(reader, FZL_TOKTYPE_LANGLE);
|
token = rd_single(reader, FZL_TOKTYPE_LANGLE);
|
||||||
else if (curr == '!')
|
else if (curr == '!')
|
||||||
token = add_single(reader, FZL_TOKTYPE_NOT);
|
token = rd_single(reader, FZL_TOKTYPE_NOT);
|
||||||
else if (curr == ';')
|
else if (curr == ';')
|
||||||
token = add_single(reader, FZL_TOKTYPE_SEMICOLON);
|
token = rd_single(reader, FZL_TOKTYPE_SEMICOLON);
|
||||||
else if (curr == '{')
|
else if (curr == '{')
|
||||||
token = add_single(reader, FZL_TOKTYPE_LBRACE);
|
token = rd_single(reader, FZL_TOKTYPE_LBRACE);
|
||||||
else if (curr == '}')
|
else if (curr == '}')
|
||||||
token = add_single(reader, FZL_TOKTYPE_RBRACE);
|
token = rd_single(reader, FZL_TOKTYPE_RBRACE);
|
||||||
else if (curr == '(')
|
else if (curr == '(')
|
||||||
token = add_single(reader, FZL_TOKTYPE_LPAREN);
|
token = rd_single(reader, FZL_TOKTYPE_LPAREN);
|
||||||
else if (curr == ')')
|
else if (curr == ')')
|
||||||
token = add_single(reader, FZL_TOKTYPE_RPAREN);
|
token = rd_single(reader, FZL_TOKTYPE_RPAREN);
|
||||||
else if (curr == ',')
|
else if (curr == ',')
|
||||||
token = add_single(reader, FZL_TOKTYPE_COMMA);
|
token = rd_single(reader, FZL_TOKTYPE_COMMA);
|
||||||
else if (curr == '.')
|
else if (curr == '.')
|
||||||
token = add_single(reader, FZL_TOKTYPE_DOT);
|
token = rd_single(reader, FZL_TOKTYPE_DOT);
|
||||||
else if (curr == '*')
|
else if (curr == '*')
|
||||||
token = add_single(reader, FZL_TOKTYPE_STAR);
|
token = rd_single(reader, FZL_TOKTYPE_STAR);
|
||||||
else if (curr == '/')
|
else if (curr == '/')
|
||||||
token = add_single(reader, FZL_TOKTYPE_SLASH);
|
token = rd_single(reader, FZL_TOKTYPE_SLASH);
|
||||||
else if (curr == '+')
|
else if (curr == '+')
|
||||||
token = add_single(reader, FZL_TOKTYPE_PLUS);
|
token = rd_single(reader, FZL_TOKTYPE_PLUS);
|
||||||
else if (curr == '-')
|
else if (curr == '-')
|
||||||
token = add_single(reader, FZL_TOKTYPE_MINUS);
|
token = rd_single(reader, FZL_TOKTYPE_MINUS);
|
||||||
else if (curr == '^')
|
else if (curr == '^')
|
||||||
token = add_single(reader, FZL_TOKTYPE_CARET);
|
token = rd_single(reader, FZL_TOKTYPE_CARET);
|
||||||
else if (curr == '%')
|
else if (curr == '%')
|
||||||
token = add_single(reader, FZL_TOKTYPE_PERCENT);
|
token = rd_single(reader, FZL_TOKTYPE_PERCENT);
|
||||||
else if (curr == '=')
|
else if (curr == '=')
|
||||||
token = add_single(reader, FZL_TOKTYPE_EQ);
|
token = rd_single(reader, FZL_TOKTYPE_EQ);
|
||||||
|
else if (curr == '$' && reader->source[p + 1] == '"')
|
||||||
|
{
|
||||||
|
move(reader, 2);
|
||||||
|
is_format_str = true;
|
||||||
|
token = fzl_mktoken(FZL_TOKTYPE_STR_FORMAT_START, 0, 0, NULL, 0, "");
|
||||||
|
}
|
||||||
else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') ||
|
else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') ||
|
||||||
curr == '_')
|
curr == '_')
|
||||||
token = parse_name(reader);
|
token = rd_name(reader);
|
||||||
else if (curr >= '0' && curr <= '9')
|
else if (curr >= '0' && curr <= '9')
|
||||||
token = parse_number(reader);
|
token = rd_number(reader);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fzl_file_loc l;
|
fzl_file_loc l;
|
||||||
@@ -371,8 +164,6 @@ int fzl_read(fzl_reader_t *reader)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Read zone end ---
|
|
||||||
|
|
||||||
char *fzl_reader_geterror() { return last_err; }
|
char *fzl_reader_geterror() { return last_err; }
|
||||||
|
|
||||||
void free_node_and_next(fzl_reader_ll_t *node)
|
void free_node_and_next(fzl_reader_ll_t *node)
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col,
|
|||||||
// Free allocated token
|
// Free allocated token
|
||||||
void fzl_freetoken(fzl_token_t *tok)
|
void fzl_freetoken(fzl_token_t *tok)
|
||||||
{
|
{
|
||||||
|
if (!tok)
|
||||||
|
return;
|
||||||
|
|
||||||
if (tok->store_value)
|
if (tok->store_value)
|
||||||
free(tok->value);
|
free(tok->value);
|
||||||
|
|
||||||
free(tok);
|
free(tok);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,6 +203,20 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
|||||||
{
|
{
|
||||||
switch (node->type)
|
switch (node->type)
|
||||||
{
|
{
|
||||||
|
case FZL_NODETYPE_FMT_STRING:
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < node->list.entry_count; i++)
|
||||||
|
{
|
||||||
|
fzl_walk_res_t res = walk(walker, node->list.entries[i]);
|
||||||
|
if (res.error)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_op(walker, FZL_OPCODE_BUILD_STR);
|
||||||
|
push_word(walker, node->list.entry_count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case FZL_NODETYPE_BREAK:
|
case FZL_NODETYPE_BREAK:
|
||||||
{
|
{
|
||||||
fzl_walk_ctx_t *ctx = walker->ctx;
|
fzl_walk_ctx_t *ctx = walker->ctx;
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Parse string format
|
||||||
|
fzl_token_t *rd_fmtstr(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
size_t p = reader->position;
|
||||||
|
char *src = reader->source;
|
||||||
|
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src[p] == '{')
|
||||||
|
{
|
||||||
|
move(reader, 1);
|
||||||
|
fzl_token_t *id = rd_name(reader);
|
||||||
|
|
||||||
|
if (id == NULL || src[reader->position] != '}')
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err),
|
||||||
|
"'%s':%zu:%zu => failed to parse format string", l.filename,
|
||||||
|
l.line, l.col);
|
||||||
|
fzl_freetoken(id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(reader, 1);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src[p] == '"')
|
||||||
|
{
|
||||||
|
move(reader, 1);
|
||||||
|
|
||||||
|
return fzl_mktoken(FZL_TOKTYPE_STR_FORMAT_END, l.line, l.col, NULL, 0,
|
||||||
|
l.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = 0;
|
||||||
|
size_t lpos = p;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (src[lpos + 1] == '"')
|
||||||
|
break;
|
||||||
|
|
||||||
|
size++;
|
||||||
|
lpos++;
|
||||||
|
} while (lpos < reader->size && reader->source[lpos] != '{' &&
|
||||||
|
reader->source[lpos] != '"');
|
||||||
|
|
||||||
|
ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *value = malloc(size);
|
||||||
|
memcpy(value, reader->source + reader->position, size);
|
||||||
|
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value,
|
||||||
|
size, l.filename);
|
||||||
|
free(value);
|
||||||
|
move(reader, size);
|
||||||
|
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Try parse name
|
||||||
|
fzl_token_t *rd_name(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
size_t lpos = reader->position;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lpos++;
|
||||||
|
size++;
|
||||||
|
} while ((reader->source[lpos] >= 'A' && reader->source[lpos] <= 'Z') ||
|
||||||
|
(reader->source[lpos] >= 'a' && reader->source[lpos] <= 'z') ||
|
||||||
|
(reader->source[lpos] >= '0' && reader->source[lpos] <= '9') ||
|
||||||
|
(reader->source[lpos] == '_'));
|
||||||
|
|
||||||
|
char *value = malloc(size + 1);
|
||||||
|
memcpy(value, reader->source + reader->position, size);
|
||||||
|
value[size] = '\0';
|
||||||
|
|
||||||
|
size_t start = reader->position;
|
||||||
|
move(reader, size);
|
||||||
|
|
||||||
|
fzl_token_t *tok;
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, start, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(value, "class") == 0)
|
||||||
|
tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_CLASS, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "for") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_FOR, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "while") == 0)
|
||||||
|
tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_WHILE, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "break") == 0)
|
||||||
|
tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_BREAK, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "new") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_NEW, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "fn") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_FUNCTION, l.line, l.col, value, size,
|
||||||
|
l.filename);
|
||||||
|
else if (strcmp(value, "return") == 0)
|
||||||
|
tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_RETURN, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "if") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_IF, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "else") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_ELSE, l.line, l.col, value, size, l.filename);
|
||||||
|
else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_BOOL_LITERAL, l.line, l.col, value, size,
|
||||||
|
l.filename);
|
||||||
|
else if (strcmp(value, "null") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_NULL_LITERAL, l.line, l.col, value, size,
|
||||||
|
l.filename);
|
||||||
|
else if (strcmp(value, "str") == 0 || strcmp(value, "char") == 0 ||
|
||||||
|
strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 ||
|
||||||
|
strcmp(value, "int") == 0 || strcmp(value, "i8") == 0 ||
|
||||||
|
strcmp(value, "i16") == 0 || strcmp(value, "i32") == 0 ||
|
||||||
|
strcmp(value, "i64") == 0 || strcmp(value, "u8") == 0 ||
|
||||||
|
strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 ||
|
||||||
|
strcmp(value, "u64") == 0)
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_TYPE, l.line, l.col, value, size, l.filename);
|
||||||
|
else
|
||||||
|
tok = fzl_mktoken(FZL_TOKTYPE_NAME, l.line, l.col, value, size, l.filename);
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/fzl_token.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Parse numeric literal
|
||||||
|
fzl_token_t *rd_number(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
if (!reader)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t size = 0;
|
||||||
|
size_t lpos = reader->position;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size++;
|
||||||
|
lpos++;
|
||||||
|
} while ((reader->source[lpos] >= '0' && reader->source[lpos] <= '9') &&
|
||||||
|
lpos < reader->size);
|
||||||
|
|
||||||
|
char *value = malloc(size * sizeof(char) + 1);
|
||||||
|
memcpy(value, reader->source + reader->position, size);
|
||||||
|
value[size] = '\0';
|
||||||
|
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, l.line, l.col, value,
|
||||||
|
size, l.filename);
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
if (!tok)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
move(reader, size);
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/fzl_token.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Try parse string literal
|
||||||
|
fzl_token_t *rd_string_literal(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
size_t lpos = reader->position;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (reader->source[lpos] != '\'' && reader->source[lpos] != '"')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char open_symbol = reader->source[lpos];
|
||||||
|
char close_symbol = '\0';
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lpos++;
|
||||||
|
size++;
|
||||||
|
|
||||||
|
if (reader->source[lpos] == open_symbol)
|
||||||
|
close_symbol = open_symbol;
|
||||||
|
|
||||||
|
} while (reader->source[lpos] != open_symbol && lpos < reader->size);
|
||||||
|
size++;
|
||||||
|
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close_symbol != open_symbol)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "'%s': unterminated string at %ld:%ld",
|
||||||
|
l.filename, l.line, l.col);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 2)
|
||||||
|
{
|
||||||
|
fzl_token_t *tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, "", 0, l.filename);
|
||||||
|
move(reader, 2);
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *value = malloc(size - 2);
|
||||||
|
memcpy(value, reader->source + reader->position + 1, size - 2);
|
||||||
|
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value,
|
||||||
|
size - 2, l.filename);
|
||||||
|
free(value);
|
||||||
|
move(reader, size);
|
||||||
|
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include <compiler/fzl_reader.h>
|
||||||
|
#include <compiler/internals/reader.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Move cursor forward
|
||||||
|
size_t move(fzl_reader_t *reader, size_t len)
|
||||||
|
{
|
||||||
|
if (!reader)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return reader->position += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add single-char token
|
||||||
|
fzl_token_t *rd_single(fzl_reader_t *reader, fzl_toktype_t type)
|
||||||
|
{
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(reader, 1);
|
||||||
|
return fzl_mktoken(type, l.line, l.col, "", 0, l.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add double-char token
|
||||||
|
fzl_token_t *rd_double(fzl_reader_t *reader, fzl_toktype_t type)
|
||||||
|
{
|
||||||
|
fzl_file_loc l;
|
||||||
|
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(reader, 2);
|
||||||
|
return fzl_mktoken(type, l.line, l.col, "", 0, l.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip symbols until '\n' or EOF
|
||||||
|
void rd_comment(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
move(reader, 2);
|
||||||
|
|
||||||
|
while (reader->position < reader->size)
|
||||||
|
{
|
||||||
|
if (reader->source[reader->position++] == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/// Converts integer [value] to string
|
||||||
|
extern fn itos(int value) str;
|
||||||
|
|
||||||
|
/// Converts string [value] to integer
|
||||||
|
extern fn stoi(str value) int;
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/// Get the minimum of specified values
|
||||||
|
extern fn min([]int ...values) int;
|
||||||
|
|
||||||
|
/// Get the maximum of specified values
|
||||||
|
extern fn max([]int ...values) int;
|
||||||
|
|
||||||
+147
-8
@@ -13,6 +13,7 @@
|
|||||||
#include <vm/fzl_vm_env.h>
|
#include <vm/fzl_vm_env.h>
|
||||||
#include <vm/fzl_vm_object.h>
|
#include <vm/fzl_vm_object.h>
|
||||||
|
|
||||||
|
char build_result[512];
|
||||||
char last_err[256];
|
char last_err[256];
|
||||||
size_t last_jmp_ip = 0;
|
size_t last_jmp_ip = 0;
|
||||||
size_t total_jmp_on_same = 0;
|
size_t total_jmp_on_same = 0;
|
||||||
@@ -28,14 +29,16 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->consts = NULL;
|
vm->consts = NULL;
|
||||||
vm->consts_count = 0;
|
vm->consts_count = 0;
|
||||||
vm->ops = NULL;
|
vm->ops = NULL;
|
||||||
vm->ops_count = 0;
|
vm->ops_count = 0;
|
||||||
vm->ip = 0;
|
vm->externs = NULL;
|
||||||
vm->dtop = 0;
|
vm->externs_count = 0;
|
||||||
vm->ctop = 0;
|
vm->ip = 0;
|
||||||
vm->etop = 0;
|
vm->dtop = 0;
|
||||||
|
vm->ctop = 0;
|
||||||
|
vm->etop = 0;
|
||||||
|
|
||||||
memset(vm->dstack, 0, sizeof(vm->dstack));
|
memset(vm->dstack, 0, sizeof(vm->dstack));
|
||||||
memset(vm->cstack, 0, sizeof(vm->cstack));
|
memset(vm->cstack, 0, sizeof(vm->cstack));
|
||||||
@@ -63,6 +66,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
|
|||||||
size_t consts_count, ops_count;
|
size_t consts_count, ops_count;
|
||||||
fread(&consts_count, sizeof(size_t), 1, fd);
|
fread(&consts_count, sizeof(size_t), 1, fd);
|
||||||
fread(&ops_count, sizeof(size_t), 1, fd);
|
fread(&ops_count, sizeof(size_t), 1, fd);
|
||||||
|
// TODO: read externs count
|
||||||
|
|
||||||
if (ops_count < 1)
|
if (ops_count < 1)
|
||||||
{
|
{
|
||||||
@@ -116,6 +120,8 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
|
|||||||
fread(&op, sizeof(uint64_t), 1, fd);
|
fread(&op, sizeof(uint64_t), 1, fd);
|
||||||
vm->ops[i] = op;
|
vm->ops[i] = op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: read externs
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
|
|
||||||
return vm;
|
return vm;
|
||||||
@@ -292,6 +298,139 @@ int fzl_vm_run(fzl_vm_t *vm, bool allow_infinite, uint64_t max_iter)
|
|||||||
|
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
|
case FZL_OPCODE_BUILD_STR:
|
||||||
|
{
|
||||||
|
uint64_t n = vm->ops[++vm->ip];
|
||||||
|
if (vm->dtop < n)
|
||||||
|
{
|
||||||
|
snprintf(last_err, sizeof(last_err),
|
||||||
|
"runtime error - expected %zu value(s) in dstack", n);
|
||||||
|
print_err_data(vm);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[64];
|
||||||
|
size_t gi = 0;
|
||||||
|
memset(build_result, 0, sizeof(build_result));
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
if (gi >= 512)
|
||||||
|
{
|
||||||
|
for (size_t i = 511; i > 508; i--)
|
||||||
|
build_result[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(temp, 0, sizeof(temp));
|
||||||
|
fzl_value_t val = vm->dstack[i];
|
||||||
|
|
||||||
|
switch (val.type)
|
||||||
|
{
|
||||||
|
case FZL_TYPE_UINT:
|
||||||
|
snprintf(temp, sizeof(temp), "%zu", val.as.u);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_UINT64:
|
||||||
|
snprintf(temp, sizeof(temp), "%lu", val.as.u64);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_UINT32:
|
||||||
|
snprintf(temp, sizeof(temp), "%u", val.as.u32);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_UINT16:
|
||||||
|
snprintf(temp, sizeof(temp), "%u", val.as.u16);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_UINT8:
|
||||||
|
snprintf(temp, sizeof(temp), "%u", val.as.u8);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_INT:
|
||||||
|
snprintf(temp, sizeof(temp), "%zd", val.as.i);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_INT64:
|
||||||
|
snprintf(temp, sizeof(temp), "%ld", val.as.i64);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_INT32:
|
||||||
|
snprintf(temp, sizeof(temp), "%d", val.as.i32);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_INT16:
|
||||||
|
snprintf(temp, sizeof(temp), "%d", val.as.i16);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_INT8:
|
||||||
|
snprintf(temp, sizeof(temp), "%d", val.as.i8);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_BOOL:
|
||||||
|
snprintf(build_result + gi, sizeof(build_result) - gi, "%s",
|
||||||
|
val.as.b ? "true" : "false");
|
||||||
|
gi += val.as.b ? 4 : 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_CHAR:
|
||||||
|
snprintf(build_result + gi, sizeof(build_result) - gi, "%d",
|
||||||
|
val.as.c);
|
||||||
|
gi += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_STRING:
|
||||||
|
snprintf(build_result + gi, sizeof(build_result) - gi, "%s",
|
||||||
|
val.as.s.value);
|
||||||
|
gi += val.as.s.length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_EXTERN_FN:
|
||||||
|
snprintf(temp, sizeof(temp), "<extern:%zu>", val.as.u);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_OBJECT:
|
||||||
|
snprintf(temp, sizeof(temp), "<ref:%p>", val.as.obj);
|
||||||
|
strcpy(build_result + gi, temp);
|
||||||
|
gi += strlen(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_TYPE_NULL:
|
||||||
|
snprintf(build_result + gi, sizeof(build_result) - gi, "<null>");
|
||||||
|
gi += 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->dtop -= n;
|
||||||
|
vm->dstack[vm->dtop++] =
|
||||||
|
(fzl_value_t){.type = FZL_TYPE_STRING,
|
||||||
|
.as.s.length = strlen(build_result),
|
||||||
|
.as.s.value = build_result};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case FZL_OPCODE_DEREFERENCE:
|
case FZL_OPCODE_DEREFERENCE:
|
||||||
{
|
{
|
||||||
if (vm->dtop < 1)
|
if (vm->dtop < 1)
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
|
|||||||
|
|
||||||
switch (vm->ops[i])
|
switch (vm->ops[i])
|
||||||
{
|
{
|
||||||
|
case FZL_OPCODE_BUILD_STR:
|
||||||
|
printf("BUILD_STR %zu\n", vm->ops[++i]);
|
||||||
|
break;
|
||||||
|
|
||||||
case FZL_OPCODE_DEREFERENCE:
|
case FZL_OPCODE_DEREFERENCE:
|
||||||
printf("DEREFERENCE\n");
|
printf("DEREFERENCE\n");
|
||||||
break;
|
break;
|
||||||
@@ -163,9 +167,6 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
|
|||||||
case FZL_OPCODE_JMP:
|
case FZL_OPCODE_JMP:
|
||||||
printf("JMP IP: %ld\n", vm->ops[++i]);
|
printf("JMP IP: %ld\n", vm->ops[++i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
printf("<UNKNOWN>\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
printline($"Something's on the {way}")
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
$"jopa {abc}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
int a1 = 2 * 2;
|
||||||
|
printline($"First tests: build string and print. 2 * 2 = {a1}");
|
||||||
|
|
||||||
|
str a2 = "Mike Tyson";
|
||||||
|
printline($"Hello, {a2}");
|
||||||
|
|
||||||
Reference in New Issue
Block a user