[comp.lang.modula3] Modula-3 binding for Tcl

muller@src.dec.com (Eric Muller) (03/16/91)

[ For tcl-oriented readers: Modula-3 is a programming language
  developed by Digital Equipment SRC and Olivetti. Send me a message
  if you want more info, or join the comp.lang.modula3 newsgroup. ]

[ For Modula-3-oriented readers: tcl is a simple command language; you
  can embed tcl interpreters in programs. There is also an associated X
  toolkit. Send me a message if you want more info, or join the tcl
  mailing list (tcl-request@sprite.berkeley.edu). ]


I played with tcl and being a Modula-3 fanatic I made a binding
interface. The shar file below contains TclC.i3 and Test.m3, a simple
test program. Test.m3 defines the "fact" command (implemented in
Modula-3) and repeatedly reads stdin to feed an interpreter and sends
its output to stdout.

This interface is a "raw" interface. It maps directly the C world. I
will probably work on a "nice" interface, using Text.T rather than
C.char_star and so on. Another thing would be a TclWriter.T, created on
top of another Wr.T; when tcl commands are fed into this TclWriter, it
writes the result of the evaluation on its underlying Wr.T.
Suggestions are welcome.

While doing this exercise, I discovered the following details about
the tcl man pages:
  - Tcl_AddErrorInfo:   returns void (instead of char*)
  - Tcl_AppendResult:   interp is an in argument (instead of out)
  - Tcl_Eval:           flags is an int (instead of char)
  - Tcl_RecordAndEval:  idem
  - Tcl_GetInt:         TCL_OK and TCL_ERRROR are in roman (instead of bold)


Thanks to John for this great little tool,
Eric.



---- Cut Here and unpack ----
#!/bin/sh
# This is a shell archive (shar 3.32)
# made 03/16/1991 06:28 UTC by muller@procope.pa.dec.com
# Source directory /flimflam/dlusers2/muller/src/Tk/m3
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   5976 -rw-r--r-- TclC.i3
#   1880 -rw-r--r-- Test.m3
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= TclC.i3 ==============
echo "x - extracting TclC.i3 (Text)"
sed 's/^X//' << 'SHAR_EOF' > TclC.i3 &&
X(* Copyright (C) 1991, Digital Equipment Corporation           *)
X(* All rights reserved.                                        *)
X
X(* Last modified on Sat Mar 16 07:37:04 1991 by muller         *)
X
X
X(* This file has been derived from tcl.h, covered by the following copyright:
X
X * Copyright 1987, 1990 Regents of the University of California
X * Permission to use, copy, modify, and distribute this
X * software and its documentation for any purpose and without
X * fee is hereby granted, provided that the above copyright
X * notice appear in all copies.  The University of California
X * makes no representations about the suitability of this
X * software for any purpose.  It is provided "as is" without
X * express or implied warranty.
X *)
X
XUNSAFE INTERFACE TclC;
X
XFROM Ctypes IMPORT char_star, int_star, int, char, double;
XIMPORT Word;
X
XCONST
X  TCL_OK       = 0;
X  TCL_ERROR    = 1;
X  TCL_RETURN   = 2;
X  TCL_BREAK    = 3;
X  TCL_CONTINUE = 4;
X
X  BRACKET_TERM  = 1;
X  NO_EVAL       = -1;
X
X  STATIC   = 0;
X  DYNAMIC  = 1;
X  VOLATILE = 2;
X
X  TRACE_READS	= 1;
X  TRACE_WRITES  = 2;
X  TRACE_DELETES = 4;
X
X  VARIABLE_UNDEFINED = 8;
X
X
XTYPE
X  Argv   = UNTRACED REF ARRAY [0..255] OF char_star;
X  Interp = UNTRACED REF RECORD
X             result: char_star; (* Points to result string returned by 
X                                   command. *)
X             dynamic: int;	(* Non-zero means result is dynamically-
X				   allocated and must be freed by Eval
X				   before executing the next command. *)
X             errorLine: int;    (* When TCL_ERROR is returned, this gives
X				   the line number within the command where
X				   the error occurred (1 means first line). *)
X             END;
X
X  ClientData = Word.T;
X
X             
X
X<*EXTERNAL Tcl_AddErrorInfo *>
XPROCEDURE AddError (interp: Interp; message: char_star);
X
X<*EXTERNAL Tcl_AppendResult *>
XPROCEDURE AppendResult (interp: Interp; s1, s2, s3, s4, s5: char_star := NIL);
X
XTYPE
X  CmdBuf = int_star;
X
X<*EXTERNAL Tcl_CreateCmdBuf *>
XPROCEDURE CreateCmdBuf (): CmdBuf;
X
X<*EXTERNAL Tcl_DeleteCmdBuf *>
XPROCEDURE DeleteCmdBuf (buffer: CmdBuf);
X
X<*EXTERNAL Tcl_AssembleCmd *>
XPROCEDURE AssembleCmd (buffer: CmdBuf; string: char_star): char_star;
X
X<*EXTERNAL Tcl_Backslash *>
XPROCEDURE Backslash (src: char_star; VAR count: int): char;
X
X<*EXTERNAL Tcl_Concat *>
XPROCEDURE Concat (argc: int; argv: Argv): char_star;
X
XTYPE
X  CommandProc = PROCEDURE (clientData: ClientData;
X                           interp: Interp;
X                           argc:   int;
X                           argv:   Argv): int;
X
X  DeleteProc  = PROCEDURE (clientData: ClientData);
X
X<*EXTERNAL Tcl_CreateCommand *>
XPROCEDURE CreateCommand (interp: Interp; 
X                         cmdName: char_star; 
X                         proc: CommandProc;
X                         clientData: ClientData;
X                         deleteProc: DeleteProc);
X
X<*EXTERNAL Tcl_CreateInterp *>
XPROCEDURE CreateInterp (): Interp;
X
XTYPE
X  TraceProc = PROCEDURE (clientData: ClientData;
X                         interp: Interp;
X                         level: int;
X                         command: char_star;
X                         cmdProc: CommandProc;
X                         cmdClientData: ClientData;
X                         argc: int;
X                         argv: Argv);
X  Trace = int_star;
X
X<*EXTERNAL Tcl_CreateTrace *>
XPROCEDURE CreateTrace (interp: Interp;
X                       level: int;
X                       proc: TraceProc;
X                       clientData: ClientData): Trace;
X
X<*EXTERNAL Tcl_DeleteCommand *>
XPROCEDURE DeleteCommand (interp: Interp; cmdName: char_star);
X
X<*EXTERNAL Tcl_DeleteInterp *>
XPROCEDURE DeleteInterp (interp: Interp);
X
X<*EXTERNAL Tcl_DeleteTrace *>
XPROCEDURE DeleteTrace (interp: Interp; trace: Trace);
X
X<*EXTERNAL Tcl_Eval *>
XPROCEDURE Eval (interp: Interp;
X                cmd: char_star;
X                flags: int;
X                termPtr: Argv): int;
X
X<*EXTERNAL Tcl_Expr *>
XPROCEDURE Expr (interp: Interp; string: char_star; VAR value: int): int;
X
X<*EXTERNAL Tcl_GetInt *>
XPROCEDURE GetInt (interp: Interp; string: char_star; VAR val: int): int;
X
X<*EXTERNAL Tcl_GetDouble *>
XPROCEDURE GetDouble (interp: Interp; string: char_star; VAR val: double): int;
X
X<*EXTERNAL Tcl_GetBoolean *>
XPROCEDURE GetBoolean (interp: Interp; string: char_star; VAR value: int): int;
X
X<*EXTERNAL Tcl_GetVar *>
XPROCEDURE GetVar (interp: Interp; varName: char_star; global: int): char_star;
X
X<*EXTERNAL Tcl_Merge *>
XPROCEDURE Merge (argc: int; argv: Argv): char_star;
X
X<*EXTERNAL Tcl_ParseVar *>
XPROCEDURE ParseVar (interp: Interp;
X	            string: char_star;
X		    term: Argv): char_star;
X
X<*EXTERNAL Tcl_RecordAndEval *>
XPROCEDURE RecordAndEval (interp: Interp; cmd: char_star; flags: int): int;
X
X<*EXTERNAL Tcl_Return *>
XPROCEDURE Return (interp: Interp; string: char_star; status: int);
X
X<*EXTERNAL Tcl_SetVar *>
XPROCEDURE SetVar (interp: Interp; varName, newValue: char_star; global: int);
X
X<*EXTERNAL Tcl_SplitList *>
XPROCEDURE SplitList (interp: Interp; 
X 		     list: char_star;
X		     VAR argc: int;
X		     VAR argv: Argv): int;
X
X<*EXTERNAL Tcl_StringMatch *>
XPROCEDURE StringMatch (string, pattern: char_star): int;
X
X<*EXTERNAL Tcl_TildeSubst *>
XPROCEDURE TildeSubst (interp: Interp; name: char_star): char_star;
X
XTYPE
X  VarTraceProc = PROCEDURE (clientData: ClientData;
X                            interp: Interp;
X			    varName: char_star;
X                            global, flags: int;
X                            oldValue, newValue: char_star): char_star;
X
X<*EXTERNAL Tcl_TraceVar *>
XPROCEDURE TraceVar (interp: Interp; 
X		    varName: char_star;
X		    global, flags: int;
X		    proc: VarTraceProc;
X		    clientData: ClientData): int;
X
X<*EXTERNAL Tcl_UnTraceVar *>
XPROCEDURE UnTraceVar (interp: Interp; varName: char_star; global: int);
X
X<*EXTERNAL Tcl_VarTraceInfo *>
XPROCEDURE VarTraceInfo (interp: Interp; 
X			varName: char_star; 
X			global: int;
X			VAR proc: VarTraceProc;
X			VAR clientData: ClientData): int;
X
XEND TclC.
SHAR_EOF
$TOUCH -am 0315222891 TclC.i3 &&
chmod 0644 TclC.i3 ||
echo "restore of TclC.i3 failed"
set `wc -c TclC.i3`;Wc_c=$1
if test "$Wc_c" != "5976"; then
	echo original size 5976, current size $Wc_c
fi
# ============= Test.m3 ==============
echo "x - extracting Test.m3 (Text)"
sed 's/^X//' << 'SHAR_EOF' > Test.m3 &&
X(* Copyright (C) 1991, Digital Equipment Corporation           *)
X(* All rights reserved.                                        *)
X

X
XUNSAFE MODULE Test EXPORTS Main;
X
XIMPORT TclC;
XIMPORT Rd, Wr, Stdio, Fmt;
XFROM M3toC IMPORT TtoS, CopyTtoS, CopyStoT;
XFROM Ctypes IMPORT int, char_star;
X
XPROCEDURE FactCmd (<*UNUSED*> clientData: TclC.ClientData;
X		   interp: TclC.Interp;
X   	 	   argc: int;
X		   argv: TclC.Argv): int =
X  BEGIN
X    IF argc # 2 THEN
X      interp.result := TtoS ("fact has exactly one argument");
X      RETURN TclC.TCL_ERROR; 
X    ELSE
X      VAR i: INTEGER; BEGIN
X        IF TclC.GetInt (interp, argv[1], i) = TclC.TCL_ERROR THEN
X          RETURN TclC.TCL_ERROR; END;
X        interp.result := CopyTtoS (Fmt.Int (Fact (i)));
X        RETURN TclC.TCL_OK; END; END;
X  END FactCmd;
X
XPROCEDURE Fact (i: INTEGER): INTEGER =
X  BEGIN
X    IF i = 1 THEN
X      RETURN 1;
X    ELSE 
X      RETURN i * Fact (i - 1); END;
X  END Fact;
X
X
XVAR
X  i: TclC.Interp;
X  buf: TclC.CmdBuf;
X  s: char_star;
X  status: int;
X
XBEGIN
X  i := TclC.CreateInterp ();
X  TclC.CreateCommand (i, TtoS ("fact"), FactCmd, 0, NIL);
X  buf := TclC.CreateCmdBuf ();
X
X  TRY
X    LOOP 
X      s := TclC.AssembleCmd (buf, TtoS (Rd.GetLine (Stdio.stdin) & "\n"));
X      IF s # NIL THEN
X        status := TclC.Eval (i, s, 0, NIL);
X        CASE status OF 
X        | TclC.TCL_OK =>
X            Wr.PutText (Stdio.stderr, "-> " & CopyStoT (i.result) & "\n"); 
X        | TclC.TCL_ERROR =>
X            Wr.PutText (Stdio.stderr, "error: " & CopyStoT (i.result) & "\n"); 
X        ELSE
X            Wr.PutText (Stdio.stderr, "TclC.Eval returned with code = " 
X					& Fmt.Int (status) & "\n"); 
X                                                        END; END; END; 
X  EXCEPT
X  | Rd.EndOfFile => END;
X
X  TclC.DeleteCmdBuf (buf);
X  TclC.DeleteInterp (i);
XEND Test.
SHAR_EOF
$TOUCH -am 0315222691 Test.m3 &&
chmod 0644 Test.m3 ||
echo "restore of Test.m3 failed"
set `wc -c Test.m3`;Wc_c=$1
if test "$Wc_c" != "1880"; then
	echo original size 1880, current size $Wc_c
fi
exit 0