2hnenature@kuhub.cc.ukans.edu (03/30/91)
I seem to have a problem with using the type POINTER with linked lists.
I have a seperate module with linked list functions such as Delete,Insert,
NewList etc., that I have written myself. The problem is that I wish to make
these procedures as general as possible so they can be used with a variety of
programs. Is it possible to specify a general POINTER type that can point to
any data type? I assume it must be possible since the function NEW(x) allows x
to be a pointer to any type of data.
Related to this, I have a field in my linked list of RECORDS that contains a
pointer to the next element in the linked list. The field is presently called
Link and I use this field to traverse the list:
eg. WHILE Current#NIL DO
Current:=Current^.Link...
As it stands now any linked list that wants to use these functions must have
a field called "Link." Is there any way I could remove this limitation? It is
handicapping, since if I want to use two different linked lists in a program I
must have a field "Link" in each list.
Am I making any sense?
BTW I am using a VMS Modula-2 compiler.
Thanks for any help...
S Pendleton
2hnenature@kuhub.cc.ukans.eduGerhard.Moeller@arbi.informatik.uni-oldenburg.de (Gerhard Moeller) (04/01/91)
Hi. 2hnenature@kuhub.cc.ukans.edu writes: > I seem to have a problem with using the type POINTER with linked lists. >I have a seperate module with linked list functions such as Delete,Insert, >NewList etc., that I have written myself. The problem is that I wish to make >these procedures as general as possible so they can be used with a variety of >programs. Is it possible to specify a general POINTER type that can point to >any data type? I assume it must be possible since the function NEW(x) allows x >to be a pointer to any type of data. Yes, as far as I know, use ADDRESS. (Must be imported from SYSTEM) Then you can do something like this: PROCEDURE InsertElement (Root :ADDRESS; Element :ADDRESS) : BOOLEAN; Now it doesn't care of what Element the Pointer points. But however yet be warned: The internal Structure of the Elements should be at least similar, I don't want to know what happens if you try to insert a FIFO-List-Element into a Bayer-Tree... > Related to this, I have a field in my linked list of RECORDS that contains a >pointer to the next element in the linked list. The field is presently called >Link and I use this field to traverse the list: > >eg. WHILE Current#NIL DO > Current:=Current^.Link... >As it stands now any linked list that wants to use these functions must have >a field called "Link." What I said above. ;-) >Is there any way I could remove this limitation? It is >handicapping, since if I want to use two different linked lists in a program I >must have a field "Link" in each list. Tricky. (As I'm not a Modula-Guru, I really have to think now for a while. Imagine me walking all around the room and drinking coffee...) Well, I would assume the following: Create an opake Type ElementLink that contains a variant Record for e.g. single lists, double, Trees, B-Trees, and whatever you like. Any Element you create has now a field "next : ElementLink". But, of course, now you can only use your own routines for accessing, creating, deleting and so on. I hope you got me? { TYPE tLinkTypes : (List, DoubleList, Tree, BTree, TwoThreeTree, ...) TYPE tElementLink : RECORD CASE LinkType OF tLinkType (* sorry, I forgot the syntax for variant records. Please have a look by your own. (It's a long time ago, I programmed in Modula...) *) | List : next :ADDRESS; | DoubleList: next, prev :ADDRESS; . . . } >Am I making any sense? Well, I don't even know if I was making sense, so how could I know about you? > BTW I am using a VMS Modula-2 compiler. > Thanks for any help... > S Pendleton I don't know that one, if it's standard, no problems... (Except if I was tellin' bull.) Ciao, Yours Gerhard. ("Never trust a hippy"... - Sex Pistols) -- +---------------------------< principiis obsta! >---------------------------+ | Gerhard Moeller, Teichstrasse 12, 2900 Oldenburg (FRG) [Geb. 02/21/68] | | inhouse: gimli!gemoe uucp: ...(unido!)uniol!gmoeller | |DOMAIN: gerhard.moeller@arbi.informatik.uni-oldenburg.de | |BITNET: gmoeller%arbi.informatik.uni-oldenburg.de@DOLUNI1 (106495@DOLUNI1) | +-----------------------> the medium is the message <-----------------------+
2hnenature@kuhub.cc.ukans.edu (04/01/91)
In article <5164@uniol.UUCP>, Gerhard.Moeller@arbi.informatik.uni-oldenburg.de (Gerhard Moeller) writes: > Hi. > 2hnenature@kuhub.cc.ukans.edu writes: > > >> I seem to have a problem with using the type POINTER with linked lists. >>I have a seperate module with linked list functions such as Delete,Insert, >>NewList etc., that I have written myself. The problem is that I wish to make >>these procedures as general as possible so they can be used with a variety of >>programs. Is it possible to specify a general POINTER type that can point to >>any data type? I assume it must be possible since the function NEW(x) allows x >>to be a pointer to any type of data. > Yes, as far as I know, use ADDRESS. (Must be imported from SYSTEM) Then > you can do something like this: > > PROCEDURE InsertElement (Root :ADDRESS; > Element :ADDRESS) : BOOLEAN; > > Now it doesn't care of what Element the Pointer points. But however yet > be warned: The internal Structure of the Elements should be at least > similar, I don't want to know what happens if you try to insert a > FIFO-List-Element into a Bayer-Tree... OK, that makes sense, but when I try to implement it and try to access a field of the record that for example "Root" is pointing to I get an error: Current:=Root^.Link ^ Is not a field of a record (something like that) and that makes sense too since the compiler sees "Root" as an ADDRESS type and not as a pointer to a record. Thus the fields are not recognized, (I guess). Also DISPOSE and NEW do not let me send an ADDRESS type as a parameter. Furthermore (as if you guys have nothing better to do than help me) another error I get is: Current:=Root^.Link ^ Incompatible type (?) I get this error because the field "Link" is a pointer to a record and not an ADDRESS type. Is there any way around this or should I give up? Does anybody know where I could get some source code for linked list functions that are already written? Thanks for help recieved. > >> Related to this, I have a field in my linked list of RECORDS that contains a >>pointer to the next element in the linked list. The field is presently called >>Link and I use this field to traverse the list: >> >>eg. WHILE Current#NIL DO >> Current:=Current^.Link... > >>As it stands now any linked list that wants to use these functions must have >>a field called "Link." > What I said above. ;-) > >>Is there any way I could remove this limitation? It is >>handicapping, since if I want to use two different linked lists in a program I >>must have a field "Link" in each list. >> Thanks for any help... >> S Pendleton > Ciao, Yours Gerhard. > ("Never trust a hippy"... - Sex Pistols) > -- > > +---------------------------< principiis obsta! >---------------------------+ > | Gerhard Moeller, Teichstrasse 12, 2900 Oldenburg (FRG) [Geb. 02/21/68] | > | inhouse: gimli!gemoe uucp: ...(unido!)uniol!gmoeller | > |DOMAIN: gerhard.moeller@arbi.informatik.uni-oldenburg.de | > |BITNET: gmoeller%arbi.informatik.uni-oldenburg.de@DOLUNI1 (106495@DOLUNI1) | > +-----------------------> the medium is the message <-----------------------+
seurer+@rchland.ibm.com (Bill Seurer) (04/02/91)
You can do what you want, but it is pretty ugly. I am working on an example and will place it here when I have it ready. (It's a good challenge and will make a fine test case) - Bill Seurer IBM: seurer@rchland Prodigy: CNSX71A Rochester, MN Internet: seurer@rchland.vnet.ibm.com
seurer+@rchland.ibm.com (Bill Seurer) (04/02/91)
Here it is. It's not pretty, it throws type checking to the wind
(mostly), but it works (as far as I tested it)!
Some notes:
1) This will allow you to make lists of anything. The lists need not be
all the same type. This is EXTREMELY dangerous.
2) I didn't test it much. I suspect that List.Delete is not fully
functional. Whadaya expect for less than half an hour?
3) Some compilers might not like some of the typecasting that was done.
Enjoy!
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Output of the test program:
2147483647
0
42
-906
906
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DEFINITION MODULE List;
(* "Generic" lists module *)
FROM SYSTEM IMPORT ADDRESS, BYTE;
TYPE
T (*Opaque type*);
Element (*Opaque type*);
CONST
NilList = T(NIL);
NilElement = Element(NIL);
PROCEDURE NewList(): T;
(* Create a new list *)
PROCEDURE Insert (list: T;
after: Element;
actualElement: ARRAY OF BYTE);
(* Add a new element to a list *)
PROCEDURE Delete (list: T;
element: Element);
(* Delete an element from a list *)
PROCEDURE First(list: T): Element;
(* Get the first element of a list *)
PROCEDURE Next(previous: Element): Element;
(* Get the next element of a list *)
PROCEDURE Data(of: Element): ADDRESS;
(* Get the (address of the) data of an element *)
END List.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
IMPLEMENTATION MODULE List;
(* "Generic" lists module *)
FROM SYSTEM IMPORT ADDRESS, BYTE, ADR;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
TYPE
T = POINTER TO ListRcd;
Element = POINTER TO ElementRcd;
ListRcd = RECORD
first: Element;
END (*ListRcd*);
ElementRcd = RECORD
next: Element;
data: ADDRESS;
dataSize: CARDINAL;
END (*ElementRcd*);
BytePtr = POINTER TO ARRAY[0..32767] OF BYTE;
PROCEDURE CopyBytes(from, to: BytePtr;
nbr: CARDINAL);
(* Ugly internal procedure to copy bytes from one address to another *)
VAR
cnt: CARDINAL;
BEGIN
FOR cnt := 0 TO nbr DO
to^[cnt] := from^[cnt];
END (*For*);
END CopyBytes;
PROCEDURE NewList(): T;
(* Create a new list *)
VAR
newList: T;
BEGIN
NEW(newList);
newList^.first := NIL;
RETURN newList;
END NewList;
PROCEDURE Insert (list: T;
after: Element;
element: ARRAY OF BYTE);
(* Add a new element to a list *)
VAR
new: Element;
BEGIN
NEW(new);
new^.dataSize := HIGH(element)+1;
ALLOCATE(new^.data, new^.dataSize);
IF after = NIL THEN
new^.next := list^.first;
list^.first := new;
ELSE
new^.next := after^.next;
after^.next := new;
END (*Else*);
CopyBytes(ADR(element), new^.data, new^.dataSize);
END Insert;
PROCEDURE Delete (list: T;
element: Element);
(* Delete an element from a list *)
VAR
previous, current: Element;
BEGIN
previous := list^.first;
current := previous;
LOOP
IF current = NIL THEN
EXIT (*Loop*);
ELSIF current = element THEN
IF current = list^.first THEN
list^.first := list^.first^.next;
ELSE
previous^.next := current^.next;
END (*Else*);
DEALLOCATE(current^.data, current^.dataSize);
DISPOSE(current);
EXIT (*Loop*);
ELSE
previous := current;
current := current^.next;
END (*Else*);
END (*While*);
element := NIL;
END Delete;
PROCEDURE First(list: T): Element;
(* Get the first element of a list *)
BEGIN
RETURN list^.first;
END First;
PROCEDURE Next(previous: Element): Element;
(* Get the next element of a list *)
BEGIN
RETURN previous^.next;
END Next;
PROCEDURE Data(of: Element): ADDRESS;
(* Get the (address of the) data of an element *)
BEGIN
RETURN of^.data;
END Data;
END List.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
MODULE tryList;
IMPORT List, InOut;
TYPE
IntPtr = POINTER TO INTEGER;
VAR
somelist: List.T;
el: List.Element;
int: IntPtr;
BEGIN
somelist := List.NewList();
List.Insert(somelist, List.NilElement, INTEGER(906));
(* typecast to prevent SHORTINTs from being used *)
List.Insert(somelist, List.NilElement, INTEGER(-906));
List.Insert(somelist, List.NilElement, INTEGER(42));
List.Insert(somelist, List.NilElement, INTEGER(0));
List.Insert(somelist, List.NilElement, MAX(INTEGER));
el := List.First(somelist);
WHILE el <> List.NilElement DO
int := IntPtr(List.Data(el));
InOut.WriteInt(int^, 1);
InOut.WriteLn;
el := List.Next(el);
END (*While*);
LOOP
el := List.First(somelist);
IF el = List.NilElement THEN
EXIT(*Loop*);
END (*If*);
List.Delete(somelist, el);
END (*Loop*);
END tryList.
- Bill Seurer IBM: seurer@rchland Prodigy: CNSX71A
Rochester, MN Internet: seurer@rchland.vnet.ibm.com
This material contains code that is supplied for illustrative purposes
only. IBM has not tested this code via its ordinary process and it is
not supported. IBM provides the code AS IS and specifically DISCLAIMS
ALL WARRANTIES, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR PARTICULAR PURPOSE. In no event will
IBM be responsible for any special, incidental or consequential damages,
even if advised of the possibility thereof.
If you think *I* wrote that...warwick@cs.uq.oz.au (Warwick Allison) (04/02/91)
As a representative example, let me show you:
DEFINITION MODULE Lists;
FROM SYSTEM IMPORT BYTE;
TYPE List;
PROCEDURE EmptyList():List;
PROCEDURE Insert(VAR Into:List; Element:ARRAY OF BYTE);
END Lists.
-------------------
IMPLEMENTATION MODULE Lists;
FROM SYSTEM IMPORT BYTE;
FROM Storage IMPORT ALLOCATE;
TYPE List=POINTER TO ListRec;
ListRec =
RECORD
Data:ADDRESS;
Size:CARDINAL;
Next:List;
END;
PROCEDURE EmptyList():List;
BEGIN
RETURN NIL
END EmptyList;
PROCEDURE Insert(VAR Into:List; Element:ARRAY OF BYTE);
VAR Head:List;
Byte:CARDINAL;
BEGIN
NEW(Head);
WITH Head^ DO
Size:=HIGH(Element)+1;
ALLOCATE(Data,Size);
FOR Byte:=0 TO HIGH(Element) DO
Data[Byte]:=Element[Byte];
END;
Next:=Into;
END;
Into:=Head;
END Insert;
END Lists.
------------------------------
Okay, ignoring any syntax errors I have made, this works on most
Modula-2 compilers. In particular, those supporting the ARRAY OF BYTE
standard. This standard dictates that ANY type can be passed to a field
which is an ARRAY OF BYTE.
This is in no way a full complement of procedures, but it is
easy to implement the rest, once you see the basic technique.
now try... Append, Delete, NthElement, Cardinality, IsIn, etc.
Oh, notice that these procedures are not VERY efficient, with all the
block data passing, but they work quite well, and are very generic.
Have fun,
Warwick.
--
_--_|\ warwick@cs.uq.oz.au
/ * <-- Computer Science Department,
\_.--._/ University of Queensland,
v AUSTRALIA.AL281785@VMTECSLP.BITNET (RoDoGu) (04/03/91)
Here is another Lists ADT. It works (i have used for two years).
The lasts procedures (ResetList and NextList) are based on the same philosophy
as JPI Btree Toolkit.
DEFINITION MODULE Lists;
FROM SYSTEM
IMPORT BYTE,ADDRESS;
TYPE
List;
NodePointer;
PROCEDURE InitList(VAR l : List);
PROCEDURE EmptyList(l : List):BOOLEAN;
PROCEDURE First(l : List):NodePointer;
PROCEDURE Last(l : List):NodePointer;
PROCEDURE LengthList(l : List):CARDINAL;
PROCEDURE InsertRight(VAR l : List;place : NodePointer;x : ARRAY OF BYTE);
PROCEDURE InsertLeft(VAR l : List;place : NodePointer;x : ARRAY OF BYTE);
PROCEDURE UpdateList(VAR l : List;place : NodePointer;x : ARRAY OF BYTE);
PROCEDURE DeleteList(VAR l : List;VAR place : NodePointer);
PROCEDURE Retrieve(VAR l : List;place : NodePointer; VAR x : ARRAY OF BYTE);
PROCEDURE Next(place : NodePointer):NodePointer;
PROCEDURE Previous(place : NodePointer):NodePointer;
PROCEDURE EndList(place : NodePointer):BOOLEAN;
PROCEDURE ClearList(VAR l : List);
PROCEDURE DestroyList(VAR l : List);
PROCEDURE ResetList(VAR l : List);
PROCEDURE NextList(VAR l : List;VAR data : ARRAY OF BYTE) : BOOLEAN;
END Lists.
IMPLEMENTATION MODULE Lists;
FROM SYSTEM
IMPORT ADDRESS,ADR,SIZE,BYTE;
FROM Storage
IMPORT ALLOCATE,DEALLOCATE;
TYPE
NodePointer = POINTER TO Node;
List = POINTER TO
RECORD
Start,
Curr,
First,Last : NodePointer;
len : CARDINAL
END;
Node = RECORD
Info : ADDRESS;
Mem : CARDINAL;
Left,Right : NodePointer
END;
TYPE
PtrAdr = POINTER TO ARRAY 0..0FFFFH-1| OF BYTE;
PROCEDURE Move(f,t : PtrAdr; (* check type compativility *)
c : CARDINAL);
TYPE
xu : CARDINAL;
BEGIN
FOR xu := 0 TO c - 1 DO
t^xu| := f^xu|
END (* for *);
END Move;
PROCEDURE InitList(VAR l : List);
BEGIN
NEW(l);
WITH l^ DO
First := NIL;
Last := NIL;
NEW(Start);
len := 0
END
END InitList;
PROCEDURE EmptyList(l : List):BOOLEAN;
BEGIN
RETURN l^.First = NIL
END EmptyList;
PROCEDURE First(l : List):NodePointer;
BEGIN
RETURN l^.First
END First;
PROCEDURE Last(l : List):NodePointer;
BEGIN
RETURN l^.Last
END Last;
PROCEDURE LengthList(l : List):CARDINAL;
BEGIN
RETURN l^.len
END LengthList;
PROCEDURE InsertRight(VAR l : List;place : NodePointer;x : ARRAY OF BYTE);
VAR
t : NodePointer;
BEGIN
WITH l^ DO
NEW(t);
t^.Mem := SIZE(x);
ALLOCATE(t^.Info,t^.Mem);
MoveFwd(ADR(x),t^.Info,SIZE(x));
INC(len);
IF First = NIL THEN
First := t;
Last := t;
t^.Right := NIL;
t^.Left := NIL
ELSIF place = Last THEN
Last^.Right := t;
t^.Left := Last;
t^.Right := NIL;
Last := t
ELSIF place # NIL THEN
t^.Right := place^.Right;
t^.Left := place;
place^.Right := t;
t^.Right^.Left := t
ELSE
DEALLOCATE(t^.Info,t^.Mem);
DISPOSE(t);
DEC(len)
END
END
END InsertRight;
PROCEDURE InsertLeft(VAR l : List;place : NodePointer;x : ARRAY OF BYTE);
VAR
t : NodePointer;
BEGIN
WITH l^ DO
NEW(t);
t^.Mem := SIZE(x);
ALLOCATE(t^.Info,t^.Mem);
MoveFwd(ADR(x),t^.Info,SIZE(x));
INC(len);
IF First = NIL THEN
First := t;
Last := t;
t^.Right := NIL;
t^.Left := NIL
ELSIF place = First THEN
t^.Right := First;
t^.Left := NIL;
First^.Left := t;
First := t
ELSIF place # NIL THEN
t^.Left := place^.Left;
t^.Right := place;
t^.Left^.Right := t;
place^.Left := t
ELSE
DEALLOCATE(t^.Info,t^.Mem);
DISPOSE(t);
DEC(len)
END
END
END InsertLeft;
PROCEDURE UpdateList(VAR l : List;place : NodePointer; x : ARRAY OF BYTE);
BEGIN
WITH l^ DO
IF (First # NIL) & (place # NIL) THEN
MoveFwd(ADR(x),place^.Info,place^.Mem)
END
END
END UpdateList;
PROCEDURE DeleteList(VAR l : List;VAR place : NodePointer);
VAR
t : NodePointer;
BEGIN
WITH l^ DO
IF First # NIL THEN
IF place = First THEN
t := First;
First := First^.Right;
place := First;
IF First # NIL THEN First^.Left := NIL END
ELSIF place = Last THEN
t := Last;
Last := Last^.Left;
place := NIL;
Last^.Right := NIL
ELSIF place # NIL THEN
t := place;
place := place^.Right;
t^.Right^.Left := t^.Left;
t^.Left^.Right := t^.Right
ELSE
t := NIL
END;
IF t # NIL THEN
DEALLOCATE(t^.Info,t^.Mem);
DISPOSE(t);
DEC(len)
END
END
END
END DeleteList;
PROCEDURE Retrieve(VAR l : List;place : NodePointer; VAR x : ARRAY OF BYTE);
BEGIN
WITH l^ DO
IF (First # NIL) & (place # NIL) THEN
MoveFwd(place^.Info,ADR(x),place^.Mem)
END
END
END Retrieve;
PROCEDURE Next(place : NodePointer):NodePointer;
BEGIN
IF place # NIL THEN
RETURN place^.Right
ELSE
RETURN NIL
END
END Next;
PROCEDURE Previous(place : NodePointer):NodePointer;
BEGIN
IF place # NIL THEN
RETURN place^.Left
ELSE
RETURN NIL
END
END Previous;
PROCEDURE EndList(place : NodePointer):BOOLEAN;
BEGIN
RETURN place = NIL
END EndList;
PROCEDURE ClearList(VAR l : List);
VAR
trace : NodePointer;
BEGIN
trace := First(l);
WHILE NOT EndList(trace) DO
DeleteList(l,trace)
END
END ClearList;
PROCEDURE DestroyList(VAR l : List);
BEGIN
ClearList(l);
DISPOSE(l^.Start);
DISPOSE(l)
END DestroyList;
PROCEDURE ResetList(VAR l : List);
BEGIN
WITH l^ DO
Start^.Right := First;
Start^.Left := Last;
Curr := Start;
END (* with *)
END ResetList;
PROCEDURE NextList(VAR l : List;VAR data : ARRAY OF BYTE) : BOOLEAN;
BEGIN
WITH l^ DO
Curr := Next(Curr);
IF ~ EndList(Curr) THEN
Retrieve(l,Curr,data);
RETURN TRUE
ELSE
RETURN FALSE
END (* if *);
END (* with *);
END NextList;
END Lists.
MODULE Example;
(* using ResetList and NextList *);
VAR
n : CARDINAL;
l : List;
BEGIN
-
-
-
ResetList(l);
WHILE NextList(l,n) DO (* this is beautiful! *)
WrCard(n,0);
WrLn
END (* while *);
END Example.
Instituto Tecnologico y de Estudios Superiores de Monterrey, Campus San Luis
ROberto DOminguez GUtierrez.Gerhard.Moeller@arbi.informatik.uni-oldenburg.de (Gerhard Moeller) (04/03/91)
Hi again... >In article <5164@uniol.UUCP>, Gerhard.Moeller@arbi.informatik.uni-oldenburg.de (Gerhard Moeller) writes: >> Hi. >> 2hnenature@kuhub.cc.ukans.edu writes: >> >> >>> I seem to have a problem with using the type POINTER with linked lists. >>>I have a seperate module with linked list functions such as Delete,Insert, >>>NewList etc., that I have written myself. The problem is that I wish to make >>>these procedures as general as possible so they can be used with a variety of >>>programs. Is it possible to specify a general POINTER type that can point to >>>any data type? I assume it must be possible since the function NEW(x) allows x >>>to be a pointer to any type of data. >> Yes, as far as I know, use ADDRESS. (Must be imported from SYSTEM) Then >> you can do something like this: >> >> PROCEDURE InsertElement (Root :ADDRESS; >> Element :ADDRESS) : BOOLEAN; >> >> Now it doesn't care of what Element the Pointer points. But however yet >> be warned: The internal Structure of the Elements should be at least >> similar, I don't want to know what happens if you try to insert a >> FIFO-List-Element into a Bayer-Tree... > OK, that makes sense, but when I try to implement it and try to access a field >of the record that for example "Root" is pointing to I get an error: > Current:=Root^.Link > ^ Is not a field of a record (something like that) > >and that makes sense too since the compiler sees "Root" as an ADDRESS type and >not as a pointer to a record. Thus the fields are not recognized, (I guess). >Also DISPOSE and NEW do not let me send an ADDRESS type as a parameter. > Furthermore (as if you guys have nothing better to do than help me) another >error I get is: > > Current:=Root^.Link > ^ Incompatible type (?) > I get this error because the field "Link" is a pointer to a record and not an >ADDRESS type. > Is there any way around this or should I give up? Does anybody know where >I could get some source code for linked list functions that are already >written? > Thanks for help recieved. Well, before I start explaning, I'd better send a copy of source that I've written many days ago. It sure works and should be self-explaining. (Sometimes a sample helps more than 1000 words.) BTW the following source implements a few useful system-calls of the UNIX c-library and therefore only works with Unix... have a close look at the time-routines for example. (* for UNIX only *) FOREIGN MODULE MySysLib; FROM SYSTEM IMPORT ADDRESS; TYPE int = INTEGER; SIGNED = INTEGER; UNSIGNED = INTEGER; inoT = CARDINAL; offT = INTEGER; devT = SHORTINT; timeT = INTEGER; Stat = RECORD stDev : devT; stIno : inoT; stMode : SHORTCARD; stNlink : SHORTINT; stUid : SHORTINT; stGid : SHORTINT; stRdev : devT; stSize : offT; stAtime : timeT; stSpare1 : INTEGER; stMtime : timeT; stSpare2 : INTEGER; stCtime : timeT; stSpare3 : INTEGER; stBlksize: INTEGER; stBlocks : INTEGER; stSpare4 : ARRAY [0..1] OF INTEGER; END; tms = RECORD utime : timeT; stime : timeT; cutime : timeT; cstime : timeT; END; tmtype = RECORD tm_sec : int; tm_min : int; tm_hour : int; tm_mday : int; tm_mon : int; tm_year : int; tm_wday : int; tm_yday : int; tm_istdst : int; END; CONST (* signals *) SIGHUP = 01; (* hangup *) SIGINT = 02; (* interrupt *) SIGQUIT = 03; (* [1] quit *) SIGILL = 04; (* [1] illegal instruction (not reset when caught) *) SIGTRAP = 05; (* [1] trace trap (not reset when caught) *) SIGIOT = 06; (* [1] IOT instruction *) SIGEMT = 07; (* [1] EMT instruction *) SIGFPE = 08; (* [1] floating point exception *) SIGKILL = 09; (* kill (cannot be caught or ignored) *) SIGBUS = 10; (* [1] bus error *) SIGSEGV = 11; (* [1] segmentation violation *) SIGSYS = 12; (* [1] bad argument to system call *) SIGPIPE = 13; (* write on a pipe with no one to read it *) SIGALRM = 14; (* alarm clock *) SIGTERM = 15; (* software termination signal *) SIGADDR = 16; (* [1] address error: odd address *) SIGZERO = 17; (* [1] zero divide *) SIGCHK = 18; (* [1] check error (68000 chk instruction) *) SIGOVER = 19; (* [1] software termination signal *) SIGPRIV = 20; (* [1] software termination signal *) SIGUSR1 = 21; (* user-defined signal 1 *) SIGUSR2 = 22; (* user-defined signal 2 *) SIGCLD = 23; (* [2] death of a child *) SIGPWR = 24; (* [2] power fail *) SIGWINCH = 25; (* [2] window size changed *) SIGPOLL = 26; (* [3] selectable event pending *) (* flags for open *) oTRUNC = 01000B; (* open with truncation *) oAPPEND = 010B; (* append, i.e writes at the end *) oRDWR = 02B; (* open for reading and writing *) oWRONLY = 01B; (* open for writing only *) oRDONLY = 0B; (* open for reading only *) (* file access permisson flags (for create and umask) *) pXUSID = 04000B; (* set user ID on execution *) pXGRID = 02000B; (* set group ID on execution *) pSTEXT = 01000B; (* save text image after execution *) pROWNER = 0400B; (* read by owner *) pWOWNER = 0200B; (* write by owner *) pXOWNER = 0100B; (* execute by owner *) pRGROUP = 040B; (* read by group *) pWGROUP = 020B; (* write by group *) pXGROUP = 010B; (* execute by group *) pROTHERS = 04B; (* read by others *) pWOTHERS = 02B; (* write by others *) pXOTHERS = 01B; (* execute by others *) pEMPTY = 0B; (* no flag set *) (* file access check flags (for access) *) cREAD = 04H; (* check if readable *) cWRITE = 02H; (* check if writable *) cEXEC = 01H; (* check if executable *) cEXISTS = 0H; (* check existance *) PROCEDURE umask (cmask : SIGNED) : SIGNED; PROCEDURE access (path : ADDRESS; amode : SIGNED) : SIGNED; PROCEDURE creat (path : ADDRESS; cmode : SIGNED) : SIGNED; PROCEDURE open (path : ADDRESS; oflag : SIGNED) : SIGNED; PROCEDURE close (fildes : SIGNED) : SIGNED; PROCEDURE unlink (path : ADDRESS) : SIGNED; PROCEDURE read (fildes : SIGNED; buf : ADDRESS; nbyte : UNSIGNED) : SIGNED; PROCEDURE write (fildes : SIGNED; buf : ADDRESS; nbyte : UNSIGNED) : SIGNED; PROCEDURE malloc (size : UNSIGNED) : ADDRESS; PROCEDURE free (ptr : ADDRESS); PROCEDURE stat (path: ADDRESS; VAR buf: Stat) : INTEGER; PROCEDURE fstat (fd: SIGNED ; VAR buf: Stat) : INTEGER; PROCEDURE time (VAR t : INTEGER); PROCEDURE times (VAR buffer: tms); PROCEDURE localtime (clockpointer : ADDRESS) : ADDRESS; PROCEDURE system (string : ADDRESS) : SIGNED; PROCEDURE exit (n: INTEGER); PROCEDURE alarm (sec : UNSIGNED); PROCEDURE signal (sig :int; func :PROC); PROCEDURE sigset (sig :int; func :PROC); PROCEDURE sighold (sig :int); PROCEDURE sigrelse (sig :int); PROCEDURE sigignore (sig :int); PROCEDURE sigpause (sig :int); END MySysLib. (*============================================================================*) IMPLEMENTATION MODULE MySysLib; (* implemented by C library *) END MySysLib. (*============================================================================*) [...] (* Stuff deleted *) MODULE Editor; (* @@ EXPORT Edit (Filename); *) FROM MyStuff IMPORT (* TYPE *) StringType; FROM MySysLib IMPORT (* TYPE *) SIGNED, (* PROC *) system; [...] (* Stuff deleted *) CONST Editor = "em "; Filename = "Test"; PROCEDURE Edit (File :ARRAY OF CHAR); VAR EditFile : StringType; unixcommand : StringType; unixcall : POINTER TO StringType; error : SIGNED; BEGIN (* Edit *) Concat (Editor, File, EditFile); ALLOCATE (unixcall, SIZE (unixcommand)); unixcall^ := EditFile; error := system (unixcall); DEALLOCATE (unixcall, SIZE(unixcommand)); END Edit; BEGIN (* Editor *) [...] (* Stuff deleted *) END Editor. [...] (* Stuff deleted *) (*============================================================================*) Ok?? Hope that helped, Gerhard.
Jon.Guthrie@p25.f506.n106.z1.fidonet.org (Jon Guthrie) (04/03/91)
On a message of 31-Mar-91, 2hnenature@kuhub.cc.ukans.edu (1:105/42.0) Said: > Is it possible to specify a general POINTER type that can point to > any data type? I assume it must be possible since the function > NEW(x) allows x to be a pointer to any type of data. Yes, SYSTEM exports the data type ADDRESS which is assignable to (and from) any pointer type. (Check whatever documentation you have for more details.) As for the assumption that it must be possible based on the NEW() procedure, I'd have to say that you're on thin ice. Standard procedures are allowed to break rules in a variety of ways, and may, in fact, be implemented as additions to the syntax of the language rather than as procedures. -- uucp: uunet!m2xenix!puddle!106!506.25!Jon.Guthrie Internet: Jon.Guthrie@p25.f506.n106.z1.fidonet.org
Rajah.Dodger@urchin.fidonet.org (Rajah Dodger) (04/04/91)
I may be naive here (I haven't done any serious programming in three years) but I see no reason why you couldn't have a "generic pointer". What you would need to do would be to make it a pointer to some (arbitrarily chosen) data type that is large enough to hold the largest item your programs would want to point to. Then you dereference and do a type cast. I can see a few problems with this, but it looks like a reasonable start. The alternative option is to use pointer to CHAR, get the address of the item pointer to and then do your own memory magic to pull it up as the right type information. Any way you slice it, you're going to have to do some type casting.
gkt@iitmax.iit.edu (George Thiruvathukal) (04/09/91)
In article <10726.27FA98F3@urchin.fidonet.org>, Rajah.Dodger@urchin.fidonet.org (Rajah Dodger) writes: > I may be naive here (I haven't done any serious programming in three > years) but I see no reason why you couldn't have a "generic pointer". You are correct. Modula-2, as defined in Programming in Modula-2, has two data types which are "generic" in nature: WORD and ADDRESS. These types are defined in the SYSTEM module. > What you would need to do would be to make it a pointer to some > (arbitrarily chosen) data type that is large enough to hold the largest > item your programs would want to point to. Then you dereference and do a > type cast. I can see a few problems with this, but it looks like a > reasonable start. Actually, you have a good handle on the concepts. The generic pointer (of type ADDRESS) is a pointer which can hold any pointer type. It cannot be dereferenced, however, because it is unknown at compile time what the generic pointer points to. In short, to actually examine what is pointed to by a variable of type ADDRESS, one must assign the variable to a pointer to a specific type and dereference that pointer. You might want to contrast this with the mechanism employed in the C language, where a "cast operator" is present for the purpose of explicitly changing the type of the pointer, even if it is generic, into another pointer type. -- George Thiruvathukal Laboratory for Parallel Computing and Languages Illinois Institute of Technology Chicago