Hash :
1a08f436
Author :
Date :
2010-08-25T09:23:17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
\ patch.fth 2.11 01/04/06
\ Copyright 1985-1994 Bradley Forthware
\ copyright: Copyright 1995-2001 Sun Microsystems, Inc. All Rights Reserved
\ Patch utility. Allows you to make patches to already-defined words.
\ Usage:
\ PATCH new old word-to-patch
\ In the definition of "word-to-patch", replaces the first
\ occurence of "old" with "new". "new" may be either a word
\ or a number. "old" may be either a word or a number.
\
\ n-new n-old NPATCH word-to-patch
\ In the definition of "word-to-patch", replaces the first
\ compiled instance of the number "n-old" with the number
\ "n-new".
\
\ n-new n-old start-adr end-adr (NPATCH
\ replaces the first occurrence of "n-old" in the word "acf"
\ with "n-new"
\
\ acf-new acf-old acf (PATCH
\ replaces the first occurrence of "acf-old" in the word "acf"
\ with "acf-new"
\
\ new new-type old old-type acf (PATCH)
\ replaces the first occurrence of "old" in the word "acf" with "new".
\ If "new-type" is true, "new" is a number, otherwise "new" is an acf.
\ If "old-type" is true, "old" is a number, otherwise "old" is an acf.
\
\ n start-adr end-adr SEARCH
\ searches for an occurrence of "n" between start-adr and
\ end-adr. Leaves the adress where found and a success flag.
\
\ c start-adr end-adr CSEARCH
\ searches for a byte between start-adr and end-adr
\
\ w start-adr end-adr WSEARCH
\ searches for a 16-bit word between start-adr and end-adr
\
\ acf start-adr end-adr TSEARCH
\ searches for a compiled adress between start-adr and end-adr
\
\
decimal
: csearch ( c start end -- loc true | false )
false -rot swap ?do ( c false )
over i c@ = if
drop i swap true leave
then
/c +loop nip
;
: wsearch ( w start end -- loc true | false )
rot n->w \ strip off any high bits
false 2swap swap ?do ( w false )
over i w@ = if
drop i swap true leave
then
/w +loop nip
;
: tsearch ( adr start end -- loc true | false )
false -rot swap ?do ( targ false )
over i token@ = if
drop i swap true leave
then
\ Can't use /token because tokens could be 32-bits, aligned on 16-bit
\ boundaries, with 16-bit branch offsets realigning the token list.
#talign +loop nip
;
: search ( n start end -- loc true | false )
false -rot swap ?do ( n false )
over i @ = if
drop i swap true leave
then
#talign +loop nip
;
headerless
: get-next-token ( adr -- adr token )
dup token@ ( n adr token )
dup ['] unnest = abort" Can't find word to replace" ( n adr token )
;
: find-lit ( n acf -- adr )
>body
begin
get-next-token ( n adr token )
\t16 dup ['] (wlit) = if ( n adr token )
\t16 drop ( n adr )
\t16 2dup ta1+ w@ 1- = if ( n adr )
\t16 nip exit ( adr )
\t16 else ( n adr )
\t16 ta1+ wa1+ ( n adr' )
\t16 then ( n adr )
\t16 else ( n adr token )
dup ['] (lit) = if ( n adr token )
drop ( n adr )
2dup ta1+ @ = if ( n adr )
nip exit ( adr )
else ( n adr )
ta1+ na1+ ( n adr' )
then ( n adr )
else ( n adr token )
['] (llit) = if ( n adr )
2dup ta1+ l@ 1- = if ( n adr )
nip exit ( adr )
else ( n adr )
ta1+ la1+ ( n adr' )
then ( n adr' )
else ( n adr )
ta1+ ( n adr' )
then ( n adr' )
then ( n adr' )
\t16 then
again
;
: find-token ( n acf -- adr )
>body
begin
get-next-token ( n adr token )
2 pick = if nip exit then ( n adr )
ta1+ ( n adr' )
again
;
: make-name ( n digit -- adr len )
>r <# u#s ascii # hold r> hold u#> ( adr len )
;
: put-constant ( n adr -- )
over
base @ d# 16 = if
ascii h make-name
else
push-decimal
ascii d make-name
pop-base
then ( n adr name-adr name-len )
\ We don't use "create .. does> @ because we want this word
\ to decompile as 'constant'
warning @ >r warning off
$header ( n adr )
constant-cf swap , ( adr )
r> warning !
lastacf swap token!
;
: put-noop ( adr -- ) ta1+ ['] noop swap token! ;
\t16 : short-number? ( n -- flag ) -1 h# fffe between ;
\t32 : long-number? ( n -- flag ) -1 h# ffff.fffe n->l between ;
headers
: (patch) ( new number? old number? word -- )
swap if ( new number? old acf ) \ Dest. is num
find-lit ( new number? adr )
\t16 dup token@ ['] (wlit) = if ( new number? old ) \ Dest. slot is wlit
\t16 swap if ( new adr ) \ replacement is a number
\t16 over short-number? if ( new adr ) \ replacement is short num
\t16 ta1+ swap 1+ swap w! ( )
\t16 exit
\t16 then ( new adr ) \ Replacement is long num
\t16 tuck put-constant ( adr )
\t16 put-noop ( )
\t16 exit
\t16 then ( new adr ) \ replacement is a word
\t16 tuck token! put-noop ( )
\t16 exit
\t16 then ( new number? adr ) \ Dest. slot is lit
\t32 dup token@ ['] (llit) = if ( new number? old ) \ Dest. slot is wlit
\t32 swap if ( new adr ) \ replacement is a number
\t32 over long-number? if ( new adr ) \ replacement is short num
64\ \t32 ta1+ swap 1+ swap l! ( )
32\ \t32 ta1+ l! ( )
\t32 exit
\t32 then ( new adr ) \ Replacement is long num
\t32 tuck put-constant ( adr )
\t32 put-noop ( )
\t32 exit
\t32 then ( new adr ) \ replacement is a word
\t32 tuck token! put-noop ( )
\t32 exit
\t32 then ( new number? adr ) \ Dest. slot is lit
swap if ta1+ ! exit then ( new adr ) \ replacement is a word
tuck token! ( adr )
32\ \t16 dup put-noop ta1+ ( )
64\ \t16 dup put-noop ta1+ dup put-noop dup put-noop ta1+ ( )
64\ \t32 dup put-noop ta1+
put-noop ( )
exit
then ( new number? old acf ) \ Dest. is token
find-token ( new number? adr )
swap if put-constant exit then ( new adr ) \ replacement is a number
token!
;
headerless
: get-word-type \ word ( -- val number? )
parse-word $find if false exit then ( adr len )
$dnumber? 1 <> abort" ?" true
;
headers
: (npatch ( newn oldn acf -- ) >r true tuck r> (patch) ;
: (patch ( new-acf old-acf acf -- ) >r false tuck r> (patch) ;
\ substitute new for first occurrence of old in word "name"
: npatch \ name ( new old -- )
true tuck ' ( new true old true acf ) (patch)
;
: patch \ new old word ( -- )
get-word-type get-word-type ' (patch)
;