320 lines
7.3 KiB
C
320 lines
7.3 KiB
C
/*
|
|
* tag: dict management
|
|
*
|
|
* Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz
|
|
*
|
|
* See the file "COPYING" for further information about
|
|
* the copyright and warranty status of this work.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "kernel/kernel.h"
|
|
#include "dict.h"
|
|
#ifdef BOOTSTRAP
|
|
#include <string.h>
|
|
#else
|
|
#include "libc/string.h"
|
|
#endif
|
|
#include "cross.h"
|
|
|
|
|
|
unsigned char *dict = NULL;
|
|
ucell *last;
|
|
cell dicthead = 0;
|
|
cell dictlimit = 0;
|
|
|
|
/* lfa2nfa
|
|
* converts a link field address to a name field address,
|
|
* i.e find pointer to a given words name
|
|
*/
|
|
|
|
ucell lfa2nfa(ucell ilfa)
|
|
{
|
|
/* get offset from dictionary start */
|
|
ilfa = ilfa - (ucell)pointer2cell(dict);
|
|
ilfa--; /* skip status */
|
|
while (dict[--ilfa] == 0); /* skip all pad bytes */
|
|
ilfa -= (dict[ilfa] - 128);
|
|
return ilfa + (ucell)pointer2cell(dict);
|
|
}
|
|
|
|
/* lfa2cfa
|
|
* converts a link field address to a code field address.
|
|
* in this forth implementation this is just a fixed offset
|
|
*/
|
|
|
|
static xt_t lfa2cfa(ucell ilfa)
|
|
{
|
|
return (xt_t)(ilfa + sizeof(cell));
|
|
}
|
|
|
|
|
|
/* fstrlen - returns length of a forth string. */
|
|
|
|
ucell fstrlen(ucell fstr)
|
|
{
|
|
fstr -= pointer2cell(dict)+1;
|
|
//fstr -= pointer2cell(dict); FIXME
|
|
while (dict[++fstr] < 128)
|
|
;
|
|
return dict[fstr] - 128;
|
|
}
|
|
|
|
/* to_lower - convert a character to lowecase */
|
|
|
|
static int to_lower(int c)
|
|
{
|
|
return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c;
|
|
}
|
|
|
|
/* fstrcmp - compare null terminated string with forth string. */
|
|
|
|
static int fstrcmp(const char *s1, ucell fstr)
|
|
{
|
|
char *s2 = (char*)cell2pointer(fstr);
|
|
while (*s1) {
|
|
if ( to_lower(*(s1++)) != to_lower(*(s2++)) )
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* fstrncpy - copy a forth string to a destination (with NULL termination) */
|
|
|
|
void fstrncpy(char *dest, ucell src, unsigned int maxlen)
|
|
{
|
|
int len = fstrlen(src);
|
|
|
|
if (fstrlen(src) >= maxlen) len = maxlen - 1;
|
|
memcpy(dest, cell2pointer(src), len);
|
|
*(dest + len) = '\0';
|
|
}
|
|
|
|
|
|
/* findword
|
|
* looks up a given word in the dictionary. This function
|
|
* is used by the c based interpreter and to find the "initialize"
|
|
* word.
|
|
*/
|
|
|
|
xt_t findword(const char *s1)
|
|
{
|
|
ucell tmplfa, len;
|
|
|
|
if (!last)
|
|
return 0;
|
|
|
|
tmplfa = read_ucell(last);
|
|
|
|
len = strlen(s1);
|
|
|
|
while (tmplfa) {
|
|
ucell nfa = lfa2nfa(tmplfa);
|
|
|
|
if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) {
|
|
return lfa2cfa(tmplfa);
|
|
}
|
|
|
|
tmplfa = read_ucell(cell2pointer(tmplfa));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* findsemis_wordlist
|
|
* Given a DOCOL xt and a wordlist, find the address of the semis
|
|
* word at the end of the word definition. We do this by finding
|
|
* the word before this in the dictionary, then counting back one
|
|
* from the NFA.
|
|
*/
|
|
|
|
static ucell findsemis_wordlist(ucell xt, ucell wordlist)
|
|
{
|
|
ucell tmplfa, nextlfa, nextcfa;
|
|
|
|
if (!wordlist)
|
|
return 0;
|
|
|
|
tmplfa = read_ucell(cell2pointer(wordlist));
|
|
nextcfa = lfa2cfa(tmplfa);
|
|
|
|
/* Catch the special case where the lfa of the word we
|
|
* want is the last word in the dictionary; in that case
|
|
* the end of the word is given by "here" - 1 */
|
|
if (nextcfa == xt)
|
|
return pointer2cell(dict) + dicthead - sizeof(cell);
|
|
|
|
while (tmplfa) {
|
|
|
|
/* Peek ahead and see if the next CFA in the list is the
|
|
* one we are searching for */
|
|
nextlfa = read_ucell(cell2pointer(tmplfa));
|
|
nextcfa = lfa2cfa(nextlfa);
|
|
|
|
/* If so, count back 1 cell from the current NFA */
|
|
if (nextcfa == xt)
|
|
return lfa2nfa(tmplfa) - sizeof(cell);
|
|
|
|
tmplfa = nextlfa;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* findsemis
|
|
* Given a DOCOL xt, find the address of the semis word at the end
|
|
* of the word definition by searching all vocabularies */
|
|
|
|
ucell findsemis(ucell xt)
|
|
{
|
|
ucell usesvocab = findword("vocabularies?") + sizeof(cell);
|
|
unsigned int i;
|
|
|
|
if (read_ucell(cell2pointer(usesvocab))) {
|
|
/* Vocabularies are in use, so search each one in turn */
|
|
ucell numvocabs = findword("#order") + sizeof(cell);
|
|
|
|
for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
|
|
ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
|
|
ucell semis = findsemis_wordlist(xt, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
|
|
|
|
/* If we get a non-zero result, we found the xt in this vocab */
|
|
if (semis)
|
|
return semis;
|
|
}
|
|
} else {
|
|
/* Vocabularies not in use */
|
|
return findsemis_wordlist(xt, read_ucell(last));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* findxtfromcell_wordlist
|
|
* Given a cell and a wordlist, determine the CFA of the word containing
|
|
* the cell or 0 if we are unable to return a suitable CFA
|
|
*/
|
|
|
|
ucell findxtfromcell_wordlist(ucell incell, ucell wordlist)
|
|
{
|
|
ucell tmplfa;
|
|
|
|
if (!wordlist)
|
|
return 0;
|
|
|
|
tmplfa = read_ucell(cell2pointer(wordlist));
|
|
while (tmplfa) {
|
|
if (tmplfa < incell)
|
|
return lfa2cfa(tmplfa);
|
|
|
|
tmplfa = read_ucell(cell2pointer(tmplfa));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* findxtfromcell
|
|
* Given a cell, determine the CFA of the word containing
|
|
* the cell by searching all vocabularies
|
|
*/
|
|
|
|
ucell findxtfromcell(ucell incell)
|
|
{
|
|
ucell usesvocab = findword("vocabularies?") + sizeof(cell);
|
|
unsigned int i;
|
|
|
|
if (read_ucell(cell2pointer(usesvocab))) {
|
|
/* Vocabularies are in use, so search each one in turn */
|
|
ucell numvocabs = findword("#order") + sizeof(cell);
|
|
|
|
for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
|
|
ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
|
|
ucell semis = findxtfromcell_wordlist(incell, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
|
|
|
|
/* If we get a non-zero result, we found the xt in this vocab */
|
|
if (semis)
|
|
return semis;
|
|
}
|
|
} else {
|
|
/* Vocabularies not in use */
|
|
return findxtfromcell_wordlist(incell, read_ucell(last));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void dump_header(dictionary_header_t *header)
|
|
{
|
|
printk("OpenBIOS dictionary:\n");
|
|
printk(" version: %d\n", header->version);
|
|
printk(" cellsize: %d\n", header->cellsize);
|
|
printk(" endianess: %s\n", header->endianess?"big":"little");
|
|
printk(" compression: %s\n", header->compression?"yes":"no");
|
|
printk(" relocation: %s\n", header->relocation?"yes":"no");
|
|
printk(" checksum: %08x\n", target_long(header->checksum));
|
|
printk(" length: %08x\n", target_long(header->length));
|
|
printk(" last: %0" FMT_CELL_x "\n", target_cell(header->last));
|
|
}
|
|
|
|
ucell load_dictionary(const char *data, ucell len)
|
|
{
|
|
u32 checksum=0;
|
|
const char *checksum_walk;
|
|
ucell *walk, *reloc_table;
|
|
dictionary_header_t *header=(dictionary_header_t *)data;
|
|
|
|
/* assertions */
|
|
if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8))
|
|
return 0;
|
|
#ifdef CONFIG_DEBUG_DICTIONARY
|
|
dump_header(header);
|
|
#endif
|
|
|
|
checksum_walk=data;
|
|
while (checksum_walk<data+len) {
|
|
checksum+=read_long(checksum_walk);
|
|
checksum_walk+=sizeof(u32);
|
|
}
|
|
|
|
if(checksum) {
|
|
printk("Checksum invalid (%08x)!\n", checksum);
|
|
return 0;
|
|
}
|
|
|
|
data += sizeof(dictionary_header_t);
|
|
|
|
dicthead = target_long(header->length);
|
|
|
|
memcpy(dict, data, dicthead);
|
|
reloc_table=(ucell *)(data+dicthead);
|
|
|
|
#ifdef CONFIG_DEBUG_DICTIONARY
|
|
printk("\nmoving dictionary (%x bytes) to %x\n",
|
|
(ucell)dicthead, (ucell)dict);
|
|
printk("\ndynamic relocation...");
|
|
#endif
|
|
|
|
for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead);
|
|
walk++) {
|
|
int pos, bit, l;
|
|
l=(walk-(ucell *)dict);
|
|
pos=l/BITS;
|
|
bit=l&~(-BITS);
|
|
if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) {
|
|
// printk("%lx, pos %x, bit %d\n",*walk, pos, bit);
|
|
write_ucell(walk, read_ucell(walk)+pointer2cell(dict));
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_DICTIONARY
|
|
printk(" done.\n");
|
|
#endif
|
|
|
|
last = (ucell *)(dict + target_ucell(header->last));
|
|
|
|
return -1;
|
|
}
|