/* * A Z-Machine * Copyright (C) 2000 Andrew Hunter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Tokenise a word/string */ #include #include #include #include "zmachine.h" #include "tokenise.h" #include "hash.h" #include "zscii.h" struct dict_entry { ZUWord address; }; ZDictionary* dictionary_cache(const ZUWord dict_pos) { ZByte* dct; ZWord dpos; ZDictionary* dict; int x; int text_len; /* See if we've already parsed this dictionary */ dict = hash_get(machine.cached_dictionaries, (unsigned char*) &dict_pos, sizeof(ZUWord)); if (dict != NULL) { return dict; } #ifdef DEBUG printf_debug("Caching dictionary $%x\n", dict_pos); #endif dct = machine.memory + dict_pos; /* Parse the dictionary */ dict = malloc(sizeof(ZDictionary)); dict->words = hash_create(); for (x=0; x<256; x++) dict->sep[x] = 0; dict->sep[0] = 1; dict->sep[32] = 1; /* Mark word seperators */ for (x=0; xsep[dct[x+1]] = 1; } /* Parse dictionary entries */ dpos = dict_pos+1+dct[0]; dct += 1+dct[0]; if (ReadByte(0) <= 3) text_len = 4; else text_len = 6; { int entry_length; ZWord no_entries; entry_length = dct[0]; no_entries = (dct[1]<<8)|dct[2]; if (no_entries < 0) { zmachine_warning("Unsorted dictionaries not supported correctly"); no_entries = -no_entries; /* Unsorted dictionary */ } if (entry_length < text_len) zmachine_fatal("Bad dictionary: entry length is less than %i", text_len); for (x=0; xaddress = dpos+3+entry_length*x; #ifdef DEBUG printf_debug("Adding word $%x%x $%x%x (@%x) - ", dct[3+entry_length*x], dct[3+entry_length*x+1], dct[3+entry_length*x+2], dct[3+entry_length*x+3], entry->address); { int blob,y; unsigned char packed[12]; int* unicode = zscii_to_unicode(dct + 3+entry_length*x, &blob); for (y=0; unicode[y] !=0; y++); /* y = length of string */ pack_zscii(unicode, y, packed, 9); printf_debug("%s (", zscii_to_ascii(dct + 3+entry_length*x, &blob)); for (y=0; ywords, dct + (3+entry_length*x), text_len, entry); } } hash_store_happy(machine.cached_dictionaries, (unsigned char*)&dict_pos, sizeof(ZUWord), dict); return dict; } int cache = 1; inline ZUWord lookup_word(unsigned int* word, int wordlen, ZUWord dct) { ZByte packed[12]; int zscii_len; int text_len; ZDictionary* cached; ZWord no_entries, entry_length; int x; #ifdef DEBUG printf_debug("Looking up '"); { int x; for (x=0; x 0 || dct > machine.dynamic_ceiling)) { struct dict_entry* ent; #ifdef DEBUG printf_debug("Using cached version of dictionary $%x\n", dct); #endif ent = hash_get(cached->words, packed, text_len); if (ent == NULL) return 0; return ent->address; } else { if (no_entries < 0) no_entries = -no_entries; #ifdef DEBUG printf_debug("Using linear search of dictionary $%x\n", dct); #endif for (x=0; xsep[string[strpos]] == 0) { strpos++; wordlen++; } /* Look the word up */ if (wordlen>0) { ent = lookup_word(word, wordlen, dct); #ifdef DEBUG if (ent != 0) printf_debug("Found\n"); else printf_debug("Not found\n"); #endif if (ent != 0) { tokbuf[tokpos++] = ent>>8; tokbuf[tokpos++] = ent; tokbuf[tokpos++] = wordlen; tokbuf[tokpos++] = wordstart + add; wordno++; } else { if (!flag) { tokbuf[tokpos++] = 0; tokbuf[tokpos++] = 0; tokbuf[tokpos++] = wordlen; tokbuf[tokpos++] = wordstart + add; } else tokpos+=4; /* Leave the entry as-is */ wordno++; } } if (string[strpos] != 0) { #ifdef DEBUG printf_debug("Whitespace %x\n", string[strpos]); #endif ent = 0; if (string[strpos] != 32) ent = lookup_word(string + strpos, 1, dct); if (ent != 0) { tokbuf[tokpos++] = ent>>8; tokbuf[tokpos++] = ent; tokbuf[tokpos++] = 1; tokbuf[tokpos++] = strpos + add; wordno++; } else if (string[strpos] != 32) { if (!flag) { tokbuf[tokpos++] = 0; tokbuf[tokpos++] = 0; tokbuf[tokpos++] = 1; tokbuf[tokpos++] = strpos + add; } else { tokpos += 4; } wordno++; } strpos++; } } tokbuf[1] = wordno; }