num arithmetic.

main
bog 2024-03-18 18:20:40 +01:00
parent 3493fda418
commit ab34370e39
35 changed files with 2328 additions and 6 deletions

View File

@ -9,4 +9,5 @@ install: build
check: check:
@cppcheck --enable=all -q ccm lib \ @cppcheck --enable=all -q ccm lib \
--suppress=missingIncludeSystem --suppress=missingIncludeSystem \
--suppress=unusedFunction

View File

@ -1,7 +1,50 @@
#include <stdio.h> #include <stdio.h>
#include <module.h>
#include <exec.h>
int main() int main(int argc, char** argv)
{ {
printf("Hello World!\n"); int status = 0;
return 0;
if (argc > 1)
{
module_t module;
module_init(&module);
module_load(&module, argv[1]);
if (!err_is_ok(&module.err))
{
err_print_stack_trace(&module.err);
status = 1;
goto free_module;
}
exec_t exec;
exec_init(&exec);
exec_module(&exec, &module);
if (!err_is_ok(&module.ccm.err)
|| !err_is_ok(&exec.err))
{
err_print_stack_trace(&module.ccm.err);
err_print_stack_trace(&exec.err);
status = 1;
goto free_exec;
}
char trace[CCM_STRLEN];
memset(trace, 0, CCM_STRLEN);
ccm_str(&module.ccm, trace, CCM_STRLEN);
printf("%s\n", trace);
free_exec:
exec_free(&exec);
free_module:
module_free(&module);
}
return status;
} }

16
doc/grammar.bnf Normal file
View File

@ -0,0 +1,16 @@
MODULE ::= EXPR*
EXPR ::=
| TERM
| ASSERT
ASSERT ::= (assert_eq|assert_ne) tuple
TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= USUB ((mul|div|mod) USUB)*
USUB ::= sub* POW
POW ::= LITERAL (pow LITERAL)?
LITERAL ::=
| BUILTIN
| TUPLE
| opar EXPR cpar
TUPLE ::=
| opar EXPR+ cpar
BUILTIN ::= num

View File

@ -3,7 +3,20 @@ cmake_minimum_required(VERSION 3.28)
project(ccm_library) project(ccm_library)
add_library(ccm_lib add_library(ccm_lib
vec.c
str.c
node.c node.c
lexer.c
parser.c
module.c
err.c
type.c
value.c
ccm.c
bytecode.c
prog.c
compiler.c
exec.c
) )
set_property(TARGET ccm_lib PROPERTY C_STANDARD 99) set_property(TARGET ccm_lib PROPERTY C_STANDARD 99)
@ -15,4 +28,8 @@ target_compile_options(ccm_lib
target_include_directories(ccm_lib target_include_directories(ccm_lib
PUBLIC "${CMAKE_SOURCE_DIR}/lib" PUBLIC "${CMAKE_SOURCE_DIR}/lib"
) )
target_link_libraries(ccm_lib
PUBLIC -lm
)
install(TARGETS ccm_lib) install(TARGETS ccm_lib)

3
lib/bytecode.c Normal file
View File

@ -0,0 +1,3 @@
#include "bytecode.h"
CCM_ENUM_C(Opcode, OPCODES);

14
lib/bytecode.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef CCM_BYTECODE_H
#define CCM_BYTECODE_H
#include "commons.h"
#define OPCODES(G) \
G(OP_PUSH), G(OP_POP), \
G(OP_ADD), G(OP_SUB), G(OP_USUB), G(OP_MUL), \
G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
G(OP_ASSERT_EQ), G(OP_ASSERT_NE)
CCM_ENUM_H(Opcode, OPCODES);
#endif

210
lib/ccm.c Normal file
View File

@ -0,0 +1,210 @@
#include "ccm.h"
void ccm_init(ccm_t* self)
{
assert(self);
vec_init(&self->values);
vec_init(&self->stack);
err_init(&self->err);
}
void ccm_free(ccm_t* self)
{
assert(self);
err_free(&self->err);
vec_free_elements(&self->values, (void*) value_free);
vec_free(&self->values);
vec_free(&self->stack);
}
size_t ccm_str(ccm_t* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
for (size_t i=0; i<self->stack.size; i++)
{
value_t* val = self->values.data[(CCM) self->stack.data[i]];
sz += value_str(val, buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, "\n");
}
return sz;
}
int ccm_is_num(ccm_t* self, CCM value)
{
value_t const* val = self->values.data[value];
return val->type == TYPE_NUM;
}
double ccm_from_num(ccm_t* self, CCM value)
{
assert(self);
assert(value < self->values.size);
if (!ccm_is_num(self, value))
{
err_push(&self->err,
((value_t*) self->values.data[value])->line,
"not a num");
return 0.0;
}
value_t* val = self->values.data[value];
return val->data.num;
}
CCM ccm_to_num(ccm_t* self, double value, int line)
{
assert(self);
value_t* val = malloc(sizeof(value_t));
value_init_num(val, value, line);
vec_push(&self->values, val);
return self->values.size - 1;
}
int ccm_is_tuple(ccm_t* self, CCM value)
{
assert(self);
value_t* val = self->values.data[value];
assert(val);
return val->type == TYPE_TUPLE;
}
vec_t* ccm_from_tuple(ccm_t* self, CCM value)
{
assert(self);
value_t* val = self->values.data[value];
if (!ccm_is_tuple(self, value))
{
err_push(&self->err, val->line, "not a tuple");
return NULL;
}
return val->data.tuple;
}
CCM ccm_to_tuple(ccm_t* self, vec_t* values, int line)
{
assert(self);
assert(values);
value_t* value = malloc(sizeof(value_t));
value_init_new_tuple(value, values, line);
vec_push(&self->values, value);
return self->values.size - 1;
}
void ccm_push(ccm_t* self, CCM value)
{
assert(self);
vec_push(&self->stack, (void*) value);
}
CCM ccm_pop(ccm_t* self)
{
assert(self);
void* val = vec_pop(&self->stack);
return (CCM) val;
}
CCM ccm_top(ccm_t* self, int depth)
{
assert(self);
assert((size_t) depth < self->stack.size);
return (CCM) self->stack.data[self->stack.size - 1 - depth];
}
void ccm_add(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs + rhs, line));
}
void ccm_sub(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs - rhs, line));
}
void ccm_usub(ccm_t* self)
{
assert(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, -lhs, line));
}
void ccm_mul(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs * rhs, line));
}
void ccm_div(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs / rhs, line));
}
void ccm_mod(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, fmod(lhs, rhs), line));
}
void ccm_pow(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, powf(lhs, rhs), line));
}

42
lib/ccm.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CCM_CCM_H
#define CCM_CCM_H
#include "commons.h"
#include "vec.h"
#include "value.h"
#include "err.h"
typedef unsigned long long CCM;
typedef struct {
err_t err;
vec_t values;
vec_t stack;
} ccm_t;
void ccm_init(ccm_t* self);
void ccm_free(ccm_t* self);
size_t ccm_str(ccm_t* self, char* buffer, size_t size);
int ccm_is_num(ccm_t* self, CCM value);
double ccm_from_num(ccm_t* self, CCM value);
CCM ccm_to_num(ccm_t* self, double value, int line);
int ccm_is_tuple(ccm_t* self, CCM value);
vec_t* ccm_from_tuple(ccm_t* self, CCM value);
CCM ccm_to_tuple(ccm_t* self, vec_t* values, int line);
void ccm_push(ccm_t* self, CCM value);
CCM ccm_pop(ccm_t* self);
CCM ccm_top(ccm_t* self, int depth);
void ccm_add(ccm_t* self);
void ccm_sub(ccm_t* self);
void ccm_usub(ccm_t* self);
void ccm_mul(ccm_t* self);
void ccm_div(ccm_t* self);
void ccm_mod(ccm_t* self);
void ccm_pow(ccm_t* self);
#endif

24
lib/commons.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef CCM_COMMONS_H
#define CCM_COMMONS_H
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#define CCM_STRLEN 256
#define CCM_ENUM_ENUM(X) X
#define CCM_ENUM_STR(X) #X
#define CCM_ENUM_H(PREFIX, DEF) \
typedef enum { DEF(CCM_ENUM_ENUM) } PREFIX ; \
extern char const* PREFIX ## Str []
#define CCM_ENUM_C(PREFIX, DEF) \
char const* PREFIX ## Str [] = {DEF(CCM_ENUM_STR)}
#endif

116
lib/compiler.c Normal file
View File

@ -0,0 +1,116 @@
#include "compiler.h"
void compiler_init(compiler_t* self, module_t* module)
{
assert(self);
err_init(&self->err);
self->module = module;
}
void compiler_free(compiler_t* self)
{
assert(self);
err_free(&self->err);
}
void compiler_compile(compiler_t* self,
node_t* node,
prog_t* prog)
{
assert(self);
assert(node);
assert(prog);
if (!err_is_ok(&self->err))
{
return;
}
switch (node->kind)
{
case NODE_ASSERT_EQ: {
compiler_compile(self, node->children.data[0], prog);
prog_add_instr(prog, OP_ASSERT_EQ, CCM_NO_PARAM);
} break;
case NODE_ASSERT_NE: {
compiler_compile(self, node->children.data[0], prog);
prog_add_instr(prog, OP_ASSERT_NE, CCM_NO_PARAM);
} break;
case NODE_MODULE: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_compile(self,
node->children.data[i],
prog);
}
} break;
case NODE_NUM: {
size_t id = prog_add_new_constant(
prog,
ccm_to_num(&self->module->ccm,
atof(node->value),
node->line)
);
prog_add_instr(prog, OP_PUSH, id);
} break;
case NODE_TUPLE: {
for (size_t i=0; i<node->children.size; i++)
{
size_t k = node->children.size - 1 - i;
compiler_compile(self,
node->children.data[k],
prog);
}
prog_add_instr(prog, OP_MK_TUPLE, node->children.size);
} break;
case NODE_SUB: {
compiler_compile(self, node->children.data[0], prog);
if (node->children.size == 2)
{
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_SUB, CCM_NO_PARAM);
}
else
{
prog_add_instr(prog, OP_USUB, CCM_NO_PARAM);
}
} break;
case NODE_ADD:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
Opcode op;
switch (node->kind)
{
case NODE_ADD: op = OP_ADD; break;
case NODE_MUL: op = OP_MUL; break;
case NODE_DIV: op = OP_DIV; break;
case NODE_MOD: op = OP_MOD; break;
case NODE_POW: op = OP_POW; break;
default: abort();
}
prog_add_instr(prog, op, CCM_NO_PARAM);
} break;
default: {
fprintf(stderr, "cannot compile node %s\n",
NodeKindStr[node->kind]);
abort();
}
}
}

22
lib/compiler.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef CCM_COMPILER_H
#define CCM_COMPILER_H
#include "commons.h"
#include "bytecode.h"
#include "prog.h"
#include "node.h"
#include "err.h"
#include "module.h"
typedef struct {
module_t* module;
err_t err;
} compiler_t;
void compiler_init(compiler_t* self, module_t* module);
void compiler_free(compiler_t* self);
void compiler_compile(compiler_t* self,
node_t* node,
prog_t* prog);
#endif

43
lib/err.c Normal file
View File

@ -0,0 +1,43 @@
#include "err.h"
void err_init(err_t* self)
{
assert(self);
vec_init(&self->logs);
}
void err_free(err_t* self)
{
assert(self);
vec_free_elements(&self->logs, NULL);
vec_free(&self->logs);
}
int err_is_ok(err_t* self)
{
return self->logs.size == 0;
}
void err_push(err_t* self, int line, char const* format, ...)
{
va_list lst;
va_start(lst, format);
err_log_t* log = malloc(sizeof(err_log_t));
log->line = line;
vsnprintf(log->msg, CCM_STRLEN, format, lst);
va_end(lst);
vec_push(&self->logs, log);
}
void err_print_stack_trace(err_t* self)
{
assert(self);
for (size_t i=0; i<self->logs.size; i++)
{
err_log_t const* log = self->logs.data[i];
fprintf(stderr, "[ERR:%d] %s\n", log->line, log->msg);
}
}

23
lib/err.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef CCM_ERR_H
#define CCM_ERR_H
#include "commons.h"
#include "vec.h"
typedef struct {
int line;
char msg[CCM_STRLEN];
} err_log_t;
typedef struct {
vec_t logs;
} err_t;
void err_init(err_t* self);
void err_free(err_t* self);
int err_is_ok(err_t* self);
void err_push(err_t* self, int line, char const* format, ...);
void err_print_stack_trace(err_t* self);
#endif

130
lib/exec.c Normal file
View File

@ -0,0 +1,130 @@
#include "exec.h"
#include "bytecode.h"
void exec_init(exec_t* self)
{
assert(self);
self->pc = 0;
err_init(&self->err);
}
void exec_free(exec_t* self)
{
assert(self);
err_free(&self->err);
}
void exec_module(exec_t* self, module_t* module)
{
assert(self);
assert(module);
self->pc = 0;
while (self->pc < module->prog.instrs.size)
{
if (!err_is_ok(&self->err))
{
return;
}
instr_t const* instr = module->prog.instrs.data[self->pc];
exec_instr(self, module, instr->opcode, instr->param);
}
}
void exec_instr(exec_t* self,
module_t* module,
Opcode op,
int param)
{
assert(self);
ccm_t* ccm = &module->ccm;
switch (op)
{
case OP_ASSERT_NE:
case OP_ASSERT_EQ: {
CCM val = ccm_pop(ccm);
vec_t* values = ccm_from_tuple(ccm, val);
assert(values->size == 2);
int oracle = 1;
if (op == OP_ASSERT_NE)
{
oracle = 0;
}
if (value_equals(values->data[0],
values->data[1]) == !oracle)
{
char lhs[CCM_STRLEN];
value_str(values->data[0], lhs, CCM_STRLEN);
char rhs[CCM_STRLEN];
value_str(values->data[1], rhs, CCM_STRLEN);
char const* operator = oracle ? "==" : "!=";
err_push(
&self->err,
((value_t*) values->data[0])->line,
"assertion failed: <%s> %s <%s>",
lhs, operator, rhs
);
}
self->pc++;
} break;
case OP_PUSH: {
CCM value = (CCM) module->prog.constants.data[param];
ccm_push(ccm, value);
self->pc++;
} break;
case OP_POP: {
ccm_pop(ccm);
self->pc++;
} break;
case OP_ADD: { ccm_add(ccm); self->pc++; } break;
case OP_SUB: { ccm_sub(ccm); self->pc++; } break;
case OP_USUB: { ccm_usub(ccm); self->pc++; } break;
case OP_MUL: { ccm_mul(ccm); self->pc++; } break;
case OP_DIV: { ccm_div(ccm); self->pc++; } break;
case OP_MOD: { ccm_mod(ccm); self->pc++; } break;
case OP_POW: { ccm_pow(ccm); self->pc++; } break;
case OP_MK_TUPLE: {
vec_t* values = malloc(sizeof(vec_t));
vec_init(values);
int line = -1;
for (int i=0; i<param; i++)
{
CCM val = ccm_pop(ccm);
value_t* v = value_new_clone(ccm->values.data[val]);
vec_push(values, v);
if (line == -1)
{
line = v->line;
}
}
CCM value = ccm_to_tuple(ccm, values, line);
ccm_push(ccm, value);
self->pc++;
} break;
default: {
fprintf(stderr,
"cannot exec opcode '%s'",
OpcodeStr[op]);
abort();
}
}
}

22
lib/exec.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef CCM_EXEC_H
#define CCM_EXEC_H
#include "commons.h"
#include "module.h"
#include "err.h"
typedef struct {
err_t err;
size_t pc;
} exec_t;
void exec_init(exec_t* self);
void exec_free(exec_t* self);
void exec_module(exec_t* self, module_t* module);
void exec_instr(exec_t* self,
module_t* module,
Opcode op,
int param);
#endif

354
lib/lexer.c Normal file
View File

@ -0,0 +1,354 @@
#include "lexer.h"
#include "str.h"
#define CCM_KEYWORD(KW, KIND, HAS_VAL) \
if ( (node = lexer_try_new_keyword(self, KW, KIND, HAS_VAL)) ) \
{\
return node; \
}
void lexer_init(lexer_t* self)
{
assert(self);
self->source = NULL;
err_init(&self->err);
str_init(&self->separators);
vec_init(&self->texts);
lexer_add_text(self, ",", NODE_COMMA);
lexer_add_text(self, "(", NODE_OPAR);
lexer_add_text(self, ")", NODE_CPAR);
lexer_add_text(self, "+", NODE_ADD);
lexer_add_text(self, "-", NODE_SUB);
lexer_add_text(self, "*", NODE_MUL);
lexer_add_text(self, "/", NODE_DIV);
lexer_add_text(self, "^", NODE_POW);
lexer_add_text(self, "%", NODE_MOD);
}
void lexer_free(lexer_t* self)
{
assert(self);
if (self->source)
{
free(self->source);
self->source = NULL;
}
err_free(&self->err);
str_free(&self->separators);
vec_free_elements(&self->texts, NULL);
vec_free(&self->texts);
}
void lexer_scan(lexer_t* self, char const* source)
{
assert(self);
assert(source);
self->line = 1;
self->cursor = 0;
self->source = strdup(source);
}
void lexer_add_text(lexer_t* self, char const* repr, NodeKind kind)
{
assert(self);
lexer_entry_t* entry = malloc(sizeof(lexer_entry_t));
entry->repr = repr;
entry->kind = kind;
str_push(&self->separators, repr[0]);
vec_push(&self->texts, entry);
}
node_t* lexer_peek(lexer_t* self, int lookahead)
{
assert(self);
lexer_state_t state = lexer_state(self);
node_t* node = NULL;
for (int i=0; i<=lookahead; i++)
{
node = lexer_try_new_next(self);
if (node && i < lookahead)
{
node_free(node);
free(node);
}
}
lexer_restore(self, state);
return node;
}
int lexer_peek_kind(lexer_t* self, NodeKind kind, int lookahead)
{
assert(self);
node_t* peek = lexer_peek(self, lookahead);
int res = (peek != NULL && peek->kind == kind);
if (peek)
{
node_free(peek);
free(peek);
}
return res;
}
lexer_state_t lexer_state(lexer_t* self)
{
assert(self);
lexer_state_t state = {
self->cursor,
self->line
};
return state;
}
void lexer_restore(lexer_t* self, lexer_state_t state)
{
assert(self);
self->cursor = state.cursor;
self->line = state.line;
}
node_t* lexer_try_new_next(lexer_t* self)
{
assert(self);
if (!err_is_ok(&self->err))
{
return NULL;
}
lexer_skip_spaces(self);
while (self->cursor < (ssize_t) strlen(self->source)
&& self->source[self->cursor] == '#')
{
while (self->cursor < (ssize_t) strlen(self->source)
&& self->source[self->cursor] != '\n')
{
self->cursor++;
}
lexer_skip_spaces(self);
}
node_t* node = NULL;
if ( (node = lexer_try_new_num(self)) )
{
return node;
}
for (size_t i=0; i<self->texts.size; i++)
{
if ( (node = lexer_try_new_text(
self,
((lexer_entry_t*) self->texts.data[i])->repr,
((lexer_entry_t*) self->texts.data[i])->kind, 0)) ) {
return node;
}
}
CCM_KEYWORD("assert_eq", NODE_ASSERT_EQ, 0);
CCM_KEYWORD("assert_ne", NODE_ASSERT_NE, 0);
if (self->cursor < (ssize_t) strlen(self->source))
{
str_t s;
str_init(&s);
size_t i = self->cursor;
while (i < strlen(self->source)
&& !lexer_is_sep(self, i))
{
str_push(&s, self->source[i]);
i++;
}
err_push(&self->err, self->line, "unknown symbol '%s'", s.value);
str_free(&s);
}
return NULL;
}
int lexer_consume_next(lexer_t* self, NodeKind kind)
{
assert(self);
node_t* node = lexer_try_new_next(self);
if (node == NULL)
{
err_push(&self->err, self->line,
"expected token '%s' but got nothing",
NodeKindStr[kind] + strlen("NODE_"));
return 0;
}
else if (node->kind != kind)
{
err_push(&self->err, self->line,
"expected token '%s' but got '%s'",
NodeKindStr[kind] + strlen("NODE_"),
NodeKindStr[node->kind] + strlen("NODE_"));
node_free(node);
free(node);
return 0;
}
node_free(node);
free(node);
return 1;
}
void lexer_skip_spaces(lexer_t* self)
{
assert(self);
while (self->cursor < (ssize_t) strlen(self->source)
&& isspace(self->source[self->cursor]))
{
if (self->source[self->cursor] == '\n')
{
self->line++;
}
self->cursor++;
}
}
int lexer_is_sep(lexer_t* self, ssize_t pos)
{
assert(self);
if (pos < 0 || pos >= (ssize_t) strlen(self->source)) { return 1; }
char c = self->source[pos];
if (str_find(&self->separators, c) >= 0)
{
return 1;
}
return isspace(c);
}
node_t* lexer_try_new_keyword(lexer_t* self,
char const* keyword,
NodeKind kind,
int has_value)
{
assert(self);
assert(keyword);
for (size_t i=0; i<strlen(keyword); i++)
{
if (self->cursor + i >= strlen(self->source)
|| keyword[i] != self->source[self->cursor + i])
{
return NULL;
}
}
if (!lexer_is_sep(self, self->cursor - 1)
|| !lexer_is_sep(self, self->cursor + strlen(keyword)))
{
return NULL;
}
node_t* res = malloc(sizeof(node_t));
node_init(res, kind, (has_value ? keyword : ""), self->line);
self->cursor += strlen(keyword);
return res;
}
node_t* lexer_try_new_text(lexer_t* self,
char const* text,
NodeKind kind,
int has_value)
{
assert(self);
assert(text);
for (size_t i=0; i<strlen(text); i++)
{
if (self->cursor + i >= strlen(self->source)
|| text[i] != self->source[self->cursor + i])
{
return NULL;
}
}
node_t* res = malloc(sizeof(node_t));
node_init(res, kind, (has_value ? text : ""), self->line);
self->cursor += strlen(text);
return res;
}
node_t* lexer_try_new_num(lexer_t* self)
{
assert(self);
size_t cursor = self->cursor;
str_t value;
str_init(&value);
if (cursor < strlen(self->source)
&& self->source[cursor] == '-')
{
str_push(&value, self->source[cursor]);
cursor++;
}
while (cursor < strlen(self->source)
&& isdigit(self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
if (cursor < strlen(self->source)
&& self->source[cursor] == '.')
{
str_push(&value, self->source[cursor]);
cursor++;
while (cursor < strlen(self->source)
&& isdigit(self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
}
if (value.size == 0
|| (value.size == 1 && !isdigit(value.value[0]))
|| !lexer_is_sep(self, self->cursor - 1)
|| !lexer_is_sep(self, cursor)
)
{
str_free(&value);
return NULL;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_NUM, value.value, self->line);
str_free(&value);
self->cursor = cursor;
return node;
}

56
lib/lexer.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef CCM_LEXER_H
#define CCM_LEXER_H
#include "commons.h"
#include "node.h"
#include "str.h"
#include "err.h"
typedef struct {
ssize_t cursor;
int line;
} lexer_state_t;
typedef struct {
char const* repr;
NodeKind kind;
} lexer_entry_t;
typedef struct {
err_t err;
str_t separators;
char* source;
ssize_t cursor;
int line;
vec_t texts;
} lexer_t;
void lexer_init(lexer_t* self);
void lexer_free(lexer_t* self);
void lexer_scan(lexer_t* self, char const* source);
void lexer_skip_spaces(lexer_t* self);
int lexer_is_sep(lexer_t* self, ssize_t pos);
void lexer_add_text(lexer_t* self, char const* repr, NodeKind kind);
node_t* lexer_peek(lexer_t* self, int lookahead);
int lexer_peek_kind(lexer_t* self, NodeKind kind, int lookahead);
lexer_state_t lexer_state(lexer_t* self);
void lexer_restore(lexer_t* self, lexer_state_t state);
node_t* lexer_try_new_next(lexer_t* self);
int lexer_consume_next(lexer_t* self, NodeKind kind);
node_t* lexer_try_new_keyword(lexer_t* self,
char const* keyword,
NodeKind kind,
int has_value);
node_t* lexer_try_new_text(lexer_t* self,
char const* text,
NodeKind kind,
int has_value);
node_t* lexer_try_new_num(lexer_t* self);
#endif

115
lib/module.c Normal file
View File

@ -0,0 +1,115 @@
#include "module.h"
#include "lexer.h"
#include "parser.h"
#include "compiler.h"
void module_init(module_t* self)
{
assert(self);
self->source = NULL;
prog_init(&self->prog);
err_init(&self->err);
ccm_init(&self->ccm);
}
void module_free(module_t* self)
{
assert(self);
if (self->source)
{
free(self->source);
}
ccm_free(&self->ccm);
prog_free(&self->prog);
err_free(&self->err);
}
int module_load(module_t* self, char const* path)
{
assert(self);
assert(path);
if (module_load_source(self, path) != 0)
{
return 1;
}
lexer_t lexer;
lexer_init(&lexer);
lexer_scan(&lexer, self->source);
parser_t parser;
parser_init(&parser, &lexer);
node_t* ast = parser_try_new_parse(&parser);
if (!err_is_ok(&lexer.err) || !err_is_ok(&parser.err))
{
err_print_stack_trace(&lexer.err);
err_print_stack_trace(&parser.err);
err_push(&self->err, lexer.line, "invalid module");
goto free_parser;
}
compiler_t compiler;
compiler_init(&compiler, self);
compiler_compile(&compiler, ast, &self->prog);
compiler_free(&compiler);
node_free(ast);
free(ast);
free_parser:
parser_free(&parser);
lexer_free(&lexer);
return 0;
}
int module_load_source(module_t* self, char const* path)
{
assert(self);
FILE* file = fopen(path, "r+");
if (!file)
{
err_push(&self->err, 0, "cannot load file '%s'", path);
return 1;
}
size_t sz = 0;
size_t cap = 2;
char* data = malloc(sizeof(char) * cap);
char buf;
size_t size;
while ( (size = fread(&buf, 1, sizeof(char), file)) )
{
if (sz + 1 >= cap)
{
cap *= 2;
char* next = realloc(data, sizeof(char) * cap);
if (next)
{
data = next;
}
}
data[sz] = buf;
sz++;
}
data[sz] = '\0';
self->source = strdup(data);
free(data);
fclose(file);
return 0;
}

22
lib/module.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef CCM_MODULE_H
#define CCM_MODULE_H
#include "commons.h"
#include "prog.h"
#include "err.h"
#include "ccm.h"
typedef struct {
err_t err;
char* source;
prog_t prog;
ccm_t ccm;
} module_t;
void module_init(module_t* self);
void module_free(module_t* self);
int module_load(module_t* self, char const* path);
int module_load_source(module_t* self, char const* path);
#endif

View File

@ -1 +1,78 @@
#include "node.h" #include "node.h"
CCM_ENUM_C(NodeKind, NODE_KIND);
void node_init(node_t* self,
NodeKind kind,
char const* value,
int line)
{
assert(self);
self->line = line;
self->kind = kind;
vec_init(&self->children);
if (value)
{
self->value = strdup(value);
}
}
void node_free(node_t* self)
{
assert(self);
vec_free_elements(&self->children, (void*) node_free);
vec_free(&self->children);
if (self->value)
{
free(self->value);
self->value = NULL;
}
}
void node_push_new_child(node_t* self, node_t* child)
{
assert(self);
assert(child);
vec_push(&self->children, child);
}
size_t node_str(node_t* self, char* buffer, size_t size)
{
assert(self);
size_t sz = 0;
sz += snprintf(
buffer + sz, size - sz, "%s",
NodeKindStr[self->kind] + strlen("NODE_")
);
if (strlen(self->value) > 0)
{
sz += snprintf(buffer + sz, size - sz, "[%s]", self->value);
}
if (self->children.size > 0)
{
sz += snprintf(buffer + sz, size - sz, "(");
for (size_t i=0; i<self->children.size; i++)
{
if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, ",");
}
sz += node_str(
self->children.data[i],
buffer + sz, size - sz
);
}
sz += snprintf(buffer + sz, size - sz, ")");
}
return sz;
}

View File

@ -1,4 +1,30 @@
#ifndef NODE_H #ifndef CCM_NODE_H
#define NODE_H #define CCM_NODE_H
#include "commons.h"
#include "vec.h"
#define NODE_KIND(G) \
G(NODE_MODULE), \
G(NODE_NUM), G(NODE_OPAR), G(NODE_CPAR), \
G(NODE_POW), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
G(NODE_DIV), G(NODE_MOD), G(NODE_COMMA), G(NODE_TUPLE), \
G(NODE_ASSERT_EQ), G(NODE_ASSERT_NE)
CCM_ENUM_H(NodeKind, NODE_KIND);
typedef struct {
NodeKind kind;
char* value;
vec_t children;
int line;
} node_t;
void node_init(node_t* self, NodeKind kind,
char const* value, int line);
void node_free(node_t* self);
void node_push_new_child(node_t* self, node_t* child);
size_t node_str(node_t* self, char* buffer, size_t size);
#endif #endif

381
lib/parser.c Normal file
View File

@ -0,0 +1,381 @@
#include "parser.h"
#define CCM_TRY(rule) parser_try_new_rule(self, rule)
void parser_init(parser_t* self, lexer_t* lexer)
{
assert(self);
assert(lexer);
self->lexer = lexer;
err_init(&self->err);
self->current = NULL;
}
void parser_free(parser_t* self)
{
err_free(&self->err);
}
node_t* parser_try_new_parse(parser_t* self)
{
assert(self);
return CCM_TRY(parser_try_new_module);
}
node_t* parser_try_new_rule(parser_t* self, rule_t rule)
{
if (!err_is_ok(&self->err))
{
return NULL;
}
lexer_state_t state = lexer_state(self->lexer);
node_t* result = rule(self);
if (result) { return result; }
lexer_restore(self->lexer, state);
return (void*) NULL;
}
int parser_ensure(parser_t* self, node_t* node, NodeKind kind)
{
assert(self);
if (!node)
{
err_push(&self->err, self->lexer->line,
"expected token '%s', got nothing",
NodeKindStr[kind] + strlen("NODE_"));
return 0;
}
if (node->kind != kind)
{
err_push(&self->err, self->lexer->line,
"expected token '%s', got '%s'",
NodeKindStr[kind] + strlen("NODE_"),
NodeKindStr[node->kind] + strlen("NODE_"));
return 0;
}
return 1;
}
node_t* parser_try_new_module(parser_t* self)
{
assert(self);
node_t* module = malloc(sizeof(node_t));
node_init(module, NODE_MODULE, "", self->lexer->line);
node_t* node = NULL;
do {
node = CCM_TRY(parser_try_new_expr);
if (!node)
{
node_free(module);
free(module);
return NULL;
}
node_push_new_child(module, node);
lexer_skip_spaces(self->lexer);
} while(self->lexer->cursor < (ssize_t) strlen(self->lexer->source));
return module;
}
node_t* parser_try_new_expr(parser_t* self)
{
assert(self);
if (lexer_peek_kind(self->lexer, NODE_ASSERT_EQ, 0)
|| lexer_peek_kind(self->lexer, NODE_ASSERT_NE, 0))
{
return CCM_TRY(parser_try_new_assert);
}
return CCM_TRY(parser_try_new_term);
}
node_t* parser_try_new_assert(parser_t* self)
{
assert(self);
node_t* node = malloc(sizeof(node_t));
if (lexer_peek_kind(self->lexer, NODE_ASSERT_EQ, 0))
{
lexer_consume_next(self->lexer, NODE_ASSERT_EQ);
node_init(node, NODE_ASSERT_EQ, "", self->lexer->line);
}
else if (lexer_peek_kind(self->lexer, NODE_ASSERT_NE, 0))
{
lexer_consume_next(self->lexer, NODE_ASSERT_NE);
node_init(node, NODE_ASSERT_NE, "", self->lexer->line);
}
else
{
free(node);
return NULL;
}
node_t* tuple = CCM_TRY(parser_try_new_tuple);
if (!tuple)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, tuple);
return node;
}
node_t* parser_try_new_term(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_factor);
if (!lhs) { return NULL; }
while (lexer_peek_kind(self->lexer, NODE_ADD, 0)
|| lexer_peek_kind(self->lexer, NODE_SUB, 0))
{
node_t* node = lexer_try_new_next(self->lexer);
node_t* rhs = CCM_TRY(parser_try_new_factor);
if (!rhs)
{
node_free(lhs);
free(lhs);
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
node_t* parser_try_new_factor(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_usub);
if (!lhs) { return NULL; }
while (lexer_peek_kind(self->lexer, NODE_MUL, 0)
|| lexer_peek_kind(self->lexer, NODE_DIV, 0)
|| lexer_peek_kind(self->lexer, NODE_MOD, 0))
{
node_t* node = lexer_try_new_next(self->lexer);
node_t* rhs = CCM_TRY(parser_try_new_usub);
if (!rhs)
{
node_free(lhs);
free(lhs);
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
node_t* parser_try_new_usub(parser_t* self)
{
assert(self);
if (lexer_peek_kind(self->lexer, NODE_SUB, 0))
{
lexer_consume_next(self->lexer, NODE_SUB);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_SUB, "", self->lexer->line);
node_t* rhs = CCM_TRY(parser_try_new_usub);
if (!rhs)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, rhs);
return node;
}
else
{
return CCM_TRY(parser_try_new_pow);
}
return NULL;
}
node_t* parser_try_new_pow(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_literal);
if (!lhs) { return NULL; }
if (lexer_peek_kind(self->lexer, NODE_POW, 0))
{
if (!lexer_consume_next(self->lexer, NODE_POW))
{
node_free(lhs);
free(lhs);
return NULL;
}
node_t* rhs = CCM_TRY(parser_try_new_literal);
if (!rhs)
{
node_free(lhs);
free(lhs);
return NULL;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_POW, "", self->lexer->line);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
node_t* parser_try_new_literal(parser_t* self)
{
assert(self);
if (lexer_peek_kind(self->lexer, NODE_OPAR, 0))
{
node_t* tuple = CCM_TRY(parser_try_new_tuple);
if (tuple)
{
return tuple;
}
if (!lexer_consume_next(self->lexer, NODE_OPAR))
{
return NULL;
}
node_t* expr = CCM_TRY(parser_try_new_expr);
if (!lexer_consume_next(self->lexer, NODE_CPAR))
{
if (expr)
{
node_free(expr);
free(expr);
}
return NULL;
}
return expr;
}
return CCM_TRY(parser_try_new_builtin);
}
node_t* parser_try_new_tuple(parser_t* self)
{
assert(self);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_TUPLE, "", self->lexer->line);
if (!lexer_consume_next(self->lexer, NODE_OPAR))
{
node_free(node);
free(node);
return NULL;
}
node_t* lhs = CCM_TRY(parser_try_new_expr);
if (!lhs)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, lhs);
int contains_more_than_one_expr = 0;
while (lexer_peek_kind(self->lexer, NODE_COMMA, 0))
{
lexer_consume_next(self->lexer, NODE_COMMA);
node_t* child = CCM_TRY(parser_try_new_expr);
if (!child)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, child);
contains_more_than_one_expr = 1;
}
lexer_consume_next(self->lexer, NODE_CPAR);
if (!contains_more_than_one_expr)
{
node_free(node);
free(node);
return NULL;
}
return node;
}
node_t* parser_try_new_builtin(parser_t* self)
{
assert(self);
node_t* node = lexer_try_new_next(self->lexer);
parser_ensure(self, node, NODE_NUM);
if (node && node->kind == NODE_NUM)
{
return node;
}
if (node)
{
node_free(node);
free(node);
}
return NULL;
}

35
lib/parser.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef CCM_PARSER_H
#define CCM_PARSER_H
#include "commons.h"
#include "lexer.h"
#include "str.h"
#include "err.h"
typedef struct {
err_t err;
lexer_t* lexer;
node_t* current;
} parser_t;
typedef node_t* (*rule_t)(parser_t*);
void parser_init(parser_t* self, lexer_t* lexer);
void parser_free(parser_t* self);
node_t* parser_try_new_parse(parser_t* self);
node_t* parser_try_new_rule(parser_t* self, rule_t rule);
int parser_ensure(parser_t* self, node_t* node, NodeKind kind);
node_t* parser_try_new_module(parser_t* self);
node_t* parser_try_new_expr(parser_t* self);
node_t* parser_try_new_assert(parser_t* self);
node_t* parser_try_new_term(parser_t* self);
node_t* parser_try_new_factor(parser_t* self);
node_t* parser_try_new_usub(parser_t* self);
node_t* parser_try_new_pow(parser_t* self);
node_t* parser_try_new_literal(parser_t* self);
node_t* parser_try_new_tuple(parser_t* self);
node_t* parser_try_new_builtin(parser_t* self);
#endif

65
lib/prog.c Normal file
View File

@ -0,0 +1,65 @@
#include "prog.h"
void prog_init(prog_t* self)
{
assert(self);
vec_init(&self->instrs);
vec_init(&self->constants);
}
void prog_free(prog_t* self)
{
assert(self);
vec_free_elements(&self->instrs, NULL);
vec_free(&self->instrs);
vec_free(&self->constants);
}
size_t prog_add_instr(prog_t* self, Opcode opcode, int param)
{
assert(self);
instr_t* instr = malloc(sizeof(instr_t));
instr->opcode = opcode;
instr->param = param;
vec_push(&self->instrs, instr);
return self->instrs.size - 1;
}
size_t prog_add_new_constant(prog_t* self, CCM value)
{
assert(self);
vec_push(&self->constants, (void*) value);
return self->constants.size - 1;
}
size_t prog_str(prog_t* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
for (size_t i=0; i<self->instrs.size; i++)
{
instr_t const* instr = self->instrs.data[i];
if (instr->param == CCM_NO_PARAM)
{
sz += snprintf(buffer + sz, size - sz, "%zu\t%s\n",
i,
OpcodeStr[instr->opcode]
+ strlen("OP_"));
}
else
{
sz += snprintf(buffer + sz, size - sz, "%zu\t%s %d\n",
i,
OpcodeStr[instr->opcode] + strlen("OP_"),
instr->param);
}
}
return sz;
}

31
lib/prog.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef CCM_PROG_H
#define CCM_PROG_H
#include "commons.h"
#include "vec.h"
#include "bytecode.h"
#include "value.h"
#include "ccm.h"
#define CCM_NO_PARAM (-1)
typedef struct {
Opcode opcode;
int param;
} instr_t;
typedef struct {
vec_t instrs;
vec_t constants;
} prog_t;
void prog_init(prog_t* self);
void prog_free(prog_t* self);
size_t prog_add_instr(prog_t* self, Opcode opcode, int param);
size_t prog_add_new_constant(prog_t* self, CCM value);
size_t prog_str(prog_t* self, char* buffer, size_t size);
#endif

69
lib/str.c Normal file
View File

@ -0,0 +1,69 @@
#include "str.h"
void str_init(str_t* self)
{
assert(self);
self->size = 0;
self->capacity = 0;
self->value = NULL;
}
void str_free(str_t* self)
{
assert(self);
if (self->value)
{
free(self->value);
}
}
ssize_t str_find(str_t* self, char c)
{
assert(self);
for (size_t i=0; i<self->size; i++)
{
if (self->value[i] == c)
{
return i;
}
}
return -1;
}
void str_push(str_t* self, char c)
{
assert(self);
if (self->value == NULL)
{
self->capacity = 1;
self->value = malloc(sizeof(char) * self->capacity);
}
if (self->size + 2 >= self->capacity)
{
self->capacity *= 2;
self->value = realloc(
self->value,
sizeof(char) * self->capacity
);
}
self->value[self->size] = c;
self->size++;
self->value[self->size] = '\0';
}
void str_push_cstr(str_t* self, char const* rhs)
{
assert(self);
assert(rhs);
for (size_t i=0; i<strlen(rhs); i++)
{
str_push(self, rhs[i]);
}
}

20
lib/str.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef CCM_STR_H
#define CCM_STR_H
#include "commons.h"
typedef struct {
size_t size;
size_t capacity;
char* value;
} str_t;
void str_init(str_t* self);
void str_free(str_t* self);
ssize_t str_find(str_t* self, char c);
void str_push(str_t* self, char c);
void str_push_cstr(str_t* self, char const* rhs);
#endif

3
lib/type.c Normal file
View File

@ -0,0 +1,3 @@
#include "type.h"
CCM_ENUM_C(Type, TYPES);

12
lib/type.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef CCM_TYPE_H
#define CCM_TYPE_H
#include "commons.h"
#define TYPES(G) \
G(TYPE_NUM), \
G(TYPE_TUPLE)
CCM_ENUM_H(Type, TYPES);
#endif

148
lib/value.c Normal file
View File

@ -0,0 +1,148 @@
#include "value.h"
void value_init_num(value_t* self, double num, int line)
{
assert(self);
self->data.num = num;
self->type = TYPE_NUM;
self->line = line;
}
void value_init_new_tuple(value_t* self, vec_t* values, int line)
{
assert(self);
assert(values);
self->data.tuple = values;
self->type = TYPE_TUPLE;
self->line = line;
}
value_t* value_new_clone(value_t* self)
{
assert(self);
value_t* value = malloc(sizeof(value_t));
switch (self->type)
{
case TYPE_NUM: {
value_init_num(value, self->data.num, self->line);
} break;
case TYPE_TUPLE: {
vec_t* vec = malloc(sizeof(vec_t));
vec_init(vec);
for (size_t i=0; i<self->data.tuple->size; i++)
{
vec_push(
vec,
value_new_clone(self->data.tuple->data[i])
);
}
value_init_new_tuple(value, vec, self->line);
} break;
default: {
free(value);
fprintf(stderr, "cannot clone value of type '%s'\n",
TypeStr[self->type]);
abort();
} break;
}
return value;
}
void value_free(value_t* self)
{
if (self->type == TYPE_TUPLE)
{
vec_free_elements(self->data.tuple, (void*) value_free);
vec_free(self->data.tuple);
free(self->data.tuple);
}
}
size_t value_str(value_t* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
switch (self->type)
{
case TYPE_NUM: {
sz += snprintf(buffer + sz, size - sz, "%lf",
self->data.num);
} break;
case TYPE_TUPLE: {
sz += snprintf(buffer + sz, size - sz, "(");
for (size_t i=0; i < self->data.tuple->size; i++)
{
if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, ", ");
}
sz += value_str(self->data.tuple->data[i],
buffer + sz,
size - sz);
}
sz += snprintf(buffer + sz, size - sz, ")");
} break;
default: assert(0);
}
return sz;
}
int value_equals(value_t* self, value_t* rhs)
{
assert(self);
assert(rhs);
if (self->type != rhs->type)
{
return 0;
}
switch (self->type)
{
case TYPE_NUM: {
return self->data.num == rhs->data.num;
} break;
case TYPE_TUPLE: {
if (self->data.tuple->size != rhs->data.tuple->size)
{
return 0;
}
for (size_t i=0; i<self->data.tuple->size; i++)
{
if (!value_equals(
self->data.tuple->data[i],
rhs->data.tuple->data[i]
))
{
return 0;
}
}
return 1;
} break;
default: {
fprintf(
stderr,
"cannot test equality on value of type '%s'\n",
TypeStr[self->type]);
abort();
} break;
}
}

26
lib/value.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef CCM_VALUE_H
#define CCM_VALUE_H
#include "commons.h"
#include "type.h"
#include "vec.h"
typedef struct {
union {
double num;
vec_t* tuple;
} data;
Type type;
int line;
} value_t;
void value_init_num(value_t* self, double num, int line);
void value_init_new_tuple(value_t* self, vec_t* values, int line);
value_t* value_new_clone(value_t* self);
void value_free(value_t* self);
size_t value_str(value_t* self, char* buffer, size_t size);
int value_equals(value_t* self, value_t* rhs);
#endif

72
lib/vec.c Normal file
View File

@ -0,0 +1,72 @@
#include "vec.h"
void vec_init(vec_t* self)
{
assert(self);
self->size = 0;
self->capacity = 0;
self->data = NULL;
}
void vec_free_elements(vec_t* self, void (*free_fun)(void*))
{
assert(self);
for (size_t i=0; i<self->size; i++)
{
if (free_fun)
{
free_fun(self->data[i]);
}
free(self->data[i]);
}
}
void vec_free(vec_t* self)
{
assert(self);
free(self->data);
self->data = NULL;
self->size = 0;
self->capacity = 0;
}
void vec_push(vec_t* self, void* value)
{
assert(self);
if (self->capacity == 0)
{
self->capacity = 2;
self->data = calloc(self->capacity, sizeof(void*));
}
if (self->size + 1 >= self->capacity)
{
self->capacity *= 2;
void** v = realloc(
self->data,
self->capacity * sizeof(void*)
);
assert(v);
self->data = v;
}
self->data[self->size] = value;
self->size++;
}
void* vec_pop(vec_t* self)
{
assert(self);
assert(self->size > 0);
void* value = self->data[self->size - 1];
self->size--;
return value;
}

22
lib/vec.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef CCM_VEC_H
#define CCM_VEC_H
#include "commons.h"
/**
* @file saze
**/
typedef struct {
size_t capacity;
size_t size;
void** data;
} vec_t;
void vec_init(vec_t* self);
void vec_free_elements(vec_t* self, void (*free_fun)(void*));
void vec_free(vec_t* self);
void vec_push(vec_t* self, void* value);
void* vec_pop(vec_t* self);
#endif

23
tests/num.ccm Normal file
View File

@ -0,0 +1,23 @@
assert_eq (0, 0)
# PRECEDENCE
# ==========
assert_eq (1 + 2 * 3, 7)
assert_eq ((1 + 2) * 3, 9)
# MOD
# ===
assert_eq (2, 100 % 3.5)
# POW
# ===
assert_eq (-8, -2^3)
assert_eq (5, 25^0.5)
# UNARY SUB
# =========
assert_eq (16, --16)
assert_eq (-16, ---16)

39
tests/run.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
TOTAL=0
FAILED=0
for file in $(find . -name "*.ccm" | sort)
do
LOG=$(ccm $file 2>&1)
RET=$?
TOTAL=$(($TOTAL + 1))
if [ $RET -eq 0 ]
then
echo -e "\e[36m$file\t\e[32mok\e[0m"
else
echo -e "\e[36m$file\t\e[31mfailed\e[0m"
echo "$LOG"
FAILED=$(($FAILED + 1))
fi
done
echo
if [ $FAILED -eq 0 ]
then
echo -e "\e[32m--- All tests passed ($TOTAL) ---\e[0m"
else
TEST_WORD="tests"
if [ $FAILED -eq 1 ]
then
TEST_WORD="test"
fi
echo -e "\e[31m--- $FAILED $TEST_WORD failed ---\e[0m"
fi