added function backend
This commit is contained in:
parent
1e60890919
commit
2804fd552b
|
@ -9,22 +9,35 @@ static struct CodegenBackend_t {
|
|||
const char* name;
|
||||
} CodegenBackend;
|
||||
|
||||
BackendError new_backend_error(BackendErrorKind kind) {
|
||||
return new_backend_impl_error(kind, NULL, NULL);
|
||||
}
|
||||
|
||||
BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message) {
|
||||
BackendError error;
|
||||
error.kind = kind;
|
||||
error.impl.ast_node = node;
|
||||
error.impl.message = message;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
BackendError init_backend(void) {
|
||||
DEBUG("initializing backend: %s", CodegenBackend.name);
|
||||
|
||||
if (CodegenBackend.init_func == NULL) {
|
||||
ERROR("backend: %s is not properly initialized", CodegenBackend.name);
|
||||
return NoBackend;
|
||||
return new_backend_error(NoBackend);
|
||||
}
|
||||
|
||||
size_t code = CodegenBackend.init_func();
|
||||
BackendError code = CodegenBackend.init_func();
|
||||
|
||||
if (code) {
|
||||
if (code.kind != Success) {
|
||||
ERROR("failed to initialize backend: %s with code: %ld", CodegenBackend.name, code);
|
||||
return Other;
|
||||
return code;
|
||||
}
|
||||
|
||||
return Success;
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
BackendError deinit_backend(void) {
|
||||
|
@ -32,17 +45,17 @@ BackendError deinit_backend(void) {
|
|||
|
||||
if (CodegenBackend.deinit_func == NULL) {
|
||||
ERROR("backend: %s is not properly initialized", CodegenBackend.name);
|
||||
return NoBackend;
|
||||
return new_backend_error(NoBackend);
|
||||
}
|
||||
|
||||
size_t code = CodegenBackend.deinit_func();
|
||||
BackendError code = CodegenBackend.deinit_func();
|
||||
|
||||
if (code) {
|
||||
if (code.kind != Success) {
|
||||
ERROR("failed to undo initialization of backend: %s with code: %ld", CodegenBackend.name, code);
|
||||
return Other;
|
||||
return code;
|
||||
}
|
||||
|
||||
return Success;
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
BackendError set_backend(const codegen_init init_func, const codegen_deinit deinit_func, const codegen codegen_func, const char* name) {
|
||||
|
@ -51,7 +64,7 @@ BackendError set_backend(const codegen_init init_func, const codegen_deinit dein
|
|||
CodegenBackend.codegen_func = codegen_func;
|
||||
CodegenBackend.name = name;
|
||||
|
||||
return Success;
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
BackendError generate_code(const AST_NODE_PTR root, void** output) {
|
||||
|
@ -59,14 +72,14 @@ BackendError generate_code(const AST_NODE_PTR root, void** output) {
|
|||
|
||||
if (CodegenBackend.codegen_func == NULL) {
|
||||
ERROR("backend: %s is not properly initialized", CodegenBackend.name);
|
||||
return NoBackend;
|
||||
return new_backend_error(NoBackend);
|
||||
}
|
||||
|
||||
size_t code = CodegenBackend.codegen_func(root, output);
|
||||
if (code) {
|
||||
BackendError code = CodegenBackend.codegen_func(root, output);
|
||||
if (code.kind) {
|
||||
ERROR("code generation of backend: %s failed with code: %ld", CodegenBackend.name, code);
|
||||
return Other;
|
||||
return code;
|
||||
}
|
||||
|
||||
return Success;
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
|
|
@ -4,28 +4,42 @@
|
|||
|
||||
#include <ast/ast.h>
|
||||
|
||||
typedef enum BackendError_t {
|
||||
typedef struct BackendImplError_t {
|
||||
// faulty AST node
|
||||
AST_NODE_PTR ast_node;
|
||||
// error message
|
||||
const char* message;
|
||||
} BackendImplError;
|
||||
|
||||
typedef enum BackendErrorKind_t {
|
||||
Success,
|
||||
NoBackend,
|
||||
BackendAlreadySet,
|
||||
Other
|
||||
Unimplemented,
|
||||
// some error occurred in the backend implementation
|
||||
Implementation
|
||||
} BackendErrorKind;
|
||||
|
||||
typedef struct BackendError_t {
|
||||
BackendErrorKind kind;
|
||||
BackendImplError impl;
|
||||
} BackendError;
|
||||
|
||||
/**
|
||||
* @brief Function called by the compiler backend to generate an intermediate format
|
||||
* from AST. Returns a custom container for its intermediate language.
|
||||
*/
|
||||
typedef size_t (*codegen)(const AST_NODE_PTR, void**);
|
||||
typedef BackendError (*codegen)(const AST_NODE_PTR, void**);
|
||||
|
||||
/**
|
||||
* @brief Initialize the code generation backend.
|
||||
*/
|
||||
typedef size_t (*codegen_init)(void);
|
||||
typedef BackendError (*codegen_init)(void);
|
||||
|
||||
/**
|
||||
* @brief Undo initialization of code generation backend.
|
||||
*/
|
||||
typedef size_t (*codegen_deinit)(void);
|
||||
typedef BackendError (*codegen_deinit)(void);
|
||||
|
||||
/**
|
||||
* @brief Set the backend functions to use
|
||||
|
@ -65,4 +79,14 @@ BackendError deinit_backend(void);
|
|||
[[nodiscard]]
|
||||
BackendError generate_code(const AST_NODE_PTR root, void** code);
|
||||
|
||||
/**
|
||||
* @brief Create a new backend error
|
||||
*
|
||||
* @param kind must ne != Implementation
|
||||
* @return BackendError
|
||||
*/
|
||||
BackendError new_backend_error(BackendErrorKind kind);
|
||||
|
||||
BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message);
|
||||
|
||||
#endif // CODEGN_BACKEND_H_
|
||||
|
|
|
@ -10,7 +10,7 @@ typedef enum LLVMBackendError_t {
|
|||
UnresolvedImport
|
||||
} LLVMBackendError;
|
||||
|
||||
static size_t llvm_backend_codegen(const AST_NODE_PTR, void**) {
|
||||
static BackendError llvm_backend_codegen(const AST_NODE_PTR, void**) {
|
||||
// we start with a LLVM module
|
||||
LLVMContextRef context = LLVMContextCreate();
|
||||
LLVMModuleRef module = LLVMModuleCreateWithNameInContext("gemstone application", context);
|
||||
|
@ -20,21 +20,21 @@ static size_t llvm_backend_codegen(const AST_NODE_PTR, void**) {
|
|||
LLVMDisposeModule(module);
|
||||
LLVMContextDispose(context);
|
||||
|
||||
return Success;
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
static size_t llvm_backend_codegen_init(void) {
|
||||
return Success;
|
||||
static BackendError llvm_backend_codegen_init(void) {
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
static size_t llvm_backend_codegen_deinit(void) {
|
||||
return Success;
|
||||
static BackendError llvm_backend_codegen_deinit(void) {
|
||||
return new_backend_error(Success);
|
||||
}
|
||||
|
||||
void llvm_backend_init() {
|
||||
BackendError err = set_backend(&llvm_backend_codegen_init, &llvm_backend_codegen_deinit, &llvm_backend_codegen, "LLVM");
|
||||
|
||||
if (err != Success) {
|
||||
if (err.kind != Success) {
|
||||
PANIC("unable to init llvm backend: %ld", err);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include <llvm/function/function.h>
|
||||
#include <llvm/types/type.h>
|
||||
#include <string.h>
|
||||
|
||||
static enum IO_Qualifier_t io_qualifier_from_string(const char* str) {
|
||||
if (strcmp(str, "in") == 0) {
|
||||
return In;
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
static enum IO_Qualifier_t merge_qualifier(enum IO_Qualifier_t a, enum IO_Qualifier_t b) {
|
||||
enum IO_Qualifier_t result = Unspec;
|
||||
|
||||
if (a == In && b == Out) {
|
||||
result = InOut;
|
||||
} else if (a == Out && b == In) {
|
||||
result = InOut;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum IO_Qualifier_t io_qualifier_from_ast_list(const AST_NODE_PTR node) {
|
||||
// node is expected to be a list
|
||||
if (node->kind != AST_List) {
|
||||
PANIC("Node must be of type AST_List: %s", AST_node_to_string(node));
|
||||
}
|
||||
|
||||
enum IO_Qualifier_t qualifier = Unspec;
|
||||
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
|
||||
AST_NODE_PTR qualifier_node = AST_get_node(node, i);
|
||||
|
||||
if (qualifier_node->kind != AST_Qualifyier) {
|
||||
PANIC("Node must be of type AST_Qualifyier: %s", AST_node_to_string(node));
|
||||
}
|
||||
|
||||
enum IO_Qualifier_t local_qualifier = io_qualifier_from_string(qualifier_node->value);
|
||||
|
||||
if (qualifier == Unspec) {
|
||||
qualifier = local_qualifier;
|
||||
} else {
|
||||
qualifier = merge_qualifier(qualifier, local_qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (qualifier == Unspec)
|
||||
qualifier = In;
|
||||
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
GemstoneParam param_from_ast(const AST_NODE_PTR node) {
|
||||
GemstoneParam param;
|
||||
|
||||
// node is expected to be a parameter
|
||||
if (node->kind != AST_Parameter) {
|
||||
PANIC("Node must be of type AST_ParamList: %s", AST_node_to_string(node));
|
||||
}
|
||||
|
||||
AST_NODE_PTR qualifier_list = AST_get_node(node, 0);
|
||||
param.qualifier = io_qualifier_from_ast_list(qualifier_list);
|
||||
|
||||
AST_NODE_PTR param_decl = AST_get_node(node, 1);
|
||||
AST_NODE_PTR param_type = AST_get_node(param_decl, 0);
|
||||
param.typename = get_type_from_ast(param_type);
|
||||
param.name = AST_get_node(param_decl, 1)->value;
|
||||
|
||||
return param;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
#ifndef LLVM_FUNCTION_H_
|
||||
#define LLVM_FUNCTION_H_
|
||||
|
||||
#include <ast/ast.h>
|
||||
#include <llvm/types/type.h>
|
||||
|
||||
enum IO_Qualifier_t {
|
||||
Unspec,
|
||||
In,
|
||||
Out,
|
||||
InOut
|
||||
};
|
||||
|
||||
typedef struct GemstoneParam_t {
|
||||
const char* name;
|
||||
enum IO_Qualifier_t qualifier;
|
||||
GemstoneType typename;
|
||||
} GemstoneParam;
|
||||
|
||||
typedef struct GemstoneFun_t {
|
||||
const char* name;
|
||||
// TODO: add array of parameters
|
||||
} GemstoneFun;
|
||||
|
||||
/**
|
||||
* @brief Convert an AST node into a function parameter struct
|
||||
*
|
||||
* @param node the node starting a function parameter
|
||||
* @return GemstoneParam
|
||||
*/
|
||||
GemstoneParam param_from_ast(const AST_NODE_PTR node);
|
||||
|
||||
/**
|
||||
* @brief Convert an AST node into a function
|
||||
*
|
||||
* @param node the node starting a function
|
||||
* @return GemstoneFun
|
||||
*/
|
||||
GemstoneFun fun_from_ast(const AST_NODE_PTR node);
|
||||
|
||||
#endif // LLVM_FUNCTION_H_
|
|
@ -1,52 +1,8 @@
|
|||
|
||||
#include <ast/ast.h>
|
||||
#include <llvm/types/composite.h>
|
||||
#include <string.h>
|
||||
#include <sys/log.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/Types.h>
|
||||
|
||||
#define BITS_PER_BYTE 8
|
||||
|
||||
enum Sign_t {
|
||||
Signed,
|
||||
Unsigned
|
||||
};
|
||||
|
||||
enum Precision_t {
|
||||
ATOM = 1,
|
||||
HALF = 2,
|
||||
SINGLE = 4,
|
||||
DOUBLE = 8,
|
||||
QUAD = 16,
|
||||
OCTO = 32
|
||||
};
|
||||
|
||||
enum Primitive_t {
|
||||
Int,
|
||||
Float
|
||||
};
|
||||
|
||||
typedef struct CompositeType_t {
|
||||
const char* name;
|
||||
enum Sign_t sign;
|
||||
enum Precision_t scale;
|
||||
enum Primitive_t prim;
|
||||
} Composite;
|
||||
|
||||
typedef struct TypeScope_t {
|
||||
// vector of composite data types
|
||||
Composite* composites;
|
||||
size_t composite_len;
|
||||
size_t composite_cap;
|
||||
} TypeScope;
|
||||
|
||||
Composite* get_composite_type(const char* name);
|
||||
|
||||
typedef struct CompositeType_t* COMPOSITE_REF;
|
||||
|
||||
#define INVALID_COMPOSITE NULL
|
||||
|
||||
LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const COMPOSITE_REF composite) {
|
||||
LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const CompositeRef composite) {
|
||||
DEBUG("converting composite to LLVM type...");
|
||||
|
||||
LLVMTypeRef type = INVALID_COMPOSITE;
|
||||
|
@ -61,6 +17,7 @@ LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const COMPOSITE_REF
|
|||
switch (composite->scale) {
|
||||
case HALF:
|
||||
type = LLVMHalfTypeInContext(context);
|
||||
break;
|
||||
case SINGLE:
|
||||
type = LLVMDoubleTypeInContext(context);
|
||||
break;
|
||||
|
@ -89,7 +46,7 @@ double get_scale_factor(const char* keyword) {
|
|||
PANIC("invalid scale factor: %s", keyword);
|
||||
}
|
||||
|
||||
enum Precision_t collapse_scale_list(const AST_NODE_PTR list) {
|
||||
enum Scale_t collapse_scale_list(const AST_NODE_PTR list) {
|
||||
double sum = 1.0;
|
||||
|
||||
for (size_t i = 0; i < list->child_count; i++) {
|
||||
|
@ -99,7 +56,7 @@ enum Precision_t collapse_scale_list(const AST_NODE_PTR list) {
|
|||
}
|
||||
|
||||
if (sum >= 1.0 && sum <= 32) {
|
||||
return (enum Precision_t) sum;
|
||||
return (enum Scale_t) sum;
|
||||
}
|
||||
|
||||
PANIC("invalid combination of scale factors");
|
||||
|
@ -115,6 +72,18 @@ enum Sign_t string_to_sign(const char* keyword) {
|
|||
PANIC("invalid sign: %s", keyword);
|
||||
}
|
||||
|
||||
static enum Primitive_t resolve_primitive(const char* typename) {
|
||||
|
||||
if (strcmp(typename, "int") == 0) {
|
||||
return Int;
|
||||
} else if (strcmp(typename, "float") == 0) {
|
||||
return Float;
|
||||
}
|
||||
|
||||
// TODO: implement lookup of ident type
|
||||
return Int;
|
||||
}
|
||||
|
||||
struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type) {
|
||||
size_t count = type->child_count;
|
||||
|
||||
|
@ -152,8 +121,7 @@ struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type) {
|
|||
composite.scale = collapse_scale_list(AST_get_node(type, 0));
|
||||
composite.prim = resolve_primitive(AST_get_node(type, 2)->value);
|
||||
}
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
void generate_builtin_types(LLVMContextRef context) {
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
#ifndef LLVM_TYPE_H_
|
||||
#define LLVM_TYPE_H_
|
||||
|
||||
#include <ast/ast.h>
|
||||
#include <sys/log.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/Types.h>
|
||||
|
||||
#define BITS_PER_BYTE 8
|
||||
|
||||
enum Sign_t {
|
||||
Signed,
|
||||
Unsigned
|
||||
};
|
||||
|
||||
enum Scale_t {
|
||||
ATOM = 1,
|
||||
HALF = 2,
|
||||
SINGLE = 4,
|
||||
DOUBLE = 8,
|
||||
QUAD = 16,
|
||||
OCTO = 32
|
||||
};
|
||||
|
||||
enum Primitive_t {
|
||||
Int,
|
||||
Float
|
||||
};
|
||||
|
||||
typedef struct CompositeType_t {
|
||||
const char* name;
|
||||
enum Sign_t sign;
|
||||
enum Scale_t scale;
|
||||
enum Primitive_t prim;
|
||||
} Composite;
|
||||
|
||||
typedef struct TypeScope_t {
|
||||
// vector of composite data types
|
||||
Composite* composites;
|
||||
size_t composite_len;
|
||||
size_t composite_cap;
|
||||
} TypeScope;
|
||||
|
||||
typedef struct CompositeType_t* CompositeRef;
|
||||
|
||||
#define INVALID_COMPOSITE NULL
|
||||
|
||||
LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const CompositeRef composite);
|
||||
|
||||
struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type);
|
||||
|
||||
#endif // LLVM_TYPE_H_
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#include <llvm/types/composite.h>
|
||||
#include <ast/ast.h>
|
||||
#include <llvm/types/type.h>
|
||||
|
||||
GemstoneType get_type_from_ast(const AST_NODE_PTR type_node) {
|
||||
if (type_node->kind != AST_Type) {
|
||||
PANIC("Node must be of type AST_Type: %s", AST_node_to_string(type_node));
|
||||
}
|
||||
|
||||
GemstoneType type;
|
||||
|
||||
if (type_node->child_count > 1) {
|
||||
// must be composite
|
||||
type.kind = TypeComposite;
|
||||
type.specs.composite = ast_type_to_composite(type_node);
|
||||
} else {
|
||||
// either custom type or box
|
||||
// TODO: resolve concrete type from TypeScope
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#ifndef GEMSTONE_TYPE_H_
|
||||
#define GEMSTONE_TYPE_H_
|
||||
|
||||
#include <ast/ast.h>
|
||||
#include <llvm/types/composite.h>
|
||||
|
||||
enum GemstoneTypeKind_t {
|
||||
TypeComposite,
|
||||
TypeReference,
|
||||
TypeBox
|
||||
};
|
||||
|
||||
struct GemstoneType_t;
|
||||
|
||||
typedef struct GemstoneRefType_t {
|
||||
struct GemstoneType_t* type;
|
||||
} GemstoneRefType;
|
||||
|
||||
typedef struct GemstoneType_t {
|
||||
enum GemstoneTypeKind_t kind;
|
||||
union GemstoneTypeSpecs_t {
|
||||
Composite composite;
|
||||
GemstoneRefType reference;
|
||||
} specs;
|
||||
} GemstoneType;
|
||||
|
||||
struct TypeScope_t;
|
||||
|
||||
typedef struct TypeScope_t {
|
||||
// TODO: array of child scopes
|
||||
// TODO: array of types
|
||||
} TypeScope;
|
||||
|
||||
/**
|
||||
* @brief Convert a type declaration into a concrete type.
|
||||
*
|
||||
* @param type A type declaration (either identifier or composite)
|
||||
* @return GemstoneType
|
||||
*/
|
||||
GemstoneType get_type_from_ast(const AST_NODE_PTR type);
|
||||
|
||||
#endif // GEMSTONE_TYPE_H_
|
29
src/main.c
29
src/main.c
|
@ -53,6 +53,24 @@ void setup(void) {
|
|||
DEBUG("finished starting up gemstone...");
|
||||
}
|
||||
|
||||
void run_backend_codegen() {
|
||||
llvm_backend_init();
|
||||
|
||||
BackendError err;
|
||||
err = init_backend();
|
||||
if (err.kind != Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* code = NULL;
|
||||
err = generate_code(root, &code);
|
||||
if (err.kind != Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = deinit_backend();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
setup();
|
||||
|
@ -77,16 +95,9 @@ int main(int argc, char *argv[]) {
|
|||
root = AST_new_node(AST_Module, NULL);
|
||||
yyparse();
|
||||
|
||||
llvm_backend_init();
|
||||
run_backend_codegen();
|
||||
|
||||
init_backend();
|
||||
|
||||
void* code = NULL;
|
||||
generate_code(root, &code);
|
||||
|
||||
deinit_backend();
|
||||
|
||||
FILE *output = fopen("test.txt", "w");
|
||||
FILE *output = fopen("test.gv", "w");
|
||||
AST_fprint_graphviz(output, root);
|
||||
fclose(output);
|
||||
AST_delete_node(root);
|
||||
|
|
Loading…
Reference in New Issue