Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -2111,14 +2111,35 @@ === Pattern matching === Where an instruction is expected, you can have pattern matching. This can -be (P ) or (,P ) where the first one uses the -current location, and the second kind uses the position and direction of -the specified object as the matching. It pushes the found object to the -stack, or pushes zero if the pattern does not match. +be ( ) where the operator can be one of: + +P + Find starting at the current location, with the current object's + direction. Pushes the found object, or zero if not found. + +,P + Find starting at the specified object's location and direction. Pushes + the found object, or zero if not found. + +=P + Searches everywhere. Pushes the found object, or zero if not found. + +P* + Like P but push all found objects, or pushes nothing if not found. + +,P* + Like ,P but push all found objects, or pushes nothing if not found. + +=P* + Like =P but push all found objects, or pushes nothing if not found. + +Inside the pattern, the following commands are allowed (although the +commands that push stuff to the stack should not be used in the patterns +with P* or ,P* or =P*): Match an object of the specified class. Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -1786,11 +1786,19 @@ break; case OP_OBJTOPAT: n=obj_top_at(x,y); break; case OP_RET: - return n==VOIDLINK?obj_bottom_at(x,y):n; + if(all) { + if(vstackptr>=VSTACKSIZE-1) Throw("Stack overflow"); + if(n==VOIDLINK) n=obj_bottom_at(x,y); + Push(OVALUE(n)); + goto fail; + } else { + return n==VOIDLINK?obj_bottom_at(x,y):n; + } + break; case OP_SUB: if(vstackptr>=VSTACKSIZE-1) Throw("Stack overflow"); Push(NVALUE(0)); break; case OP_THEN: @@ -1804,21 +1812,36 @@ break; default: Throw("Unimplemented opcode in pattern"); } goto again; fail: - if(vstackptrdepth) Throw("Stack underflow in pattern matching"); - vstackptr=cp[cpi].depth; + if(!all) { + if(vstackptrdepth) Throw("Stack underflow in pattern matching"); + vstackptr=cp[cpi].depth; + } if(!cpi) return VOIDLINK; x=cp[cpi].x; y=cp[cpi].y; d=cp[cpi].dir; ptr=cp[cpi].ptr; n=VOIDLINK; cpi--; goto again; } + +static Uint32 v_pattern_anywhere(Uint16*code,int ptr,char all) { + int i; + Uint32 n; + for(i=0;ia)) #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))) @@ -2114,10 +2137,14 @@ case OP_OBJMOVINGTO: StackReq(2,0); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); v_obj_moving_to(t1.u,t2.u); break; case OP_OBJTOPAT: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); i=obj_top_at(t1.u,t2.u); Push(OVALUE(i)); break; case OP_OVER: StackReq(2,3); t2=Pop(); t1=Pop(); Push(t1); Push(t2); Push(t1); break; case OP_PATTERN: StackReq(0,1); i=code[ptr++]; j=v_pattern(code,ptr,obj,0); ptr=i; Push(OVALUE(j)); break; case OP_PATTERN_C: StackReq(1,1); i=code[ptr++]; j=v_object(Pop()); if(j!=VOIDLINK) j=v_pattern(code,ptr,j,0); ptr=i; Push(OVALUE(j)); break; + case OP_PATTERN_E: StackReq(0,1); i=code[ptr++]; j=v_pattern_anywhere(code,ptr,0); ptr=i; Push(OVALUE(j)); break; + case OP_PATTERNS: StackReq(0,1); i=code[ptr++]; v_pattern(code,ptr,obj,1); ptr=i; break; + case OP_PATTERNS_C: StackReq(1,1); i=code[ptr++]; j=v_object(Pop()); if(j!=VOIDLINK) v_pattern(code,ptr,j,1); ptr=i; break; + case OP_PATTERNS_E: StackReq(0,1); i=code[ptr++]; v_pattern_anywhere(code,ptr,1); ptr=i; break; case OP_PICK: StackReq(0,1); t1=Pop(); Numeric(t1); if(t1.u>=vstackptr) Throw("Stack index out of range"); t1=vstack[vstackptr-t1.u-1]; Push(t1); break; case OP_PLAYER: StackReq(0,1); if(classes[o->class]->cflags&CF_PLAYER) Push(NVALUE(1)); else Push(NVALUE(0)); break; case OP_PLAYER_C: StackReq(1,1); GetClassFlagOf(CF_PLAYER); break; case OP_PLUSMOVE: StackReq(1,1); t1=Pop(); Numeric(t1); i=defer_move(obj,t1.u,1); Push(NVALUE(i)); break; case OP_PLUSMOVE_C: StackReq(2,1); t1=Pop(); Numeric(t1); i=v_object(Pop()); i=defer_move(i,t1.u,1); Push(NVALUE(i)); break;