int literals.

main
bog 2024-03-31 23:10:56 +02:00
parent e0502c7825
commit 1f71fce283
34 changed files with 1393 additions and 13 deletions

View File

@ -5,7 +5,7 @@ build:
cmake --build build
tests: build
build/tests/skopy-tests \
@build/tests/skopy-tests \
&& echo -e "\e[32m--- all tests passed ---\e[0m" \
|| echo -e "\e[31m--- some tests failed ---\e[0m"
@ -14,4 +14,5 @@ install: tests
check:
@cppcheck --enable=all -q lib tests cli \
--suppress=missingIncludeSystem
--suppress=missingIncludeSystem \
--suppress=missingInclude

View File

@ -1,7 +1,21 @@
#include <stdio.h>
#include <module.h>
#include <errors.h>
int main()
int main(int argc, char** argv)
{
printf("Hello World!\n");
if (argc == 2)
{
errors_init();
struct module module;
module_init(&module);
module_load_source(&module, argv[1]);
module_compile(&module);
module_free(&module);
errors_free();
}
return 0;
}

4
doc/grammar.bnf Normal file
View File

@ -0,0 +1,4 @@
ROOT ::= EXPR*
EXPR ::= BUILTIN
BUILTIN ::=
| int

View File

@ -4,6 +4,24 @@ project(skopy-lib)
add_library(skopy-lib SHARED
src/commons.c
src/vec.c
src/str.c
src/token.c
src/lexer.c
src/node.c
src/parser.c
src/prog.c
src/value.c
src/compiler.c
src/state.c
src/exec.c
src/module.c
src/errors.c
)
file(GLOB_RECURSE

View File

@ -1,5 +1,25 @@
#ifndef SK_COMMONS_H
#define SK_COMMONS_H
#include <ctype.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "str.h"
#include "vec.h"
#include "errors.h"
#define SK_ENUM_ENUM(X) X
#define SK_ENUM_STR(X) #X
#define SK_ENUM_H(PREFIX, DEF) \
typedef enum { DEF(SK_ENUM_ENUM) } PREFIX;\
extern char const* PREFIX ## Str []
#define SK_ENUM_C(PREFIX, DEF) \
char const* PREFIX ## Str [] = {DEF(SK_ENUM_STR)}
#endif

19
lib/include/compiler.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef SK_COMPILER_H
#define SK_COMPILER_H
#include "commons.h"
#include "prog.h"
struct compiler
{
};
void compiler_init(struct compiler* self);
void compiler_free(struct compiler* self);
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog);
#endif

30
lib/include/errors.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef SK_ERROR_H
#define SK_ERROR_H
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <vec.h>
#include <str.h>
struct error
{
int line;
char* msg;
};
extern struct vec* errors;
void errors_init();
void errors_free();
void errors_push(int line, char const* format, ...);
bool errors_ok();
void errors_dump();
void error_init(struct error* self, int line, char* msg);
void error_free(struct error* self);
#endif

20
lib/include/exec.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef SK_EXEC_H
#define SK_EXEC_H
#include "commons.h"
#include "state.h"
#include "prog.h"
struct exec
{
size_t pc;
};
void exec_init(struct exec* self);
void exec_free(struct exec* self);
void exec_execute(struct exec* self,
struct state* state,
struct prog* prog);
#endif

30
lib/include/lexer.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef SK_LEXER_H
#define SK_LEXER_H
#include "commons.h"
#include "token.h"
struct context
{
int line;
size_t cursor;
};
struct lexer
{
char* source;
size_t len;
struct context context;
};
void lexer_init(struct lexer* self, char const* source);
void lexer_free(struct lexer* self);
void lexer_skip_spaces(struct lexer* self);
bool lexer_next_is(struct lexer* self, TokenKind kind);
struct token* lexer_try_new_next(struct lexer* self);
struct token* lexer_try_scan_int(struct lexer* self);
#endif

21
lib/include/module.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef SK_MODULE_H
#define SK_MODULE_H
#include "commons.h"
#include "prog.h"
struct module
{
struct str source;
struct prog prog;
};
void module_init(struct module* self);
void module_free(struct module* self);
void module_load_source(struct module* self,
char const* path);
void module_compile(struct module* self);
#endif

27
lib/include/node.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef SK_NODE_H
#define SK_NODE_H
#include "commons.h"
#define NODE_KIND(G) \
G(NODE_ROOT), \
G(NODE_INT)
SK_ENUM_H(NodeKind, NODE_KIND);
struct node
{
NodeKind kind;
struct vec children;
struct token* token;
};
void node_init(struct node* self,
NodeKind kind,
struct token* token);
void node_free(struct node* self);
void node_push_new_child(struct node* self, struct node* child);
void node_str(struct node* self, struct str* dest);
#endif

25
lib/include/parser.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef SK_PARSER_H
#define SK_PARSER_H
#include "commons.h"
#include "node.h"
#include "lexer.h"
struct parser
{
struct lexer lexer;
};
void parser_init(struct parser* self, char const* source);
void parser_free(struct parser* self);
struct node* parser_try(struct parser* self,
struct node* (*rule)(struct parser*));
struct node* parser_try_parse(struct parser* self);
struct node* parser_try_root(struct parser* self);
struct node* parser_try_expr(struct parser* self);
struct node* parser_try_builtin(struct parser* self);
#endif

29
lib/include/prog.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef SK_PROG_H
#define SK_PROG_H
#include "commons.h"
#include "value.h"
#define SK_NO_PARAM (-1)
#define OPCODE(G) \
G(OP_PUSH)
SK_ENUM_H(Opcode, OPCODE);
struct prog
{
struct vec opcodes;
struct vec params;
struct vec constants;
};
void prog_init(struct prog* self);
void prog_free(struct prog* self);
size_t prog_add_instr(struct prog* self,
Opcode opcode,
size_t param);
size_t prog_add_constant(struct prog* self,
struct value* new_value);
#endif

47
lib/include/state.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef SK_STATE_H
#define SK_STATE_H
#include "commons.h"
#include "value.h"
#define SK size_t
struct local
{
size_t addr;
struct value* value;
};
struct frame
{
struct vec locals;
struct vec stack;
};
struct state
{
struct vec frames;
size_t addr;
};
void local_init(struct local* self,
size_t addr,
struct value* new_value);
void local_free(struct local* self);
void frame_init(struct frame* self);
void frame_free(struct frame* self);
void state_init(struct state* self);
void state_free(struct state* self);
struct frame* state_frame(struct state* self);
void state_push_frame(struct state* self);
bool state_has_top(struct state* self);
SK state_top(struct state* self);
struct value* state_try_get_value(struct state* self, SK value);
SK state_push_int(struct state* self, int integer);
#endif

24
lib/include/str.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef SK_STR_H
#define SK_STR_H
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
struct str
{
size_t size;
size_t capacity;
char* value;
};
void str_init(struct str* self);
void str_free(struct str* self);
void str_push(struct str* self, char c);
void str_extend(struct str* self, char* src);
void str_format(struct str* self, char const* format, ...);
#endif

27
lib/include/token.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef SK_TOKEN_H
#define SK_TOKEN_H
#include "commons.h"
#define TOKEN_KIND(G) \
G(TOKEN_ROOT), \
G(TOKEN_INT)
SK_ENUM_H(TokenKind, TOKEN_KIND);
struct token
{
TokenKind kind;
char* value;
int line;
};
void token_init(struct token* self,
TokenKind kind,
char const* value,
int line);
void token_free(struct token* self);
void token_str(struct token* self, struct str* dest);
#endif

32
lib/include/value.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef SK_VALUE_H
#define SK_VALUE_H
#include "commons.h"
#include "node.h"
#define TYPE_KIND(G) \
G(TYPE_INT)
SK_ENUM_H(TypeKind, TYPE_KIND);
union val
{
int integer;
};
struct value
{
TypeKind type;
union val val;
};
void value_init(struct value* self,
TypeKind type,
union val val);
void value_free(struct value* self);
void value_str(struct value* self, struct str* dest);
#endif

22
lib/include/vec.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef SK_VEC_H
#define SK_VEC_H
#include <stdlib.h>
#include <assert.h>
struct vec
{
size_t size;
size_t capacity;
void** data;
};
void vec_init(struct vec* self);
void vec_free_elements(struct vec* self,
void (*destructor)(void*));
void vec_free(struct vec* self);
void vec_push(struct vec* self, void* element);
#endif

48
lib/src/compiler.c Normal file
View File

@ -0,0 +1,48 @@
#include "compiler.h"
#include "token.h"
void compiler_init(struct compiler* self)
{
assert(self);
}
void compiler_free(struct compiler* self)
{
assert(self);
}
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog)
{
assert(self);
assert(node);
assert(prog);
switch (node->kind)
{
case NODE_ROOT: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_compile(self, node->children.data[i],
prog);
}
} break;
case NODE_INT: {
struct value* value = malloc(sizeof(struct value));
union val val;
val.integer = atoi(node->token->value);
value_init(value, TYPE_INT, val);
size_t idx = prog_add_constant(prog, value);
prog_add_instr(prog, OP_PUSH, idx);
} break;
default: {
fprintf(stderr, "cannot compile node '%s'\n",
NodeKindStr[node->kind]);
abort();
} break;
}
}

64
lib/src/errors.c Normal file
View File

@ -0,0 +1,64 @@
#include "errors.h"
struct vec* errors = NULL;
void errors_init()
{
errors = malloc(sizeof(struct vec));
vec_init(errors);
}
void errors_free()
{
vec_free_elements(errors, (void*) error_free);
vec_free(errors);
free(errors);
}
void errors_push(int line, char const* format, ...)
{
va_list lst;
va_start(lst, format);
size_t const sz = 4096;
char buffer[sz];
vsnprintf(buffer, sz, format, lst);
struct error* err = malloc(sizeof(struct error));
error_init(err, line, buffer);
vec_push(errors, err);
va_end(lst);
}
bool errors_ok()
{
return errors->size == 0;
}
void errors_dump()
{
for (size_t i=0; i<errors->size; i++)
{
struct error const* err = errors->data[i];
fprintf(stderr, "[ERR:%d] %s\n", err->line, err->msg);
}
}
void error_init(struct error* self, int line, char* msg)
{
assert(self);
assert(msg);
self->line = line;
self->msg = strdup(msg);
}
void error_free(struct error* self)
{
assert(self);
free(self->msg);
}

48
lib/src/exec.c Normal file
View File

@ -0,0 +1,48 @@
#include "exec.h"
void exec_init(struct exec* self)
{
assert(self);
self->pc = 0;
}
void exec_free(struct exec* self)
{
assert(self);
}
void exec_execute(struct exec* self,
struct state* state,
struct prog* prog)
{
while (self->pc < prog->opcodes.size)
{
Opcode opcode = (size_t) prog->opcodes.data[self->pc];
size_t param = (size_t) prog->params.data[self->pc];
switch (opcode)
{
case OP_PUSH: {
struct value* constant = prog->constants.data[param];
switch (constant->type)
{
case TYPE_INT: {
state_push_int(state, constant->val.integer);
} break;
default: {
fprintf(stderr, "cannot push value '%s'\n",
TypeKindStr[constant->type]);
abort();
} break;
}
self->pc++;
} break;
default: {
fprintf(stderr, "cannot execute opcode '%s'\n",
OpcodeStr[opcode]);
abort();
} break;
}
}
}

127
lib/src/lexer.c Normal file
View File

@ -0,0 +1,127 @@
#include "lexer.h"
void lexer_init(struct lexer* self, char const* source)
{
assert(self);
self->source = strdup(source);
self->len = strlen(self->source);
self->context.line = 1;
self->context.cursor = 0;
}
void lexer_free(struct lexer* self)
{
assert(self);
free(self->source);
}
void lexer_skip_spaces(struct lexer* self)
{
assert(self);
while (self->context.cursor < self->len
&& isspace(self->source[self->context.cursor]))
{
if (self->source[self->context.cursor] == '\n')
{
self->context.line++;
}
self->context.cursor++;
}
}
bool lexer_next_is(struct lexer* self, TokenKind kind)
{
struct context ctx = self->context;
struct token* tok = lexer_try_new_next(self);
if (!tok)
{
return false;
}
bool res = tok->kind == kind;
token_free(tok);
free(tok);
self->context = ctx;
return res;
}
struct token* lexer_try_new_next(struct lexer* self)
{
assert(self);
if (!errors_ok())
{
return NULL;
}
lexer_skip_spaces(self);
struct token* tok = NULL;
if ( (tok=lexer_try_scan_int(self)) )
{
return tok;
}
if (self->context.cursor < self->len)
{
struct str str;
str_init(&str);
while (self->context.cursor < self->len
&& !isspace(self->source[self->context.cursor]))
{
str_push(&str, self->source[self->context.cursor]);
self->context.cursor++;
}
errors_push(self->context.line, "unknown symbol '%s'",
str.value);
str_free(&str);
}
return NULL;
}
struct token* lexer_try_scan_int(struct lexer* self)
{
assert(self);
size_t cursor = self->context.cursor;
struct str value;
str_init(&value);
if (cursor < self->len
&& self->source[cursor] == '-')
{
str_push(&value, self->source[cursor]);
cursor++;
}
while (cursor < self->len
&& isdigit(self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
struct token* tok = NULL;
if (value.size > 0)
{
tok = malloc(sizeof(struct token));
token_init(tok, TOKEN_INT,
value.value, self->context.line);
self->context.cursor = cursor;
}
str_free(&value);
return tok;
}

89
lib/src/module.c Normal file
View File

@ -0,0 +1,89 @@
#include "module.h"
#include "parser.h"
#include "compiler.h"
#include "state.h"
#include "exec.h"
void module_init(struct module* self)
{
assert(self);
str_init(&self->source);
prog_init(&self->prog);
}
void module_free(struct module* self)
{
assert(self);
str_free(&self->source);
prog_free(&self->prog);
}
void module_load_source(struct module* self,
char const* path)
{
assert(self);
FILE* file = fopen(path, "r");
assert(file);
char buf;
while ( fread(&buf, 1, sizeof(char), file) > 0 )
{
str_push(&self->source, buf);
}
fclose(file);
}
void module_compile(struct module* self)
{
assert(self);
struct parser parser;
parser_init(&parser, self->source.value);
struct node* root = parser_try_parse(&parser);
if (!errors_ok())
{
errors_dump();
goto free_node;
}
struct compiler compiler;
compiler_init(&compiler);
compiler_compile(&compiler, root, &self->prog);
struct exec exec;
exec_init(&exec);
struct state state;
state_init(&state);
exec_execute(&exec, &state, &self->prog);
if (state_has_top(&state))
{
struct value* value = state_try_get_value(
&state,
state_top(&state)
);
assert(value);
struct str str;
str_init(&str);
value_str(value, &str);
printf("%s\n", str.value);
str_free(&str);
}
// Free
state_free(&state);
exec_free(&exec);
compiler_free(&compiler);
free_node:
node_free(root);
free(root);
parser_free(&parser);
}

57
lib/src/node.c Normal file
View File

@ -0,0 +1,57 @@
#include "node.h"
#include "token.h"
SK_ENUM_C(NodeKind, NODE_KIND);
void node_init(struct node* self,
NodeKind kind,
struct token* token)
{
assert(self);
self->kind = kind;
vec_init(&self->children);
self->token = token;
}
void node_free(struct node* self)
{
assert(self);
vec_free_elements(&self->children, (void*) node_free);
vec_free(&self->children);
if (self->token)
{
token_free(self->token);
free(self->token);
}
}
void node_push_new_child(struct node* self, struct node* child)
{
vec_push(&self->children, child);
}
void node_str(struct node* self, struct str* dest)
{
assert(self);
assert(dest);
assert(self->token);
str_format(dest, "%s",
NodeKindStr[self->kind] + strlen("NODE_"));
if (strcmp(self->token->value, "") != 0)
{
str_format(dest, "[%s]", self->token->value);
}
if (self->children.size > 0)
{
str_extend(dest, "(");
for (size_t i=0; i<self->children.size; i++)
{
if (i > 0) { str_push(dest, ','); }
node_str(self->children.data[i], dest);
}
str_extend(dest, ")");
}
}

83
lib/src/parser.c Normal file
View File

@ -0,0 +1,83 @@
#include "parser.h"
#define SK_TRY(RULE) parser_try(self, RULE)
void parser_init(struct parser* self, char const* source)
{
assert(self);
lexer_init(&self->lexer, source);
}
void parser_free(struct parser* self)
{
assert(self);
lexer_free(&self->lexer);
}
struct node* parser_try(struct parser* self,
struct node* (*rule)(struct parser*))
{
assert(self);
assert(rule);
struct context ctx = self->lexer.context;
struct node* res = (*rule)(self);
if (res == NULL)
{
self->lexer.context = ctx;
}
return res;
}
struct node* parser_try_parse(struct parser* self)
{
assert(self);
return SK_TRY(parser_try_root);
}
struct node* parser_try_root(struct parser* self)
{
assert(self);
struct node* node = malloc(sizeof(struct node));
struct token* tok = malloc(sizeof(struct token));
token_init(tok,
TOKEN_ROOT,
"",
self->lexer.context.line);
node_init(node, NODE_ROOT, tok);
while (true)
{
struct node* expr = SK_TRY(parser_try_expr);
if (!expr) { break; }
node_push_new_child(node, expr);
}
return node;
}
struct node* parser_try_expr(struct parser* self)
{
return SK_TRY(parser_try_builtin);
}
struct node* parser_try_builtin(struct parser* self)
{
if (lexer_next_is(&self->lexer, TOKEN_INT))
{
struct node* node = malloc(sizeof(struct node));
node_init(node,
NODE_INT,
lexer_try_new_next(&self->lexer));
return node;
}
return NULL;
}

42
lib/src/prog.c Normal file
View File

@ -0,0 +1,42 @@
#include "prog.h"
#include "value.h"
SK_ENUM_C(Opcode, OPCODE);
void prog_init(struct prog* self)
{
assert(self);
vec_init(&self->opcodes);
vec_init(&self->params);
vec_init(&self->constants);
}
void prog_free(struct prog* self)
{
assert(self);
vec_free(&self->opcodes);
vec_free(&self->params);
vec_free_elements(&self->constants, (void*)value_free);
vec_free(&self->constants);
}
size_t prog_add_instr(struct prog* self,
Opcode opcode,
size_t param)
{
assert(self);
size_t addr = self->opcodes.size;
vec_push(&self->opcodes, (void*) opcode);
vec_push(&self->params, (void*) param);
return addr;
}
size_t prog_add_constant(struct prog* self,
struct value* new_value)
{
assert(self);
vec_push(&self->constants, new_value);
return self->constants.size - 1;
}

117
lib/src/state.c Normal file
View File

@ -0,0 +1,117 @@
#include "state.h"
void local_init(struct local* self,
size_t addr,
struct value* new_value)
{
assert(self);
assert(new_value);
self->addr = addr;
self->value = new_value;
}
void local_free(struct local* self)
{
value_free(self->value);
free(self->value);
self->value = NULL;
}
void frame_init(struct frame* self)
{
vec_init(&self->locals);
vec_init(&self->stack);
}
void frame_free(struct frame* self)
{
vec_free_elements(&self->locals, (void*) local_free);
vec_free(&self->locals);
vec_free(&self->stack);
}
void state_init(struct state* self)
{
assert(self);
vec_init(&self->frames);
self->addr = 1;
state_push_frame(self);
}
void state_free(struct state* self)
{
assert(self);
vec_free_elements(&self->frames, (void*) frame_free);
vec_free(&self->frames);
}
struct frame* state_frame(struct state* self)
{
assert(self);
assert(self->frames.size > 0);
return self->frames.data[self->frames.size - 1];
}
void state_push_frame(struct state* self)
{
assert(self);
struct frame* frame = malloc(sizeof(struct frame));
frame_init(frame);
vec_push(&self->frames, frame);
}
bool state_has_top(struct state* self)
{
struct frame* frame = state_frame(self);
return frame->stack.size > 0;
}
SK state_top(struct state* self)
{
assert(self);
struct frame* frame = state_frame(self);
assert(frame->stack.size > 0);
return (SK) frame->stack.data[frame->stack.size - 1];
}
struct value* state_try_get_value(struct state* self, SK value)
{
assert(self);
struct frame* frame = state_frame(self);
for (size_t i=0; i<frame->locals.size; i++)
{
struct local* local = frame->locals.data[i];
if (local->addr == value)
{
return local->value;
}
}
return NULL;
}
SK state_push_int(struct state* self, int integer)
{
assert(self);
struct value* value = malloc(sizeof(struct value));
union val val;
val.integer = integer;
value_init(value, TYPE_INT, val);
struct frame* frame = state_frame(self);
struct local* local = malloc(sizeof(struct local));
local_init(local, self->addr, value);
vec_push(&frame->locals, local);
vec_push(&frame->stack, (void*) self->addr);
self->addr++;
return self->addr - 1;
}

72
lib/src/str.c Normal file
View File

@ -0,0 +1,72 @@
#include "str.h"
void str_init(struct str* self)
{
assert(self);
self->size = 0;
self->capacity = 0;
self->value = NULL;
}
void str_free(struct str* self)
{
assert(self);
if (self->value)
{
free(self->value);
}
self->size = 0;
self->capacity = 0;
self->value = NULL;
}
void str_push(struct str* self, char c)
{
assert(self);
if (self->capacity == 0)
{
self->capacity = 2;
self->value = malloc(sizeof(char) * self->capacity);
}
if (self->size + 2 >= self->capacity)
{
self->capacity *= 2;
char* buffer = realloc(self->value,
sizeof(char) * self->capacity);
assert(buffer);
self->value = buffer;
}
self->value[self->size] = c;
self->value[self->size + 1] = '\0';
self->size++;
}
void str_extend(struct str* self, char* src)
{
assert(self);
assert(src);
size_t sz = strlen(src);
for (size_t i=0; i<sz; i++)
{
str_push(self, src[i]);
}
}
void str_format(struct str* self, char const* format, ...)
{
va_list lst;
va_start(lst, format);
size_t SZ = 4096;
char value[SZ];
vsnprintf(value, SZ, format, lst);
str_extend(self, value);
va_end(lst);
}

38
lib/src/token.c Normal file
View File

@ -0,0 +1,38 @@
#include "token.h"
SK_ENUM_C(TokenKind, TOKEN_KIND);
void token_init(struct token* self,
TokenKind kind,
char const* value,
int line)
{
assert(self);
self->kind = kind;
self->value = strdup(value);
self->line = line;
}
void token_free(struct token* self)
{
assert(self);
free(self->value);
}
void token_str(struct token* self, struct str* dest)
{
assert(self);
assert(dest);
if (self->value == NULL || strcmp(self->value, "") == 0)
{
str_format(dest, "%s",
TokenKindStr[self->kind] + strlen("TOKEN_"));
}
else
{
str_format(dest, "%s[%s]",
TokenKindStr[self->kind] + strlen("TOKEN_"),
self->value);
}
}

36
lib/src/value.c Normal file
View File

@ -0,0 +1,36 @@
#include "value.h"
SK_ENUM_C(TypeKind, TYPE_KIND);
void value_init(struct value* self,
TypeKind type,
union val val)
{
assert(self);
self->type = type;
self->val = val;
}
void value_free(struct value* self)
{
assert(self);
}
void value_str(struct value* self, struct str* dest)
{
assert(self);
assert(dest);
switch (self->type)
{
case TYPE_INT: {
str_format(dest, "%d", self->val.integer);
} break;
default: {
fprintf(stderr, "cannot get value string of '%s'\n",
TypeKindStr[self->type]);
abort();
} break;
}
}

59
lib/src/vec.c Normal file
View File

@ -0,0 +1,59 @@
#include "vec.h"
void vec_init(struct vec* self)
{
assert(self);
self->size = 0;
self->capacity = 0;
self->data = NULL;
}
void vec_free_elements(struct vec* self,
void (*destructor)(void*))
{
for (size_t i=0; i<self->size; i++)
{
if (destructor)
{
(*destructor)(self->data[i]);
}
free(self->data[i]);
}
}
void vec_free(struct vec* self)
{
assert(self);
free(self->data);
self->size = 0;
self->capacity = 0;
self->data = NULL;
}
void vec_push(struct vec* self, void* element)
{
assert(self);
if (self->data == NULL)
{
self->capacity = 2;
self->data = malloc(sizeof(void*) * self->capacity);
}
if (self->size >= self->capacity)
{
self->capacity *= 2;
void** buffer = realloc(
self->data,
sizeof(void*) * self->capacity
);
assert(buffer);
self->data = buffer;
}
self->data[self->size] = element;
self->size++;
}

54
tests/lexer.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef SK_TEST_LEXER_H
#define SK_TEST_LEXER_H
#include <CUnit/CUnit.h>
#include <lexer.h>
#include <token.h>
static void test_lexer(char const* source, int count, ...)
{
struct lexer lexer;
lexer_init(&lexer, source);
va_list lst;
va_start(lst, count);
for (int i=0; i<count; i++)
{
struct token* tok = lexer_try_new_next(&lexer);
CU_ASSERT_FATAL(tok != NULL);
struct str tok_str;
str_init(&tok_str);
token_str(tok, &tok_str);
char* oracle = va_arg(lst, char*);
if (strcmp(oracle, tok_str.value) != 0)
{
fprintf(stderr, "%s != %s\n", oracle, tok_str.value);
}
CU_ASSERT_STRING_EQUAL(tok_str.value, oracle);
str_free(&tok_str);
token_free(tok);
free(tok);
}
va_end(lst);
lexer_free(&lexer);
}
static void test_lexer_int()
{
test_lexer(" 4 -23 720 ", 3,
"INT[4]",
"INT[-23]",
"INT[720]"
);
}
void register_lexer()
{
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
CU_add_test(suite, "Integers", test_lexer_int);
}
#endif

View File

@ -1,17 +1,15 @@
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
void test_trivial()
{
CU_ASSERT(1 + 1 == 2);
}
#include "lexer.h"
#include "parser.h"
int main()
{
errors_init();
CU_initialize_registry();
CU_pSuite suite = CU_add_suite("First suite", 0, 0);
CU_add_test(suite, "Trivial", test_trivial);
register_lexer();
register_parser();
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
@ -19,6 +17,6 @@ int main()
int status = CU_get_number_of_failures();
CU_cleanup_registry();
errors_free();
return status;
}

38
tests/parser.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef SK_TEST_PARSER_H
#define SK_TEST_PARSER_H
#include <CUnit/CUnit.h>
#include "node.h"
#include <parser.h>
static void test_parser(char const* oracle, char const* source)
{
struct parser parser;
parser_init(&parser, source);
struct node* node = parser_try_parse(&parser);
CU_ASSERT_FATAL(node != NULL);
struct str str;
str_init(&str);
node_str(node, &str);
CU_ASSERT_STRING_EQUAL(oracle, str.value);
str_free(&str);
node_free(node);
free(node);
parser_free(&parser);
}
static void test_parser_int()
{
test_parser("ROOT(INT[32])", " 32 ");
test_parser("ROOT(INT[32],INT[-2],INT[24])", " 32 -2 24");
}
void register_parser()
{
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
CU_add_test(suite, "Integers", test_parser_int);
}
#endif