[comp.lang.modula2] Clever way to deal with this?

MARK@UCF1VM.BITNET (Mark Woodruff) (02/12/90)

Anyone know of a clever way to express this in Modula-2?

I have a data structure consisting of a cardinal value followed by a
variable number of characters.  The cardinal indicates how many characters
follow.

How would you express this in Modula-2?

mark
-------
Bitnet:  MARK@UCF1VM.BITNET
Internet:  mark@mamab.FIDONET.ORG
UUCP:  uunet!tarpit!libcmp!mamab!mark
Fidonet:  mark at 1:363/9.0

HJ647C@GWUVM.BITNET (Pete Davis) (02/13/90)

  Mark, it sounds like you're going to need to make it a variable length
dynamic structure. You'd have to have routines to allocate variable sized
spaces in memory, kind of the equivilent of Turbo Pascals GETMEM and FREEMEM.
As I'm just starting to get into Modula-2, I can't give you anything real
specific right now. Sorry.

                                           _Pete Davis
                                           BitNet: HJ647C at GWUVM
                                           FidoNet: Pete Davis @ 1:109/138

UK4H@DKAUNI2.BITNET ("JAE ", Juergen A. Erhard) (02/13/90)

mark wrote:
{ lines DO taste fine, ya know. }
> I have a data structure consisting of a cardinal value followed by a
> variable number of characters.  The cardinal indicates how many characters
> follow.
>
> How would you express this in Modula-2?
How DO you express that in, say, C. Or some other language (not a 4GL,
OC)
What I like to know is: Are you porting a program from another language
to M2, or did you devise such a struct out of thin air?
Anyway you want it, M2 is not the ideal language for such a struct.
Some way (a kludge, to be honest) would be:

  type mytype=record
                numOfChars:CARDINAL;
                chars:POINTER TO ARRAY <0..Max> OF CHAR;
              end;

Two notes:
  1. The idea behind the whole thing is to Storage.ALLOCATE() (or some
     such) as much memory as needed to hold all chars. This would mean
     you have to do all ALLOCATE'ING/DEALLOCATE'ING by 'hand'.
  2. Set square brackets for < and > (I'm sittin' in front of a grubby
     old IBM 3278 (sucks!), and it doesn't give me no squares...)
     Also set Max and mytype to your choice...

Another way (but still kludge, and in some way more, in another less
awkward than the first)

  type mytype2=record
                 numOfChars:CARDINAL;
                 chars:ARRAY <0..Max> OF CHAR;
               end;

Again, replace <,> and Max, mytype2...
Note: This needs no great care, BUT (there's always a BUT to everything,
it seems) it needs the same fixed amount of storage all the time, no
matter how much of it is used.

Of course, the latter is more of a kludge: it's nonsense. Except if
you absolutely need it (some OS'es are sooo demanding...). Why?
Well, M2 has (limited...) support for strings. But you can look up
the string support of M2 in any good M2 reference... (guess I wasted
enough net bandwidth already...)
> mark
> -------
> Internet:  mark@mamab.FIDONET.ORG
> UUCP:  uunet!tarpit!libcmp!mamab!mark
> Fidonet:  mark at 1:363/9.0

                                          -jae

========================================================================
Juergen A. Erhard
eMail: uk4h@dkauni2.bitnet
phone: (+49) 721/591602
"You know that it's monday when you wake up and it's tuesday."
                                                    Garfield
DISCLAIMER: none, I don't speak legalese.

MARK@UCF1VM.BITNET (Mark Woodruff) (02/13/90)

In article <"90-02-12-20:09:32.76*UK4H"@DKAUNI2.BITNET>,
"JAE (Juergen A. Erhard)" <UK4H@DKAUNI2.BITNET> says:

>mark wrote:

>> I have a data structure consisting of a cardinal value followed by a
>> variable number of characters.  The cardinal indicates how many
>> characters follow.
>>
>> How would you express this in Modula-2?

>How DO you express that in, say, C. Or some other language (not a 4GL,
>OC)

Let's assume I want to print the characters in my buffer and that
the number of characters run from one to MAX(CARDINAL):

In 370 Assembly, I'd say:

             LH    2,COUNT
             LA    3,TEXT
             WRTERM (3),(R2)
    *
    BUFFER   DSECT ,
    COUNT    DS    H
    TEXT     DS    C

In C, I'd say:

    struct
    {
         int count;
         char c;
    } buffer;

    for (i = 0; i <= count; i++)
    {
         putchar(&buffer.c+i);
    }

In Smalltalk, I'd just create a class with count as an instance
variable with byteIndexedInstanceVariables for the characters.

In Modula-2, I said:

    TYPE
       BuffType =
          RECORD
             count:  CARDINAL;
             text:  CHAR;
          END;

    VAR
       buffer:  BuffType;
       i:  CARDINAL;
       charPtr:  POINTER TO CHAR;

    BEGIN
       FOR i := 0 TO buffer.count DO
          charPtr := SYSTEM.ADDRESS(buffer.text)+i;
          InOut.Write(charPtr@)
       END;
    END;

(note:  I haven't actually tried to write this in assembly or C
and I don't have my Modula-2 code at hand, so this is from memory)

I'm not thrilled with this, but it's about the best equivalent to
an equate or a pointer to a character I can get in Modula-2.

>What I like to know is: Are you porting a program from another language
>to M2, or did you devise such a struct out of thin air?

I'm using this representation to represent buffers in an editor.
The actual characters are fixed in length, but the length is entirely
determined at run time.

This arrangement is also the same as variable blocked records on
standard labeled tapes.

>Anyway you want it, M2 is not the ideal language for such a struct.
>Some way (a kludge, to be honest) would be:
>
>  type mytype=record
>                numOfChars:CARDINAL;
>                chars:POINTER TO ARRAY <0..Max> OF CHAR;
>              end;
>
>Two notes:
>  1. The idea behind the whole thing is to Storage.ALLOCATE() (or some
>     such) as much memory as needed to hold all chars. This would mean
>     you have to do all ALLOCATE'ING/DEALLOCATE'ING by 'hand'.
>  2. Set square brackets for < and > (I'm sittin' in front of a grubby
>     old IBM 3278 (sucks!), and it doesn't give me no squares...)
>     Also set Max and mytype to your choice...

By the way, you can get brackets on almost any 3270 terminal by
setting the right input and output translations.  Send me mail
if you want more info.
>
>Juergen A. Erhard

mark
-------
Bitnet:  MARK@UCF1VM.BITNET
Internet:  mark@mamab.FIDONET.ORG
UUCP:  uunet!tarpit!libcmp!mamab!mark
Fidonet:  mark at 1:363/9.0

bailey%candide@GARGOYLE.UCHICAGO.EDU (Stephen Wilson Bailey) (02/13/90)

TYPE
  BufType = RECORD
    length: CARDINAL;
    data: ARRAY [0..MAX(CARDINAL)] OF CHAR;
  END;
  BufPtrType = POINTER TO BufType;

VAR
  mybuf: BufPtrType;

(*
 * Somewhere in this code you either malloc
 *  the buffer, or cast something to it.
 *)
    .
    .
    .
  PrintBuffer(mybuf);
    .
    .
    .

PROCEDURE PrintBuffer(bptr: BufPtrType);
VAR curchar: CARDINAL;
BEGIN
  FOR curchar := 0 TO bptr^.length DO
    Write(bptr^.data[i]);
  END;
END;


--------------------------------------
If you don't trust your compiler to optimize away the
de-reference, using ``WITH bptr^ DO'' will usually
force the issue ('though not always.  Personally, I leave it
up to the compiler).

You're right, it isn't handled as well as it could be.
The WRL Modula-2 includes a ``flexible array'' extension for
just this purpose.  I assume Modula-3 has a comparable notion.

Steph

MARK@ECNCDC.BITNET (02/13/90)

I'm not sure this will work, because I have never tried it myself in
a language like Modula-2, but I think that this (or very close to
this) will take care of your problem for you:

TYPE
    pRec = POINTER TO Rec;
    Rec = RECORD
        NumChars : CARDINAL;
        Chars : ARRAY [ 0..MAX( CARDINAL ) ] OF CHAR;
    END;

VAR
  Data : pRec;
  Num : CARDINAL;

BEGIN
    Num = { Some cardinal number };
    ALLOCATE( pRec, SIZE( Num ) + Num );   (*  assuming CHARs are 1 byte *)
 ... etc.

You have to be careful not to do the following:
1)  Don't have Rec as the type of any parameter, but always access
    it through the dereferencing of the pointer.
2)  Don't rely on ANY Modula-2 string procedures, but always use
    NumChars for the integrity check.

Hope this works for you,

Mark Morrell
Software Specialist
Western Illinois University

MARK @ ECNCDC

cmp8118@sys.uea.ac.uk (D.S. Cartwright) (02/13/90)

MARK@UCF1VM.BITNET (Mark Woodruff) writes:

>Anyone know of a clever way to express this in Modula-2?

>I have a data structure consisting of a cardinal value followed by a
>variable number of characters.  The cardinal indicates how many characters
>follow.

Well, how about some sort of RECORD structure thus :

	TYPE
		VarString : POINTER TO CHAR ;

		DataStructure : RECORD
				 NoOfChars : CARDINAL ;
				 Chars     : VarString ;
				END (* RECORD *) ;

	You could then knock up some little routine to handle the creation
and general all-round handling of the linked list of characters without too
much hassle, and all should [!!!! }:^)] be hunky-dory.

		Dave C, SYS II, UEA, Norwich.

rxg3321@ultb.isc.rit.edu (R.X. Getter) (02/14/90)

In article <90043.054652MARK@UCF1VM.BITNET> Modula2 List <INFO-M2%UCF1VM.BITNET@PSUVM.PSU.EDU> writes:
>Anyone know of a clever way to express this in Modula-2?
>
>I have a data structure consisting of a cardinal value followed by a
>variable number of characters.  The cardinal indicates how many characters
>follow.

you need a linked list of characters to handle this.

TYPE
	string = RECORD
			numChars : CARDINAL;
			text     : POINTER TO Node;
	END;

	Node = RECORD
			char : CHAR;
			next : POINTER TO Node;
	END;

you will also need a bunch of utility procedures for manipulating this.
also, the cardinal value isn't really needed unless you're using it as
a reference. What are you doing? the only things I have ever seen which
use a structure like this are basic interpreters. that's how they 
do strings.

no sig yet,

	Robert Getter

TRL3@psuvm.psu.edu (Tim Larson) (02/14/90)

In article <90043.154337MARK@UCF1VM.BITNET>, MARK@UCF1VM.BITNET (Mark Woodruff)
says:
>In C, I'd say:
>
>    struct
>    {
>         int count;
>         char c;
>    } buffer;
>
>    for (i = 0; i <= count; i++)
>    {
>         putchar(&buffer.c+i);
>    }
>
>In Modula-2, I said:
>
>    TYPE
>       BuffType =
>          RECORD
>             count:  CARDINAL;
>             text:  CHAR;
>          END;
>
>    VAR
>       buffer:  BuffType;
>       i:  CARDINAL;
>       charPtr:  POINTER TO CHAR;
>
>    BEGIN
>       FOR i := 0 TO buffer.count DO
>          charPtr := SYSTEM.ADDRESS(buffer.text)+i;
>          InOut.Write(charPtr@)
>       END;
>    END;
>
>(note:  I haven't actually tried to write this in assembly or C
>and I don't have my Modula-2 code at hand, so this is from memory)
>
>I'm not thrilled with this, but it's about the best equivalent to
>an equate or a pointer to a character I can get in Modula-2.
>
>I'm using this representation to represent buffers in an editor.
>The actual characters are fixed in length, but the length is entirely
>determined at run time.
>
Most Modula-2 systems won't like the address arithmetic, so it would be
better to write

   TYPE
      BuffType = RECORD
         count: CARDINAL;
         text: ARRAY CARDINAL OF CHAR
      END;

   VAR
      buffer: BuffType;
      i: CARDINAL;
      charPtr: POINTER TO CHAR;

   BEGIN
      FOR i := 0 TO buffer.count DO
         charPtr := SYSTEM.ADR(buffer.text[i]);
         InOut.Write(charPtr:)
      END
   END;

This is essentially what you wrote except for the use of ADR and the use
of i as an index into buffer.text, which required a change in the type
definition.  This is according to PIM 3e Modula-2.  I'm not sure what the
upcoming standard will provide but I think JPI's M2 would be a little more
succinct

   TYPE
      bufType = RECORD
         count: CARDINAL;
         text: ARRAY CARDINAL OF CHAR
      END;

   VAR
      buffer: bufType;
      i: CARDINAL;

   BEGIN
      FOR i := 0 TO buffer.count DO
         IO.WrChar (CHAR([ADR(buffer.text[i])]:))
      END
   END ...

Not a compelling reason to buy JPI's product, perhaps, but just a touch
more elegant since it eliminates the need for the charPtr variable and
probably speeds the compiled code up the tiniest fraction.  In Modula-2,
which relies on words more than symbols, you just will never get the
bulk of this type of code down to C-size.  On the other hand, it is more
difficult to do something wrong and much easier to read.

The other way to do this (if possible) is to null-terminate the string
at location buffer.count+1 and simply use WriteString.

   TYPE
      bufType = RECORD
         count: CARDINAL;
         text: ARRAY CARDINAL OF CHAR
      END;

   VAR
      buffer: bufType;

   BEGIN
      IF buffer.count<MAX(CARDINAL) THEN buffer.text[buffer.count+1] := 0C END;
      InOut.WriteString (buffer.text)
   END ...

Hope this adds something to the discussion.

-Tim Larson
trl3@psuvm.bitnet

jensting@DIKU.DK (Jens Tingleff) (02/16/90)

In comp.lang.modula2 you write:

>Anyone know of a clever way to express this in Modula-2?

>I have a data structure consisting of a cardinal value followed by a
>variable number of characters.  The cardinal indicates how many characters
>follow.

>How would you express this in Modula-2?

>mark

Well, I would use a C-like idea (phooey), and use pointers.
Don't get me wrong, I prefer the strict checking of Modula-2 to the
do-it-all-without-a-single-warning approach of C, but a job like this
needs a little tricky code. Here goes (I Haven't tried it on a compiler
incidently):

        The data structures are allocated using ALLOCATE explicitely.

        So, to get a pointer to an area with N chars, you do

        >VAR ptr : ADDRESS;
        >ALLOCATE(ptr, N + SIZE(CARDINAL)); (* Might need TSIZE *)

        To check the number of chars stored:

        >TYPE CardPtr = POINTER TO CARDINAL;

        >VAR nelems : CARDINAL;

        >nelems := CardPtr(ptr)^ ;

        To access the n'th char

        >TYPE CharPtr = POINTER TO CHAR;
        >VAR ch : CHAR;

        >ch := CharPtr(CARDINAL(ptr) + SIZE(CARDINAL) + n)^ ;

This should work, as the ecplicit type transfer (but NOT size conversion)
of `CharPtr()' and `CardPtr()' should put the type checking system to sleep.

All this assumes that SIZE(CHAR) = 1, and that you don't hit any alignment
problems. Off course all this is just a straight translation of the
equivalent C code (which wouln't need the type transfers...).

I used the

>TYPE CharPtr = POINTER TO CHAR; VAR ptr : ADDRESS; ch : CHAR;
>
>BEGIN ptr := ....;
>  WHILE CharPtr(ptr)^ # 00C DO
>    ch := ptr^;
>    INC(CARDINAL(ptr));
>     ........

to implement a C like StringCompare(), WHAM!!   30 % speed increase for
dhrystone benchmark (on 8 bit CPM).

The more civilised way is to make an upper limit for the number of
chars, and then make a RECORD POINTER type, and NOT accessing
more than the real number of chars.. .

        >CONST  AllTheCharsINeed = 1000000;
        >TYPE VarSizeRec = RECORD cnt : CARDINAL;
        >                         elems : ARRAY [0 .. AllTheCharsINeed-1]
        >                                       OF CHAR;
        >                  END;
        >TYPE VarRecPtr = POINTER TO VarSizeRec;
        >VAR ptr : VarRecPtr;

        >  ALLOCATE(ptr, SIZE(CARDINAL) + N);   (* N actual max.        *)
        >  ch := ptr^.elems[n];                 (* Or whatever.         *)

The last has an arbitrary limit (get around this by stopping index check..).

Anyway, I always think that if you need something as sticky as variable length,
you're going to work hard to get it... .

        Jens

rxg3321@ultb.isc.rit.edu (R.X. Getter) (02/16/90)

In article <1294@sys.uea.ac.uk> cmp8118@sys.uea.ac.uk (D.S. Cartwright) writes:
>MARK@UCF1VM.BITNET (Mark Woodruff) writes:
>
>Well, how about some sort of RECORD structure thus :
>
>	TYPE
>		VarString : POINTER TO CHAR ;
>
>		DataStructure : RECORD
>				 NoOfChars : CARDINAL ;
>				 Chars     : VarString ;
>				END (* RECORD *) ;
>
>	You could then knock up some little routine to handle the creation
>and general all-round handling of the linked list of characters without too
>much hassle, and all should [!!!! }:^)] be hunky-dory.
>
>		Dave C, SYS II, UEA, Norwich.
no, this won't work, you need VarString to be a pointer to a record,
sometimes called node which contains a character and a pointer to a new
node. then you can handle this as a linked list. The above will
work in C, but not in modula2.

try this:

TYPE
	VarString = POINTER TO Node;
	Node = RECORD
		char : CHAR;
		next : VarString;
	END; (* node *)

put this in with data structure, then be sure to set the terminating
pointer to NIL and handle this like you would any linked list.
don't forget to allocate memory with NEW() to get new nodes and 
deallocate it with DISPOSE() properly whenever you release a node.

Robert Getter.

MARK@UCF1VM.BITNET (Mark Woodruff) (02/20/90)

Cute idea!  I never thought of doing that.  By putting an additional
nul at the end of the buffer, you should be able to use all the
standard Strings functions too!

I knew there was a better way to work with these things than
filling my code with SYSTEM.ADR() and SYSTEM.ADDRESS() calls.

Thanks,
mark

mac@HARRIS.CIS.KSU.EDU ("Myron A. Calhoun") (02/20/90)

In article <90050.112710MARK@UCF1VM.BITNET> you write:
>Cute idea!  I never thought of doing that.  By putting an additional
>nul at the end of the buffer, you should be able to use all the
>standard Strings functions too!
>
>I knew there was a better way to work with these things than
>filling my code with SYSTEM.ADR() and SYSTEM.ADDRESS() calls.

I must have MISSED the clever way, although I did see (several
weeks ago?) the original question.  Can you email me a copy of
the apparently-best solution?
--Myron.
--
#-------------------------------------------------------------------------
# Myron A. Calhoun, Ph.D. E.E.; Associate Professor   (913) 539-4448 home
# INTERNET: mac@harris.cis.ksu.edu   (129.130.10.2)         532-6350 work
# UUCP: ...{rutgers, texbell}!ksuvax1!harry!mac             532-7004 fax
# AT&T Mail:  attmail!ksuvax1!mac