[comp.lang.pascal] need a little flexibility

amead@s.psych.uiuc.edu (alan mead) (04/25/91)

Hi.  I want to manipulate a data structure in the cleanest way possible 
(after I write this, I'd like to minimize maintenance time).  I've been
working with something like this:

Block = record
       x    : byte;
       y    : byte;
       ...
       data : array[1..252] of byte;
end;

but the elements of data are sometimes words instead of bytes and this
structure doesn't compile (I guess you cannot declare ABSOLUTE structures
in a type declaration?):

Block = record
       x    : byte;
       y    : byte;
       ...
       data : array[1..252] of byte;
       dataW: array[1..126] of word ABSOLUTE data;
end;

If it did work, then I could assign words to DataW[ index*2 ] and bytes to 
Data[] just like Port & PortW and Mem and MemW.

But it doesn't.  I could declare the variables individually, but that
will probably cause confusion (ie, I'd rather use a record, and I don't
think I can declare a variable ABSOLUTE to a field in a record, and
even then it would be confusing).

And a variant record requires an exhaustive listing of it's fields right?

Any ideas?  Thanks much.

-alan : amead@s.psych.uiuc.edu

dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) (04/25/91)

amead@s.psych.uiuc.edu (alan mead) writes:

> Block = record
>        x    : byte;
>        y    : byte;
>        ...
>        data : array[1..252] of byte;
>        dataW: array[1..126] of word ABSOLUTE data;
> end;
  ...
> And a variant record requires an exhaustive listing of it's fields right?

I think this does what you want, by using variant records:

const
  n = 126;
type
  Block = record
            x,y: Byte;
	    ...
            case Byte of
              1 : (data : array[1..2*n] of Byte);
              2 : (dataW: array[1..n] of Word);
            end;

Daniel Lewart
d-lewart@uiuc.edu

nmouawad@watmath.waterloo.edu (Naji Mouawad) (04/25/91)

In article <1991Apr24.183315.7997@ux1.cso.uiuc.edu> amead@s.psych.uiuc.edu (alan mead) writes:
>Hi.  I want to manipulate a data structure in the cleanest way possible 
>(after I write this, I'd like to minimize maintenance time).  I've been
>working with something like this:
>
>Block = record
>       x    : byte;
>       y    : byte;
>       ...
>       data : array[1..252] of byte;
>end;
>
>but the elements of data are sometimes words instead of bytes and this
>structure doesn't compile (I guess you cannot declare ABSOLUTE structures
>in a type declaration?):
>
>Block = record
>       x    : byte;
>       y    : byte;
>       ...
>       data : array[1..252] of byte;
>       dataW: array[1..126] of word ABSOLUTE data;
>end;
>
>And a variant record requires an exhaustive listing of it's fields right?

I don't understand your last statement, it seems that a record of
the following form:

Block = record
   x : byte;
   y : byte;
   case boolean of
    True : (data : array[1..252] of byte);
    False: (dataw: array[1..126] of word);
end;

would do the trick. You could access just as easily data or dataw
as follows:

Var B : block;
    w : word;

Begin
  w := 12345;
  b.data[i] := hi(w);
  b.dataw[i] := w;
end.

Isn't this what you were looking for ?

--Naji.
-- 
     -------------------------------------------------------------------
    | Naji Mouawad  |          nmouawad@watmath.waterloo.edu            |
    |  University   |---------------------------------------------------|
    | Of Waterloo   |   "The Stranger in us is our most familiar Self"  |

Dave_Wyble.wbst147@xerox.com (04/25/91)

>And a variant record requires an exhaustive listing of it's fields right?<

I don't think so.  Look in the TP manual and see how the type Regs is declared
in the DOS unit.  The variant record is set up so all the fields that may be
variant (AX -> AH AL etc) are at the beginning of the declaration.  The rest of
the registers (ie: the ones that can't be split: SI, DI etc) are at the end,
and are *not* repeated in the second part of the declaration.

Seems to me you could just cluster the variant parts in the beginning, unless
ALL of your fields may be used as bytes or words.  If you need all of them to
be variant, you are right, it might get exhausting.

Dave Wyble
drw.wbst147@xerox.com

IO92203@MAINE.BITNET (Scott Maxell) (04/25/91)

In article <1991Apr24.235739.25115@watmath.waterloo.edu>,
nmouawad@watmath.waterloo.edu (Naji Mouawad) says:
>
>In article <1991Apr24.183315.7997@ux1.cso.uiuc.edu> amead@s.psych.uiuc.edu    n
>(ala
>mead) writes:
>>Hi.  I want to manipulate a data structure in the cleanest way possible
>>(after I write this, I'd like to minimize maintenance time).  I've been
>>working with something like this:
>>
>>Block = record
>>       x    : byte;
>>       y    : byte;
>>       ...
>>       data : array[1..252] of byte;
>>end;
>>
***... text deleted ...***
>>And a variant record requires an exhaustive listing of it's fields right?
>
>I don't understand your last statement, it seems that a record of
>the following form:
>
>Block = record
>   x : byte;
>   y : byte;
>   case boolean of
>    True : (data : array[1..252] of byte);
>    False: (dataw: array[1..126] of word);
>end;
>
>would do the trick. You could access just as easily data or dataw
>as follows:
>
>Var B : block;
>    w : word;
>
>Begin
>  w := 12345;
>  b.data[i] := hi(w);
>  b.dataw[i] := w;
>end.
>

   This last approach won't work as stated because a variant record can
only contain one of the possible fields declared. The field in the variant
should also have a declared variable and not just a type.

Type
  Block = RECORD
            X,
            Y : Byte;
            Case WordData : Boolean OF
              True  : ( DataW : ARRAY [1..126] OF Word );
              False : ( Data  : ARRAY [1..252] OF Byte );
          END;  (* record *)

VAR
  WordData : BOOLEAN;
  OneWord  : Word;
  OneByte  : Byte;

BEGIN
  B.WordData := True;   (* or false depending on what your data is. *)
  OneByte    := ????;   (* Your byte data.                          *)
  OneWord    := ????;   (* Your word data.                          *)
  n          := ????;   (* Array index.                             *)
  Case B.WordData OF
    True  : B.Data  [n] := OneByte;
    False : B.DataW [n] := OneWord;
  END;  (* case *)
END;

  When adding data to a variant record, there needs to be a value placed in
the tag field, or you will generally get an error.

//////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+---------+ Scott Maxell  -- Bitnet   ->> IO92203 @ maine
|         |               -- Internet ->> IO92203 @ maine.maine.edu
|    O    |
|    |    | "What I need is a computer that will do what I want it to
+---------+ do, not what I tell it to do..."

wyoung@cis.ksu.edu (William J. Young) (04/26/91)

In article <91115.111155IO92203@MAINE.BITNET> IO92203@MAINE.BITNET (Scott Maxell) writes:
>In article <1991Apr24.235739.25115@watmath.waterloo.edu>,
>nmouawad@watmath.waterloo.edu (Naji Mouawad) says:
>>
>>Block = record
>>   x : byte;
>>   y : byte;
>>   case boolean of
>>    True : (data : array[1..252] of byte);
>>    False: (dataw: array[1..126] of word);
>>end;
>>
>
>   This last approach won't work as stated because a variant record can
>only contain one of the possible fields declared.

Have you tried it?  It does work.  A variable of a variant record type
does allow accessing either of the named fields.  It's up to the
programmer to do the error checking necessary to avoid misuse.

> The field in the variant
>should also have a declared variable and not just a type.
 ^^^^^^
>
>Type
>  Block = RECORD
>            X,
>            Y : Byte;
>            Case WordData : Boolean OF
>              True  : ( DataW : ARRAY [1..126] OF Word );
>              False : ( Data  : ARRAY [1..252] OF Byte );
>          END;  (* record *)
>
** rest deleted **

Not necessary.  This is nice for doing the error checking I mentioned,
but you can leave it off and access either field as needed.

--
----------------------------
Bill Young 
wyoung@cis.ksu.edu

nmouawad@watmath.waterloo.edu (Naji Mouawad) (04/26/91)

In article <91115.111155IO92203@MAINE.BITNET> IO92203@MAINE.BITNET (Scott Maxell) writes:
>>Block = record
>>   x : byte;
>>   y : byte;
>>   case boolean of
>>    True : (data : array[1..252] of byte);
>>    False: (dataw: array[1..126] of word);
>>end;
>>
>>would do the trick. You could access just as easily data or dataw
>>as follows:
>>
>>Var B : block;
>>    w : word;
>>
>>Begin
>>  w := 12345;
>>  b.data[i] := hi(w);
>>  b.dataw[i] := w;
>>end.
>>
>
>   This last approach won't work as stated because a variant record can
>only contain one of the possible fields declared. The field in the variant
>should also have a declared variable and not just a type.
>
>Type
>  Block = RECORD
>            X,
>            Y : Byte;
>            Case WordData : Boolean OF
>              True  : ( DataW : ARRAY [1..126] OF Word );
>              False : ( Data  : ARRAY [1..252] OF Byte );
>          END;  (* record *)
>
>VAR
>  WordData : BOOLEAN;
>  OneWord  : Word;
>  OneByte  : Byte;
>
>BEGIN
>  B.WordData := True;   (* or false depending on what your data is. *)
>  OneByte    := ????;   (* Your byte data.                          *)
>  OneWord    := ????;   (* Your word data.                          *)
>  n          := ????;   (* Array index.                             *)
>  Case B.WordData OF
>    True  : B.Data  [n] := OneByte;
>    False : B.DataW [n] := OneWord;
>  END;  (* case *)
>END;
>
>  When adding data to a variant record, there needs to be a value placed in
>the tag field, or you will generally get an error.
>

Hi Scott,

  While this may be true in Pascal, it is not the case in Turbo
Pascal:

 "An *optional* identifier, the tag field identifier, can be placed
  in the variant part. If a tag field identifier is present, it becomes
  the identifier of an additional fixed field - the tag field - of
  the record. The program can use the tag field's value to show 
  which variant is active at a given time. Whithout a tag field,
  the program selects a variant by another criterion."
               TP V 6.0 programmer's manual, page 31.

Cheers,

--Naji.
-- 
     -------------------------------------------------------------------
    | Naji Mouawad  |          nmouawad@watmath.waterloo.edu            |
    |  University   |---------------------------------------------------|
    | Of Waterloo   |   "The Stranger in us is our most familiar Self"  |

milne@ics.uci.edu (Alastair Milne) (04/27/91)

In <91115.111155IO92203@MAINE.BITNET> IO92203@MAINE.BITNET (Scott Maxell) writes:

>In article <1991Apr24.235739.25115@watmath.waterloo.edu>,
>>   x : byte;
>>   y : byte;
>>   case boolean of
>>    True : (data : array[1..252] of byte);
>>    False: (dataw: array[1..126] of word);
>>end;
>>
....
>>  b.data[i] := hi(w);
>>  b.dataw[i] := w;
>>end.
>>

>   This last approach won't work as stated because a variant record can
>only contain one of the possible fields declared. The field in the variant
>should also have a declared variable and not just a type.

   Not true!!

   Pascal does *not* guard against using whichever of the variants you
   want at any time.  Ada has constructions which do, but Pascal does not.

   Nor does the tagfield actually have to be an allocated field,
   rather than just a type.  It *can* be, of course, if you want your
   program to be able to ask as which variant a give instance of the 
   record was created, but there's no obligation.

>Type
>  Block = RECORD
>            X,
>            Y : Byte;
>            Case WordData : Boolean OF
>              True  : ( DataW : ARRAY [1..126] OF Word );
>              False : ( Data  : ARRAY [1..252] OF Byte );
>          END;  (* record *)

>VAR
>  WordData : BOOLEAN;
>  OneWord  : Word;
>  OneByte  : Byte;

>BEGIN
>  B.WordData := True;   (* or false depending on what your data is. *)
>  OneByte    := ????;   (* Your byte data.                          *)
>  OneWord    := ????;   (* Your word data.                          *)
>  n          := ????;   (* Array index.                             *)
>  Case B.WordData OF
>    True  : B.Data  [n] := OneByte;
>    False : B.DataW [n] := OneWord;

      { All this is internally consistent, but you could as easily write
	FALSE: B.Data[N] := OneByte; 
	and Pascal wouldn't care at all. }
>  END;  (* case *)
>END;

>  When adding data to a variant record, there needs to be a value placed in
>the tag field, or you will generally get an error.

    You will get errors if the program is counting on telling by the 
    tag field which variant is being used, since not being able to 
    tell may cause it to assign to the wrong variant, possibly with 
    the wrong size, overwrite memory, etc. etc. .  Then an uninitialised
    tag field will wreak havoc -- but not because of any internal bindings,
    simply because it's supplying the assignment algorithm with false
    information.  But this is typically in the case of dynamically allocated 
    variant records, not the static ones given here.

    But if your routines are not themselves making use of the tag field,
    there is no need to have one.

    Note I am speaking of UCSD Pascal and Turbo Pascal.  I don't have the 
    ANSI standards available -- they may be more rigid.


    Alastair Milne

CDHWilli@exua.exeter.ac.uk (Charles Williams) (04/28/91)

[Sensible text and helpful reply deleted]
Scott Maxell joins in...
SM>
SM>   This last approach won't work as stated because a variant record can
SM>only contain one of the possible fields declared. The field in the variant
SM>should also have a declared variable and not just a type.
SM>
SM>Type
SM>  Block = RECORD
SM>            X,
SM>            Y : Byte;
SM>            Case WordData : Boolean OF
SM>              True  : ( DataW : ARRAY [1..126] OF Word );
SM>              False : ( Data  : ARRAY [1..252] OF Byte );
SM>          END;  (* record *)
SM>
SM>VAR
SM>  WordData : BOOLEAN;
SM>  OneWord  : Word;
SM>  OneByte  : Byte;
SM>
SM>BEGIN
SM>  B.WordData := True;   (* or false depending on what your data is. *)
SM>  OneByte    := ????;   (* Your byte data.                          *)
SM>  OneWord    := ????;   (* Your word data.                          *)
SM>  n          := ????;   (* Array index.                             *)
SM>  Case B.WordData OF
SM>    True  : B.Data  [n] := OneByte;
SM>    False : B.DataW [n] := OneWord;
SM>  END;  (* case *)
SM>END;
SM>
SM>  When adding data to a variant record, there needs to be a value placed in
SM>the tag field, or you will generally get an error.

The label associated with a variant field is optional.  For example here
is a routine to "and" two integers.  It is *real* code, from a *real* program,
it *really* works on a Sparcstation and according to my compiler is
ISO and ANSI compliant.  Of course whether it works on a particular machine
depends on the word length.

{------------------------------------------------------------------------------
/    ANDint(I,J) logically ANDs integers I,J
/-----------------------------------------------------------------------------}

function ANDint( I,J: integer ): integer;

const

  IntDigits = 32;

type

  Overlay = record case boolean of
              False: ( IntType: integer);
              True : ( SetType: set of 1..IntDigits )
            end{record};

var

  {  Dual type variables                   }  A, B:          Overlay;

begin{ANDint}
  A.IntType:=I;  B.IntType:=J;
  A.SetType:=A.SetType*B.SetType;
  ANDint:=A.IntType
end{ANDint};


SM>"What I need is a computer that will do what I want it to
SM> do, not what I tell it to do..."

I can see why ;-)

===============================================================================
============ My signature and I have separated for a trial period =============
===============================================================================