the interpreter implementation is now hidden behing the src/libnoja/noja.h facade. Also I wrote a disassembler that lets you build noja executables by specifying the bytecode directly in a text format
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
|
||||
/* +--------------------------------------------------------------------------+
|
||||
** | _ _ _ |
|
||||
** | | \ | | (_) |
|
||||
** | | \| | ___ _ __ _ |
|
||||
** | | . ` |/ _ \| |/ _` | |
|
||||
** | | |\ | (_) | | (_| | |
|
||||
** | |_| \_|\___/| |\__,_| |
|
||||
** | _/ | |
|
||||
** | |__/ |
|
||||
** +--------------------------------------------------------------------------+
|
||||
** | Copyright (c) 2022 Francesco Cozzuto <francesco.cozzuto@gmail.com> |
|
||||
** +--------------------------------------------------------------------------+
|
||||
** | This file is part of The Noja Interpreter. |
|
||||
** | |
|
||||
** | The Noja Interpreter is free software: you can redistribute it and/or |
|
||||
** | modify it under the terms of the GNU General Public License as published |
|
||||
** | by the Free Software Foundation, either version 3 of the License, or (at |
|
||||
** | your option) any later version. |
|
||||
** | |
|
||||
** | The Noja Interpreter is distributed in the hope that it will be useful, |
|
||||
** | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
** | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
||||
** | Public License for more details. |
|
||||
** | |
|
||||
** | You should have received a copy of the GNU General Public License along |
|
||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
||||
** +--------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bucketlist.h"
|
||||
#include "defs.h"
|
||||
|
||||
#define MIN_BUCKET_SIZE 4096
|
||||
|
||||
typedef struct Bucket Bucket;
|
||||
struct Bucket {
|
||||
Bucket* next;
|
||||
int size,
|
||||
used,
|
||||
aidx;
|
||||
char body[];
|
||||
};
|
||||
|
||||
struct xBucketList {
|
||||
BPAlloc *alloc;
|
||||
Bucket *head,
|
||||
*tail;
|
||||
int size;
|
||||
};
|
||||
|
||||
BucketList *BucketList_New(BPAlloc *alloc)
|
||||
{
|
||||
assert(alloc != NULL);
|
||||
|
||||
BucketList *blist = BPAlloc_Malloc(alloc, sizeof(BucketList) + sizeof(Bucket) + MIN_BUCKET_SIZE);
|
||||
|
||||
if(blist == NULL)
|
||||
return NULL;
|
||||
|
||||
Bucket *head = (Bucket*) (blist + 1);
|
||||
head->next = NULL;
|
||||
head->size = MIN_BUCKET_SIZE;
|
||||
head->used = 0;
|
||||
head->aidx = 0;
|
||||
|
||||
blist->alloc = alloc;
|
||||
blist->head = head;
|
||||
blist->tail = head;
|
||||
blist->size = 0;
|
||||
return blist;
|
||||
}
|
||||
|
||||
int BucketList_Size(BucketList *blist)
|
||||
{
|
||||
return blist->size;
|
||||
}
|
||||
|
||||
static Bucket *make_bucket(BPAlloc *alloc, int size)
|
||||
{
|
||||
Bucket *new_bucket = BPAlloc_Malloc(alloc, sizeof(Bucket) + size);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return NULL;
|
||||
|
||||
// Initialize it.
|
||||
new_bucket->next = NULL;
|
||||
new_bucket->size = size;
|
||||
new_bucket->used = 0;
|
||||
new_bucket->aidx = -1;
|
||||
return new_bucket;
|
||||
}
|
||||
|
||||
static void append_bucket(BucketList *blist, Bucket *new_bucket)
|
||||
{
|
||||
new_bucket->aidx = blist->size;
|
||||
blist->tail->next = new_bucket;
|
||||
blist->tail = new_bucket;
|
||||
}
|
||||
|
||||
_Bool BucketList_Append(BucketList *blist, const void *data, int size)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
int not_copied_yet = size;
|
||||
|
||||
while(not_copied_yet > 0)
|
||||
{
|
||||
// Copy until there's nothing left
|
||||
// or until the current bucket is
|
||||
// full. If the bucket is already
|
||||
// full, add another one.
|
||||
|
||||
int left_in_bucket = blist->tail->size - blist->tail->used;
|
||||
|
||||
if(left_in_bucket == 0)
|
||||
{
|
||||
Bucket *new_bucket = make_bucket(blist->alloc, MIN_BUCKET_SIZE);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return 0;
|
||||
|
||||
append_bucket(blist, new_bucket);
|
||||
}
|
||||
|
||||
// Decide how much to copy.
|
||||
int copying = MIN(not_copied_yet, left_in_bucket);
|
||||
|
||||
// Copy into the bucket.
|
||||
{
|
||||
char *dst = blist->tail->body + blist->tail->used;
|
||||
|
||||
if(data == NULL)
|
||||
memset(dst, 0, copying);
|
||||
else
|
||||
memcpy(dst, data + size - not_copied_yet, copying);
|
||||
|
||||
blist->tail->used += copying;
|
||||
}
|
||||
|
||||
not_copied_yet -= copying;
|
||||
}
|
||||
|
||||
blist->size += size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *BucketList_Append2(BucketList *blist, const void *data, int size)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
// If the data doesn't fit inside the
|
||||
// current bucket, add another one with
|
||||
// enough space.
|
||||
if(blist->tail->used + size > blist->tail->size)
|
||||
{
|
||||
int bucket_size = MAX(MIN_BUCKET_SIZE, size);
|
||||
|
||||
Bucket *new_bucket = make_bucket(blist->alloc, bucket_size);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return 0;
|
||||
|
||||
append_bucket(blist, new_bucket);
|
||||
}
|
||||
|
||||
void *addr = blist->tail->body + blist->tail->used;
|
||||
|
||||
// Do the copying.
|
||||
if(data == NULL)
|
||||
memset(addr, 0, size);
|
||||
else
|
||||
memcpy(addr, data, size);
|
||||
|
||||
blist->tail->used += size;
|
||||
blist->size += size;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void BucketList_Copy(BucketList *blist, void *dest, int len)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if(len < 0)
|
||||
len = blist->size;
|
||||
|
||||
int copied = 0;
|
||||
|
||||
Bucket *bucket = blist->head;
|
||||
|
||||
while(bucket && copied < len)
|
||||
{
|
||||
int copying = MIN(len - copied, bucket->used);
|
||||
assert(copying >= 0);
|
||||
|
||||
memcpy((char*) dest + copied, bucket->body, copying);
|
||||
|
||||
copied += copying;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
}
|
||||
|
||||
BPAlloc *BucketList_GetAlloc(BucketList *blist)
|
||||
{
|
||||
return blist->alloc;
|
||||
}
|
||||
Reference in New Issue
Block a user