Skip to content

Commit

Permalink
Change the Dictionary directive (currently deprecated) to have the fo…
Browse files Browse the repository at this point in the history
…rms:

  Dictionary 'word';
  Dictionary 'word' val1;
  Dictionary 'word' val1 val3;

The first just adds the word to the dictionary, with all flags set to
zero, if it's not already in the dictionary. The second form also sets
the dict_par1 flag to the given value, or bit-or's the value in if the
word already exists. The third form also sets/ors dict_par3.

The values can be numeric literals or constants. They can be 0-255 for
Z-code, 0-65535 for Glulx.
  • Loading branch information
Andrew Plotkin committed Dec 9, 2011
1 parent bfbc5f6 commit 8f48e29
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 7 deletions.
70 changes: 67 additions & 3 deletions directs.c
Expand Up @@ -183,12 +183,76 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
break;

/* --------------------------------------------------------------------- */
/* Dictionary constantname "word" */
/* Dictionary 'word' */
/* Dictionary 'word' val1 */
/* Dictionary 'word' val1 val3 */
/* --------------------------------------------------------------------- */

case DICTIONARY_CODE:
obsolete_warning("use 'word' as a constant dictionary address");
goto ParseConstantSpec;
/* In Inform 5, this directive had the form
Dictionary SYMBOL "word";
This was deprecated as of I6 (if not earlier), and is no longer
supported at all. The current form just creates a dictionary word,
with the given values for dict_par1 and dict_par3. If the word
already exists, the values are bit-or'd in with the existing
values.
(We don't offer a way to set dict_par2, because that is entirely
reserved for the verb number. Or'ing values into it would create
garbage.)
*/
get_next_token();
if (token_type != SQ_TT && token_type != DQ_TT) {
ebf_error("dictionary word", token_text);
break;
}

{
char *wd = token_text;
int val1 = 0;
int val3 = 0;

get_next_token();
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
put_token_back();
}
else {
put_token_back();
assembly_operand AO;
AO = parse_expression(CONSTANT_CONTEXT);
if (module_switch && (AO.marker != 0))
error("A definite value must be given as a Dictionary flag");
else
val1 = AO.value;

get_next_token();
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
put_token_back();
}
else {
put_token_back();
assembly_operand AO;
AO = parse_expression(CONSTANT_CONTEXT);
if (module_switch && (AO.marker != 0))
error("A definite value must be given as a Dictionary flag");
else
val3 = AO.value;
}
}

if (!glulx_mode) {
if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
warning("Dictionary flag values cannot exceed $FF in Z-code");
}
}
else {
if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
warning("Dictionary flag values cannot exceed $FFFF in Glulx");
}
}

dictionary_add(wd, val1, 0, val3);
}
break;

/* --------------------------------------------------------------------- */
/* End */
Expand Down
38 changes: 34 additions & 4 deletions text.c
Expand Up @@ -1462,13 +1462,39 @@ extern void optimise_abbreviations(void)
/* construct_storyfile() stage in "tables.c") and then a sequence of */
/* records, one per word, in the form */
/* */
/* <Z-coded text> <flags> <adjectivenumber> <verbnumber> */
/* 4 or 6 bytes byte byte byte */
/* <Z-coded text> <flags> <verbnumber> <adjectivenumber> */
/* 4 or 6 bytes byte byte byte */
/* */
/* For Glulx, the form is instead: (But see below about Unicode-valued */
/* dictionaries and my heinie.) */
/* */
/* <plain text> <flags> <verbnumber> <adjectivenumber> */
/* DICT_WORD_SIZE short short short */
/* */
/* These records are stored in "accession order" (i.e. in order of their */
/* first being received by these routines) and only alphabetically sorted */
/* by construct_storyfile() (using the array below). */
/* ------------------------------------------------------------------------- */
/* */
/* Further notes about the data fields... */
/* The flags are currently: */
/* bit 0: word is used as a verb (in verb grammar) */
/* bit 1: word is used as a meta verb */
/* bit 2: word is plural (set by '//p') */
/* bit 3: word is used as a preposition (in verb grammar) */
/* bit 6: set for all verbs, but not used by the parser? */
/* bit 7: word is used as a noun (set for every word that appears in */
/* code or in an object property) */
/* */
/* In grammar version 2, the third field (adjectivenumber) is unused (and */
/* zero). */
/* */
/* The compiler generates special constants #dict_par1, #dict_par2, */
/* #dict_par3 to refer to the byte offsets of the three fields. In */
/* Z-code v3, these are 4/5/6; in v4+, they are 6/7/8. In Glulx, they */
/* are $DICT_WORD_SIZE+2/4/6, referring to the *low* bytes of the three */
/* fields. (The high bytes are $DICT_WORD_SIZE+1/3/5.) */
/* ------------------------------------------------------------------------- */

uchar *dictionary, /* (These two pointers are externally
used only in "tables.c" when
Expand Down Expand Up @@ -1793,9 +1819,11 @@ static int dictionary_find(char *dword)
}

/* ------------------------------------------------------------------------- */
/* Add "dword" to the dictionary with (x,y,z) as its data bytes; unless */
/* Add "dword" to the dictionary with (x,y,z) as its data fields; unless */
/* it already exists, in which case OR the data with (x,y,z) */
/* */
/* These fields are one byte each in Z-code, two bytes each in Glulx. */
/* */
/* Returns: the accession number. */
/* ------------------------------------------------------------------------- */

Expand Down Expand Up @@ -1823,7 +1851,9 @@ extern int dictionary_add(char *dword, int x, int y, int z)
}
else {
p = dictionary+4 + at*DICT_ENTRY_BYTE_LENGTH + DICT_ENTRY_FLAG_POS;
p[1]=(p[1])|x; p[2]=(p[2])|(y/256); p[3]=(p[3])|(y%256); p[5]=(p[5])|z;
p[0]=(p[0])|(x/256); p[1]=(p[1])|(x%256);
p[2]=(p[2])|(y/256); p[3]=(p[3])|(y%256);
p[4]=(p[4])|(z/256); p[5]=(p[5])|(z%256);
if (x & 128) p[1] = (p[1]) | number_and_case;
}
return at;
Expand Down

0 comments on commit 8f48e29

Please sign in to comment.