238 lines
8.9 KiB
Plaintext
238 lines
8.9 KiB
Plaintext
|
obj
|
||
|
str: "stringx"
|
||
|
|
||
|
dat
|
||
|
cog long 0
|
||
|
|
||
|
pub Init( p0, p1 )
|
||
|
pFree := p0 ' leave some room for the stack, then free space.
|
||
|
pLimit := p1
|
||
|
|
||
|
Stop
|
||
|
sync~~
|
||
|
cog := cognew( @LookerUpper, @input ) + 1
|
||
|
ifnot cog
|
||
|
abort string("Couldn't start bintree cog")
|
||
|
repeat while sync
|
||
|
|
||
|
pub Stop
|
||
|
if cog
|
||
|
cogstop( cog~ - 1 )
|
||
|
|
||
|
pub FindInTable( s, p ) | d
|
||
|
{{
|
||
|
Finds string s in table pointed to by p.
|
||
|
Returns pointer to s's data area if s is found, 0 otherwise.
|
||
|
}}
|
||
|
input[0] := s
|
||
|
input[1] := p
|
||
|
sync~~
|
||
|
repeat while sync
|
||
|
return output
|
||
|
{
|
||
|
ifnot p
|
||
|
return 0
|
||
|
d := str.Compare( s, p+4 )
|
||
|
ifnot d
|
||
|
return p + 4 + strsize(s) + 1
|
||
|
if d < 0
|
||
|
return FindInTable( s, Peekw(p) )
|
||
|
' else
|
||
|
return FindInTable( s, Peekw(p+2) )
|
||
|
}
|
||
|
|
||
|
pub AddToTable( s, pP ) | p, d
|
||
|
{{
|
||
|
Adds string s to table. Note: pP is a pointer-to-pointer to table.
|
||
|
Returns a pointer to s's data area (actually pFree, so if you add
|
||
|
any data, increment pFree past it).
|
||
|
}}
|
||
|
ifnot p := PeekW( pP )
|
||
|
PokeW( pP, pFree )
|
||
|
PokeW( pFree, 0 )
|
||
|
pFree += 2
|
||
|
PokeW( pFree, 0 )
|
||
|
pFree += 2
|
||
|
str.Copy( pFree, s )
|
||
|
pFree += strsize(s) + 1
|
||
|
return pFree
|
||
|
|
||
|
d := str.Compare( s, p+4 )
|
||
|
{
|
||
|
term.dec(d)
|
||
|
term.out(13)
|
||
|
waitcnt( clkfreq + cnt )
|
||
|
}
|
||
|
ifnot d
|
||
|
abort string("Symbol already defined")
|
||
|
if d < 0
|
||
|
return AddToTable( s, @word[p][0] )
|
||
|
' else
|
||
|
return AddToTable( s, @word[p][1] )
|
||
|
|
||
|
pub PeekW( p )
|
||
|
return byte[p++] + byte[p] << 8
|
||
|
|
||
|
pub PokeW( p, w )
|
||
|
byte[p++] := w
|
||
|
byte[p] := w >> 8
|
||
|
|
||
|
pub PeekL( p ) : t
|
||
|
repeat 4
|
||
|
t := (t | byte[p++]) -> 8
|
||
|
|
||
|
pub PokeL( p, l )
|
||
|
repeat 4
|
||
|
byte[p++] := l
|
||
|
l >>= 8
|
||
|
|
||
|
dat
|
||
|
pFree long 0
|
||
|
pLimit long 0
|
||
|
|
||
|
pub Alloc( n )
|
||
|
result := pFree
|
||
|
if (pFree += n) > pLimit
|
||
|
abort string("Out of symbol table space")
|
||
|
|
||
|
dat
|
||
|
input long 0 ' rendezvous variables for LookerUpper
|
||
|
output long 0
|
||
|
sync long 1
|
||
|
|
||
|
{
|
||
|
This PASM routine is equivalent to the following:
|
||
|
|
||
|
pub FindInTable( s, p ) | d
|
||
|
{{
|
||
|
Finds string s in table pointed to by p.
|
||
|
Returns pointer to s's data area if s is found, 0 otherwise.
|
||
|
}}
|
||
|
ifnot p
|
||
|
return 0
|
||
|
d := str.Compare( s, p+4 )
|
||
|
ifnot d
|
||
|
return p + 4 + strsize(s) + 1
|
||
|
if d < 0
|
||
|
return FindInTable( s, Peekw(p) )
|
||
|
' else
|
||
|
return FindInTable( s, Peekw(p+2) )
|
||
|
}
|
||
|
|
||
|
dat org 0
|
||
|
LookerUpper
|
||
|
mov pInput, par ' Enter with par pointing to rendezvous area,
|
||
|
mov pOutput, par ' sync = 1
|
||
|
add pOutput, #4
|
||
|
mov pSync, par
|
||
|
add pSync, #8
|
||
|
|
||
|
rdlong pTable, pInput ' Save @tableStart
|
||
|
' and ack to inform Spin program that the cog is running.
|
||
|
Ack
|
||
|
wrlong retval, pOutput
|
||
|
mov temp, #0
|
||
|
wrlong temp, pSync
|
||
|
|
||
|
:wait ' Wait for caller to set sync to indicate that input is ready.
|
||
|
rdlong temp, pSync wz
|
||
|
if_z jmp #:wait
|
||
|
|
||
|
rdlong pString, pInput ' input[0] points to string to look up.
|
||
|
rdlong ptr, pOutput ' input[1] points to table. (input[1] = output)
|
||
|
|
||
|
mov retval, #0
|
||
|
:loop
|
||
|
tjz ptr, #Ack
|
||
|
|
||
|
mov pLeft, pString ' Compare string
|
||
|
mov pRight, ptr ' to string at current position in table
|
||
|
add pRight, #4 ' (bump up ptr by 4 to skip two link words).
|
||
|
|
||
|
call #StringCompare
|
||
|
|
||
|
if_e jmp #:equal
|
||
|
if_b jmp #:less
|
||
|
:greater ' If left > right,
|
||
|
add ptr, #2 ' use the 2nd link.
|
||
|
:less ' If left < right, use 1st link.
|
||
|
rdbyte temp, ptr ' Follow the link
|
||
|
add ptr, #1 ' It would be nice to just "rdword ptr, ptr" here
|
||
|
rdbyte ptr, ptr ' but ptr might be odd so we have to go through
|
||
|
shl ptr, #8 ' some extra gyrations.
|
||
|
add ptr, temp
|
||
|
|
||
|
jmp #:loop ' and recurse (well, just iterate).
|
||
|
|
||
|
:equal ' If left = right, return ptr + 4 + strsize(pString) + 1
|
||
|
mov retval, ptr
|
||
|
add retval, #5
|
||
|
:x
|
||
|
rdbyte temp, pString wz ' add strsize(pString)
|
||
|
if_z jmp #:y
|
||
|
add retval, #1
|
||
|
add pString, #1
|
||
|
jmp #:x
|
||
|
:y
|
||
|
jmp #Ack
|
||
|
|
||
|
StringCompare
|
||
|
' Compares zero-terminated strings pointed to by pLeft and pRight.
|
||
|
' On return, Z and C are set appropriately.
|
||
|
rdbyte temp, pLeft wz
|
||
|
add pLeft, #1
|
||
|
if_z jmp #:leftEnd
|
||
|
rdbyte temp1, pRight wz
|
||
|
add pRight, #1
|
||
|
if_z jmp #:rightEnd
|
||
|
cmp temp, temp1 wc, wz
|
||
|
if_e jmp #StringCompare ' If they match, try the next pair.
|
||
|
jmp #StringCompare_ret ' Otherwise, we're done.
|
||
|
|
||
|
:leftEnd rdbyte temp1, pRight wz ' If we're at the end of both strings,
|
||
|
if_z jmp #StringCompare_ret ' leave (with Z set).
|
||
|
' Otherwise, left string is shorter than the right
|
||
|
' and therefore less.
|
||
|
neg temp, #1
|
||
|
mov temp, temp wc, wz ' Set C=1 and Z=0 for "less than"
|
||
|
jmp #StringCompare_ret
|
||
|
:rightEnd ' Here we've reached the end of the right string.
|
||
|
' The left string is longer than the right
|
||
|
' and therefore greater.
|
||
|
mov temp, #1 wc, wz ' Set C=0 and Z=0 for "greater than"
|
||
|
|
||
|
StringCompare_ret
|
||
|
ret
|
||
|
|
||
|
temp res 1
|
||
|
temp1 res 1
|
||
|
ptr res 1
|
||
|
pLeft res 1
|
||
|
pRight res 1
|
||
|
pString res 1
|
||
|
pTable res 1
|
||
|
pInput res 1
|
||
|
pOutput res 1
|
||
|
pSync res 1
|
||
|
retval res 1
|
||
|
|
||
|
{{
|
||
|
Copyright (c) 2009 Michael Park
|
||
|
+------------------------------------------------------------------------------------------------------------------------------+
|
||
|
| TERMS OF USE: MIT License |
|
||
|
+------------------------------------------------------------------------------------------------------------------------------+
|
||
|
|Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
|
||
|
|files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
|
||
|
|modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
|
||
|
|is furnished to do so, subject to the following conditions: |
|
||
|
| |
|
||
|
|The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
|
||
|
| |
|
||
|
|THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
||
|
|WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
||
|
|COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|
||
|
|ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
||
|
+------------------------------------------------------------------------------------------------------------------------------+
|
||
|
}}
|
||
|
|
||
|
|