1. More usefuls for Euphoria
(Continued from previous message)
In stack.e, I've taken advantage of Euphoria's scope rules. A
small amount of testing revealed that if stack.e was included
in another program, even a bound/shrouded one, the variable
stacks would be accessible only to the procedures in stack.e,
and not to anything else - and if I defined another variable
stacks elsewhere in the program, the stack procedures would
happily ignore it, and use the one that I intended. Very nice,
Robert.
Also, Robert - Could your master's thesis be made available to
interested Euphoria programmers? I'd like to (at least try) to
understand your thought processes; I think that ultimately it
will make me a better analyst/programmer.
=========================================================================
Jeff Zeitlin jeff.zeitlin at execnet.com
---
~ OLXWin 1.00b ~ I hate this tagline. I really do. LOATHE!
2. More usefuls for Euphoria
... as promised ...
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-- associative lists
-- an associative list is implemented as a sequence that contains sequences;
-- each sequence is a key/value pair: {{key,value},{key,value},...}.
-- keys and values may be any valid Euphoria object.
include stddefs.e -- need errorexit function
constant alist_key = 1
constant alist_value = 2
-- an associative list is either an empty sequence, or one where each element
-- other than the first is a {key,value} pair. The first element is a
-- sequence with one member, the default value
-- the following types and procedures are supplied:
-- the type assoc_list
-- alist = alist_set(assoc_list alist, object key, object value)
-- returns an association list with the indicated {key,value} pair.
-- Adds a new pair if the key value isn't already in the list; changes
-- the value of an existing pair if it is. If no default is set, sets
-- the default to an empty sequence.
-- obj = alist_reference(assoc_list alist, object key)
-- returns the value stored in the association list pair with the
-- supplied key. If the key is not in the list, returns the default
-- value for the list. If no default has ever been set, the default is
-- an empty sequence.
-- alist = alist_default(assoc_list list, object default)
-- sets the default value for alist_reference to return for non-existent
-- keys.
global type assoc_list(sequence s)
if length(s) = 0 then -- empty list
return 1 -- yes, it is - and therefore valid
end if
if length(s[1]) != 1 then -- default value properly stored?
return 0 -- no, fail type check.
end if
if length(s) > 1 then
for i = 2 to length(s) do
if length(s[i]) != 2 then -- is it a {key, value}?
return 0 -- no, it's not, so fail type-check
end if
end for
end if
return 1 -- yes, it's a valid alist.
end type
global function alist_default(assoc_list list, object defval)
assoc_list newlist
if length(list) = 0 then
newlist = {{defval}}
else
newlist[1] = {defval}
end if
return newlist
end function
global function alist_set(assoc_list list, object key, object val)
-- sets a {key,value} pair.
-- changes an existing value, or adds a new pair for a nonexistent key
-- stored in sorted order by key to improve retrieval time.
-- Also sets the default value to null if the default is not already set.
assoc_list newlist
integer index
integer len
index = 1
newlist = list
len = length(newlist)
if len = 0 then
newlist = {{{}}} -- equivalent to alist_default({},{})
elsif length(newlist[1]) = 2 then
newlist = prepend(newlist,{{}})
end if
while compare(list[index][alist_key], key) = -1 do
index = index + 1 -- bypass all "lesser" keys
end while
if compare(list[index][alist_key],key) = 0 then
newlist[index][alist_value] = val -- change val for existing key
else -- add a new key
newlist = append(newlist[1..index-1],{key,value}) & newlist[index..len]
end if
return newlist
end function
global function alist_reference(assoc_list list, object key)
-- search the association list via a binary search.
-- if we end up checking element 1 of the list, then the key value is
-- not found, and we return the default value.
integer index
integer interval
integer comp
if length(list) = 0 then
return {}
end if
interval = floor(length(list)/2)
index = interval
while interval > 0 do
interval = floor(interval / 2)
comp = compare(list[index][alist_key],key)
if comp = 0 then -- found the key
return list[index][alist_value]
else
index = index - (comp * interval)
-- comp is -1 if the viewed key is less than the desired
-- key, so we have to *increase* the index to look farther
-- "down" the array. Subtracting a negative number is
-- equivalent to adding. Comp is 1 if the viewed key is
-- greater than the desired key.
if index = 1 then -- the desired key is less than any key in list
return list[1][1] -- the default value
end if
end if
end while
return list[1][1] -- we haven't ended up on index 1, but we still
-- haven't found the key, and we can't search any more,
-- so return the default.
end function
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-- stack.e
-- by Jeff Zeitlin (jeff.zeitlin at execnet.com)
-- implements a stack type for Euphoria with proper syntax.
-- stack s
-- declares the type stack, and checks to see if it is initialized
-- stack s
-- s = init()
-- creates a new stack, returns a "handle" to be used to refer to this
-- stack hereafter.
-- push(stack s, object o)
-- puts object o on the top of stack s
-- object o
-- o = pop(stack s)
-- takes object off top of stack s, and returns it.
-- boolean/integer b
-- b = empty(stack s)
-- returns TRUE (1) if there are no objects on stack s, FALSE (0) otherwise
-- clear(stack s)
-- makes existing stack s empty, discarding all information on it.
-- private procedures and variables
procedure errorexit(integer code, sequence message)
printf(2,"%s",{message})
abort(code)
end procedure
sequence stacks
stacks = {}
-- public interface
global type stack(integer s)
return s <= length(stacks)
end type
global function init()
stacks = append(stacks,{})
return length(stacks)
end function
global procedure push(stack s, object o)
stack[s] = append(stack[s], o)
end procedure
global function empty(stack s)
return length(stacks[s]) = 0
end function
global function pop(stack s)
object val
if empty(s) then
errorexit(1,"stack underflow error\n")
end if
val = stacks[s][length(stacks[s])]
stacks[s] = stacks[s][1..length(stacks[s])-1]
return val
end function
global procedure clear(stack s)
stacks[s] = {}
end procedure
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
(Continued to next message)
---
~ OLXWin 1.00b ~ I hate this tagline. I really do. LOATHE!
3. More usefuls for Euphoria
- Posted by Robert Craig <robert_craig at COMPUSERVE.COM>
Mar 09, 1997
-
Last edited Mar 10, 1997
Thanks Jeff for all the fascinating code you've posted -
I'll put it on the Web page.
> Also, Robert - Could your master's thesis be made available to
> interested Euphoria programmers? I'd like to (at least try) to
> understand your thought processes; I think that ultimately it
> will make me a better analyst/programmer.
Believe it or not, there's no machine-readable copy of my
thesis. There's a bound copy collecting dust on my book shelf,
and the University of Toronto has a couple of bound copies
somewhere.
If you can find some information on the "FP" language by
John Backus, you'll see where I got the idea for atoms and
sequences. Euphoria has deviated a lot from FP however.
For example, in FP a string is a kind of atom, whereas in Euphoria
it's a sequence of characters. Also FP does *everything* via
expressions. It has no statements. A program is one big complicated
expression. I found FP programs to be very hard to read, but I
liked the idea of atoms and sequences.
As part of my thesis I implemented an interpreter for FP. It was
very simple and elegant but extremely slow.
Regards,
Rob Craig
Rapid Deployment Software