hammer/src/internal.h

396 lines
12 KiB
C
Raw Normal View History

/* Internals for Hammer.
* Copyright (C) 2012 Meredith L. Patterson, Dan "TQ" Hirsch
*
* This program 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, version 2.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* NOTE: This is an internal header and installed for use by extensions. The
* API is not guaranteed stable.
*/
2012-04-23 19:39:44 +01:00
#ifndef HAMMER_INTERNAL__H
#define HAMMER_INTERNAL__H
#include <stdint.h>
#include <assert.h>
2012-05-13 01:01:26 +01:00
#include <err.h>
#include <string.h>
2012-04-23 19:39:44 +01:00
#include "hammer.h"
2012-05-13 01:01:26 +01:00
#ifdef NDEBUG
#define assert_message(check, message) do { } while(0)
#else
#define assert_message(check, message) do { \
if (!(check)) \
2012-05-18 12:37:36 +02:00
errx(1, "Assertion failed (programmer error): %s", message); \
2012-05-13 01:01:26 +01:00
} while(0)
#endif
2012-10-10 15:58:03 +02:00
#define HAMMER_FN_IMPL_NOARGS(rtype_t, name) \
rtype_t name(void) { \
return name##__m(system_allocator); \
} \
rtype_t name##__m(HAllocator* mm__)
// Functions with arguments are difficult to forward cleanly. Alas, we will need to forward them manually.
#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count))))
#define h_free(addr) (mm__->free(mm__, (addr)))
2014-01-16 18:58:36 +01:00
#ifndef __cplusplus
#define false 0
#define true 1
2014-01-16 18:58:36 +01:00
#endif
#ifdef __cplusplus
extern "C" {
#endif
2012-10-10 15:58:03 +02:00
// This is going to be generally useful.
static inline void h_generic_free(HAllocator *allocator, void* ptr) {
allocator->free(allocator, ptr);
}
2013-04-26 20:36:54 -07:00
extern HAllocator system_allocator;
typedef struct HCFStack_ HCFStack;
2012-10-10 15:58:03 +02:00
2012-05-26 13:01:23 +02:00
typedef struct HInputStream_ {
// This should be considered to be a really big value type.
const uint8_t *input;
size_t index;
size_t length;
char bit_offset;
char endianness;
char overrun;
2012-05-26 13:01:23 +02:00
} HInputStream;
typedef struct HSlistNode_ {
void* elem;
struct HSlistNode_ *next;
} HSlistNode;
typedef struct HSlist_ {
HSlistNode *head;
struct HArena_ *arena;
} HSlist;
// {{{ HSArray
typedef struct HSArrayNode_ {
size_t elem;
size_t index;
void* content;
} HSArrayNode;
typedef struct HSArray_ {
// Sparse array
// Element n is valid iff arr->nodes[n].index < arr.used && arr.nodes[arr.nodes[n].index].elem == n
HSArrayNode *nodes; // content for node at index n is stored at position n.
size_t capacity;
size_t used;
HAllocator *mm__;
} HSArray;
HSArray *h_sarray_new(HAllocator *mm__, size_t size);
void h_sarray_free(HSArray *arr);
static inline bool h_sarray_isset(HSArray *arr, size_t n) {
assert(n < arr->capacity);
return (arr->nodes[n].index < arr->used && arr->nodes[arr->nodes[n].index].elem == n);
}
static inline void* h_sarray_get(HSArray *arr, size_t n) {
assert(n < arr->capacity);
if (h_sarray_isset(arr, n))
return arr->nodes[n].content;
return NULL;
}
static inline void* h_sarray_set(HSArray *arr, size_t n, void* val) {
assert(n < arr->capacity);
arr->nodes[n].content = val;
if (h_sarray_isset(arr, n))
return val;
arr->nodes[arr->used].elem = n;
arr->nodes[n].index = arr->used++;
return val;
}
static inline void h_sarray_clear(HSArray *arr) {
arr->used = 0;
}
#define H__APPEND2(a,b) a##b
#define H__APPEND(a,b) H__APPEND2(a,b)
#define H__INTVAR(pfx) H__APPEND(intvar__##pfx##__,__COUNTER__)
#define H_SARRAY_FOREACH_KV_(var,idx,arr,intvar) \
for (size_t intvar = 0, idx = (var = (arr)->nodes[(arr)->nodes[intvar].elem].content,(arr)->nodes[intvar].elem); \
intvar < (arr)->used; \
idx = (arr)->nodes[intvar].elem, var = (arr)->nodes[(arr)->nodes[intvar].elem].content, intvar=intvar+1)
#define H_SARRAY_FOREACH_KV(var,index,arr) H_SARRAY_FOREACH_KV_(var,index,arr,H__INTVAR(idx))
#define H_SARRAY_FOREACH_V(var,arr) H_SARRAY_FOREACH_KV_(var,H__INTVAR(elem),arr,H__INTVAR(idx))
#define H_SARRAY_FOREACH_K(index,arr) H_SARRAY_FOREACH_KV_(H__INTVAR(val),index,arr,H__INTVAR(idx))
// }}}
typedef unsigned int *HCharset;
static inline HCharset new_charset(HAllocator* mm__) {
HCharset cs = h_new(unsigned int, 256 / sizeof(unsigned int));
memset(cs, 0, 256);
return cs;
}
static inline int charset_isset(HCharset cs, uint8_t pos) {
return !!(cs[pos / sizeof(*cs)] & (1 << (pos % sizeof(*cs))));
}
static inline void charset_set(HCharset cs, uint8_t pos, int val) {
cs[pos / sizeof(*cs)] =
val
? cs[pos / sizeof(*cs)] | (1 << (pos % sizeof(*cs)))
: cs[pos / sizeof(*cs)] & ~(1 << (pos % sizeof(*cs)));
}
typedef unsigned int HHashValue;
typedef HHashValue (*HHashFunc)(const void* key);
typedef bool (*HEqualFunc)(const void* key1, const void* key2);
typedef struct HHashTableEntry_ {
struct HHashTableEntry_ *next;
2013-04-30 17:44:54 +02:00
const void* key;
void* value;
HHashValue hashval;
} HHashTableEntry;
typedef struct HHashTable_ {
HHashTableEntry *contents;
HHashFunc hashFunc;
HEqualFunc equalFunc;
size_t capacity;
size_t used;
HArena *arena;
} HHashTable;
/* The state of the parser.
*
* Members:
2012-05-26 13:13:41 +02:00
* cache - a hash table describing the state of the parse, including partial HParseResult's. It's a hash table from HParserCacheKey to HParserCacheValue.
* input_stream - the input stream at this state.
* arena - the arena that has been allocated for the parse this state is in.
2012-05-26 13:13:41 +02:00
* lr_stack - a stack of HLeftRec's, used in Warth's recursion
* recursion_heads - table of recursion heads. Keys are HParserCacheKey's with only an HInputStream (parser can be NULL), values are HRecursionHead's.
*
*/
2012-05-26 12:03:58 +02:00
struct HParseState_ {
HHashTable *cache;
2012-05-26 13:01:23 +02:00
HInputStream input_stream;
HArena * arena;
HSlist *lr_stack;
HHashTable *recursion_heads;
};
typedef struct HParserBackendVTable_ {
int (*compile)(HAllocator *mm__, HParser* parser, const void* params);
2013-05-12 00:20:27 +02:00
HParseResult* (*parse)(HAllocator *mm__, const HParser* parser, HInputStream* stream);
2013-04-26 20:36:54 -07:00
void (*free)(HParser* parser);
} HParserBackendVTable;
/* The (location, parser) tuple used to key the cache.
*/
2012-05-26 13:13:41 +02:00
typedef struct HParserCacheKey_ {
2012-05-26 13:01:23 +02:00
HInputStream input_pos;
const HParser *parser;
2012-05-26 13:13:41 +02:00
} HParserCacheKey;
/* A value in the cache is either of value Left or Right (this is a
* holdover from Scala, which used Either here). Left corresponds to
2012-05-26 13:13:41 +02:00
* HLeftRec, which is for left recursion; Right corresponds to
2012-05-26 13:01:23 +02:00
* HParseResult.
*/
2012-05-26 13:13:41 +02:00
typedef enum HParserCacheValueType_ {
PC_LEFT,
PC_RIGHT
2012-05-26 13:13:41 +02:00
} HParserCacheValueType;
/* A recursion head.
*
* Members:
* head_parser - the parse rule that started this recursion
2012-05-26 13:01:23 +02:00
* involved_set - A list of rules (HParser's) involved in the recursion
* eval_set -
*/
2012-05-26 13:13:41 +02:00
typedef struct HRecursionHead_ {
2012-05-26 13:01:23 +02:00
const HParser *head_parser;
HSlist *involved_set;
HSlist *eval_set;
2012-05-26 13:13:41 +02:00
} HRecursionHead;
/* A left recursion.
*
* Members:
* seed -
* rule -
* head -
*/
2012-05-26 13:13:41 +02:00
typedef struct HLeftRec_ {
2012-05-26 13:01:23 +02:00
HParseResult *seed;
const HParser *rule;
2012-05-26 13:13:41 +02:00
HRecursionHead *head;
} HLeftRec;
2012-05-26 13:13:41 +02:00
/* Tagged union for values in the cache: either HLeftRec's (Left) or
2012-05-26 13:01:23 +02:00
* HParseResult's (Right).
* Includes the position (input_stream) to advance to after using this value.
*/
2012-05-26 13:13:41 +02:00
typedef struct HParserCacheValue_t {
HParserCacheValueType value_type;
union {
2012-05-26 13:13:41 +02:00
HLeftRec *left;
HParseResult *right;
};
HInputStream input_stream;
2012-05-26 13:13:41 +02:00
} HParserCacheValue;
// This file provides the logical inverse of bitreader.c
struct HBitWriter_ {
uint8_t* buf;
HAllocator *mm__;
size_t index;
size_t capacity;
char bit_offset; // unlike in bit_reader, this is always the number
// of used bits in the current byte. i.e., 0 always
// means that 8 bits are available for use.
char flags;
};
// }}}
2013-01-13 17:01:10 +01:00
// Backends {{{
extern HParserBackendVTable h__packrat_backend_vtable;
extern HParserBackendVTable h__llk_backend_vtable;
2013-06-04 22:14:06 +02:00
extern HParserBackendVTable h__lalr_backend_vtable;
extern HParserBackendVTable h__glr_backend_vtable;
// }}}
// TODO(thequux): Set symbol visibility for these functions so that they aren't exported.
2012-04-23 19:39:44 +01:00
int64_t h_read_bits(HInputStream* state, int count, char signed_p);
2012-05-26 14:06:52 +02:00
// need to decide if we want to make this public.
HParseResult* h_do_parse(const HParser* parser, HParseState *state);
2012-05-26 13:01:23 +02:00
void put_cached(HParseState *ps, const HParser *p, HParseResult *cached);
2012-05-13 01:01:26 +01:00
static inline
HParser *h_new_parser(HAllocator *mm__, const HParserVtable *vt, void *env) {
HParser *p = h_new(HParser, 1);
memset(p, 0, sizeof(HParser));
p->vtable = vt;
p->env = env;
return p;
}
HCFChoice *h_desugar(HAllocator *mm__, HCFStack *stk__, const HParser *parser);
2012-05-26 14:06:52 +02:00
HCountedArray *h_carray_new_sized(HArena * arena, size_t size);
HCountedArray *h_carray_new(HArena * arena);
void h_carray_append(HCountedArray *array, void* item);
2012-10-08 17:11:47 +02:00
HSlist* h_slist_new(HArena *arena);
HSlist* h_slist_copy(HSlist *slist);
2012-10-08 17:11:47 +02:00
void* h_slist_pop(HSlist *slist);
2013-06-20 11:05:57 +02:00
void* h_slist_drop(HSlist *slist);
2012-10-08 17:11:47 +02:00
void h_slist_push(HSlist *slist, void* item);
bool h_slist_find(HSlist *slist, const void* item);
HSlist* h_slist_remove_all(HSlist *slist, const void* item);
2012-10-08 17:11:47 +02:00
void h_slist_free(HSlist *slist);
2013-05-11 15:14:10 +02:00
static inline bool h_slist_empty(const HSlist *sl) { return (sl->head == NULL); }
2012-05-26 16:00:43 +02:00
HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashFunc);
2013-05-08 17:01:23 +02:00
void* h_hashtable_get(const HHashTable* ht, const void* key);
2013-04-30 17:44:54 +02:00
void h_hashtable_put(HHashTable* ht, const void* key, void* value);
void h_hashtable_update(HHashTable* dst, const HHashTable *src);
void h_hashtable_merge(void *(*combine)(void *v1, const void *v2),
2013-05-22 21:57:46 +02:00
HHashTable *dst, const HHashTable *src);
2013-05-08 17:01:23 +02:00
int h_hashtable_present(const HHashTable* ht, const void* key);
2013-04-30 17:44:54 +02:00
void h_hashtable_del(HHashTable* ht, const void* key);
2012-10-08 19:20:36 +02:00
void h_hashtable_free(HHashTable* ht);
2013-05-08 17:01:23 +02:00
static inline bool h_hashtable_empty(const HHashTable* ht) { return (ht->used == 0); }
typedef HHashTable HHashSet;
#define h_hashset_new(a,eq,hash) h_hashtable_new(a,eq,hash)
#define h_hashset_put(ht,el) h_hashtable_put(ht, el, NULL)
#define h_hashset_put_all(a,b) h_hashtable_update(a, b)
#define h_hashset_present(ht,el) h_hashtable_present(ht,el)
#define h_hashset_empty(ht) h_hashtable_empty(ht)
#define h_hashset_del(ht,el) h_hashtable_del(ht,el)
#define h_hashset_free(ht) h_hashtable_free(ht)
2013-06-05 15:12:48 +02:00
bool h_hashset_equal(const HHashSet *a, const HHashSet *b);
2012-10-08 19:20:36 +02:00
bool h_eq_ptr(const void *p, const void *q);
HHashValue h_hash_ptr(const void *p);
uint32_t h_djbhash(const uint8_t *buf, size_t len);
typedef struct HCFSequence_ HCFSequence;
struct HCFChoice_ {
enum HCFChoiceType {
HCF_END,
HCF_CHOICE,
HCF_CHARSET,
HCF_CHAR
} type;
union {
HCharset charset;
HCFSequence** seq;
uint8_t chr;
};
2013-05-14 11:54:43 +02:00
HAction reshape; // take CFG parse tree to HParsedToken of expected form.
// to execute before action and pred are applied.
HAction action;
2013-02-20 20:43:16 -05:00
HPredicate pred;
void* user_data;
};
struct HCFSequence_ {
HCFChoice **items; // last one is NULL
};
struct HParserVtable_ {
HParseResult* (*parse)(void *env, HParseState *state);
bool (*isValidRegular)(void *env);
bool (*isValidCF)(void *env);
bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean.
void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env);
};
2013-03-09 21:42:49 -08:00
bool h_false(void*);
bool h_true(void*);
bool h_not_regular(HRVMProg*, void*);
2013-03-09 21:42:49 -08:00
#if 0
#include <stdlib.h>
2012-10-08 22:06:33 +02:00
#define h_arena_malloc(a, s) malloc(s)
#endif
2014-01-16 18:58:36 +01:00
#ifdef __cplusplus
} // extern "C"
#endif
2012-04-23 19:39:44 +01:00
#endif // #ifndef HAMMER_INTERNAL__H