T3X/0 - A NEW T3X COMPILER T3X is a family of small, portable, procedural, block-structured, recursive, and almost typeless programming languages. The T3X syntax is similar to Pascal, its semantics resembles BCPL's. T3X/0 is the latest member of the T3X family. It is simpler than the full (Release 7) language, but more complete than the more minimalistic T3X9 branch. See the files "docs/t3x.txt" and "docs/t3x-libs.txt" for an introduction to T3X/0 and its modules. See the "programs" directory for lots of T3X/0 example programs. The coolest thing about the T3X/0 compiler is its simplicity. All you *really* need to compile and run T3X/0 programs is contained in the base directory of the source tree. You do not even need to install the compiler. From there you can build incrementally: build DOS and CP/M cross compilers, install the compiler, build native code compilers for Unix on the 386, x86 or 32-bit ARM. The compiler presented here is a single-stage two-pass compiler that is aimed to be ported quickly to new platforms, typically by just writing a new machine description file. The compiler can run on systems as minimal as CP/M on a Z80 CPU and easily fits in a tiny model DOS executable. It self-compiles in ten minutes on a 4MHz CP/M system -- and in the blink of an eye on a modern Unix system. CURRENTLY SUPPORTED PLATFORMS Operating System CPU Output format Requires ------------------ ------ ------------------- ----------------- Generic Unix VM Tcode/0 TCVM Generic Unix 386 assembly language C compiler Generic Unix x86_64 assembly language C compiler Generic Unix ARMv6 assembly language C compiler Generic Unix ARMv7 assembly language C compiler FreeBSD 386 assembly language assembler, loader macOS x86_64 assembly language C compiler PCDOS 2.0 VM Tcode/0 TCVM PCDOS 2.0 8086 COM - CP/M 2.2 Z80 COM 46K bytes TPA The compiler can operate natively or as a cross-compiler. Almost all combinations are supported: for example, you can cross- compile on CP/M for the TCVM, on the TVCM for Unix, on Unix for DOS, and on DOS for CP/M. Or on CP/M for DOS, etc. The only combinations that are not possible are cross-compilation to Unix on CP/M or DOS, because the source code emitter is too large. ---------------------------------------------------------------- NOTE ---------------------------------------------------------------- When compilation is aborted and re-compilation fails, this is usually due to the wrong code generator being linked in place. In this case the following line should bring the code back to a useful state: make clean; make reset; make QUICK BUILD To build and test the T3X/0 compiler, just run make triple test This will build the compiler and run the triple test and the test suite. This step should print "Looks good!" at the end. If compilation of the TCVM (tcvm.c) should fail, try removing its EXTRA, SYSTEM, and/or CONSOLE options in the Makefile. QUICK USAGE After building the compiler successfully, you can compile programs by typing ./tcvm txtrn program This will compile "program.t" to "program.tc". You can then run the program by typing ./tvcm program You can also specify an output file name, e.g.: ./tcvm txtrn programs/apfel test which will compile "programs/apfel.t" and place the binary in the file "test.tc" in the local directory. INSTALLATION ON UNIX First select a host platform and edit at least the HOST, T3XDIR and BINDIR variables in Makefile. T3XDIR is where the T3X binary tree will be installed and BINDIR is where the "tx0" compiler driver and the TCVM binary will go. Some platforms also require to select specific CFLAGS in Makefile. If you are only building the Tcode (bytecode) compiler, you do not need to configure the HOST variable. Also edit T3XDIR in bin/tx0.sh. You also may have to select a "target" manually, if the script fails to guess it, but you can do that later. Finally update the T3XDIR variables in the code generators. This is only necessary if you actually changed T3XDIR above. This step involves replacing the default T3XDIR (/usr/local/t3x/0/) with your new one in all strings in the modpath functions of all code generators -- but you do not have to do this manually. The bin/modpath.sh script will automate this task for you. Just run bin/modpath.sh your-new-t3xdir/ !!! Note the trailing slash, it has to be there! !!! "your-new-t3xdir" must be an absolute path. You are then ready to compile and install T3X/0. If you are running a system that supports native code generation (see list at the top of this file), run # you may have to acquire root privileges make install-native or make all-native # you may have to acquire root privileges make install-native If you are running a different system (or if the above fails), you may still install Tcode binaries of the compiler. They will offer most of the functionality as the native compiler, but run at reduced speed. To install the Tcode binaries, run make install-tcode INSTALLATION ON MACOS The instructions for installing T3X/0 on Unix should also work for installing it on macOS. INSTALLATION ON CP/M AND DOS If you are running DOS or CP/M, you can just install the pre-compiled binaries from the "bin" directory. To install the compiler on CP/M, copy the file "bin/tx-cpm.com" to TX0.COM on your CP/M disk. Then convert the file "targets/txcpmz80.t" to CP/M text file format and install it as T3X.T on your CP/M disk. The program "programs/cpmfile.t" can be used to convert the file on Unix: ./tcvm txtrn programs/cpmfile cpmfile ./tcvm cpmfile targets/txcpmz80.t t3x-cpm.t To install the compiler on DOS, copy the file "bin/tx-dos.com" to TX0.COM on your DOS disk and install "targets/txdos86c.t" as T3X.T. Conversion to DOS text file format is optional (it can be done with the program "programs/dosfile.t"). You may also copy the library files in the library/ directory to your DOS or CP/M system. Note that there are multiple versions of the CONSOLE, HOST, and SYSTEM, modules, one for every supported system. Only one of the files must be installed as CONSOLE.T, HOST.T, and SYSTEM.T. The location of the library files depends on the "modpath" setting of your compiler configuration. A simple solution is to put the compiler binaries and the library files in the same directory (or a subdirectory called "library"). Programs can then be compiled from within the directory in which the compiler resides. Alternatively, you may compile the TXCONF utility contained in the "programs" directory and use it to patch the compiler so that it can be installed in a location of your choice. Library files must be converted to CP/M text format on CP/M. COMPILER USAGE This requires either the Tcode or native code binaries to be installed on your system. See INSTALLATION, above. The T3X/0 compiler driver is called TX0. When just a program file name is passed to it, it will compile it to an executable program, e.g. tx0 hello will compile the file "hello.t" and produce an executable file. When an output file name is also given, the resulting executable will be placed in that file. E.g. tx0 foo bar will compile "foo.t" to an executable named "bar". The executable may or may not have a suffix, depending on the type of the generated file. Note that the compiler will generate suffixes itself, so running tx0 hello.t ### WRONG ### will not work. The name of the executable file depends on the selected target. Tcode files will have a ".tc" suffix, Unix executables will not have any suffix at all, and DOS and CP/M executables will have a ".com" suffix. The default target will be Tcode when only Tcode binaries are installed on your system and Unix executables when native code binaries are installed on a Unix system. A different target can be specified using the -t option. For example, tx0 -t cpm hello will generate a CP/M executable named "hello.com". The targets "tcvm", "dos", and "cpm" are available in both native and Tcode installations. Unix installations add a "unix" target, like "unix-386" or "unix-armv6". The default is "tcvm" in Tcode installations and a "unix" target in Unix installations. Run TX0 without argument to print a list of available targets. In native code installations, specifying the "-t tcvm" option will generate Tcode instead of native code. The -b option will invoke the boostrapping compiler. The only difference between the bootstrapping compiler and the regular TCVM compiler is that the bootstrapping compiler will look for modules in the current working directory first, while the regular compilers will search system-dependent directories first. When "/V" is specified as an output file name, the compiler will print the name of each procedure it compiles. The name of the output file will be the default, i.e. the name of the input file with its suffix removed and an executable suffix attached, if any. BUILDING CROSS COMPILERS The "bin/build.sh" script can be used to build all T3X/0 cross compilers automatically. Just run bin/build.sh host target to generate a compiler that will run on the given host and generate code for the given target. There is a total of 14 different compilers that can be built from the code: Target --> TCVM CP/M DOS Unix(*) Host ---- TCVM txtrn.tc tx-cpm.tc tx-dos.tc tx-unix-*.tc txtcvm.t txcpmz80.t txdos86c.t txunx*.t CP/M tx-tcvm.com tx-cpm.com tx-dos.com (**) txtcvm.t txcpmz80.t txdos86c.t DOS tx-tcvm.com tx-cpm.com tx-dos.com (**) txtcvm.t txcpmz80.t txdos86c.t Unix(*) tx-tcvm tx-cpm tx-dos tx-unix-* txtcvm.t txcpmz80.t txdos86c.t txunx*.t (*) There are different CPU-specific Unix backends, like unix-386 or unix-armv6. Only the backend for the host platform can be installed. No cross compilation between the Unix platforms is possible. There is also an alternative backend for FreeBSD. See below. (**) These compilers cannot be built, because they would be too large. For example, bin/build.sh cpm dos will generate an executable named "tx-dos.com" that will run on CP/M and generate code for DOS. In order to work, the compiler will need a matching core module named "t3x.t", in this case the file "targets/txdos86c.t" renamed as "t3x.t". Note that there will be lots of naming conflicts. The DOS and CP/M compilers all share names, and the core module of every compiler must be named "t3x.t". When installed, the Unix compiler driver "tx0" will take care of these details. On other systems it is up to you to create a workable solution. X86-64 AND 386 BACKENDS The x86_64 and 386 backends can both be installed on an x86_64 machine, if it supports 32-bit executables. You can choose either one or you can install both. In order to install both, build T3X/0 using one host, install it, rebuild it with the other host and install it again. E.g.: $ make clean --> change HOST to unix-386 in Makefile, add -m32 to CFLAGS $ make install-native $ make clean --> change HOST to unix-686, remove -m32 from CFLAGS $ make install-native After installing both, the 686 (x86_64) backend will be used by default, but 32-bit binaries can be generated using the the -t option: $ tx0 -t unix-386 program THE FREEBSD BACKEND There is a backend for FreeBSD which has some advantages and some disadvantages compared to the generic Unix backend. PRO: - fast - small, static executables CON: - less portable - no T.BREAK function - no external procedures The greatest advantage is that is compiles to very compact *static* executables and does not depend on the C runtime library. The static T3X/0 compiler executable has a size of less than 40K bytes. It is smaller than the dynamic executable generated by the generic Unix backend. The greatest disadvantage is that there is no C runtime library to gloss over the internal differences between the various FreeBSD systems, so there is no guarantee that it will run on any system except for FreeBSD 12.4 (on which it has been tested). Then compile times are lightning fast, because no multi-megabyte C compiler behemoth has to be shoveled into memory. This might not be a big issue these days, but self-compiling T3X/0 in 0.17 seconds on a 1000MHz system is pretty cool (0.31s using the generic Unix backend). However, the FreeBSD backend does not have the T3X.BREAK function for intercepting keyboard interrupts, because the emulation of signal() has become so bizarrely complicated in the recent years that I have just given up on it. Also the FreeBSD backend currently does not support external procedures. This could theoretically be fixed in the compiler driver, bin/tx0.sh. To use the FreeBSD backend, change the value of HOST in Makefile to "fbsd-386" and then run make clean; make; make fbsd-386-test If it works, great! If it fails, use the generic Unix backend. You can use HOST=unix-386 and the "install-fbsd-native" make target to install both the generic Unix backend and the FreeBSD backend. The Unix backend will be the default, but you can use tx0 -t fbsd-386 program to activate the FreeBSD static code generator.