Sx ( was: Ideas about enhancements to fileobjects )

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Tue, 23 Nov 1993 12:01:57 -0500

On Nov 23, 11:02, jredford@lehman.com wrote:
>
> >> Eh, not everybody on the list may know what you mean. I presume with
> >> M3 you mean Modula-3. But what is Sx?
>
> Yes, Modula-3. Sx is the Symbolic expression interface. it can read:
> (2, [3,4], (1,'foo','bar'))
> as plain text, and convert it to a List.T containing elements pointing
> to an INTEGER, an ARRAY, and another List.T. Additionally you can
> define tokens which are converted to something pre-defined:
>
> (Text "quit") -> List.T -> 4 (* Assuming 'Text' was bound to integer 4 *)
> |
> List.T -> "quit"
>
> This is what the SRC-Modula-3 compiler uses to parse Modula-3 code.
> FormsVBT also uses this interface. It seems like it would be easy
> enough to do in Python, and it would provide a good generic parser.
>

Well, you can already do the first part with 'eval'.

If I'm preparing a data file specifically for python ( a rare event, I
admit ) I often use something (exactly) like:

( 'NaCl', 'Na-Cl', (( 'Na', 1, 265009.09 ), ( 'Cl', 1, 400633.12 )))
#( 'NaClref.1', 'Na-Cl', (( 'Na', 1,2855556.75 ), ( 'Cl', 1,3901121.25 )))
( 'Al2SO4', 'Al2-(S-O4)3', (( 'Al', 2, 162266.12 ), ( 'S', 3, 216014.30 )))
( 'Ca2SO4', 'Ca-S-O4', (( 'Ca', 1, 117697.49 ), ( 'S', 1, 79024.09 )))
( 'CaCl2', 'Ca-Cl2', (( 'Ca', 1, 100187.59 ), ( 'Cl', 2, 136969.91 )))
( 'CaSO4ref.1', 'Ca-C-O4', (( 'Ca', 1, 395892.78 ), ( 'S', 1, 286905.53 )))
#( 'KCl', 'K-Cl', (( 'K', 1, 442115.34 ), ( 'Cl', 1, 390104.62 )))
( 'KClref.1', 'K-Cl', (( 'K', 1, 127577.69 ), ( 'Cl', 1, 103768.53 )))
( 'KH2PO4', 'K-H2-P-O4', (( 'K', 1, 705903.81 ), ( 'P', 1, 561341.06 )))
( 'KH2PO4ref.1','K-H2-P-O4', (( 'K', 1, 328863.38 ), ( 'P', 1, 274755.06 )))
( 'MgCl2', 'Mg-Cl2', (( 'Mg', 1, 56007.41 ), ( 'Cl', 2, 118563.66 )))
( 'MgCl2ref.1', 'Mg-Cl2', (( 'Mg', 1, 292367.59 ), ( 'Cl', 2, 602392.81 )))
( 'MgSO4_ref', 'Mg-S-O4', (( 'Mg', 1, 13198.88 ), ( 'S', 1, 15590.63 )))
( 'Na2SO4', 'Na2-S-O4', (( 'Na', 2, 265931.09 ), ( 'S', 1, 161030.58 )))
( 'Na2SO4ref.1','Na2-S-O4', (( 'Na', 2, 480462.41 ), ( 'S', 1, 275711.53 )))
#( 'Na4P2O7', 'Na4-P2-O7', (( 'Na', 4, 510323.47 ), ( 'P', 2, 313325.44 )))
( 'Na4P2O7ref.1','Na4-P2-O7', (( 'Na', 4, 404343.19 ), ( 'P', 2, 288411.31 )))

You can read each non-comment line in with eval(file.readline()).
I use the following module to read it in. ( I don't think I would
do it quite the same way now. This was one of the first python modules
I ever wrote. ) And it would be better if it handled multi-line
statements, and more generalized handling of comments, but I was't
worried about that at the time.

feval( file-object_or_filename-string ) reads a line and returns
the evaluated object or a comment string ( or on error, a tuple
describing the error. )
getlist( filename ) returns the list constructed from feval-ing
every line in the file ( leaving out the comment lines )

The return values are a bit too kludgey for general purpose use -
Maybe now that I've dug this out, I'll try to write a better one.

#! /usr/local/python
# (no main - not executable - above is just there for unix 'file' cmd )
#
# feval( file )
# evaluates a line from file
# Intended for loading python formatted data from a file
# Will not work for expressions longer than a line.
#

from string import strip
import sys

def feval( File ):
if type(File) == type('') : File = open(File,'r')
try:
line = File.readline()
if line == '' :
return line
if strip(line)[:1] == '#' : return strip(line)
return eval( strip( line ))
except EOFError:
return EOFError
except ( TypeError,NameError,RuntimeError), what:
return ( sys.last_type, what, strip(line))

def getlist(filename):
b = open( filename, 'r' )
N = []
while 1:
x = feval( b )
if x == '' :
break
elif ((type(x) == type('')) and (x[:1] == '#')) :
pass
else:
N.append( x )
b.close()
return N

Keywords can be implemented by putting the in a dictionary object,
and passing that to eval:

>>>eval( 'tok + 1', { 'tok':1 } )
2

Now that there is also exec, one could use that to build a local
scope in which to define the tokens/keywords.

This suggests a more generalized facility:
for the file:
exec all statements in a new local scope
print all comments ( ? maybe )
eval and append all non-assigned non-voids to a list ( but don't print )
throw away the temp local scope and return the list.

- Steve Majewski (804-982-0831) <sdm7g@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics