The ModulaTor logo 7KB

The ModulaTor

Oberon-2 and Modula-2 Technical Publication

Ubaye's First Independent Modula-2 & Oberon-2 Journal! Nr. 4, May-1995

Unique I/O-Library Approach for OM2/Mithril

by Günter Dotzel, ModulaWare

Mithril is a graphical user interface with embedded Modula-2 and Oberon-2 compiler. The Mithril GUI is conceptually similar to ETH-Zuerich's Oberon System. Mithril also features an object oriented application program interface, called the Mithril API.

The compilers contained in Mithril are the same as those provided with OM2, the stand-alone (command line) compiler.

A program importing any module from the Mithril API will run only under the Mithril system at run-time. Due to the nature of Mithril, keyboard/screen-I/O is quite different to the conventional approach. Mithril does not have any query or input mode. Instead, the content of marked windows or selected text can be used as input data to any program.

To write a portable program which needs to read characters from the keyboard, it would be desirable to use a standardised library. Fortunately, the ISO Modula-2 library can be used for both, Modula-2 and Oberon-2 under Mithril and with the stand-alone compiler in OM2.

The "simple" I/O-modules such as STextIO, SRealIO, SWholeIO to read and write characters and strings, seem to be well suited to write portable, interactive program. The S-modules have a default I/O-channel, connected to the terminal or console. But under Mithril, there is neither console, terminal, nor keyboard. Instead we have selectable texts and windows. How can we know whether we want to read from a selected text or window and if there are multiple windows open, what window do we want?

Fortunately, the ISO Modula-2 library allows to extend its functionality. By using it's device modules, it is easily possible to add another I/O-module in addition to standard TermFile, SeqFile, RndFile and StreamFile.

Two new common I/O-modules for stand-alone OM2 and Mithril are provided with the Mithril kit: TextFile.(d,m), written in Modula-2 and WinChan.o, written in Oberon-2. These modules allow to write portable programs and one does not need to know whether they will run under Mithril or stand-alone.

Source code is provided. So if another stand-alone compiler is used than OM2, one simply re-compiles module TextFile (after deletion of the conditional compilation directives of ISO M2 <* ... *>; the syntax and semantics within the directives is not standardised, just the syntax of the directives itself.) and the application program. I successfully tried this, using MaX and A2O, ModulaWare's stand-alone Modula-2 and Oberon-2 compiler for DEC Alpha AXP/OpenVMS.

TextFile library with ISO Modula-2 like channels:

Copyright (1994) ModulaWare, written by AN/GD, 28-Oct-1994

The new library modules can be used under Mithril (output to window, input from marked window, selection or text file) or in stand-alone mode (input/output to/from file).

The library is provided in source form. It serves well to illustrate how to extend the ISO M2 library. The source code of TextFile.m and WinChan.o are provided under the same conditions as the OM2 and Mithril kit (non disclosure).

1) To prepare the stand-alone version:


  xc TextFile.d TextFile.m 
2) To the prepare Mithril version:

  xc :mithril WinChan.o TextFile.m 
The :mithril parameter in the command line above serves to control some source file directives.

TextFile.m contains the source code for both versions, stand-alone and Mithril.

WinChan.o is used in Mithril version only. It is recommended to prepare two versions of TextFile.ldf: one in directory \xc\ldf and another in \mi\ldf.

The stand-alone version of TextFile uses the RndFile library in its implementation.

One small problem remains: when reading plain DOS text files (such as created by popular DOS editors) using the new library module under Mithril, the "CR LF" sequence is treated as two line separators. Currently we can't propose a good solution for this problem.

Also included are two test programs: tf.o and tfs.o. tfs.o tests the stand-alone version, tf.o is the Mithril version. Not all commands in "tf.o" can be used in stand-alone mode.

Suggestions for further improvement of the library are welcome.



DEFINITION MODULE TextFile; (* Ned 20-Oct-94 *) (* Random access text files: ISO like channel to Mithril texts (text windows). When used outside Mithril operates on files. Copyright (c) 1994 xTech, Ltd. All Rights Reserved. OM2/Mithril distribution kit by http://www.ModulaWare.com/ *) IMPORT IOChan, ChanConsts; TYPE ChanId = IOChan.ChanId; FlagSet = ChanConsts.FlagSet; OpenResults = ChanConsts.OpenResults; FilePos = CARDINAL; (* Accepted singleton values of FlagSet *) CONST read = FlagSet{ChanConsts.readFlag}; (* input operations are requested/available *) write = FlagSet{ChanConsts.writeFlag}; (* output operations are requested/available *) old = FlagSet{ChanConsts.oldFlag}; (* a file may/must/did exist before the channel is opened *) text = FlagSet{ChanConsts.textFlag}; (* text operations are requested/available *) CONST (* modes for SpecialOpen *) openLog = 0; (* open SysLog text (CurrentPos = 0) *) appendLog = 1; (* open SysLog text (CurrentPos = end of text) *) marked = 2; (* open text in the marked window (CurrentPos = 0) *) selection = 3; (* open the most recent (CurrentPos = selected position *) PROCEDURE OpenOld(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); (* Attempts to obtain and open a channel connected to a text file of the given name. The old and text flags are implied; without the write flag, read is implied. If successful, assigns to cid the identity of the opened channel, assigns the value opened to res, and sets the read/write position to the start of the file. If a channel cannot be opened as required, the value of res indicates the reason, and cid identifies the invalid channel. *) PROCEDURE OpenClean(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); (* Under Mithril creates new text window with the name as file name. Otherwise, attempts to obtain and open a channel connected to a text file of the given name. The write and text flags are implied; without the write flag, read is implied. If successful, assigns to cid the identity of the opened channel, assigns the value opened to res, and truncates the file to zero length. If a channel cannot be opened as required, the value of res indicates the reason, and cid identifies the invalid channel. *) PROCEDURE SpecialOpen(VAR cid: ChanId; mode: INTEGER; flags: FlagSet; VAR res: OpenResults); (* Attempts to open text according to the mode (see constants above). The text flag is implied. If a channel cannot be opened as required, the value of res indicates the reason, and cid identifies the invalid channel. If invoked not in Mithril attepmts to open file "Sys.Log" for openLog and appendLog modes and returns "noSuchFile" for other modes. *) PROCEDURE CurrentPos(cid: ChanId): FilePos; (* If the channel identified by cid is not open to a text file, the exception wrongDevice is raised; otherwise returns the position of the current read/write position. *) PROCEDURE EndPos(cid: ChanId): FilePos; (* If the channel identified by cid is not open to a text file, the exception wrongDevice is raised; otherwise returns the first position after which there have been no writes. *) PROCEDURE SetPos(cid: ChanId; pos: FilePos); (* If the channel identified by cid is not open to a text file, the exception wrongDevice is raised; otherwise sets the read/write position to the value given by pos. *) PROCEDURE IsTextFile(cid: ChanId): BOOLEAN; (* Tests if the channel identified by cid is open to a text file. *) PROCEDURE Close(VAR cid: ChanId); (* If the channel identified by cid is not open to a text file, the exception wrongDevice is raised; otherwise closes the channel, and assigns the value identifying the invalid channel to cid. *) END TextFile. ___________________________________________________________________ (* Copyright (c) 1994 xTech Ltd, Russia. *) IMPLEMENTATION MODULE TextFile; (* Ned 20-Oct-94. *) IMPORT IOChan, ChanConsts; <*# IF MITHRIL THEN *> IMPORT WinChan; <*# ELSE *> IMPORT RndFile; <*# END *> PROCEDURE OpenOld(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); BEGIN <*# IF MITHRIL THEN *> WinChan.OpenOld(cid,name,flags,res); <*# ELSE *> INCL(flags,ChanConsts.textFlag); RndFile.OpenOld(cid,name,flags,res); <*# END *> END OpenOld; PROCEDURE OpenClean(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); BEGIN <*# IF MITHRIL THEN *> WinChan.OpenClean(cid,name,flags,res); <*# ELSE *> INCL(flags,ChanConsts.textFlag); RndFile.OpenClean(cid,name,flags,res); <*# END *> END OpenClean; PROCEDURE SpecialOpen(VAR cid: ChanId; mode: INTEGER; flags: FlagSet; VAR res: OpenResults); BEGIN <*# IF MITHRIL THEN *> WinChan.SpecialOpen(cid,mode,flags,res); <*# ELSE *> IF mode = openLog THEN RndFile.OpenOld(cid,"Sys.Log",flags,res); ELSIF mode = appendLog THEN RndFile.OpenOld(cid,"Sys.Log",flags,res); IF res = ChanConsts.opened THEN RndFile.SetPos(cid,RndFile.EndPos(cid)); END; ELSE cid:=IOChan.InvalidChan(); res:=ChanConsts.noSuchFile; END; <*# END *> END SpecialOpen; PROCEDURE CurrentPos(cid: ChanId): FilePos; BEGIN <*# IF MITHRIL THEN *> RETURN WinChan.CurrentPos(cid); <*# ELSE *> RETURN RndFile.CurrentPos(cid); <*# END *> END CurrentPos; PROCEDURE EndPos(cid: ChanId): FilePos; BEGIN <*# IF MITHRIL THEN *> RETURN WinChan.EndPos(cid); <*# ELSE *> RETURN RndFile.EndPos(cid); <*# END *> END EndPos; PROCEDURE SetPos(cid: ChanId; pos: FilePos); BEGIN <*# IF MITHRIL THEN *> WinChan.SetPos(cid,pos); <*# ELSE *> RndFile.SetPos(cid,pos); <*# END *> END SetPos; PROCEDURE IsTextFile(cid: ChanId): BOOLEAN; BEGIN <*# IF MITHRIL THEN *> RETURN WinChan.IsTextFile(cid); <*# ELSE *> RETURN RndFile.IsRndFile(cid); <*# END *> END IsTextFile; PROCEDURE Close(VAR cid: ChanId); BEGIN <*# IF MITHRIL THEN *> WinChan.Close(cid); <*# ELSE *> RndFile.Close(cid); <*# END *> END Close; BEGIN <*# IF MITHRIL THEN *> IF (openLog # WinChan.openLog) OR (appendLog # WinChan.appendLog) OR (marked # WinChan.marked) OR (selection # WinChan.selection) THEN HALT END; <*# END *> END TextFile. ___________________________________________________________________ (** Copyright (c) 1994 xTech Ltd, Russia. *) (** Mithril v2.0 *) (** Implementation of ISO channels to texts *) MODULE WinChan; (* Ned 20-Oct-94. *) IMPORT SYSTEM ,IOLink ,IOChan ,io:=IOConsts ,cc:=ChanConsts (*---------*) ,Chars ,Errors ,Texts ,Windows ,TextWindows ,Utils ; CONST (* modes for SpecialOpen *) openLog* = 0; (* open SysLog text (CurrentPos = 0) *) appendLog* = 1; (* open SysLog text (CurrentPos = end of text) *) marked* = 2; (* open text in the marked window (CurrentPos = 0) *) selection* = 3; (* open the most recent (CurrentPos = selected position *) TYPE CARDINAL = SYSTEM.CARD32; FilePos = CARDINAL; ChanId = IOChan.ChanId; FlagSet = cc.FlagSet; OpenResults = cc.OpenResults; Object = IOLink.DeviceTablePtr; File = POINTER TO FileDesc; FileDesc = RECORD R: Texts.Rider; next: File; prev: File; END; VAR did: IOLink.DeviceId; files: File; (* list of all allocated files *) (*----------------------------------------------------------------*) PROCEDURE [1] Look(x: Object; VAR ch: CHAR; VAR res: io.ReadResults); VAR f: File; BEGIN f:=SYSTEM.VAL(File,x^.cd); f.R.Read(ch); IF f.R.eos THEN res:=io.endOfInput ELSE IF Chars.eol IN Chars.class[ch] THEN res:=io.endOfLine ELSE res:=io.allRight END; f.R.base.Set(f.R,f.R.Pos()-1); END; x^.result:=res; END Look; PROCEDURE [1] Skip(x: Object); VAR f: File; ch: CHAR; BEGIN f:=SYSTEM.VAL(File,x^.cd); f.R.Read(ch); IF f.R.eos THEN IOLink.RAISEdevException(x^.cid,x^.did,IOChan.skipAtEnd,""); ELSE x^.result:=io.allRight; END; END Skip; PROCEDURE [1] SkipLook(x: Object; VAR ch: CHAR; VAR res: io.ReadResults); VAR f: File; BEGIN f:=SYSTEM.VAL(File,x^.cd); f.R.Read(ch); IF f.R.eos THEN IOLink.RAISEdevException(x^.cid,x^.did,IOChan.skipAtEnd,""); END; f.R.Read(ch); IF f.R.eos THEN res:=io.endOfInput ELSE IF Chars.eol IN Chars.class[ch] THEN res:=io.endOfLine ELSE res:=io.allRight END; f.R.base.Set(f.R,f.R.Pos()-1); END; x^.result:=res; END SkipLook; PROCEDURE [1] TextRead(x: Object; a: SYSTEM.ADDRESS; n: CARDINAL; VAR locs: CARDINAL); VAR f: File; ch: CHAR; i: CARDINAL; p: POINTER TO ARRAY 1 OF CHAR; BEGIN f:=SYSTEM.VAL(File,x^.cd); p:=a; i:=0; WHILE i < n DO f.R.Read(ch); IF f.R.eos THEN locs:=i; IF i > 0 THEN x^.result:=io.allRight; ELSE x^.result:=io.endOfInput; END; RETURN ELSIF Chars.eol IN Chars.class[ch] THEN locs:=i; f.R.base.Set(f.R,f.R.Pos()-1); IF i > 0 THEN x^.result:=io.allRight; ELSE x^.result:=io.endOfLine; END; RETURN END; <*$< CHECKINDEX - *> p^[i]:=ch; <*$>*> INC(i); END; locs:=n; x^.result:=io.allRight; END TextRead; PROCEDURE [1] WriteLn(x: Object); VAR f: File; BEGIN f:=SYSTEM.VAL(File,x^.cd); f.R.WriteLn; END WriteLn; PROCEDURE [1] TextWrite (x: Object; from: SYSTEM.ADDRESS; len: CARDINAL); VAR f: File; p: POINTER TO ARRAY 7FFFH OF CHAR; BEGIN f:=SYSTEM.VAL(File,x^.cd); p:=from; f.R.WriteBlock(p^,0,len); END TextWrite; PROCEDURE [1] GetName(x: Object; VAR s: ARRAY OF CHAR); BEGIN COPY("*** text ***",s); END GetName; PROCEDURE Create(cid: ChanId; text: Texts.Text; pos: LONGINT; flags: cc.FlagSet; VAR res: OpenResults); VAR x: IOLink.DeviceTablePtr; f: File; BEGIN NEW(f); (* insert file in the list *) f.next:=files.next; f.prev:=files; f.next.prev:=f; f.prev.next:=f; (* attach rider *) text.Set(f.R,pos); x:=IOLink.DeviceTablePtrValue(cid,did <*# IF NOT EXCELSIOR THEN *> ,IOChan.notAvailable,"" <*# END *> ); x^.cd:=f; x^.flags:=flags; IF cc.writeFlag IN flags THEN x^.doTextWrite:=TextWrite; x^.doLnWrite:=WriteLn; END; IF cc.readFlag IN flags THEN x^.doTextRead:=TextRead; x^.doSkip:=Skip; x^.doLook:=Look; x^.doSkipLook:=SkipLook; END; x^.doGetName:=GetName; res:=cc.opened; END Create; (*----------------------------------------------------------------*) PROCEDURE CodeToRes(code: LONGINT; VAR res: OpenResults); BEGIN CASE code OF |Errors.badName : res:=cc.wrongNameFormat |Errors.noEntity : res:=cc.noSuchFile |Errors.noSpace : res:=cc.noRoomOnDevice |Errors.noMoreFiles: res:=cc.tooManyOpen ELSE res:=cc.otherProblem; END; END CodeToRes; PROCEDURE OpenOld*(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); VAR text: Texts.Text; BEGIN cid:=IOChan.InvalidChan(); IF cc.rawFlag IN flags THEN res:=cc.noRawOperations; RETURN END; flags:=flags+cc.text+cc.old; IF ~ (cc.writeFlag IN flags) THEN INCL(flags,cc.readFlag) END; text:=Texts.cur.This(name); IF Texts.cur.res # NIL THEN CodeToRes(Texts.cur.res.code,res) ELSE IOLink.MakeChan(did,cid); IF cid = IOChan.InvalidChan() THEN res:=cc.outOfChans; ELSE Create(cid,text,0,flags,res); IF res#cc.opened THEN IOLink.UnMakeChan(did,cid) END; END; END; END OpenOld; PROCEDURE OpenClean*(VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); VAR text: Texts.Text; BEGIN cid:=IOChan.InvalidChan(); IF cc.rawFlag IN flags THEN res:=cc.noRawOperations; RETURN END; flags:=flags+cc.text+cc.write; text:=Texts.cur.New(); IOLink.MakeChan(did,cid); IF cid = IOChan.InvalidChan() THEN res:=cc.outOfChans; ELSE Create(cid,text,0,flags,res); IF res#cc.opened THEN IOLink.UnMakeChan(did,cid); RETURN END; END; Utils.TextViewer("WinChan",name,{Utils.menu,Utils.scrollY},text); END OpenClean; PROCEDURE SpecialOpen*(VAR cid: ChanId; mode: LONGINT; flags: FlagSet; VAR res: OpenResults); VAR M: TextWindows.SelectionMsg; v: Windows.Window; BEGIN IF cc.rawFlag IN flags THEN cid:=IOChan.InvalidChan(); res:=cc.noRawOperations; RETURN END; IOLink.MakeChan(did,cid); IF cid = IOChan.InvalidChan() THEN res:=cc.outOfChans; RETURN END; INCL(flags,cc.textFlag); IF ~ (cc.writeFlag IN flags) THEN INCL(flags,cc.readFlag) END; IF mode = openLog THEN Create(cid,Texts.log,0,flags,res); ELSIF mode = appendLog THEN Create(cid,Texts.log,Texts.log.len,flags,res); ELSIF mode = selection THEN TextWindows.GetSelection(M); IF M.stamp>=0 THEN Create(cid,M.text,M.beg,flags,res); ELSE res:=cc.noSuchFile; END; ELSIF mode = marked THEN v:=Utils.Marked(); IF v=NIL THEN res:=cc.noSuchFile; ELSE v:=Utils.Lookup(v,Utils.WORK,TRUE); IF (v=NIL) OR ~ (v IS TextWindows.Window) THEN res:=cc.wrongFileType; ELSE Create(cid,v(TextWindows.Window).text,0,flags,res); END; END; ELSE ASSERT(FALSE); END; IF res#cc.opened THEN IOLink.UnMakeChan(did,cid) END; END SpecialOpen; PROCEDURE CurrentPos*(cid: ChanId): FilePos; VAR x: Object; f: File; BEGIN x:=IOLink.DeviceTablePtrValue(cid,did <*# IF NOT EXCELSIOR THEN *> ,IOChan.notAvailable,"" <*# END *> ); f:=SYSTEM.VAL(File,x^.cd); RETURN f.R.Pos() END CurrentPos; PROCEDURE EndPos*(cid: ChanId): FilePos; VAR x: Object; f: File; BEGIN x:=IOLink.DeviceTablePtrValue(cid,did <*# IF NOT EXCELSIOR THEN *> ,IOChan.notAvailable,"" <*# END *> ); f:=SYSTEM.VAL(File,x^.cd); RETURN f.R.base.Length() END EndPos; PROCEDURE SetPos*(cid: ChanId; pos: FilePos); VAR x: Object; f: File; BEGIN x:=IOLink.DeviceTablePtrValue(cid,did <*# IF NOT EXCELSIOR THEN *> ,IOChan.notAvailable,"" <*# END *> ); f:=SYSTEM.VAL(File,x^.cd); f.R.base.Set(f.R,pos); END SetPos; PROCEDURE IsTextFile*(cid: ChanId): BOOLEAN; BEGIN RETURN IOLink.IsDevice(cid,did) END IsTextFile; PROCEDURE Close*(VAR cid: ChanId); VAR x: Object; f: File; BEGIN x:=IOLink.DeviceTablePtrValue(cid,did <*# IF NOT EXCELSIOR THEN *> ,IOChan.notAvailable,"" <*# END *> ); f:=SYSTEM.VAL(File,x^.cd); f.next.prev:=f.prev; f.prev.next:=f.next; IOLink.UnMakeChan(did,cid); END Close; BEGIN IOLink.AllocateDeviceId(did); NEW(files); files.next:=files; files.prev:=files; END WinChan. ___________________________________________________________________ Examples: ___________________________________________________________________ MODULE tf; (* AN 21-Oct-94. *) IMPORT T:=TextFile, io:=TextIO, sio:=STextIO, StdChans, ior:=IOResult; PROCEDURE OpenOut*; VAR cid,old: T.ChanId; res: T.OpenResults; BEGIN T.OpenClean(cid,"Output",T.write+T.old,res); IF res # T.opened THEN ASSERT(FALSE) END; old:=StdChans.OutChan(); StdChans.SetOutChan(cid); IF T.IsTextFile(old) THEN T.Close(old) END; END OpenOut; PROCEDURE Hello*; VAR cid: T.ChanId; res: T.OpenResults; BEGIN T.SpecialOpen(cid,T.appendLog,T.write,res); IF res # T.opened THEN ASSERT(FALSE) END; io.WriteString(cid,"Hello"); io.WriteLn(cid); T.Close(cid); END Hello; PROCEDURE Error(s: ARRAY OF CHAR); BEGIN sio.WriteString(s); sio.WriteLn; END Error; PROCEDURE Marked*; VAR cid: T.ChanId; res: T.OpenResults; ch: CHAR; BEGIN T.SpecialOpen(cid,T.marked,T.read,res); IF res # T.opened THEN Error("no marked window"); RETURN END; sio.WriteString("**** first line from marked window ****"); sio.Write Ln; LOOP io.ReadChar(cid,ch); IF ior.ReadResult(cid) # ior.allRight THEN EXIT END; sio.WriteChar(ch); END; sio.WriteLn; T.Close(cid); END Marked; PROCEDURE Selected*; VAR cid: T.ChanId; res: T.OpenResults; ch: CHAR; BEGIN T.SpecialOpen(cid,T.selection,T.read,res); IF res # T.opened THEN Error("no selection"); RETURN END; sio.WriteString("**** first line from selection ****"); sio.WriteLn; LOOP io.ReadChar(cid,ch); IF ior.ReadResult(cid) # ior.allRight THEN EXIT END; sio.WriteChar(ch); END; sio.WriteLn; T.Close(cid); END Selected; PROCEDURE Text*; VAR cid: T.ChanId; res: T.OpenResults; ch: CHAR; BEGIN T.OpenOld(cid,"tf.o",T.read,res); IF res # T.opened THEN Error("open error"); RETURN END; LOOP io.ReadChar(cid,ch); CASE ior.ReadResult(cid) OF |ior.endOfLine : io.SkipLine(cid); sio.WriteLn; |ior.endOfInput: EXIT |ior.allRight : sio.WriteChar(ch); END; END; T.Close(cid); END Text; BEGIN OpenOut; END tf. ___________________________________________________________________ MODULE tfs; (* 21-Oct-94. (c) KRONOS *) IMPORT tf, StdChans, T:=TextFile; VAR cid: T.ChanId; BEGIN tf.Marked; tf.Text; tf.Selected; cid:=StdChans.OutChan(); T.Close(cid); END tfs.

The ModulaTor Forum

Recommended Reading

by Günter Dotzel

A Gathering of Gardner, by Martin Gardner, Freeman, 1987.
This is a collection of the following three books, also available separately (with descriptions of the books' cover):

Knotted doughnuts and other mathematical entertainments, by Martin Gardner, Freeman, 1986.
From coincidences that seem to violate the laws of probaility, to the mysterious sequences of hexagrams in the I Ching, to the controversial and uproarious pseudoscientific economics of the Laffer curve.

Penrose tiles to trapdoor ciphers ... and the return of Dr. Matrix, by Martin Gardner, Freeman, 1986.
Gardner introduces us to Conway's Surreal Numbers, Mandelbrot's Fractals, and Smullyan's Logic Puzzles.

Time travel and other mathematical bewilderments, by Martin Gardner, Freeman, 1987.
From coincidences that seem to violate the laws of time and space, to the perplexities of the rubber rope, to the centuries-old delights of tangram play, the puzzles, problems, and paradoxes presented in Time travel and other mathematical bewilderments reveal just how enlightening and entertaining mathematical recreations can be.


IMPRESSUM: The ModulaTor is an unrefereed journal. Technical papers are to be taken as working papers and personal rather than organizational statements. Items are printed at the discretion of the Editor based upon his judgement on the interest and relevancy to the readership. Letters, announcements, and other items of professional interest are selected on the same basis. Office of publication: The Editor of The ModulaTor is Guenter Dotzel; he can be reached by tel/fax: [removed due to abuse] or by mailto:[email deleted due to spam]


Home | Site_index | Legal | OpenVMS_compiler | Alpha_Oberon_System | ModulaTor | Bibliography | Oberon[-2]_links | Modula-2_links |

Amazon.com [3KB] [Any browser]

Books Music Video Enter keywords...


Amazon.com logo

Webdesign by www.otolo.com/webworx, 07-Dec-1998