Anyone interested in resurrecting an open source strict Ada 83 (mil-std 1815A) compiler?

Some short news about the Ada 83 compiler. The TEXT_IO package has progressed and the private record type FILE_TYPE with a FILE_NAME_BUFFER is now used, a file can be created opened and deleted under Linux. I had to implement string slices because the FILE_TYPE has no discriminant, that means the file name must be kept in a larger fixed size string buffer with name length aside and the file name is a slice when used. I keep on to implement text file PUT, GET and other services.

The notion of type template or “patron de type” or “use info” is effectively very important in Ada, a variable has a data part and a “use info part”. This is implemented with two pointers, a pointer doublet. The use info part gives information on how to use the data part ; for example the 'FIRST and 'LAST for a string or a slice are in this “use info” with array component size.
This characteristic explains the Rational R1000 memory structure with its various stacks. It seems to me that the usual work stack can be used with less extremist policy than in the R1000 and can contain also use info and data blocks, with the conditions that their size is fixed and known at compile time. Blocks whose size is fixed but only known at runtime can be allocated in another stack with parallel frame context, and blocks whose size can vary, allocated in the heap.

Developping with fasm intermediate text is handy for debugging because everything is readable and can be edited to correct or try something. Inserting a breakpoint trap with a “db 0xCC” in the fasm text allows for gdb stop at will on x86. Debugging on gdb can be done with “lay asm”, “lay reg”, “run”, “x/” and so on.

3 Likes

Hello to all, one year later, some news of the TLALOC strict Ada 83 compiler all written in Ada 83 itself. It progresses, slowly, TEXT_IO can put/get enums, integers, floats. The fasmg macros stack machine can compute with floats. Some vicious stack bugs have been corrected. I am working on DIRECT_IO block version then full version able to compile some things as : package STRING_IO is new DIRECT_IO( STRING ). Two repositories are available and roughly in lock step, the historical one on Framagit, a second one for safety on Github : GitHub - ViMoBr/Ada83_TLALOC · GitHub . If someone is interested and needs information on how to use or develop this experimental and relatively complicated (but very interesting) system. An example of what it currently compiles and executes :

with TEXT_IO;
use  TEXT_IO;
procedure ENUM_TEST
is

  type COULEUR	is ( BLEU, BLANC, ROUGE );
  type JOUR	is ( LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE );

  package IO_COULEUR	is new ENUMERATION_IO( COULEUR );
  package IO_JOUR		is new ENUMERATION_IO( JOUR );
  package IO_MODE		is new ENUMERATION_IO( FILE_MODE );

  C	: COULEUR;
  J	: JOUR;

  G	: FILE_TYPE;

begin

  -- === 1. PUT basique ===
  PUT_LINE( "=== 1. PUT basique ===" );
  IO_COULEUR.PUT( BLEU );	NEW_LINE;
  IO_COULEUR.PUT( BLANC );	NEW_LINE;
  IO_COULEUR.PUT( ROUGE );	NEW_LINE;

  -- === 2. PUT avec WIDTH ===
  PUT_LINE( "=== 2. PUT avec WIDTH ===" );
  PUT( "[" );  IO_COULEUR.PUT( BLEU, WIDTH => 10 );   PUT_LINE( "]" );
  PUT( "[" );  IO_COULEUR.PUT( ROUGE, WIDTH => 10 );  PUT_LINE( "]" );

  -- === 3. PUT LOWER_CASE ===
  PUT_LINE( "=== 3. PUT LOWER_CASE ===" );
  IO_COULEUR.PUT( BLEU,  SET => LOWER_CASE );	NEW_LINE;
  IO_COULEUR.PUT( BLANC, SET => LOWER_CASE );	NEW_LINE;
  IO_COULEUR.PUT( ROUGE, SET => LOWER_CASE );	NEW_LINE;

  -- === 4. PUT via variable ===
  PUT_LINE( "=== 4. PUT via variable ===" );
  C := BLANC;  IO_COULEUR.PUT( C );  NEW_LINE;
  C := ROUGE;  IO_COULEUR.PUT( C );  NEW_LINE;

  -- === 5. PUT sans FILE ===
  PUT_LINE( "=== 5. PUT sans FILE ===" );
  IO_COULEUR.PUT( BLEU );  NEW_LINE;

  -- === 6. Type JOUR ===
  PUT_LINE( "=== 6. Type JOUR ===" );
  IO_JOUR.PUT( LUNDI );     NEW_LINE;
  IO_JOUR.PUT( MERCREDI );  NEW_LINE;
  IO_JOUR.PUT( DIMANCHE );  NEW_LINE;

  -- === 7. JOUR WIDTH+LOWER_CASE ===
  PUT_LINE( "=== 7. JOUR WIDTH+LOWER_CASE ===" );
  PUT( "[" );
  IO_JOUR.PUT( SAMEDI, WIDTH => 12, SET => LOWER_CASE );
  PUT_LINE( "]" );

  -- === 8. FILE_MODE ===
  PUT_LINE( "=== 8. FILE_MODE ===" );
  IO_MODE.PUT( IN_FILE );   NEW_LINE;
  IO_MODE.PUT( OUT_FILE );  NEW_LINE;

  -- === 9. Boucle couleurs ===
  PUT_LINE( "=== 9. Boucle couleurs ===" );
  for  I in COULEUR'FIRST .. COULEUR'LAST  loop
    IO_COULEUR.PUT( I );  PUT( " " );
  end loop;
  NEW_LINE;

  -- === 10. Boucle jours ===
  PUT_LINE( "=== 10. Boucle jours ===" );
  for  I in JOUR'FIRST .. JOUR'LAST  loop
    IO_JOUR.PUT( I, WIDTH => 10 );
  end loop;
  NEW_LINE;

  -- === 11. GET fichier ===
  PUT_LINE( "=== 11. GET fichier ===" );
  CREATE( G, OUT_FILE, "enum_data.dat" );
  PUT_LINE( G, "ROUGE" );
  PUT_LINE( G, "BLANC" );
  PUT_LINE( G, "BLEU" );
  CLOSE( G );

  OPEN( G, IN_FILE, "enum_data.dat" );
  PUT( "lecture 1..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 1 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  PUT( "lecture 2..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 2 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  PUT( "lecture 3..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 3 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  CLOSE( G );


  -- === 12. GET casse mixte ===
  PUT_LINE( "=== 12. GET casse mixte ===" );
  CREATE( G, OUT_FILE, "enum_data2.dat" );
  PUT_LINE( G, "Rouge" );
  PUT_LINE( G, "blanc" );
  PUT_LINE( G, "BLEU" );
  CLOSE( G );

  OPEN( G, IN_FILE, "enum_data2.dat" );
  PUT( "lecture 1..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 1 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  PUT( "lecture 2..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 2 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  PUT( "lecture 3..." ); IO_COULEUR.GET( G, C );
  PUT( "Lu 3 : " );  IO_COULEUR.PUT( C );  NEW_LINE;
  CLOSE( G );

  -- === 13. GET JOUR ===
  PUT_LINE( "=== 13. GET JOUR ===" );
  CREATE( G, OUT_FILE, "jour_data.dat" );
  PUT_LINE( G, "LUNDI" );
  PUT_LINE( G, "vendredi" );
  PUT_LINE( G, "Dimanche" );
  CLOSE( G );

  OPEN( G, IN_FILE, "jour_data.dat" );
  IO_JOUR.GET( G, J );
  PUT( "Lu 1 : " );  IO_JOUR.PUT( J );  NEW_LINE;
  IO_JOUR.GET( G, J );
  PUT( "Lu 2 : " );  IO_JOUR.PUT( J );  NEW_LINE;
  IO_JOUR.GET( G, J );
  PUT( "Lu 3 : " );  IO_JOUR.PUT( J );  NEW_LINE;
  CLOSE( G );

  -- === 14. Roundtrip PUT-GET ===
  PUT_LINE( "=== 14. Roundtrip ===" );
  CREATE( G, OUT_FILE, "roundtrip.dat" );
  for  I in COULEUR'FIRST .. COULEUR'LAST  loop
    IO_COULEUR.PUT( G, I );
    NEW_LINE( G );
  end loop;
  CLOSE( G );

  OPEN( G, IN_FILE, "roundtrip.dat" );
  for  I in COULEUR'FIRST .. COULEUR'LAST  loop
    IO_COULEUR.GET( G, C );
    IO_COULEUR.PUT( C );  PUT( " " );
  end loop;
  NEW_LINE;
  CLOSE( G );

  -- === 15. Roundtrip JOUR ===
  PUT_LINE( "=== 15. Roundtrip JOUR ===" );
  CREATE( G, OUT_FILE, "jour_rt.dat" );
  for  I in JOUR'FIRST .. JOUR'LAST  loop
    IO_JOUR.PUT( G, I );
    NEW_LINE( G );
  end loop;
  CLOSE( G );

  OPEN( G, IN_FILE, "jour_rt.dat" );
  for  I in JOUR'FIRST .. JOUR'LAST  loop
    IO_JOUR.GET( G, J );
    IO_JOUR.PUT( J );  PUT( " " );
  end loop;
  NEW_LINE;
  CLOSE( G );

  -- === 16. Boucle couleurs avec GET ===
  PUT_LINE( "=== 16. Boucle GET couleurs ===" );
  CREATE( G, OUT_FILE, "enum_data.dat" );
  IO_COULEUR.PUT( G, ROUGE );  NEW_LINE( G );
  IO_COULEUR.PUT( G, BLEU );   NEW_LINE( G );
  IO_COULEUR.PUT( G, BLANC );  NEW_LINE( G );
  CLOSE( G );

  OPEN( G, IN_FILE, "enum_data.dat" );
  for  I in 1 .. 3  loop
    IO_COULEUR.GET( G, C );
    IO_COULEUR.PUT( C );  PUT( " " );
  end loop;
  NEW_LINE;
  CLOSE( G );

  -- === 17. GET sans FILE (console) - commente pour automatiser ===
   PUT_LINE( "=== 17. GET console ===" );
   PUT( "Entrez une couleur : " );
   IO_COULEUR.GET( C );
   PUT( "Lu : " ); IO_COULEUR.PUT( C ); NEW_LINE;

  PUT_LINE( "=== FIN ===" );

end	ENUM_TEST;

I precise that TLALOC compiles its own source code entirely in DIANA and some modules are effectively compiled to fasmg macros. Once support packages work satisfactorily, the aim is to progressively compile the compiler to fasmg piece after piece (beginning with page-manager and so on).

8 Likes

After some hard work, DIRECT_IO and SEQUENTIAL_IO have been tested ok. Even with one generic type formal parameter, genericity is a complex implementation topic for Ada 83.

8 Likes

TLALOC update : simple records and multi-dimensional array aggregates are working in inits. Begins to be funny…

6 Likes

Some news on TLALOC/Ada 83 pure Ada 83 compiler : Interested readers can browse at :

https://github.com/ViMoBr/Ada83_TLALOC

and have a look in /bin for what presently compiles and executes :

text_io.ads, text_io.adb
direct_io.ads, direct_io.adb
sequential_io.ads, sequential_io.adb, 

enum_test.adb
direct_io_test.adb
sequential_io_test.adb
test_agregats.adb
3 Likes

Another update for the followers : the package CALENDAR has been written and compiled and seems mainly operational. It has been lot of suffering with the FIXED types in the expander. Now FIXED_IO is to be improved. The mix of generic types and fixed point calculus is something hard to implement. Happy to be with Ada 83 only…

5 Likes

Some funny exercises begin to be possible : Ada 83 TLALOC compiler produced a SERIAL_TEST program communicating with an Arduino UNO/ ILI9481 480×320 display shield via SEQUENTIAL_IO. The Arduino provides a color console for the Ada 83 program. Graphic display commands or robot face expression display is at hand next.

7 Likes

I’m glad someone is working on an alternative Ada compiler.

Have you considered building a bootstrap compiler to enable self hosting thereby removing the need for gnat?

Hi !
The objective is to compile the Ada 83/TLALOC compiler with itself (possible because it is a pure Ada 83 compiler written in pure Ada 83). So in fine Gnat would not be used anymore. And in fact it is halfway the case because all the TLALOC compiler Ada source is already compiled to DIANA. The “only” task remaining is the code expander so that a viable executable can be produced from DIANA, without Gnat. Some progress has been done on predefined packages. TEXT_IO is nearly complete, DIRECT_IO and SEQUENTIAL_IO also and allow normal use, CALENDAR has been painfully set up (along with the FIXED_IO and fixed types).

For the present, it would be too much work to bootstrap from a reduced Ada ; the 32000 lines whole front end would have to be rewritten without real gain.

One of the strength of the Ada 83/TLALOC compiler is a very clean structure, even interesting for education as it separates very clearly syntax analysis and semantic analysis. A student can successfully compile this with option S (stop after syntax analysis) :

          ----
procedure SPAM
is        ----
  type SPAM is new SPAM;
  SPAM : SPAM := SPAM;

begin
  SPAM := SPAM+1;

end SPAM;
    ----

This clean structure and the very good language properties of Ada 83 are the reasons why I can grasp the whole thing alone. In another language I would have abandoned.

5 Likes

So if I understand: You have already compiled TLALOC to DIANA using a version bootstrapped using GNAT. Next, package the pre-compiled TLALOC compiler in DIANA format and a DIANA expander would then build that DIANA code into a native binary. Finally, this bootstrap compiler can then build a newer version of TLALOC giving one a native Ada83 compiler built with an Ada83 compiler.

Hi ! Yes :

_____________________________________
| Ada 83 TLALOC Frontend + Expander |
| (pure Ada 83 source code)         |
_____________________________________
|    |    |        |
|    |    |        |___> Gnat with -gnat83 option
|    |    |                   |
|    |    |                   v
|    |    |    ____________________________________________________________
|    |    |___>| EXEC(1) | Gnat generated Ada 83 TLALOC compiler/expander |
|    |         | _________________________________________________________|
|    |         |                DIANA trees                               |
|    |         |                     v                                    |
|    |         |           LLIR fasmg macros text                         |
|    |         |                     v                                    |
|    |         ____________________________________________________________
|    |                            fasmg
|    |                              |
|    |                              v
|    |    ____________________________________________________
|    |___>| EXEC(2) | Ada 83/TLALOC/fasmg generated compiler |
|         |     (obtained through Gnat compiled TLALOC)      |
|         ____________________________________________________
|                             |
|                             v
|    ____________________________________________________
|___>| EXEC(3) | TLALOC compiled Ada 83/TLALOC compiler |
     |      (obtained through EXEC(2) without Gnat)     |
     ____________________________________________________

This is a very ambitious program because the frontend and the expander use Ada 83 full language with no restriction (except tasking). Obtaining from EXEC(1) a valid EXEC(2) able to produce EXEC(3) is a big task. Presently, EXEC(1) produces all DIANA from TLALOC sources, but its expander is not able to produce EXEC(2). EXEC(1) expander codes nearly all predefined packages (without exceptions), and parts of the Ada 83 basic execution model.

4 Likes

Just out of curiosity. Can DIANA represent Ada 2022 syntax tree? Libadalang seems to deploy a different format, a type structure of tagged types?

“Yes.” and “No.” are both valid, truthful answers; allow me to explain:

No — because DIANA has no nodes for the expanded syntax, and of DIANA’s goals is to make it so that the DIANA tree encodes the semantically meaningful syntax (that is, whitespace doesn’t matter).

Yes — because DIANA is meant to be expanded/“decorated” with auxiliary information (such as a static analysis or theorem proof), where all consumers of DIANA are free to process these additional annotations if they are able, but only required to process the “core” DIANA.

I am working on a “DIANA 2020” which would fully encompass the expanded syntax.

3 Likes

Hi Dmitry !

The short answer is almost certainly “no”. DIANA was specified for Ada 83. The concept of IDL specification should be usable for later Ada 9X and 2X, but it would require an entire re-specification. DIANA is a heavy system, well thought, complete, but difficult. I had this base for TLALOC whose frontend is a serious overhaul and coherent assembly of the Peregrine translator pieces for DEC Ada found in the Pine Creek ASR. Ada 2022 is a very different language (even Ada 95 was terribly different from its 83 predecessor). Also we are in 2026, so new solutions for the high level intermediate representation of modern Ada are in the order of things. I adhere to DIANA because I want to strictly stick to Ada 83 and have a verifiable compiler which can compile itself. Until now the LLIR fasmg macros backend trick seems the right choice ; but will fasmg assemble the whole compiler produced by the backend ?

Thanks for information. How do you make a leap from DIANA to code generation?

Is this where the stack machine mentioned in the git repo comes into play:

LLIR fasmg macros text

I still have to read up on fasmg but curious how you go from DIANA to fasmg. Are you directly writing assembler for e.g. x86-64?

Except that I know for a fact that DIANA backs PL/SQL & some old implementation(s) of VHDL.

Hi !

Yes, the expander walks the DIANA network using a few sub-programs (D, DI, DB) defined in /src/ada_comp/IDL.ads and produces fasmg .FINC text files which use LLIR defining macros present in text file /src/expander/fasmg/codi_x86_64.finc .
This file is the first include in the .fas wrapper and defines not only the LLIR machine macros, but also the ancillary structure defining macros (str, const, blkmov..), the Linux system calls, and the ELF header, after which at execution all elaborations proceed in straight line around defined sub_programs in later includes.

Have a look at EXPANDER.CODE_ROOT in /src/expander/expander.adb , it is the start of the expander’s DIANA tree walk.

The executable is the result of fasmg outputting x86-64 binary codes for the instructions of the LLIR stack machine when assembling the program’s .fas file which includes all the rest. There is no linking, only conditional includes of each package .FINC (fasmg include) in the required partial order of withes.

This is this structure which allows easy porting to Aarch64 and RiscV-64 under Linux for now. The arm64 Aarch64 has been experimentally tested on an Orange Pi3B SBC. The RiscV is not tested, time missing to install a Ubuntu on a Starfive VisionFive2 quad core. Some enhancements will have to be done on codi_arm64.finc and codi_riscv64.finc because the reference version is the Intel codi_x86_64 which progressed with CALENDAR, FIXED_IO, aggregates and concatenation management.

Hello !
I do not have enough knowledge of the internals of the systems you refer to, but I suspect they are DIANA inspired and use an IDL definition, not strict DIANA as intended for Ada 83.

Hello Dmitry !
I explain below in the topic. The expander walks the DIANA “tree” and writes text for a LLIR stack machine implemented with fasmg macros which output binary executable codes.