What follows are a collection of PASM routines that I've been using while
tinkering with the assembler and parrot. Feel free to use, mutilate, add
to, discuss, mock. They are:
a tokenizer
isalpha and isspace
stack routines: sort, replace, peek, reverse
a stack dump/display
Many of the stack routines need a "magic" register set (I5) to indicate the
depth of the stack, some do not. Where needed, it's indicated. This
limitation will go away some day.
Don't make fun of the sort, it works and is reasonable for small
sorts. :) If you've got a better idea, patches welcome. There's probably
a terribly clever way to sort a stack using only a couple of registers,
push, pop, and rotate_up. I'm not that clever.
As soon as the I/O routines are GC safe and readline() takes the correct
arguments (doesn't play well with OPEN!) I might have some interesting code
to show these off. I should probably fix the XML pseudo-Parser to use this
improved tokenizer. Hrm.. Sample usage:
set S10, "10 PRINT 'HELLO WORLD'"
bsr TOKENIZER
restore I5
bsr REVERSESTACK
restore S1 # Line number
dec I5 # Stack depth counting. Grrr..
restore S2 # Keyword (print)
dec I5
restore S3 # Arg ('hello world')
dec i5
# etc...
end
[I'm not subscribed to p6i, but catch it in archives. CC
[EMAIL PROTECTED] if it's important]
# tokenizer
# Input: string to be parsed on the stack (will be removed)
# Output: stack contains number of tokens first,
# then the tokens as seen right to left
# Quotes (single or double) are *preserved* so that
# Foo "bar hlaghalg"
# is two tokens, and the second is "bar hlaghalg"
#
TOKENIZER:
pushi
pushs
set I6, 0 # Inquote
set I7, 0 # ALPHA
restore S10 # String to tokenize
set I5, 0 # Stack pointer
set S9, "" # Playground
TOKLOOP: length I0, S10
eq I0, 0, ENDTOK
substr S1, S10, 0, 1
dec I0
substr S10, S10, 1, I0
eq S1, "'", QUOTE
eq S1, '"', QUOTE
branch CKQUOTED
QUOTE: ne I6, 0, EOTOK
set I6, 1
set S9, S1
branch TOKLOOP
EOTOK: set I6, 0
concat S9, S1
save S9
inc I5
set S9, ""
branch TOKLOOP
CKQUOTED:
eq I6, 0, NOTQUOTED
concat S9, S1
branch TOKLOOP
NOTQUOTED:
save S1
bsr ISWHITE
restore I2
ne I2, 1, NOTSPACE # Spaces will end a token
length I0, S9
eq I0, 0, TOKLOOP
save S9
inc I5
set S9, ""
branch TOKLOOP
NOTSPACE:
save S1
bsr ISALPHA
restore I0
length I1, S9
ne I1, 0, NOTEMPTY
set S9, S1
set I7, I0
branch TOKLOOP
NOTEMPTY:
ne I0, I7, TOKCHANGED
concat S9, S1
branch TOKLOOP
TOKCHANGED:
save S9
inc I5
set S9, S1
set I7, I0
branch TOKLOOP
ENDTOK: length I0, S9
eq I0, 0, TOKBAIL
save S9
inc I5
TOKBAIL:save I5
popi
pops
ret
# User Stack Dump (Debugging.)
# ** I5 should contain the stack depth,
# ** until I get some method of determining depth
# Types
# 1 is an int
# 2 is a num
# 3 is a string
# 4 is a PMC
DUMPSTACK:
pushi
pushn
pushs
pushp
print "Stack Dump: (top to bottom)\n"
set I0, I5
gt I5, 0, DUMPLOOP
print " -empty-\n"
branch DUMPEND
DUMPLOOP:
entrytype I1, 0
print " "
sub I2, I5, I0
print I2
print " "
ne I1, 1, DUMPNOTINT
print "Int "
restore I1
save I1
print I1
branch DUMPANOTHER
DUMPNOTINT:
ne I1, 2, DUMPNOTNUM
print "Num "
restore N0
save N0
print N0
branch DUMPANOTHER
DUMPNOTNUM:
ne I1, 3, DUMPNOTSTRING
print "Str "
restore S1
save S1
print S1
branch DUMPANOTHER
DUMPNOTSTRING:
ne I1, 4, DUMPERR
print "PMC "
restore P0
save P0
print P0
branch DUMPANOTHER
DUMPANOTHER:
print "\n"
rotate_up I5
dec I0
eq I0, 0, DUMPEND
branch DUMPLOOP
DUMPEND:
popi
popn
pops
popp
ret
DUMPERR:
print "UNKNOWN TYPE\n"
end
# Stack Library
# This'll get a whole lot cleaner when I can tell the
# depth of the stack automagically
# peek -- return whatever string is on the stack
# Inputs: the offset on the stack
# Outputs: the string
# Non-Destructive!
# Does *not* test for bounds conditions
PEEK: pushi
restore I0
set I3, I0
inc I0
set I2 0
PLOOP: ge I2, I3, POL
rotate_up I0
inc I2
branch PLOOP
POL:
restore S0
save S0
eq I0, 0, EOP
rotate_up I0
EOP: save S0
popi
ret
# REPLACE -- replace thing at stack position X
# Inputs: the offset to remove
# Outputs: the string to leave in its place
# Note: Almost *identical* to PEEK above
# Does *not* test for bounds conditions
REPLACE: pushi
pushs
restore S1
restore I0
set I3, I0
inc I0
set I2, 0
RLOOP: ge I2, I3, ROL
rotate_up I0
inc I2
branch RLOOP
ROL: restore S0
save S1
eq I0, 0, ENDOFREPLACE
rotate_up I0
ENDOFREPLACE:
save S0
popi
pops
ret
# swap -- swap the position of two strings on the stack
# Inputs: Offsets of the two things on the stack
# Outputs: None.
SWAP: pushi
pushs
restore I0
restore I1
save I0
save "-" # Just a dummy
bsr REPLACE
restore S0
save I1
save S0
bsr REPLACE
restore S1
save I0
save S1
bsr REPLACE
restore S1 # dummy
popi
pops
ret
# Sort whatever's on the stack.
# Yes, this is a bubble sort. Get over it.
# Inputs: I5 *must* be set to the stack depth
# Outputs: None
#
SORTSTACK:
pushi
pushn
pushs
set I0, 0
set I1, 0
BUBBLE: inc I1
le I1, I0, BUB1
set I1, 0
inc I0
BUB1: ge I0, I5, SORTEND
save I1
bsr PEEK
restore S2
save I0
bsr PEEK
restore S3
le S2, S3, BUBBLE
save I1
save I0
bsr SWAP
branch BUBBLE
SORTEND:
popi
popn
pops
ret
# Reverse the stack
# Inputs: I5 *must* be set to the stack depth
# Outputs: None
REVERSESTACK:
pushi
set I0, I5
REVSHIFT:
eq I0, 0, REVERSEEND
rotate_up I0
dec I0
branch REVSHIFT
REVERSEEND:
popi
ret
# Test for alphabeticness (7-bit ASCII only)
# Input: (1-char) String on stack (will be removed)
# Output: 0 or 1 (integer) on stack
# Ex: save "<"
# bsr ISALPHA
# restore I2 # False!
#
ISALPHA:
pushi
pushs
restore S1
ge S1, "A", UPPER
branch NONUP
UPPER: le S1, "Z", ALPHA
NONUP:
ge S1, "a", LOWER
branch NONLOW
LOWER: le S1, "z", ALPHA
NONLOW:
ge S1, "0", NUMBER
branch NONUM
NUMBER: le S1, "9", ALPHA
NONUM: eq S1, "_", ALPHA
# Not A-Z0-9_
set I1, 0
branch LEAVE_ISALPHA
ALPHA: set I1, 1
LEAVE_ISALPHA:
save I1
popi
pops
ret
# Test for whitespace (tab, space, newline)
# Input: (1-char) String on stack (will be removed)
# Output: 0 or 1 (integer) on stack
ISWHITE:
pushi
pushs
set I1, 1
restore S1
eq S1, " ", LEAVEWHITE
eq S1, "\n", LEAVEWHITE
eq S1, "\t", LEAVEWHITE
set I1, 0
LEAVEWHITE:
save I1
popi
pops
ret