diff --git a/bpatch.c b/bpatch.c index d488c33..0390c91 100644 --- a/bpatch.c +++ b/bpatch.c @@ -200,7 +200,7 @@ static int32 backpatch_value_g(int32 value) value = value_of_system_constant(value); break; case DWORD_MV: value = dictionary_offset + 4 - + final_dict_order[value]*(7+DICT_WORD_SIZE); + + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH; break; case ACTION_MV: break; diff --git a/directs.c b/directs.c index 0b57f4d..e01a7a4 100644 --- a/directs.c +++ b/directs.c @@ -834,8 +834,8 @@ the first constant definition"); case ZCHARACTER_CODE: if (glulx_mode) { - error("Glulx Inform does not handle Unicode yet."); - break; + error("The Zcharacter directive has no meaning in Glulx."); + return TRUE; } directive_keywords.enabled = TRUE; diff --git a/expressp.c b/expressp.c index df5236b..5dcc940 100644 --- a/expressp.c +++ b/expressp.c @@ -816,20 +816,24 @@ static int evaluate_term(token_data t, assembly_operand *o) o->type = CONSTANT_OT; switch(t.value) { + /* The three dict_par flags point at the lower byte + of the flag field, because the library is written + to expect one-byte fields, even though the compiler + generates a dictionary with room for two. */ case dict_par1_SC: o->type = BYTECONSTANT_OT; o->marker = 0; - v = DICT_WORD_SIZE+2; + v = DICT_ENTRY_FLAG_POS+1; break; case dict_par2_SC: o->type = BYTECONSTANT_OT; o->marker = 0; - v = DICT_WORD_SIZE+4; + v = DICT_ENTRY_FLAG_POS+3; break; case dict_par3_SC: o->type = BYTECONSTANT_OT; o->marker = 0; - v = DICT_WORD_SIZE+6; + v = DICT_ENTRY_FLAG_POS+5; break; /* ###fix: need to fill more of these in! */ diff --git a/files.c b/files.c index 9b2f532..97faa62 100644 --- a/files.c +++ b/files.c @@ -522,7 +522,7 @@ static void output_file_g(void) if (requested_glulx_version < VersionNum) { static char error_message_buff[256]; sprintf(error_message_buff, "Version 0x%08lx requested, but \ -game features require version 0x%08lx", requested_glulx_version, VersionNum); +game features require version 0x%08lx", (long)requested_glulx_version, (long)VersionNum); warning(error_message_buff); } else { diff --git a/header.h b/header.h index 28ca1d1..bc5f8db 100644 --- a/header.h +++ b/header.h @@ -687,6 +687,7 @@ static int32 unique_task_id(void) #define MAX_IDENTIFIER_LENGTH 32 #define MAX_ABBREV_LENGTH 64 #define MAX_DICT_WORD_SIZE 40 +#define MAX_DICT_WORD_BYTES (40*4) #define MAX_NUM_ATTR_BYTES 39 #define VENEER_CONSTRAINT_ON_CLASSES_Z 256 @@ -2287,7 +2288,8 @@ extern int endofpass_flag; extern int version_number, instruction_set_number, extend_memory_map; extern int32 scale_factor, length_scale_factor; -extern int WORDSIZE, INDIV_PROP_START, OBJECT_BYTE_LENGTH; +extern int WORDSIZE, INDIV_PROP_START, + OBJECT_BYTE_LENGTH, DICT_ENTRY_BYTE_LENGTH, DICT_ENTRY_FLAG_POS; extern int32 MAXINTWORD; extern int asm_trace_level, line_trace_level, expr_trace_level, @@ -2413,7 +2415,7 @@ extern int32 MAX_STATIC_STRINGS, MAX_ZCODE_SIZE, MAX_LINK_DATA_SIZE, extern int32 MAX_OBJ_PROP_COUNT, MAX_OBJ_PROP_TABLE_SIZE; extern int MAX_LOCAL_VARIABLES, MAX_GLOBAL_VARIABLES; -extern int DICT_WORD_SIZE, NUM_ATTR_BYTES; +extern int DICT_WORD_SIZE, DICT_CHAR_SIZE, DICT_WORD_BYTES, NUM_ATTR_BYTES; extern void *my_malloc(int32 size, char *whatfor); extern void *my_calloc(int32 size, int32 howmany, char *whatfor); diff --git a/inform.c b/inform.c index d0d43a7..f8c1275 100644 --- a/inform.c +++ b/inform.c @@ -93,6 +93,13 @@ int INDIV_PROP_START; Not used in Z-code. */ int OBJECT_BYTE_LENGTH; +/* The total length of a dict entry, in bytes. Not used in Z-code. +*/ +int DICT_ENTRY_BYTE_LENGTH; +/* The position in a dict entry that the flag values begin. + Not used in Z-code. +*/ +int DICT_ENTRY_FLAG_POS; static void select_target(int targ) { @@ -101,12 +108,15 @@ static void select_target(int targ) WORDSIZE = 2; MAXINTWORD = 0x7FFF; INDIV_PROP_START = 64; - OBJECT_BYTE_LENGTH = 0; /* not used */ if (DICT_WORD_SIZE != 6) { DICT_WORD_SIZE = 6; fatalerror("You cannot change DICT_WORD_SIZE in Z-code"); } + if (DICT_CHAR_SIZE != 1) { + DICT_CHAR_SIZE = 1; + fatalerror("You cannot change DICT_CHAR_SIZE in Z-code"); + } if (NUM_ATTR_BYTES != 6) { NUM_ATTR_BYTES = 6; fatalerror("You cannot change NUM_ATTR_BYTES in Z-code"); @@ -136,7 +146,10 @@ static void select_target(int targ) warning_numbered("NUM_ATTR_BYTES must be a multiple of four, plus three. Increasing to", NUM_ATTR_BYTES); } - OBJECT_BYTE_LENGTH = (1 + (NUM_ATTR_BYTES) + 6*4); + if (DICT_CHAR_SIZE != 1 && DICT_CHAR_SIZE != 4) { + DICT_CHAR_SIZE = 4; + warning_numbered("DICT_CHAR_SIZE must be either 1 or 4. Setting to", DICT_CHAR_SIZE); + } } if (MAX_LOCAL_VARIABLES >= 120) { @@ -159,6 +172,31 @@ static void select_target(int targ) MAX_NUM_ATTR_BYTES); /* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */ } + + /* Set up a few more variables that depend on the above values */ + + if (!targ) { + /* Z-machine */ + DICT_WORD_BYTES = DICT_WORD_SIZE; + /* The Z-code generator doesn't use the following variables, although + it would be a little cleaner if it did. */ + OBJECT_BYTE_LENGTH = 0; + DICT_ENTRY_BYTE_LENGTH = 0; + DICT_ENTRY_FLAG_POS = 0; + } + else { + /* Glulx */ + OBJECT_BYTE_LENGTH = (1 + (NUM_ATTR_BYTES) + 6*4); + DICT_WORD_BYTES = DICT_WORD_SIZE*DICT_CHAR_SIZE; + if (DICT_CHAR_SIZE == 1) { + DICT_ENTRY_BYTE_LENGTH = (7+DICT_WORD_BYTES); + DICT_ENTRY_FLAG_POS = (1+DICT_WORD_BYTES); + } + else { + DICT_ENTRY_BYTE_LENGTH = (10+DICT_WORD_BYTES); + DICT_ENTRY_FLAG_POS = (4+DICT_WORD_BYTES); + } + } } /* ------------------------------------------------------------------------- */ diff --git a/memory.c b/memory.c index a94f98b..1218ff4 100644 --- a/memory.c +++ b/memory.c @@ -171,7 +171,9 @@ int32 MAX_OBJ_PROP_TABLE_SIZE; int MAX_OBJ_PROP_COUNT; int MAX_LOCAL_VARIABLES; int MAX_GLOBAL_VARIABLES; -int DICT_WORD_SIZE; +int DICT_WORD_SIZE; /* number of characters in a dict word */ +int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */ +int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */ int NUM_ATTR_BYTES; int32 MAX_NUM_STATIC_STRINGS; int32 MAX_UNICODE_CHARS; @@ -207,6 +209,8 @@ static void list_memory_sizes(void) printf("| %25s = %-7d |\n","MAX_CLASS_TABLE_SIZE",MAX_CLASS_TABLE_SIZE); printf("| %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES); printf("| %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE); + if (glulx_mode) + printf("| %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE); printf("| %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES); printf("| %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES); printf("| %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE); @@ -413,6 +417,7 @@ extern void set_memory_sizes(int size_flag) MAX_INCLUSION_DEPTH = 5; MAX_LOCAL_VARIABLES_z = 16; MAX_LOCAL_VARIABLES_g = 32; + DICT_CHAR_SIZE = 1; DICT_WORD_SIZE_z = 6; DICT_WORD_SIZE_g = 9; NUM_ATTR_BYTES_z = 6; @@ -509,10 +514,18 @@ static void explain_parameter(char *command) can be any number.\n"); return; } + if (strcmp(command,"DICT_CHAR_SIZE")==0) + { printf( +" DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\ + (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\ + words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\ + input.)\n"); + return; + } if (strcmp(command,"NUM_ATTR_BYTES")==0) { printf( " NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\ - stores eight attribytes. In Z-code this is always 6 (only 4 are used in \n\ + stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\ v3 games). In Glulx it can be any number which is a multiple of four, \n\ plus three.\n"); return; @@ -756,6 +769,8 @@ extern void memory_command(char *command) { DICT_WORD_SIZE=j, flag=1; DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j; } + if (strcmp(command,"DICT_CHAR_SIZE")==0) + DICT_CHAR_SIZE=j, flag=1; if (strcmp(command,"NUM_ATTR_BYTES")==0) { NUM_ATTR_BYTES=j, flag=1; NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j; diff --git a/symbols.c b/symbols.c index 126bb80..a569a7d 100644 --- a/symbols.c +++ b/symbols.c @@ -566,6 +566,9 @@ static void stockup_symbols(void) } else { create_symbol("DICT_WORD_SIZE", DICT_WORD_SIZE, CONSTANT_T); + create_symbol("DICT_CHAR_SIZE", DICT_CHAR_SIZE, CONSTANT_T); + if (DICT_CHAR_SIZE != 1) + create_symbol("DICT_IS_UNICODE", 1, CONSTANT_T); create_symbol("NUM_ATTR_BYTES", NUM_ATTR_BYTES, CONSTANT_T); create_symbol("INDIV_PROP_START", INDIV_PROP_START, CONSTANT_T); } diff --git a/tables.c b/tables.c index 176ab14..5f6a28e 100644 --- a/tables.c +++ b/tables.c @@ -1458,12 +1458,12 @@ table format requested (producing number 2 format instead)"); p[mark+i] = dictionary[i]; for (i=0; iu.val; - printf("'U+%lX'\n", unicode_usage_entries[ix].ch); + printf("'U+%lX'\n", (long)unicode_usage_entries[ix].ch); break; case 9: printf("print-var @%02d\n", ent->u.val); @@ -1470,24 +1470,31 @@ int dict_entries; /* Total number of records entered */ /* as before. In Glulx, it can be any value up to MAX_DICT_WORD_SIZE. */ /* (That limit is defined as 40 in the header; it exists only for a few */ /* static buffers, and can be increased without using significant memory.) */ +/* */ +/* ###- Well, that certainly bit me on the butt, didn't it. In further */ +/* modifying the compiler to generate a Unicode dictionary, I have to */ +/* store four-byte values in the uchar array. This is handled by making */ +/* the array size DICT_WORD_BYTES (which is DICT_WORD_SIZE*DICT_CHAR_SIZE).*/ +/* Then we store the 32-bit character value big-endian. This lets us */ +/* continue to compare arrays bytewise, which is a nice simplification. */ /* ------------------------------------------------------------------------- */ extern int compare_sorts(uchar *d1, uchar *d2) { int i; - for (i=0; i=DICT_WORD_SIZE) break; - k= (int)dword[j]; + k= ((unsigned char *)dword)[j]; if (k=='\'') warning_named("Obsolete usage: use the ^ character for the \ apostrophe in", dword); @@ -1618,25 +1626,48 @@ apostrophe in", dword); k='\"'; if (k=='@') { - int32 unicode = text_to_unicode(dword+j); + unicode = text_to_unicode(dword+j); j += textual_form_length - 1; - if (unicode >= 0 && unicode < 256) { - k = unicode; - } - else { - error("Unicode characters beyond Latin-1 are not yet supported in Glulx"); - k = '?'; - } + } + else { + unicode = iso_to_unicode_grid[k]; + } + + if (DICT_CHAR_SIZE != 1 || (unicode >= 0 && unicode < 256)) { + k = unicode; + } + else { + error("The dictionary cannot contain Unicode characters beyond Latin-1. \ +Define DICT_CHAR_SIZE=4 for a Unicode-compatible dictionary."); + k = '?'; } - if (k >= 'A' && k <= 'Z') + if (k >= (unsigned)'A' && k <= (unsigned)'Z') k += ('a' - 'A'); - prepared_sort[i] = k; + if (DICT_CHAR_SIZE == 1) { + prepared_sort[i] = k; + } + else { + prepared_sort[4*i] = (k >> 24) & 0xFF; + prepared_sort[4*i+1] = (k >> 16) & 0xFF; + prepared_sort[4*i+2] = (k >> 8) & 0xFF; + prepared_sort[4*i+3] = (k) & 0xFF; + } } - for (; i0) at = dtree[at].branch[1]; else at = dtree[at].branch[0]; } @@ -1762,7 +1793,7 @@ extern int dictionary_add(char *dword, int x, int y, int z) } while (TRUE) { - n = compare_sorts(prepared_sort, dict_sort_codes+at*DICT_WORD_SIZE); + n = compare_sorts(prepared_sort, dict_sort_codes+at*DICT_WORD_BYTES); if (n==0) { if (!glulx_mode) { @@ -1771,7 +1802,7 @@ extern int dictionary_add(char *dword, int x, int y, int z) if (x & 128) p[0] = (p[0])|number_and_case; } else { - p = dictionary+4 + at*(7+DICT_WORD_SIZE) + 1+DICT_WORD_SIZE; + 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; if (x & 128) p[1] = (p[1]) | number_and_case; } @@ -1888,23 +1919,25 @@ extern int dictionary_add(char *dword, int x, int y, int z) } else { int i; - p = dictionary + 4 + (7+DICT_WORD_SIZE)*dict_entries; + p = dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*dict_entries; p[0] = 0x60; /* type byte -- dict word */ - for (i=0; iix;\ - if (ch == 0)\ - return;\ + #ifnot;\ + ch = addr-->ix;\ + #endif;\ + if (ch == 0) return;\ print (char) ch;\ }\ ]", "", "", "", "", "" diff --git a/verbs.c b/verbs.c index dc3eac1..0a9e3eb 100644 --- a/verbs.c +++ b/verbs.c @@ -235,7 +235,7 @@ static int make_adjective(char *English_word) table is left empty in GV2. */ int i; - uchar new_sort_code[MAX_DICT_WORD_SIZE]; + uchar new_sort_code[MAX_DICT_WORD_BYTES]; if (no_adjectives >= MAX_ADJECTIVES) memoryerror("MAX_ADJECTIVES", MAX_ADJECTIVES); @@ -243,11 +243,11 @@ static int make_adjective(char *English_word) dictionary_prepare(English_word, new_sort_code); for (i=0; i