❌ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNews from the Ada programming language world

Advent of Code 2022 in pictures

14 January 2023 at 09:25

Note for subscribers: if you are interested in my Ada programming articles only, you can use this RSS feed link.


Just as a teaser for the next Advent of Code in 10 1/2 months, we would like to show a few pictures related to last edition. The 25 puzzles, data and solutions can be found here and here. They are programmed with HAC (the HAC Ada Compiler), thus in a small subset of the Ada language. The HAC compiler is very fast, so you run your program without noticing it was ever compiled, which is perfect for completing a programming puzzle.

Day 22 run with HAC (here, embedded in the LEA environment)

However, the program will run substantially slower than compiled with a native, optimizing compiler like GNAT.
This is not an issue for most Advent of Code puzzles, but for some, it is, especially on the later days. Fortunately, changing from HAC to GNAT is trivial (just switch compilers), unlike the traditional reprogramming of Python prototypes in C++, for instance.

The pictures

Day 8's data is a map representing the height of trees. Once the puzzle was solved, I was curious how the forest looked like. Note that different users get different data, so you are unlikely to find a visualisation of exactly your data on the internet.


Day 12's puzzle is a shortest path problem with specific rules and a nice data - a terrain with a hill - which seems designed to trap depth-first-search algorithms into an almost infinite search. The yellowish path is the shortest from the green dot, elevation 'a', to blue dot, elevation 'z'.
The pinkish path is the shortest from the blue dot to any dot with elevation 'a'. Fortunately Dijkstra's algorithm (and perhaps others) allows for such a special criterion regarding the end point.

Click to enlarge


For day 22’s puzzle, a walk on a cube’s surface is involved, so it is helpful to sketch it on a piece of paper, cut it and glue the faces. A banana skin of that puzzle is that the example’s layout may be different from the data’s layout. We slipped on that one and ended up gluing and programming the face-to-face transitions for two layouts…


Click to enlarge

Other Adaists’ solutions, discussions and pictures can be found here and in the "2022 Day x" threads in the same forum.

LEA 0.85 - the Tabs are here!

20 November 2022 at 20:05
Note for subscribers: if you are interested in my Ada programming articles only, you can use this RSS feed link.

The 0.85 version of LEA (the Lightweight Editor for Ada) is available!

Web site: http://l-e-a.sf.net/
Source repository #1: https://sf.net/p/l-e-a/code/HEAD/tree/
Source repository #2: https://github.com/zertovitch/lea

The new version has two main new features:
  - Tabs (screenshot below)
  - LEA doesn't write scilexer.dll as a file; thus, it runs as a portable application (in the sense: you can run it from a read-only drive directly, without installation)

Click to enlarge

Enjoy!

LEA 0.84 - the Build & Run button!

12 November 2022 at 11:43

 

Note for subscribers: if you are interested in my Ada programming articles only, you can use this RSS feed link.


The 0.84 version of LEA (the Lightweight Editor for Ada) is available!


Web site: http://l-e-a.sf.net/
Source repository #1: https://sf.net/p/l-e-a/code/HEAD/tree/
Source repository #2: https://github.com/zertovitch/lea

This version is essentialy a rework of LEA's ergonomy - we had recently the chance of having a group of young first-time programmers and first-time LEA users to test it!

The main addition is the green Build & Run button, which matches a (less intuitive) menu entry and the F9 key.

Click screenshot to enlarge

Another addition is a dedicated box for the "User_Abort" internal Virtual Machine exception, so that the LEA user doesn't take the exception message for an actual error (which would be the case for any other exception).

Before:


Now:

Enjoy!


HAC as an embedded compiler

28 June 2022 at 20:32

Here is an example to illustrate how the HAC compiler is embedded in an Ada application.

The user of the application has typically only an executable (built with a "full Ada" system like GNAT) and an "Ada-pplet" (can be a few lines) that is run from that executable.

Normally, applications have different languages for building the application and for the embedded script system: Excel is written in C/C++ but embeds VBA (Visual Basic for Applications). 3D Studio Max has MaxScript. GIMP uses Script-fu, a variant of Scheme. Others use Lua or Python. Of course nobody would think about shipping a software with a scripting language where you have to fight with pointers and conditional compilation (C/C++).

But... how about an application that is written in a compiled language, but is using the same language for its scripting purposes? Since a few days, it is possible with HAC (the HAC Ada Compiler).

If you build the demo exchange_hac_side.adb (e.g. from GNAT Studio, or via the command "gprbuild hac"), you get an executable, exchange_hac_side on Linux or exchange_hac_side.exe on Windows. If you run it, you get:

Exchange_Native_Side is started.

Native: building a HAC program: exchange_hac_side.adb

   Exchange_HAC_Side is started.

   HAC: I call a parameterless callback.
      Native: Parameterless_Callback is speaking!
   HAC: done calling.

   HAC: I send some stuff through callbacks.
      Native: HAC is saying: [I'm HAC and I say hello!]
      Native: HAC has sent me the numbers: 123 456 789
      Native: HAC has sent me the numbers: 1.23000000000000E+02 4.56000000000000E+02 7.89000000000000E+02

   HAC: message before call: [I'm HAC]
      Native: HAC is saying: [I'm HAC]
   HAC: message after call: [No, I'm Native, you loser!]
   HAC: integer before call: [12]
      Native: HAC has sent me the number: 12; I will send it back squared.
   HAC: integer after call: [144]
   HAC: float before call: [11.0]
      Native: HAC has sent me the number: 1.10000000000000E+01; I will send it back squared.
   HAC: float after call: [121.0]

   HAC: integer before call: [13]
        message before call: [I'm a HAC record field]
           enum before call: [BAT]
      Native: Enum = BAT
      Native: Matrix m:
           1.10 1.20
           1.30 1.40
      Native: Matrix n:
          -2.10 2.20
          -2.30 2.40
      Native: Matrix o = m * n:
          -5.07 5.30
          -5.95 6.22
      Native: Enum = CAT
   HAC: integer after call: [169]
        message after call: [I'm a Native message now (niarg niarg niarg)!]
           enum after call: [CAT]
        matrix product:
          -5.07 5.30
          -5.95 6.22

Messages as "Native" are from the main application.

Messages as "HAC" are from the small HAC program that is run from the application.

A little disadvantage of having the same language on both sides... is that it is the same language! It could be confusing at first glance. Plus, it is not in the tradition. That may be disturbing for a number of people.

A big advantage of having the same language is that you can share some pieces of code. For instance the following package is used for building the demo application, and compiled by HAC when the application is running!

------------------------------------------- -- HAC <-> Native data exchange demo -- ------------------------------------------- -- Package used by both HAC and -- -- Native sides -- ------------------------------------------- package Exchange_Common is type Animal is (ant, bat, cat, dog); subtype Beast is Animal; subtype Insect is Animal range ant .. ant; subtype Mammal is Animal range bat .. dog; end Exchange_Common;


HAC (HAC Ada Compiler) is a quick, small, open-source Ada compiler, covering a subset of the Ada language. HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/ 

Source repositories:

 #1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/

 #2 git: https://github.com/zertovitch/hac

Ann: HAC v.0.2

25 June 2022 at 21:35

HAC (HAC Ada Compiler) is a quick, small, open-source Ada
compiler, covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/
From there, links to sources, and an executable for Windows.

Source repositories:
  #1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
  #2 git: https://github.com/zertovitch/hac

* Main improvements since v.0.1:

  - a program run by HAC can exchange data with the
      programm running HAC, through dynamically registered call-backs
      - see package HAC_Sys.Interfacing and demos:
        src/apps/exchange_native_side.adb
        src/apps/exchange_hac_side.adb

  - the compiler checks that all choices in a CASE statement
      are covered

  - the compiler performs more compile-time range checks and
      optimizes away useless run-time checks when it's safe to do so.

Enjoy!

Gautier

Ann: HAC v.0.1

14 May 2022 at 12:19

HAC (HAC Ada Compiler) is a quick, small, open-source Ada
compiler, covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/
From there, links to sources and an executable for Windows.

Source repositories:
  #1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
  #2 git: https://github.com/zertovitch/hac

* Main improvements since v.0.0996:

  - packages and subpackages are now supported
  - modularity: packages and subprograms can be standalone
      library units, stored in individual files with
      GNAT's naming convention, and accessed from other units
      via the WITH clause
  - validity checks were added for a better detection of
      uninitialized variables.

Package examples and modularity tests have been added.
Particularly, a new PDF producer package with a few demos
is located in the ./exm/pdf directory.


hakoch

Enjoy!

Gautier
__
PS: for Windows, there is an integrated editor that embeds HAC:
LEA: http://l-e-a.sf.net
PPS: HAC will be shown at the Ada-Europe conference (presentation + tutorial)
http://www.ada-europe.org/conference2022/

HAC, packages and PDF

10 May 2022 at 19:51

In order to illustrate a feature, what is better than a visual example?
In our case, the feature is the modularity, recently implemented in HAC (the HAC Ada Compiler).
So, a nice exercise was to try with a "real" visual package, PDF_Out (project Ada PDF Writer, link here).
Of course, HAC is still a small compiler project which doesn't cover all the sexy features of Ada - even those of the first version of Ada, Ada 1983, which already had extensive generics, aggregates (on-the-fly composite objects as expressions), default values in records or in subprogram parameters, exceptions or user-defined operators.
The easy way of down-stripping PDF_Out for HAC was to open the source code in the LEA editor (link here), and do frenetically and iteratively:

loop
  punch the compile key (F4)
  exit when the package compiles!
  make the code HAC-compatible (sometimes, it hurts!)
end loop


A few things that needed a downgrade for the HAC 0.1 language subset were:

  • Object-oriented type extension (tagged type for PDF stream). In the simplified version, PDF files are the only supported PDF streams.
  • Object.method notation
  • Default values in records, replaced by explicit initialization.
  • Inclusion of raster images (NB: the removal of that feature was unnecessary).
  • User-defined exceptions (PDF_stream_not_created, ...).
  • User-defined operators ("+", ...).
  • Indefinite page table and offset table.

The result can be seen here:


Click to enlarge

 

You can experiment it yourself by checking out or cloning the latest version of HAC:

#1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
#2 git: https://github.com/zertovitch/hac

The new PDF examples are located in the subdirectory ./exm/pdf




HAC: packages - now, the whole package!

11 April 2022 at 22:21

Drum rolls: HAC (the HAC Ada Compiler) now supports packages.

OK, there is still a slight limitation: library-level packages cannot contain variables and constants, nor an initialization part (begin .. end). Removing this limitation would be complex to implement and is postponed so far for HAC.

A new modularity demo can be found in the "exm" subdirectory.
The main file is "pkg_demo.adb".
It is a simple test for simulating the build of an application with numerous dependencies.
The dependencies take form of packages depending on two or more other packages, down to
a certain recursion depth.
Each package contains a procedure with the same name: "Do_it", which just writes a string related to the package name. For instance,  X_Pkg_Demo_B3.Do_it will write "[B3]", then call X_Pkg_Demo_B31.Do_it, X_Pkg_Demo_B32.Do_it, and X_Pkg_Demo_B33.Do_it.
The package dependencies can be seen the following chart:



NB: the depth and number of children can be set as you wish.

How to run the demo?
First, we generate the package tree.
For that, assume you have the "hac[.exe]" executable ready in the main directory.
Note: in what follows, replace '/' by '\' if you are on Windows.
In the "exm" directory, run from the command line: "../hac pkg_demo_gen.adb".
Alternatively, from LEA, load "pkg_demo_gen.adb" and run it (F9).
The packages ("x_*" files) will be generated.

Now, from the command line, run "../hac pkg_demo.adb" (or from LEA, load it and punch F9).

The result is:

     Specs:  [S][S1][S11][S12][S13][S2][S21][S22][S23][S3][S31][S32][S33]    
     Mixed:  [M][M1][M11][M12][M13][M2][M21][M22][M23][M3][M31][M32][M33]    
     Bodies: [B][B1][B11][B12][B13][B2][B21][B22][B23][B3][B31][B32][B33]    

    
If you are curious about how HAC does the whole build the 40 units (main procedure and 39 packages),
add the "-v2" option to the build command: "../hac -v2 pkg_demo.adb".
On an i7 machine (with HAC itself built in "Fast" mode), the time elapsed
for the entire build is around 0.08 seconds. Only one core is used.
Since GNAT builds also the library "on the fly" by automatically
finding dependencies, you can see it in action by doing:
"gnatmake -I../src -j0 pkg_demo"
Interestingly, GNAT compiles the packages for each depth successively.
Then you can see the result by doing:
"./pkg_demo"
Of course, it's identical to HAC's. 

---

HAC (the HAC Ada Compiler) is a small, quick, open-source Ada compiler,
covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/

Source repositories:
#1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
#2 git: https://github.com/zertovitch/hac
 

Enjoy!

Gautier


HAC: packages (work in progress)

27 March 2022 at 19:01

Since a few commits, HAC parses packages! But so far there are limitations : it's "work in progress".

Nevertheless you can already play a bit with the things already programmed in HAC.

File prc.ads:

with Pkg_1, Pkg_2;

procedure Prc is
  x : Pkg_1.A;
 
  use Pkg_1, Pkg_2;

  xg : G;
  y : B;
  z : Pkg_1.E;

begin
  x := 0;
  y := 0;
  z := 2;
end;

File pkg_1.ads:

package Pkg_1 is

  subtype A is Integer;
  subtype B is Pkg_1.A;
  subtype C is B range 0 .. 1000;
 
  package Sub_Pkg is    
    subtype D is C range 1 .. 100;    
  end Sub_Pkg;  
 
  subtype E is Sub_Pkg.D range 2 .. 10;
 
end Pkg_1;

File pkg_2.ads:

with Pkg_1;

package Pkg_2 is 

  subtype F is Pkg_1.E;
  use Pkg_1.Sub_Pkg;
  subtype G is D;
 
end Pkg_2;

Now, from the command-line (assume you are in the main hac directory), do:

hac -v2 prc.adb

*******[ HAC ]*******   Compiler version: 0.0997 dated 19-Mar-2022.
*******[ HAC ]*******   Caution: HAC is not a complete Ada compiler. Type "hac" for license.
. . . .[ HAC ]. . . .   Compiling main: prc.adb
. . . .[ HAC ]. . . .   .Compiling: pkg_1.ads (specification)
. . . .[ HAC ]. . . .   .Compilation of pkg_1.ads completed
. . . .[ HAC ]. . . .   .Compiling: pkg_2.ads (specification)
. . . .[ HAC ]. . . .   .Compilation of pkg_2.ads completed
. . . .[ HAC ]. . . .   Compilation of prc.adb (main) completed
. . . .[ HAC ]. . . .   --  Compilation of eventual with'ed unit's bodies  --
. . . .[ HAC ]. . . .   Build finished in 0.001255600 seconds.
. . . .[ HAC ]. . . .   Object code size: 12 of 100000 Virtual Machine instructions.
. . . .[ HAC ]. . . .   Starting p-code VM interpreter...
-------[ HAC ]-------   VM interpreter done after 0.045569300 seconds.
Execution of prc.adb completed.
Maximum stack usage: 10 of 4000000 units, around 0%.

If you want a more complex example of how HAC can create the library "on the fly" by compiling recursively everything needed to build the main procedure, it is already in the examples (subdirectory exm):

*******[ HAC ]*******   Compiler version: 0.0997 dated 19-Mar-2022.
*******[ HAC ]*******   Caution: HAC is not a complete Ada compiler. Type "hac" for license.
. . . .[ HAC ]. . . .   Compiling main: unit_a.adb
. . . .[ HAC ]. . . .   .Compiling: unit_b.ads (specification)
. . . .[ HAC ]. . . .   .Compilation of unit_b.ads completed
. . . .[ HAC ]. . . .   .Compiling: unit_c.adb (body)
. . . .[ HAC ]. . . .   .Compilation of unit_c.adb completed
. . . .[ HAC ]. . . .   Compilation of unit_a.adb (main) completed
. . . .[ HAC ]. . . .   --  Compilation of eventual with'ed unit's bodies  --
. . . .[ HAC ]. . . .   .Compiling: unit_b.adb (body)
. . . .[ HAC ]. . . .   ..Compiling: unit_e.adb (body)
. . . .[ HAC ]. . . .   ..Compilation of unit_e.adb completed
. . . .[ HAC ]. . . .   ..Compiling: unit_f.ads (specification)
. . . .[ HAC ]. . . .   ...Compiling: unit_g.ads (specification)
. . . .[ HAC ]. . . .   ...Compilation of unit_g.ads completed
. . . .[ HAC ]. . . .   ..Compilation of unit_f.ads completed
. . . .[ HAC ]. . . .   .Compilation of unit_b.adb completed
. . . .[ HAC ]. . . .   --  Compiled bodies: 1
. . . .[ HAC ]. . . .   .Compiling: unit_f.adb (body)
. . . .[ HAC ]. . . .   .Compilation of unit_f.adb completed
. . . .[ HAC ]. . . .   .Compiling: unit_g.adb (body)
. . . .[ HAC ]. . . .   .Compilation of unit_g.adb completed
. . . .[ HAC ]. . . .   --  Compiled bodies: 2
. . . .[ HAC ]. . . .   Build finished in 0.006483700 seconds.
. . . .[ HAC ]. . . .   Object code size: 350 of 100000 Virtual Machine instructions.
. . . .[ HAC ]. . . .   Starting p-code VM interpreter...
Unit_A: demo of modularity features for subprograms.

------

HAC (HAC Ada Compiler) is a small, quick, open-source Ada compiler,
covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/

Source repositories:
#1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
#2 git: https://github.com/zertovitch/hac
 

Enjoy!


Gautier

Ann: HAC v.0.0996

22 January 2022 at 09:53

HAC (HAC Ada Compiler) is a small, quick, open-source Ada compiler,
covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

Web site: http://hacadacompiler.sf.net/

Source repositories:
#1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
#2 git: https://github.com/zertovitch/hac

Main improvements since v.0.095:

  • range checks on discrete subtype assignment (:=) and conversion
  • short-circuit logical operators: "and then", "or else"
  • for S = Scalar subtype: S'First, S'Last, S'Succ, S'Pred, S'Pos, S'Val, S'Image, S'Value, S'Range attributes
  • for A = array object or array subtype: A'First [(N)], A'Last [(N)], A'Range [(N)], A'Length [(N)] attributes
  • "&", "<", ">", "=", "/=" operators defined for the String type (additionally to HAL.VString type)
  • CASE choices admit ranges
  • forward declarations for subprograms


Enjoy!

Gautier

PS: for Windows there is an integrated editor that embeds HAC:
LEA: http://l-e-a.sf.net

HAC - range checks

4 September 2021 at 18:36

Up to a few hours ago, range checks in HAC (the HAC Ada Compiler) were limited to array indices.

However, a simple and cool Ada feature is the possibility of subtyping, as in

subtype Level is Integer range 1 .. 30;
It allows to describe precisely values in your program that have to stay within a certain range and would not be meaningful outside of that range. You can also use the subtype's name in many contexts like

switch : array (Level) of Boolean;

or 

for x in Level loop ...

Furthermore it opens the possibility of checking that values are actually within the range.

Typically you have at some places a statement like:

lev := lev - 1;

for a variable defined as

lev : Level;
If your program, by mistake, decrements the variable lev to 0, a standard Ada run-time range check will detect it and raise an exception. This is a very powerful help in finding bugs in complex programs, typically data compression software.

Up to a few hours ago, HAC did not have that kind of range check. Now it is fixed.

Since types in the HAC Ada subset are fully known at compile time, the addition was actually easy:

1) Add appropriate Virtual Machine instructions:


2) Implement them in the VM interpreter:


3) On the parser side, add the run-time check for (sub)type conversions (better to do an easy case as a warm-up):


4) Add the run-time check for assignment statements (:=):

The last point was a bit less trivial. Some details had to be changed in the compiler's way of memorizing and propagating information about types and their range constraints.

For instance, for a composite type like

type Rec is record

  L : Level;

  Points : Natural;

end record;

and an array

x : array (1 .. N) of Rec;

the compiler needs to track correctly that

x(i).L

is of subtype Level, with the range 1 .. 30, and not only of the broader type Integer, when it considers checking the range of the value after := in the following statement:

x(i).L := new_value;

Conversely, in an expression like  z + y * x(i).L, the subtype has to be ignored, it is an Integer expression and nothing more (Integer in that case is called the base type). A solution was to define, in the compiler, a type extension for holding subtype informations:

In places where the subtype constraint needs to be ignored, it is easy to do:


 HAC is an open-source software and can be found here and here.


 

 

The HAC scripts invasion (follow-up)

26 July 2021 at 18:18

As a follow-up of another post about converting bash (Linux) or cmd (Windows) scripts to HAC scripts, here is a fresh example.

I needed to improve an existing cmd script for benchmarking compression software, with the possibility of switching various subsets separately: that is re-run this subset of methods, or that other subset, or the full tests (long!), etc.

Of course, if you use a real language instead of command-line interpreter ones, there is an obvious solution: you can define a set and you can programmatically flip the membership switches.

In Ada, it looks like

  type Category is (
    Reduce_Shrink,
    Deflate,
    Deflate_External,
    BZip2_External,
    PPMd_External,
    LZMA_7z,
    LZMA_3,
    TAR,
    Preselection
  );

  cat_set : array (Category) of Boolean;
The good news is that you can run an Ada program exactly like a script by using HAC (the HAC Ada Compiler). That is, it runs immediately (with HAC), and HAC doesn't drop .ali, .o, .bexch, .tmp, .exe files which are too much waste for the sake of running a small script-like job.

Below are screenshots of the quick development of bench.adb using the LEA editor, where you can punch F4 to check eventual errors. If there is one, you get instantly to the offending line / column point.

This script is part of the Zip-Ada project and is very helpful for developing and testing new compression methods.

 

Click to enlarge


Click to enlarge


Cleaning up HAC sources with AdaControl

30 April 2021 at 14:15

AdaControl is a powerful Ada source code verification tool. It's freely available here. As a side note, its name sounds like "flight control" and it is no coincidence 😊.

Our HAC (HAC Ada Compiler) project is a good opportunity to use AdaControl from scratch on a given project and to show you how capable it is.

*** 

A note about installation. The free version of AdaControl works so far with the GNAT Ada toolset called Community Edition 2019 - not later, for reasons explained in a newsgroup post titled "Status of AdaControl".

So, for example on Windows, the installation steps include installing GNAT CE 2019 (even if you use a later version), writing a script, say, go19.cmd, with the line "path c:\gnat\2019\bin;%path%". The AdaControl installer (adactl-1.21r6b-exe_setup.exe) will work correctly if you first set the correct temporary path with "go19", then launch the installer, from the same command line session.

Then, you can write a second script, say, gps_19.cmd, with the lines:

  call go19
  start gps -P hac.gpr

That way you can start your AdaControl session comfortably through GNAT Studio by just double-clicking gps_19.cmd.

***

AdaControl works with rules that you can choose to apply (or not), sometimes with sub-rules. You list the rules you want to apply in a text file. In the HAC project (see hac.gpr) we have called it "test/verif_hac.aru".

Let's start with a first rule which seems promising: "simplifiable_statements". As you know, unnecessary complications are the biggest threat to programs of any size. Small simplifications that are automatically detected are very welcome. Of course it doesn't replace larger, conceptual simplifications - but for that, you need a brain 😉.

------------------------------------------------
--  AdaControl verification rules             --
--  https://www.adalog.fr/en/adacontrol.html  --
------------------------------------------------

-- Set for HAC (HAC Ada Compiler).

--------------------------------------
--  (1) Required ("check" command)  --
--------------------------------------

check simplifiable_statements;


------------------------------------------------------------------
--  (2) Acceptable, but should be looked at ("search" command)  --
------------------------------------------------------------------ 

All but one line of the above rules file are comments starting with "--". But since AdaControl provides 579+ possible rules and sub-rules, the comments will be useful later.

So, we courageously begin with the first rule, on the main procedure of the HAC command-line compiler and VM interpreter, hac.adb (that GNAT turns into hac.exe).

Click to enlarge

After a few seconds, AdaControl completes with 74 diagnostics in 18 files (it scans recursively all units that the initial unit (hac.adb) depends on, and the units those units depend on, and so on).

That, for the "simplifiable_statements" rule only. Ouch! 😨

Click to enlarge

The first item is a loop that is simplifiable into a "for" loop. First, a disclaimer: I did not write that loop👐🚿. Remember that HAC stems from an automatic translation of SmallAda (written in the late 1980's), itself a derivation of CoPascal, which derives from Pascal-S by Pr. Wirth himself around 1975. At the time some languages did not produce a check to skip a "for" loop from a to b when a > b. If it is not skipped, the loop parameter will be incremented to "the infinity", and practically, towards an overflow error in best cases. So probably authors of SmallAda or earlier felt better using a "while" loop instead of a "for" loop in such cases.

In Ada every situation is defined in the Reference Manual (an ISO standard!), and programmers can count on the fact that the loop "for i in a .. b" is skipped if a > b.

Back to AdaControl. Obviously, it has found a case where you can simplify a "while" loop into a "for" loop.

This finding looks easy, a posteriori, for the human reader, because it is a tiny loop. But it is not trivial. Logically, AdaControl was able to figure out that the "OC'Last" part of the exit condition is invariant during the loop's activity (if not, you must stick with the "while" loop). Clever!

Plus, it has seen that the exit condition was equivalent to an upper bound check in a "for" loop. Very clever!

Plus, it has detected simple increment (LC0 := LC0 + 1;) in the main execution path of the loop - and nothing else, nowhere else, like, for instance, a modification of LC0 in the "if" statement. That's very, very clever!

So let's do the recommended simplification. The loop in

  procedure Patch_Addresses (
    OC            : in out Object_Code_Table;
    dummy_address :        Operand_2_Type
  )
  is
    LC0 : Integer := OC'First;
    use Defs;
    use type HAC_Integer;
  begin
    while LC0 < OC'Last loop
      if OC (LC0).F in Jump_Opcode and then OC (LC0).Y = dummy_address then
        OC (LC0).Y := HAC_Integer (OC'Last);
      end if;
      LC0 := LC0 + 1;
    end loop;
  end Patch_Addresses;

becomes:

    for LC0 in OC'First .. OC'Last - 1 loop
      if OC (LC0).F in Jump_Opcode and then OC (LC0).Y = dummy_address then
        OC (LC0).Y := HAC_Integer (OC'Last);
      end if;
    end loop;

As a bonus, the variable declaration, "LC0 : Integer := OC'First;", can be deleted (it is implicitely defined in Ada for the "for" loop).

But the simplification is not enough for AdaControl! It detects, on a second round, that the loop parameter (LC0) is always used as an index to an array. It says that the "for ... of" Ada 2012 statement can be used instead. This means that instead of having a loop incrementing an index to the OC array, the loop could as well scan OC's elements directly. The job is the same, but the Ada code is shorter and cleaner for human readers. In this case the gain is small, but for an array like "foo(k).bar.x3.grogu(l)" it makes a big difference in readability.

Let's apply again the recommanded change.

    for Op of OC (OC'First .. OC'Last - 1) loop
      if Op.F in Jump_Opcode and then Op.Y = dummy_address then
        Op.Y := HAC_Integer (OC'Last);
      end if;
    end loop;

Beautiful!

Here are both changes together, in colour, via GitHub: 

More AdaControl adventures in a further post...


HAC v.0.095

7 April 2021 at 20:13

A bit of brush-up after our last post about the new modularity features of HAC (the HAC Ada Compiler), we can announce the release of version 0.095.

We have tested since then parameters to units, and the use of functions instead of procedures as units.

All that with the LEA editor, in order to experiment the behaviour of compile-time errors and run-time errors. In contrast to the command-line tool called "hac" where everything is forgotten once the command is run, whatever the outcome, in an integrated editor the compiler needs to close files properly in every case - also on errors, because the editor will open them to show the error locations. Similarily, the builder needs to clear the library information between two builds. The improvements to be made to HAC for a smooth functioning were straightforward. Just a couple of statements to add here and there.

A demo of HAC's current modularity support, in one picture:

Click to enlarge

HAC (HAC Ada Compiler) is a small, quick, open-source Ada compiler,
covering a subset of the Ada language.
HAC is itself fully programmed in Ada.

HAC web site: http://hacadacompiler.sf.net/


Source repositories:
 #1 svn: https://sf.net/p/hacadacompiler/code/HEAD/tree/trunk/
 #2 git: https://github.com/zertovitch/hac

Enjoy!

First steps in modularity for HAC

5 April 2021 at 18:55

The recent development effort of HAC (the open-source HAC Ada Compiler, links here and here) is concentrated on modularity.

Some new packages were added on the compiler side:
 - HAC_Sys.Builder   : about building a program around a main procedure
 - HAC_Sys.Librarian : about registering units, compiling them if needed, and making them available to other units.
 
In order to do things step by step, we have begun with the simplest form of modularity units: subprograms. We'll do packages later.
Probably some people will be surprised that modularity units in Ada can be something else than packages.

This little-known feature is already useful for the following very simple job: making a "shell" program calling other programs. An example: someone had a series of programs:
  poly_1 (Ada name: poly_1.adb, executable: poly_1.exe)
  poly_2 (Ada name: poly_2.adb, executable: poly_2.exe)
  poly_3 (Ada name: poly_3.adb, executable: poly_3.exe)
  ...

The deployment to users of all those executables was cumbersome.
The solution was to define:

  with Poly_1, Poly_2, Poly_3, ...
  with Ada.Command_Line;

  procedure Poly_N is

    use Ada.Command_Line;
  begin
    case Argument (1) is
      when "1" => Poly_1;
      when "2" => Poly_2;
      when "3" => Poly_3;
      ...
    end case;
  end;

 
Et voilà. Of course it works because Ada doesn't have a hard-coded name for "main".

Back to HAC's development. Here is a nonsensical example, which is a bit tricky on nesting levels.

a.adb:
  with B, C, HAL;

  procedure A is
    v : Integer;
    a_msg : HAL.VString;

    use HAL;

    procedure X is
    begin
      Put("(x>");
      a_msg := +"A";
      B;
      v := v * 2;
      Put("<x)");
    end X;

  begin
    v := 111;
    a_msg := +"a";
    HAL.Put(+"(a" & a_msg & ">");
    for i in 1 .. 2 loop C; end loop;
    X;
    B;
    X;
    HAL.Put(v, 0);
    HAL.Put("<A" & a_msg & ")");
  end A;

 
b.adb:
  with C, HAL;

  procedure B is
    use HAL;
    b_msg : VString := +"b";
    --
    procedure Y is
    begin
      Put("(y>");
      C;
      HAL.Put("<y)");
      b_msg := +"B";
    end;
    procedure Y2 is
    begin
      Y;
    end;
  begin
    Put ("(b" & b_msg & ">");
    C;
    Y2;
    HAL.Put("<B" & b_msg & ")");
  end B;


c.adb:
  with HAL;
  use HAL;

  procedure C is
    c_msg : VString;
    procedure Z is
    begin
     c_msg := +"C";
     HAL.Put("z");
    end Z;
  begin
    c_msg := +"c";
    Put("(c" & c_msg & ">");
    Z;
    Put("<C" & c_msg & ")");
  end C;

 
The output is, with the GNAT compiler:
>gnatmake a -Isrc
gcc -c -Isrc a.adb
gcc -c -Isrc b.adb
gcc -c -Isrc c.adb
gcc -c -I./ -Isrc -I- src/hal.adb
gnatbind -Isrc -x a.ali
gnatlink a.ali
>a
(aa>(cc>z<CC)(cc>z<CC)(x>(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)<x)(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)(x>(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)<x)444<AA)

With HAC:
>hac a.adb
(aa>(cc>z<CC)(cc>z<CC)(x>(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)<x)(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)(x>(bb>(cc>z<CC)(y>(cc>z<CC)<y)<BB)<x)444<AA)

If we add "with B" to C, we get the "circular unit dependency" issue. Each compiler handles it, as expected.

>hac a.adb
c.adb: 2:7-8: library error: Circular unit dependency ("->" means "depends on"): B -> C -> B

>gnatmake a -Isrc
gcc -c -Isrc a.adb
a.adb:1:08: circular unit dependency
a.adb:1:08: "A (body)" depends on "B (body)"
a.adb:1:08: "B (body)" depends on "C (body)"
a.adb:1:08: "C (body)" depends on "B (body)"
a.adb:1:08: "B (body)" depends on "B (spec)"
gnatmake: "a.adb" compilation error 

 

HAC at work with shiny gold bags (Advent of Code, Day 7)

7 December 2020 at 14:13

Day 7 of the Advent of Code, titled "Handy Haversacks" is nice pair of puzzles involving recursion.

The data is a set of rules, beginning with

wavy green bags contain 1 posh black bag, 1 faded green bag, 4 wavy red bags.

dotted chartreuse bags contain 1 light beige bag.

dark white bags contain 2 dotted white bags.

... 

There are hundreds of such rules.

The puzzles involve recursion, which makes them fun.

You can see below HAC at work on the problem, from the LEA editor.

There is also a "full Ada" version. I began with that one, because the current limitations of HAC would have been too time-consuming (in terms of development time) for submitting a solution quickly enough. The limitations are not around recursion, that HAC masters like a big one, but mostly around the enumeration type I/O which is currently non-existent in HAC (v.0.081).

Click to enlarge

Solutions will be soon be posted on the HAC repositories.

❌
❌