#include "ficl.h"
#define FICL_SAFE_CALLBACK_FROM_SYSTEM(system) \
(((system) != NULL) ? &((system)->callback) : NULL)
#define FICL_SAFE_SYSTEM_FROM_DICTIONARY(dictionary) \
(((dictionary) != NULL) ? (dictionary)->system : NULL)
#define FICL_DICTIONARY_ASSERT(dictionary, expression) \
FICL_SYSTEM_ASSERT(FICL_SAFE_SYSTEM_FROM_DICTIONARY(dictionary), \
expression)
void
ficlDictionaryAbortDefinition(ficlDictionary *dictionary)
{
ficlWord *word;
ficlDictionaryLock(dictionary, FICL_TRUE);
word = dictionary->smudge;
if (word->flags & FICL_WORD_SMUDGED)
dictionary->here = (ficlCell *)word->name;
ficlDictionaryLock(dictionary, FICL_FALSE);
}
void
ficlDictionaryAlign(ficlDictionary *dictionary)
{
dictionary->here = ficlAlignPointer(dictionary->here);
}
void
ficlDictionaryAllot(ficlDictionary *dictionary, int n)
{
char *here = (char *)dictionary->here;
here += n;
dictionary->here = FICL_POINTER_TO_CELL(here);
}
void
ficlDictionaryAllotCells(ficlDictionary *dictionary, int nficlCells)
{
dictionary->here += nficlCells;
}
void
ficlDictionaryAppendCell(ficlDictionary *dictionary, ficlCell c)
{
*dictionary->here++ = c;
}
void
ficlDictionaryAppendCharacter(ficlDictionary *dictionary, char c)
{
char *here = (char *)dictionary->here;
*here++ = c;
dictionary->here = FICL_POINTER_TO_CELL(here);
}
void
ficlDictionaryAppendUnsigned(ficlDictionary *dictionary, ficlUnsigned u)
{
ficlCell c;
c.u = u;
ficlDictionaryAppendCell(dictionary, c);
}
void *
ficlDictionaryAppendData(ficlDictionary *dictionary, void *data,
ficlInteger length)
{
char *here = (char *)dictionary->here;
char *oldHere = here;
char *from = (char *)data;
if (length == 0) {
ficlDictionaryAlign(dictionary);
return ((char *)dictionary->here);
}
while (length) {
*here++ = *from++;
length--;
}
*here++ = '\0';
dictionary->here = FICL_POINTER_TO_CELL(here);
ficlDictionaryAlign(dictionary);
return (oldHere);
}
char *
ficlDictionaryAppendString(ficlDictionary *dictionary, ficlString s)
{
void *data = FICL_STRING_GET_POINTER(s);
ficlInteger length = FICL_STRING_GET_LENGTH(s);
if (length > FICL_NAME_LENGTH)
length = FICL_NAME_LENGTH;
return (ficlDictionaryAppendData(dictionary, data, length));
}
ficlWord *
ficlDictionaryAppendConstantInstruction(ficlDictionary *dictionary,
ficlString name, ficlInstruction instruction, ficlInteger value)
{
ficlWord *word = ficlDictionaryAppendWord(dictionary, name,
(ficlPrimitive)instruction, FICL_WORD_DEFAULT);
if (word != NULL)
ficlDictionaryAppendUnsigned(dictionary, value);
return (word);
}
ficlWord *
ficlDictionaryAppend2ConstantInstruction(ficlDictionary *dictionary,
ficlString name, ficlInstruction instruction, ficl2Integer value)
{
ficlWord *word = ficlDictionaryAppendWord(dictionary, name,
(ficlPrimitive)instruction, FICL_WORD_DEFAULT);
if (word != NULL) {
ficlDictionaryAppendUnsigned(dictionary,
FICL_2UNSIGNED_GET_HIGH(value));
ficlDictionaryAppendUnsigned(dictionary,
FICL_2UNSIGNED_GET_LOW(value));
}
return (word);
}
ficlWord *
ficlDictionaryAppendConstant(ficlDictionary *dictionary, char *name,
ficlInteger value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionaryAppendConstantInstruction(dictionary, s,
ficlInstructionConstantParen, value));
}
ficlWord *
ficlDictionaryAppend2Constant(ficlDictionary *dictionary, char *name,
ficl2Integer value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionaryAppend2ConstantInstruction(dictionary, s,
ficlInstruction2ConstantParen, value));
}
ficlWord *
ficlDictionarySetConstantInstruction(ficlDictionary *dictionary,
ficlString name, ficlInstruction instruction, ficlInteger value)
{
ficlWord *word = ficlDictionaryLookup(dictionary, name);
ficlCell c;
if (word == NULL) {
word = ficlDictionaryAppendConstantInstruction(dictionary,
name, instruction, value);
} else {
word->code = (ficlPrimitive)instruction;
c.i = value;
word->param[0] = c;
}
return (word);
}
ficlWord *
ficlDictionarySetConstant(ficlDictionary *dictionary, char *name,
ficlInteger value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionarySetConstantInstruction(dictionary, s,
ficlInstructionConstantParen, value));
}
ficlWord *
ficlDictionarySet2ConstantInstruction(ficlDictionary *dictionary, ficlString s,
ficlInstruction instruction, ficl2Integer value)
{
ficlWord *word;
word = ficlDictionaryLookup(dictionary, s);
#if FICL_WANT_FLOAT
if ((word != NULL) &&
((((ficlInstruction)word->code) == ficlInstruction2ConstantParen) ||
(((ficlInstruction)word->code) == ficlInstructionF2ConstantParen)))
#else
if ((word != NULL) &&
((((ficlInstruction)word->code) == ficlInstruction2ConstantParen)))
#endif
{
word->code = (ficlPrimitive)instruction;
word->param[0].u = FICL_2UNSIGNED_GET_HIGH(value);
word->param[1].u = FICL_2UNSIGNED_GET_LOW(value);
} else {
word = ficlDictionaryAppend2ConstantInstruction(dictionary, s,
instruction, value);
}
return (word);
}
ficlWord *
ficlDictionarySet2Constant(ficlDictionary *dictionary, char *name,
ficl2Integer value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionarySet2ConstantInstruction(dictionary, s,
ficlInstruction2ConstantParen, value));
}
ficlWord *
ficlDictionarySetConstantString(ficlDictionary *dictionary, char *name,
char *value)
{
ficlString s;
ficl2Integer valueAs2Integer;
FICL_2INTEGER_SET(strlen(value), (intptr_t)value, valueAs2Integer);
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionarySet2ConstantInstruction(dictionary, s,
ficlInstruction2ConstantParen, valueAs2Integer));
}
ficlWord *
ficlDictionaryAppendWord(ficlDictionary *dictionary, ficlString name,
ficlPrimitive code, ficlUnsigned8 flags)
{
ficlUnsigned8 length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(name);
char *nameCopy;
ficlWord *word;
ficlDictionaryLock(dictionary, FICL_TRUE);
nameCopy = ficlDictionaryAppendString(dictionary, name);
word = (ficlWord *)dictionary->here;
dictionary->smudge = word;
word->hash = ficlHashCode(name);
word->code = code;
word->semiParen = ficlInstructionSemiParen;
word->flags = (ficlUnsigned8)(flags | FICL_WORD_SMUDGED);
word->length = length;
word->name = nameCopy;
dictionary->here = word->param;
if (!(flags & FICL_WORD_SMUDGED))
ficlDictionaryUnsmudge(dictionary);
ficlDictionaryLock(dictionary, FICL_FALSE);
return (word);
}
ficlWord *
ficlDictionaryAppendPrimitive(ficlDictionary *dictionary, char *name,
ficlPrimitive code, ficlUnsigned8 flags)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionaryAppendWord(dictionary, s, code, flags));
}
ficlWord *
ficlDictionarySetPrimitive(ficlDictionary *dictionary, char *name,
ficlPrimitive code, ficlUnsigned8 flags)
{
ficlString s;
ficlWord *word;
FICL_STRING_SET_FROM_CSTRING(s, name);
word = ficlDictionaryLookup(dictionary, s);
if (word == NULL) {
word = ficlDictionaryAppendPrimitive(dictionary, name,
code, flags);
} else {
word->code = (ficlPrimitive)code;
word->flags = flags;
}
return (word);
}
ficlWord *
ficlDictionaryAppendInstruction(ficlDictionary *dictionary, char *name,
ficlInstruction i, ficlUnsigned8 flags)
{
return (ficlDictionaryAppendPrimitive(dictionary, name,
(ficlPrimitive)i, (ficlUnsigned8)(FICL_WORD_INSTRUCTION | flags)));
}
ficlWord *
ficlDictionarySetInstruction(ficlDictionary *dictionary, char *name,
ficlInstruction i, ficlUnsigned8 flags)
{
return (ficlDictionarySetPrimitive(dictionary, name,
(ficlPrimitive)i, (ficlUnsigned8)(FICL_WORD_INSTRUCTION | flags)));
}
int
ficlDictionaryCellsAvailable(ficlDictionary *dictionary)
{
return (dictionary->size - ficlDictionaryCellsUsed(dictionary));
}
int
ficlDictionaryCellsUsed(ficlDictionary *dictionary)
{
return (dictionary->here - dictionary->base);
}
ficlDictionary *
ficlDictionaryCreate(ficlSystem *system, unsigned size)
{
return (ficlDictionaryCreateHashed(system, size, 1));
}
ficlDictionary *
ficlDictionaryCreateHashed(ficlSystem *system, unsigned size,
unsigned bucketCount)
{
ficlDictionary *dictionary;
size_t nAlloc;
nAlloc = sizeof (ficlDictionary) + (size * sizeof (ficlCell))
+ sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *);
dictionary = ficlMalloc(nAlloc);
FICL_SYSTEM_ASSERT(system, dictionary != NULL);
dictionary->size = size;
dictionary->system = system;
ficlDictionaryEmpty(dictionary, bucketCount);
return (dictionary);
}
ficlHash *
ficlDictionaryCreateWordlist(ficlDictionary *dictionary, int bucketCount)
{
ficlHash *hash;
ficlDictionaryAlign(dictionary);
hash = (ficlHash *)dictionary->here;
ficlDictionaryAllot(dictionary,
sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *));
hash->size = bucketCount;
ficlHashReset(hash);
return (hash);
}
void
ficlDictionaryDestroy(ficlDictionary *dictionary)
{
FICL_DICTIONARY_ASSERT(dictionary, dictionary != NULL);
ficlFree(dictionary);
}
void
ficlDictionaryEmpty(ficlDictionary *dictionary, unsigned bucketCount)
{
ficlHash *hash;
dictionary->here = dictionary->base;
ficlDictionaryAlign(dictionary);
hash = (ficlHash *)dictionary->here;
ficlDictionaryAllot(dictionary,
sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *));
hash->size = bucketCount;
ficlHashReset(hash);
dictionary->forthWordlist = hash;
dictionary->smudge = NULL;
ficlDictionaryResetSearchOrder(dictionary);
}
int
ficlDictionaryIsAWord(ficlDictionary *dictionary, ficlWord *word)
{
if ((((ficlInstruction)word) > ficlInstructionInvalid) &&
(((ficlInstruction)word) < ficlInstructionLast))
return (1);
if (!ficlDictionaryIncludes(dictionary, word))
return (0);
if (!ficlDictionaryIncludes(dictionary, word->name))
return (0);
if ((word->link != NULL) &&
!ficlDictionaryIncludes(dictionary, word->link))
return (0);
if ((word->length <= 0) || (word->name[word->length] != '\0'))
return (0);
if (strlen(word->name) != word->length)
return (0);
return (1);
}
#define nSEARCH_CELLS 100
ficlWord *
ficlDictionaryFindEnclosingWord(ficlDictionary *dictionary, ficlCell *cell)
{
ficlWord *word;
int i;
if (!ficlDictionaryIncludes(dictionary, (void *)cell))
return (NULL);
for (i = nSEARCH_CELLS; i > 0; --i, --cell) {
word = (ficlWord *)
(cell + 1 - (sizeof (ficlWord) / sizeof (ficlCell)));
if (ficlDictionaryIsAWord(dictionary, word))
return (word);
}
return (NULL);
}
int
ficlDictionaryIncludes(ficlDictionary *dictionary, void *p)
{
return ((p >= (void *) &dictionary->base) &&
(p < (void *)(&dictionary->base + dictionary->size)));
}
ficlWord *
ficlDictionaryLookup(ficlDictionary *dictionary, ficlString name)
{
ficlWord *word = NULL;
ficlHash *hash;
int i;
ficlUnsigned16 hashCode = ficlHashCode(name);
FICL_DICTIONARY_ASSERT(dictionary, dictionary != NULL);
ficlDictionaryLock(dictionary, FICL_TRUE);
for (i = (int)dictionary->wordlistCount - 1; (i >= 0) && (!word); --i) {
hash = dictionary->wordlists[i];
word = ficlHashLookup(hash, name, hashCode);
}
ficlDictionaryLock(dictionary, FICL_FALSE);
return (word);
}
char *ficlDictionaryInstructionNames[] =
{
#define FICL_TOKEN(token, description) description,
#define FICL_INSTRUCTION_TOKEN(token, description, flags) description,
#include "ficltokens.h"
#undef FICL_TOKEN
#undef FICL_INSTRUCTION_TOKEN
};
void
ficlDictionarySee(ficlDictionary *dictionary, ficlWord *word,
ficlCallback *callback)
{
char *trace;
ficlCell *cell = word->param;
ficlCell *param0 = cell;
char buffer[128];
for (; cell->i != ficlInstructionSemiParen; cell++) {
ficlWord *word = (ficlWord *)(cell->p);
trace = buffer;
if ((void *)cell == (void *)buffer)
*trace++ = '>';
else
*trace++ = ' ';
trace += sprintf(trace, "%3ld ", (long)(cell - param0));
if (ficlDictionaryIsAWord(dictionary, word)) {
ficlWordKind kind = ficlWordClassify(word);
ficlCell c, c2;
switch (kind) {
case FICL_WORDKIND_INSTRUCTION:
(void) sprintf(trace, "%s (instruction %ld)",
ficlDictionaryInstructionNames[(long)word],
(long)word);
break;
case FICL_WORDKIND_INSTRUCTION_WITH_ARGUMENT:
c = *++cell;
(void) sprintf(trace, "%s (instruction %ld), "
"with argument %ld (%#lx)",
ficlDictionaryInstructionNames[(long)word],
(long)word, (long)c.i, (unsigned long)c.u);
break;
case FICL_WORDKIND_INSTRUCTION_WORD:
(void) sprintf(trace,
"%s :: executes %s (instruction word %ld)",
word->name,
ficlDictionaryInstructionNames[
(long)word->code], (long)word->code);
break;
case FICL_WORDKIND_LITERAL:
c = *++cell;
if (ficlDictionaryIsAWord(dictionary, c.p) &&
(c.i >= ficlInstructionLast)) {
ficlWord *word = (ficlWord *)c.p;
(void) sprintf(trace,
"%.*s ( %#lx literal )",
word->length, word->name,
(unsigned long)c.u);
} else
(void) sprintf(trace,
"literal %ld (%#lx)", (long)c.i,
(unsigned long)c.u);
break;
case FICL_WORDKIND_2LITERAL:
c = *++cell;
c2 = *++cell;
(void) sprintf(trace,
"2literal %ld %ld (%#lx %#lx)",
(long)c2.i, (long)c.i, (unsigned long)c2.u,
(unsigned long)c.u);
break;
#if FICL_WANT_FLOAT
case FICL_WORDKIND_FLITERAL:
c = *++cell;
(void) sprintf(trace, "fliteral %f (%#lx)",
(double)c.f, (unsigned long)c.u);
break;
#endif
case FICL_WORDKIND_STRING_LITERAL: {
ficlCountedString *counted;
counted = (ficlCountedString *)(void *)++cell;
cell = (ficlCell *)
ficlAlignPointer(counted->text +
counted->length + 1) - 1;
(void) sprintf(trace, "s\" %.*s\"",
counted->length, counted->text);
}
break;
case FICL_WORDKIND_CSTRING_LITERAL: {
ficlCountedString *counted;
counted = (ficlCountedString *)(void *)++cell;
cell = (ficlCell *)
ficlAlignPointer(counted->text +
counted->length + 1) - 1;
(void) sprintf(trace, "c\" %.*s\"",
counted->length, counted->text);
}
break;
case FICL_WORDKIND_BRANCH0:
c = *++cell;
(void) sprintf(trace, "branch0 %ld",
(long)(cell + c.i - param0));
break;
case FICL_WORDKIND_BRANCH:
c = *++cell;
(void) sprintf(trace, "branch %ld",
(long)(cell + c.i - param0));
break;
case FICL_WORDKIND_QDO:
c = *++cell;
(void) sprintf(trace, "?do (leave %ld)",
(long)((ficlCell *)c.p - param0));
break;
case FICL_WORDKIND_DO:
c = *++cell;
(void) sprintf(trace, "do (leave %ld)",
(long)((ficlCell *)c.p - param0));
break;
case FICL_WORDKIND_LOOP:
c = *++cell;
(void) sprintf(trace, "loop (branch %ld)",
(long)(cell + c.i - param0));
break;
case FICL_WORDKIND_OF:
c = *++cell;
(void) sprintf(trace, "of (branch %ld)",
(long)(cell + c.i - param0));
break;
case FICL_WORDKIND_PLOOP:
c = *++cell;
(void) sprintf(trace, "+loop (branch %ld)",
(long)(cell + c.i - param0));
break;
default:
(void) sprintf(trace, "%.*s", word->length,
word->name);
break;
}
} else {
(void) sprintf(trace, "%ld ( %#lx )", (long)cell->i,
(unsigned long)cell->u);
}
ficlCallbackTextOut(callback, buffer);
ficlCallbackTextOut(callback, "\n");
}
ficlCallbackTextOut(callback, ";\n");
}
void
ficlDictionaryResetSearchOrder(ficlDictionary *dictionary)
{
FICL_DICTIONARY_ASSERT(dictionary, dictionary);
dictionary->compilationWordlist = dictionary->forthWordlist;
dictionary->wordlistCount = 1;
dictionary->wordlists[0] = dictionary->forthWordlist;
}
void
ficlDictionarySetFlags(ficlDictionary *dictionary, ficlUnsigned8 set)
{
FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
dictionary->smudge->flags |= set;
}
void
ficlDictionaryClearFlags(ficlDictionary *dictionary, ficlUnsigned8 clear)
{
FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
dictionary->smudge->flags &= ~clear;
}
void
ficlDictionarySetImmediate(ficlDictionary *dictionary)
{
FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
dictionary->smudge->flags |= FICL_WORD_IMMEDIATE;
}
void
ficlDictionaryUnsmudge(ficlDictionary *dictionary)
{
ficlWord *word = dictionary->smudge;
ficlHash *hash = dictionary->compilationWordlist;
FICL_DICTIONARY_ASSERT(dictionary, hash);
FICL_DICTIONARY_ASSERT(dictionary, word);
if (word->length > 0)
ficlHashInsertWord(hash, word);
word->flags &= ~(FICL_WORD_SMUDGED);
}
ficlCell *
ficlDictionaryWhere(ficlDictionary *dictionary)
{
return (dictionary->here);
}