Subj : Baja arrays
To   : All
From : U. CraZy Diamond
Date : Sat Jul 10 1999 12:12 pm

Okay, folks, here it is!
Did some digging and came up with this post from yesteryear FYI:


Subj : Baja Arrays?
To   : All
From : Angus McLeod (VERT/ANJO)
Date : Mon Dec 02 1996 01:57 am AST

Until DM comes out of hibernation, we are stuck with Sync's PCMS
(Programmable Command & Menu System) at it's present state of the
art, and have to live with the fact that improvements (like arrays)
are simply not possible until then.  Right?

Well...  maybe!

Notice I spoke of the PCMS and _didn't_ say "Baja".  Baja is a
programming language which is compiled by the BAJA.EXE compiler
into a Synchronet .BINary file.  In fact, it's closer to an
assembler than a compiler.  The point being, there is nothing to
prevent some _other_ compiler being written for a totally different
language, like PL/S (Programming Language/Smeg).  PL/S can be as
sophisticated as we like.  So long as the PL/S compiler generates
valid .BIN files, then the PL/S programs will run.

PL/S might easily parse statements like:

   offset = ((rec_no - 1) * rec_size) + field_offset

and translate this to:

   opy offset rec_no
   sub offset 1
   mul offset rec_size
   add offset field_offset

or more correctly, direct into the corresponding binary and written
straight to the .BIN file.  Nothing wonderful about this - compilers
have been doing this since Backus gave us FORTRAN in 1956.

What about:

   function My_Func ( str local_str ) returns int
       local_int result
       ...
       return result
       end_function

   ...

   result = My_Func ( some_str )

being translated to:

   # declare function
   goto skip.My_Func
   :My_Func
       # declare arguments, return value and locals
       str My_Func.local_str
       int My_Func.result My_Func.return_val
       # do whatever
       ...
       # return
       copy My_Func.return_val My_Func.result
       return
       :skip.My_Func

   ...

   # call function, copying arguments in and return value out
   copy My_Func.local_str some_str
   call My_Func
   copy result My_Func.return_al

A compiler that would allow the first notation instead of forcing us
to use the second would be some considerable convenience.

But so far, our proposed PL/S compiler gives us only the notational
conveniences of expressing calculations in infix notation, or
cleaning up function definition and call.  But that does not actually
give us the power to do anything new! So what about those arrays?

Well suppose the PL/S compiler interprets:

   int My_Array[10]

to mean:

   int My_Array.1 My_Array.2 My_Array.3 ... My_Array.10

(which Baja will compile for us today) and generates ten
appropriately named integer variables for us.  That looks like a good
start.  But how would we actually ACCESS a particular variable at RUN-
TIME?  If the indexes were known at compile-time it would be easy, but
we want to access the array with indexes that are not known until run-
time.

Suppose it were possible, even if it were very ugly, then we would be
in the home stretch.  Because our PL/Scompiler would hide the ugliness
from us.

Please observe the following code, which I hope is simple enough to be
self-explanatory:

   ------[TSTARRAY.SRC]------------
   # declare Pseudo-"array" and cursor variable
   global_int Array.1 Array.2 Array.3 Cursor

   # declare loop counter
   int loop

   # stuff some data into our "array"
   set Array.1 10101
   set Array.2 22002
   set Array.3 30033

   # access each element by NAME
   set loop 1
   :next_element
       # the next two lines are the ugly ones!
       sprintf str "Cursor Array.%ld" loop
       exec *getint
       # we now have the array element value in the cursor!
       printf "the value of Array.%ld = %ld\r\n" loop Cursor

       add loop 1
       compare loop 3
       if_less_or_equal
           goto next_element
       end_if

   # wait for a screen-capture
   pause
   --------------------------------

Observe that the array has been declared as GLOBAL, as has the
"cursor variable used to access the values in this array.  If we were
using PL/S, it might declare our cursor variable(s) behind the scenes
for us, concealing from us the very necessity for a cursor variable.

Also observe the two key lines here, the SPRINTF which specifies the
destination and source variables _by name_ and the EXEC which calls a
Magic Module.  And here is the output captured from my screen:

 � Main � 0:02:04 [4] DOVE-Net [13] Sync Programming: ;EXEC *TSTARRAY
 the value of Array.1 = 10101
 the value of Array.2 = 22002
 the value of Array.3 = 30033
 [Hit a key] �

Obviously, we have been able to access the values in the array
elements!  Writing to these elements would require only the reversal of
the order of the variable names in the SPRINTF statement.  Note that
PL/S could have coded our "getint" module as a subroutine at the end of
our TSTARRAY program or even embedded the code inline.

Here for the strong-of-stomach is the nasty, nasty, Magic Module:

   ------[GTINT.SRC]------------
   !include FILE_IO.INC

   # declare some variables
   int argc dest32 source32 handle glob_int glob_str copy_int
   str tmp dest source

   # define some BAJA op-codes
   set glob_int 3711
   set glob_str 3455
   set copy_int 9343

   # set name of source and destination
   # variables to null-strings
   set source ""
   set dest ""

   # extract variable names from command string
   # (stolen piece-meal from QNET.SRC)
   set argc 0
   :process_args
   compare_str ""
   if_true
       goto end_args
       end_if
   sprintf tmp "%.1s" str
   shift_str 1
   compare tmp " "
   if_true
       add argc 1
       goto process_args
       end_if
   switch argc
       case 0
           strcat dest tmp
           end_case
       case 1
           strcat source tmp
           end_case
       default
           goto end_args
       end_switch
   goto process_args
   :end_args

   # THIS is the interesting part!    # make uppercase and find out the CRC32 of variables
   strupr source
   crc32 source32 source
   strupr dest
   crc32 dest32 dest

   #open .BIN file for writing
   fopen handle O_WRONLY+O_CREAT+O_TRUNC "%!otf%#.bin"
   if_true
       fwrite handle glob_int 2
       fwrite handle source32 4
       fwrite handle glob_int 2
       fwrite handle dest32   4
       fwrite handle copy_int 2
       fwrite handle dest32   4
       fwrite handle source32 4
       fflush handle
       fclose handle
       exec_bin "otf%#"
   end_if
   ------------------------------

What this module basically does is create a .BIN file on-the-fly and
then immediately execute it.  It will copy an GLOBAL_INT to any other
GLOBAL_INT but it does so _by name_ allowing the name to change at run-
time thus giving access to "array" elements.  Notice that a large part
of this would not be needed if we placed the code as a subroutine in
our main module or embedded the relevant parts "inline" ince we would
not have to parse the variable names.

The BAJA program we create on the fly is the following two-liner:

   global_int <source_name> <dest_name>
   copy <dest_name> <source_name>

but it is created directly as a .BIN file (no source ever exists).
For string elements, only a minor change us needed.  Yes, I know it's
ugly, and slow and 'orrible, but it's interesting.

So,  Smeg!  Get to work on PL/S right away!  Or we'll change the name
to Programming Language/Synchronet... :)

Seriously, I am interested in any comments on the academic or practical
aspects of developing a new language translator as a replacement for
the venerable BAJA compiler.  The objective of any such efforts being
to make programming for Synchronet easier, by means of notational
conveniences not available in BAJA, and if/when possible, by the
introduction of new features.

+---
� Synchronet � The ANJO BBS � Barbados � (246) 435-2235



   ...and in a nutshell, that's it.  :)


---
� Synchronet � ��� The Serial Port ��� �807�547�2134