Overview
Comment: | Implement and document key dispatch blocks. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
7e93e77e7561db345816c95237596115 |
User & Date: | user on 2021-02-10 06:52:16 |
Other Links: | manifest | tags |
Context
2021-02-11
| ||
05:54 | Add the MOVE_LIST() SQL function check-in: 1c75f94d6b user: user tags: trunk | |
2021-02-10
| ||
06:52 | Implement and document key dispatch blocks. check-in: 7e93e77e75 user: user tags: trunk | |
05:02 | Implement the ,Loc instruction. check-in: 225cba49fa user: user tags: trunk | |
Changes
Modified class.c from [e553676803] to [52031ab4ec].
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include "SDL.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "sqlite3.h" #include "smallxrm.h" #include "heromesh.h" #define TF_COMMA 0x0001 // has a comma modifier #define TF_EQUAL 0x0002 // has an equal sign modifier #define TF_ABNORMAL 0x0004 // with TF_NAME, not directly an opcode #define TF_COMPAT 0x0008 // add 1 to opcode in compatibility mode #define TF_DIR 0x0010 // token is a direction #define TF_DROP 0x0020 // add 0x2000 to opcode if followed by OP_DROP | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include "SDL.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "sqlite3.h" #include "smallxrm.h" #include "heromesh.h" #include "names.h" #define TF_COMMA 0x0001 // has a comma modifier #define TF_EQUAL 0x0002 // has an equal sign modifier #define TF_ABNORMAL 0x0004 // with TF_NAME, not directly an opcode #define TF_COMPAT 0x0008 // add 1 to opcode in compatibility mode #define TF_DIR 0x0010 // token is a direction #define TF_DROP 0x0020 // add 0x2000 to opcode if followed by OP_DROP |
︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 | Uint16 functions[0x4000]; int max_animation=32; Sint32 max_volume=10000; Uint8 back_color=1; Uint8 inv_back_color=9; char**stringpool; AnimationSlot anim_slot[8]; #define HASH_SIZE 8888 #define LOCAL_HASH_SIZE 5555 typedef struct { Uint16 id; char*txt; } Hash; | > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | Uint16 functions[0x4000]; int max_animation=32; Sint32 max_volume=10000; Uint8 back_color=1; Uint8 inv_back_color=9; char**stringpool; AnimationSlot anim_slot[8]; Uint8 keymask[256/8]; #define HASH_SIZE 8888 #define LOCAL_HASH_SIZE 5555 typedef struct { Uint16 id; char*txt; } Hash; |
︙ | ︙ | |||
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 | static void class_definition(int cla,sqlite3_stmt*vst) { Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; int ptr=0; int compat=0; int i; if(!hash) fatal("Allocation failed\n"); if(!cl) fatal("Confusion of class definition somehow\n"); if(cl->cflags&(CF_NOCLASS1|CF_NOCLASS2)) { cl->cflags=0; } else { ParseError("Duplicate definition of class $%s\n",cl->name); } begin_label_stack(); for(;;) { nxttok(); if(Tokenf(TF_EOF)) { ParseError("Unexpected end of file\n"); } else if(Tokenf(TF_MACRO)) { ParseError("Unexpected macro token\n"); } else if(Tokenf(TF_OPEN)) { nxttok(); | > | > > > > > > > > > > > > > > > > > > > > | 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 | static void class_definition(int cla,sqlite3_stmt*vst) { Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; int ptr=0; int compat=0; int i; char disp=0; if(!hash) fatal("Allocation failed\n"); if(!cl) fatal("Confusion of class definition somehow\n"); if(cl->cflags&(CF_NOCLASS1|CF_NOCLASS2)) { cl->cflags=0; } else { ParseError("Duplicate definition of class $%s\n",cl->name); } begin_label_stack(); for(;;) { nxttok(); if(Tokenf(TF_EOF)) { ParseError("Unexpected end of file\n"); } else if(Tokenf(TF_MACRO)) { ParseError("Unexpected macro token\n"); } else if(Tokenf(TF_OPEN)) { nxttok(); if(Tokenf(TF_KEY)) { if(!disp) { cl->codes=realloc(cl->codes,0x10000*sizeof(Uint16)); if(!cl->codes) fatal("Allocation failed\n"); if(get_message_ptr(cla,MSG_KEY)!=0xFFFF) ParseError("Class $%s has a KEY message already\n",cl->name); if(ptr>0xFDFF) ParseError("Out of code space\n"); disp=1; set_message_ptr(cla,MSG_KEY,ptr); cl->codes[ptr]=OP_DISPATCH; for(i=1;i<256;i++) cl->codes[ptr+i]=0; ptr+=256; } i=tokenv&255; cl->codes[cl->messages[MSG_KEY]+i]=ptr; if(cl->cflags&CF_INPUT) { nxttok(); if(tokent!=TF_NAME || tokenv!=OP_IGNOREKEY) keymask[i>>3]|=1<<(i&7); pushback=1; } ptr=parse_instructions(cla,ptr,hash,compat); } else if(Tokenf(TF_NAME)) { switch(tokenv) { case OP_IMAGE: class_def_image(cla); break; case OP_DEFAULTIMAGE: class_def_defaultimage(cla); break; |
︙ | ︙ |
Modified class.doc from [7468fdc695] to [244ac935c1].
︙ | ︙ | |||
381 382 383 384 385 386 387 | (<label> <code...>) Make a code block whose entry point is the specified label. (<message> <code...>) Make a code block whose entry point is the specified message. (<key> <code...>) | > > > | > > > > > > | > | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | (<label> <code...>) Make a code block whose entry point is the specified label. (<message> <code...>) Make a code block whose entry point is the specified message. (<key> <code...>) Add a code block for key dispatch. This cannot be combined with a KEY message in the same class; it causes the KEY message to be automatically defined for this class. If this class has the Input flag and the first instruction is not IgnoreKey, then it is entered into an internal list of key codes to not ignore. Otherwise, the automatic KEY messages (for all classes with them, not only this one) will have the effect of the IgnoreKey instruction when an unrecognized key is specified. You can still call the KEY message by yourself; Arg1 is the key code, and if Arg3 is true then the implicit IgnoreKey will not be executed (although any explicit IgnoreKey will still work). === Data types === The following data types are available: * Number: A 32-bit integer. Whether it is treated as signed or unsigned depends on the context. In some cases, it is used as bit field data. * Class: A class name with a $ prefix. * Message: A message name. User-defined message names have a # prefix; standard message names have no prefix. * Object: A reference to an object. There are no literals of this type. * String: A string in quotation marks. There are no string manipulation functions; the only thing that can be done with a string is to display it. * Sound: A named sound effect. Values of this type cannot be compared with anything, even other values of the same type. Some things are not their own types, and are other uses of numbers: * Null: A null class or null object is represented as zero. * Boolean: When a boolean is required as input to some instruction, zero is false, and most other values (of any type) are true, except for sounds |
︙ | ︙ |
Modified exec.c from [3e982fe105] to [7a4d702d39].
︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | if(*t==16) { quiz_obj.t=objects[from]->generation?:1; quiz_obj.u=from; } if(*t==31 && t[1]) t+=2; else t+=1; } } // Here is where the execution of a Free Hero Mesh bytecode subroutine is executed. #define NoIgnore() do{ changed=1; }while(0) #define GetVariableOf(a,b) (i=v_object(Pop()),i==VOIDLINK?NVALUE(0):b(objects[i]->a)) #define GetVariableOrAttributeOf(a,b) (t2=Pop(),t2.t==TY_CLASS?NVALUE(classes[t2.u]->a):(i=v_object(t2),i==VOIDLINK?NVALUE(0):b(objects[i]->a))) #define Numeric(a) do{ if((a).t!=TY_NUMBER) Throw("Type mismatch"); }while(0) #define DivideBy(a) do{ Numeric(a); if(!(a).u) Throw("Division by zero"); }while(0) | > > > > > > > > > > > > | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | if(*t==16) { quiz_obj.t=objects[from]->generation?:1; quiz_obj.u=from; } if(*t==31 && t[1]) t+=2; else t+=1; } } static int v_dispatch(const Uint16*code) { int i=msgvars.arg1.u; if(msgvars.arg1.t!=TY_NUMBER) Throw("Type mismatch"); if(msgvars.arg1.u&~0xFF) { if(current_key && !v_bool(msgvars.arg3)) key_ignored=all_flushed=1; return 0; } if(!i) return 0; if(current_key && !v_bool(msgvars.arg3) && !(keymask[i>>3]&(1<<(i&7)))) key_ignored=all_flushed=1; return code[i]; } // Here is where the execution of a Free Hero Mesh bytecode subroutine is executed. #define NoIgnore() do{ changed=1; }while(0) #define GetVariableOf(a,b) (i=v_object(Pop()),i==VOIDLINK?NVALUE(0):b(objects[i]->a)) #define GetVariableOrAttributeOf(a,b) (t2=Pop(),t2.t==TY_CLASS?NVALUE(classes[t2.u]->a):(i=v_object(t2),i==VOIDLINK?NVALUE(0):b(objects[i]->a))) #define Numeric(a) do{ if((a).t!=TY_NUMBER) Throw("Type mismatch"); }while(0) #define DivideBy(a) do{ Numeric(a); if(!(a).u) Throw("Division by zero"); }while(0) |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | case OP_DESTROY_CD: NoIgnore(); StackReq(1,0); i=v_object(Pop()); destroy(obj,i,0); break; case OP_DESTROYED: StackReq(0,1); if(o->oflags&OF_DESTROYED) Push(NVALUE(1)); else Push(NVALUE(0)); break; case OP_DESTROYED_C: StackReq(1,1); t1=Pop(); Push(NVALUE(v_destroyed(t1))); break; case OP_DIR: StackReq(0,1); Push(NVALUE(o->dir)); break; case OP_DIR_C: StackReq(1,1); Push(GetVariableOf(dir,NVALUE)); break; case OP_DIR_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->dir=resolve_dir(obj,t1.u); break; case OP_DIR_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->dir=resolve_dir(i,t1.u); break; case OP_DISTANCE: StackReq(0,1); Push(NVALUE(o->distance)); break; case OP_DISTANCE_C: StackReq(1,1); Push(GetVariableOf(distance,NVALUE)); break; case OP_DISTANCE_E: StackReq(1,0); t1=Pop(); Numeric(t1); o->distance=t1.u; break; case OP_DISTANCE_EC: StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->distance=t1.u; break; case OP_DIV: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u/t2.u)); break; case OP_DIV_C: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s/t2.s)); break; case OP_DONE: StackReq(0,1); if(o->oflags&OF_DONE) Push(NVALUE(1)); else Push(NVALUE(0)); break; | > | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 | case OP_DESTROY_CD: NoIgnore(); StackReq(1,0); i=v_object(Pop()); destroy(obj,i,0); break; case OP_DESTROYED: StackReq(0,1); if(o->oflags&OF_DESTROYED) Push(NVALUE(1)); else Push(NVALUE(0)); break; case OP_DESTROYED_C: StackReq(1,1); t1=Pop(); Push(NVALUE(v_destroyed(t1))); break; case OP_DIR: StackReq(0,1); Push(NVALUE(o->dir)); break; case OP_DIR_C: StackReq(1,1); Push(GetVariableOf(dir,NVALUE)); break; case OP_DIR_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->dir=resolve_dir(obj,t1.u); break; case OP_DIR_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->dir=resolve_dir(i,t1.u); break; case OP_DISPATCH: ptr=v_dispatch(code+ptr-1); if(!ptr) return; break; case OP_DISTANCE: StackReq(0,1); Push(NVALUE(o->distance)); break; case OP_DISTANCE_C: StackReq(1,1); Push(GetVariableOf(distance,NVALUE)); break; case OP_DISTANCE_E: StackReq(1,0); t1=Pop(); Numeric(t1); o->distance=t1.u; break; case OP_DISTANCE_EC: StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->distance=t1.u; break; case OP_DIV: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u/t2.u)); break; case OP_DIV_C: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s/t2.s)); break; case OP_DONE: StackReq(0,1); if(o->oflags&OF_DONE) Push(NVALUE(1)); else Push(NVALUE(0)); break; |
︙ | ︙ |
Modified heromesh.h from [af1df60f10] to [fad2c669ac].
︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 | extern const char*messages[0x4000]; // index is 256 less than message number extern Uint16 functions[0x4000]; extern int max_animation; // max steps in animation queue (default 32) extern Sint32 max_volume; // max total volume to allow moving diagonally (default 10000) extern Uint8 back_color,inv_back_color; extern char**stringpool; extern AnimationSlot anim_slot[8]; Uint16 get_message_ptr(int c,int m); void load_classes(void); // == bindings == typedef struct { | > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | extern const char*messages[0x4000]; // index is 256 less than message number extern Uint16 functions[0x4000]; extern int max_animation; // max steps in animation queue (default 32) extern Sint32 max_volume; // max total volume to allow moving diagonally (default 10000) extern Uint8 back_color,inv_back_color; extern char**stringpool; extern AnimationSlot anim_slot[8]; extern Uint8 keymask[256/8]; Uint16 get_message_ptr(int c,int m); void load_classes(void); // == bindings == typedef struct { |
︙ | ︙ |
Modified instruc from [cba4030e74] to [9318f5d8d4].
︙ | ︙ | |||
250 251 252 253 254 255 256 257 | ; Specials *Function *Local *Label *String *Int16 *Int32 | > | 250 251 252 253 254 255 256 257 258 | ; Specials *Function *Local *Label *String *Int16 *Int32 *Dispatch |
Modified instruc.h from [fef41e8e89] to [99711f673d].
︙ | ︙ | |||
363 364 365 366 367 368 369 370 371 372 373 374 375 376 | #define OP_YDIR_C 34992 #define OP_FUNCTION 32945 #define OP_LOCAL 32946 #define OP_LABEL 32947 #define OP_STRING 32948 #define OP_INT16 32949 #define OP_INT32 32950 #ifdef HEROMESH_CLASS static const Op_Names op_names[]={ {"*",8486935}, {"+",8421397}, {"-",8421398}, {"-rot",8421382}, {".",10518528}, | > | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | #define OP_YDIR_C 34992 #define OP_FUNCTION 32945 #define OP_LOCAL 32946 #define OP_LABEL 32947 #define OP_STRING 32948 #define OP_INT16 32949 #define OP_INT32 32950 #define OP_DISPATCH 32951 #ifdef HEROMESH_CLASS static const Op_Names op_names[]={ {"*",8486935}, {"+",8421397}, {"-",8421398}, {"-rot",8421382}, {".",10518528}, |
︙ | ︙ |