📄 patterns.hhf
字号:
#if( ! @defined( patterns_hhf ))?patterns_hhf := true;#includeOnce( "hla.hhf" )#includeOnce( "strings.hhf" )namespace pat; @fast; type FailRec: record ebpSave: dword; jmpAdrs: dword; endrecord; _actRec_: record startPosn: dword; endStr: dword; prevOpEBP: dword; FailToSave: FailRec; endrecord; // macro to make _actRec_ access easier to do: #macro ar(field); (type pat._actRec_ [ebp]).field #endmacro static WordDelims: cset; @external( "pat_WordDelims" ); FailTo: FailRec; @external( "pat_FailTo" ); CleanESP: dword; @external( "pat_CleanESP" ); StrStart: dword; @external( "pat_StrStart" ); onePatEBP: dword; @external( "pat_onePatEBP" ); zeroOrOnePatEBP: dword; @external( "pat_zeroOrOnePatEBP" ); zeroOrMorePatEBP: dword; @external( "pat_zeroOrMorePatEBP" ); oneOrMorePatEBP: dword; @external( "pat_oneOrMorePatEBP" ); // The following macro is a utility for // the pattern matching procedures. // It saves the current global "FailTo" // value in the "FailRec" variable specified // as the first parameter and sets up // FailTo to properly return control into // the current procedure at the "FailTarget" // address. Then it jumps indirectly through // the procedure's return address to transfer // control to the next (code sequential) // pattern matching routine. #macro _success_( _s_FTSave_, _s_FailTarget_ ); mov( pat.FailTo.ebpSave, _s_FTSave_.ebpSave ); mov( pat.FailTo.jmpAdrs, _s_FTSave_.jmpAdrs ); mov( ebp, pat.FailTo.ebpSave ); mov( &_s_FailTarget_, pat.FailTo.jmpAdrs ); pushd( [ebp+4] ); mov( [ebp], ebp ); ret(); #endmacro // _fail_ is a utility macro used by the pattern // matching procedures to signal failure during // the pattern matching operation. This transfers // control back to the previous routine that // supports backtracking. #macro _fail_( _f_FTAdrs_ ); mov( _f_FTAdrs_.ebpSave, ebp ); jmp( _f_FTAdrs_.jmpAdrs ); #endmacro //////////////////////////////////////////////////////////////////////////// #macro _onePat_: _op_failAdrs_, _op_successAdrs_; // Because of alternation, we may need more that one // failure address (since, for each alternation section, // the previous sections must fail to that alternate). // Hence, _op_failAdrs_ is a string that we can set to // various labels under control of this macro. ?_op_failAdrs_ := hla.genLabel; push( ebp ); // Create an activation record. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( esi, ebx ); mov( pat.FailTo.ebpSave, pat.ar( FailToSave.ebpSave )); mov( pat.FailTo.jmpAdrs, pat.ar( FailToSave.jmpAdrs )); mov( ebp, pat.FailTo.ebpSave ); mov( pat.onePatEBP, pat.ar( prevOpEBP )); mov( ebp, pat.onePatEBP ); mov( &@text( _op_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword alternate; jmp _op_successAdrs_; @text( _op_failAdrs_ ): ?_op_failAdrs_ := hla.genLabel; mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.ar( endStr ), edi ); mov( esi, ebx ); mov( &@text( _op_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword fence( _p_Fence_accept_zero_parameters_[] ); #error( "Fence is illegal within the 'onePat' macro" ); #keyword if_failure; #error( "'if_failure' is illegal within 'onePat' macro" ) #terminator endOnePat; // If we fall through from the main pattern or an alternate, // then we have success, so jump to the success label. jmp _op_successAdrs_; // Slip in some code to handle failure. // If we get here, then we've completely failed and we need to // attempt to backtrack through some previous pattern (if available). @text( _op_failAdrs_ ): mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.ar( prevOpEBP ), pat.onePatEBP ); mov( pat.ar( FailToSave.jmpAdrs ), pat.FailTo.jmpAdrs ); mov( pat.ar( FailToSave.ebpSave ), ebp ); mov( ebp, pat.FailTo.ebpSave ); jmp( pat.FailTo.jmpAdrs ); // Cascade to previous fail hndlr. // Successful match here. Note: do not restore pat.onePatEBP because // backtracking may still occur (and we will need the current value). _op_successAdrs_: mov( pat.onePatEBP, ebx ); mov( (type pat._actRec_ [ebx]).startPosn, ebx ) #endmacro //////////////////////////////////////////////////////////////////////////// #macro _zeroOrOnePat_: _zoop_failAdrs_, _zoop_successAdrs_; // Because of alternation, we may need more that one // failure address (since, for each alternation section, // the previous sections must fail to that alternate). // Hence, _zoop_failAdrs_ is a string that we can set to // various labels under control of this macro. ?_zoop_failAdrs_ := hla.genLabel; push( ebp ); // Create an activation record. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( esi, ebx ); mov( pat.FailTo.ebpSave, pat.ar( FailToSave.ebpSave )); mov( pat.FailTo.jmpAdrs, pat.ar( FailToSave.jmpAdrs )); mov( ebp, pat.FailTo.ebpSave ); mov( pat.zeroOrOnePatEBP, pat.ar( prevOpEBP )); mov( ebp, pat.zeroOrOnePatEBP ); mov( &@text( _zoop_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword alternate; jmp _zoop_successAdrs_; @text( _zoop_failAdrs_ ): ?_zoop_failAdrs_ := hla.genLabel; mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.ar( endStr ), edi ); mov( esi, ebx ); mov( &@text( _zoop_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword fence( _p_Fence_accept_zero_parameters_[] ); #error( "Fence is illegal within the 'zeroOrOnePat' macro" ); #keyword if_failure; #error( "'if_failure' is illegal within 'zeroOrOnePat' macro" ) #terminator endZeroOrOnePat:_zoop_successAdrs2_; // If we fall through from the main pattern or an alternate, // then we have success, so jump to the success label. jmp _zoop_successAdrs_; // Slip in some code to handle failure. // If we get here, then we've completely failed. But that's // okay 'cause this is *zero*OrMorePat. Clean up the stack // and return success. @text( _zoop_failAdrs_ ): mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( esi, ebx ); mov( pat.ar( prevOpEBP ), pat.zeroOrOnePatEBP ); mov( pat.ar( FailToSave.jmpAdrs ), pat.FailTo.jmpAdrs ); mov( pat.ar( FailToSave.ebpSave ), ebp ); mov( ebp, pat.FailTo.ebpSave ); jmp _zoop_successAdrs2_; // Successful match here. Note: do not restore pat.onePatEBP because // backtracking may still occur (and we will need the current value). _zoop_successAdrs_: mov( pat.zeroOrOnePatEBP, ebx ); mov( (type pat._actRec_ [ebx]).startPosn, ebx ); _zoop_successAdrs2_: // The following forces the user to provide a semicolon after // the endmatch invocation. static ; endstatic #endmacro //////////////////////////////////////////////////////////////////////////// #macro _zeroOrMorePat_: _zomp_failAdrs_, _zomp_successAdrs_; // Because of alternation, we may need more that one // failure address (since, for each alternation section, // the previous sections must fail to that alternate). // Hence, _zomp_failAdrs_ is a string that we can set to // various labels under control of this macro. ?_zomp_failAdrs_ := hla.genLabel; // Set up the record to keep track of the string's length: push( ebp ); // Create an activation record. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( pat.zeroOrMorePatEBP, pat.ar( prevOpEBP )); mov( ebp, pat.zeroOrMorePatEBP ); // Loop back to this point until we get a failure. _zomp_successAdrs_: push( ebp ); // Create an activation record. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( esi, ebx ); mov( pat.FailTo.ebpSave, pat.ar( FailToSave.ebpSave )); mov( pat.FailTo.jmpAdrs, pat.ar( FailToSave.jmpAdrs )); mov( ebp, pat.FailTo.ebpSave ); mov( &@text( _zomp_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword alternate; #error( "Alternate is illegal within the 'zeroOrMorePat' macro" ); #keyword fence( _p_Fence_accept_zero_parameters_[] ); #error( "Fence is illegal within the 'zeroOrMorePat' macro" ); #keyword if_failure; #error( "'if_failure' is illegal within 'zeroOrMorePat' macro" ) #terminator endZeroOrMorePat; // Successful match here (falling through from match or alternate). jmp _zomp_successAdrs_; // Slip in some code to handle failure. // If we get here, then we've completely failed. But that's // okay 'cause this is *zero*OrMorePat. Clean up the stack // and return success. @text( _zomp_failAdrs_ ): mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.zeroOrMorePatEBP, ebx ); mov( (type pat._actRec_ [ebx]).startPosn, ebx ); mov( pat.ar( FailToSave.jmpAdrs ), pat.FailTo.jmpAdrs ); mov( pat.ar( FailToSave.ebpSave ), ebp ); mov( ebp, pat.FailTo.ebpSave ) #endmacro //////////////////////////////////////////////////////////////////////////// #macro _oneOrMorePat_: _oomp_failAdrs_, _oomp_successAdrs_, _oomp_successAdrs2_, _oomp_succeeded; // Because of alternation, we may need more that one // failure address (since, for each alternation section, // the previous sections must fail to that alternate). // Hence, _oomp_failAdrs_ is a string that we can set to // various labels under control of this macro. ?_oomp_failAdrs_ := hla.genLabel; // Set up the record to keep track of the string's length: push( ebp ); // Create an activation record. pushd( false ); // Flags at least one match. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( pat.oneOrMorePatEBP, pat.ar( prevOpEBP )); mov( ebp, pat.oneOrMorePatEBP ); jmp _oomp_successAdrs2_; // Loop back to this point until we get a failure. _oomp_successAdrs_: // If we loop back, set the "match flag" to true. mov( pat.oneOrMorePatEBP, ebx ); mov( true, (type dword [ebx+@size( pat._actRec_ )])); _oomp_successAdrs2_: push( ebp ); // Create an activation record. sub( @size( pat._actRec_ ), esp ); mov( esp, ebp ); // Point ebp at _actRec_ data. mov( edi, pat.ar( endStr )); mov( esi, pat.ar( startPosn )); mov( esi, ebx ); mov( pat.FailTo.ebpSave, pat.ar( FailToSave.ebpSave )); mov( pat.FailTo.jmpAdrs, pat.ar( FailToSave.jmpAdrs )); mov( ebp, pat.FailTo.ebpSave ); mov( &@text( _oomp_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword alternate; jmp _oomp_successAdrs_; @text( _oomp_failAdrs_ ): ?_oomp_failAdrs_ := hla.genLabel; // If we get here, then we've failed. However, if we did match // at least one copy of the pattern, we succeed. Check for that // case here. mov( pat.oneOrMorePatEBP, ebx ); cmp( (type byte [ebx + @size( pat._actRec_ )]), 0 ); jne _oomp_succeeded; mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.ar( endStr ), edi ); mov( esi, ebx ); mov( &@text( _oomp_failAdrs_ ), pat.FailTo.jmpAdrs ); #keyword fence( _p_Fence_accept_zero_parameters_[] ); #error( "Fence is illegal within the 'zeroOrMorePat' macro" ); #keyword if_failure; #error( "'if_failure' is illegal within 'zeroOrMorePat' macro" ) #terminator endOneOrMorePat; // Successful match here (falling through from match or alternate). jmp _oomp_successAdrs_; // Slip in some code to handle failure. // If we get here, then we've completely failed. Since this is // *one*OrMorePat we have to check to see if we've matched at // least one occurrence of the pattern (maintained in the flag // just below the activation record for this match. @text( _oomp_failAdrs_ ): mov( pat.oneOrMorePatEBP, ebx ); cmp( (type byte [ebx + @size( pat._actRec_ )]), 0 ); jne _oomp_succeeded; // Okay, we really failed here. Time to try backtracking: mov( ebp, esp ); mov( pat.ar( startPosn ), esi ); mov( pat.ar( prevOpEBP ), pat.oneOrMorePatEBP ); mov( pat.ar( FailToSave.jmpAdrs ), pat.FailTo.jmpAdrs ); mov( pat.ar( FailToSave.ebpSave ), ebp ); mov( ebp, pat.FailTo.ebpSave ); jmp( pat.FailTo.jmpAdrs ); // Cascade to previous fail hndlr. _oomp_succeeded: mov( ebp, esp ); mov( pat.ar( startPosn ), esi );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -