❌ About FreshRSS

Normal view

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

Libadalang, Alire, and macOS


This exercise was prompted by the need for Scripted Testing to be supported by – as far as possible – code generation. The need is for the public or interfacing view of a supporting part (domain) of a system to be able to log calls made to it and to provide values on calls to it, using a scripting mechanism.

Read more »

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.

How would I define the __builtin_blendvps256 GCC intrinsic in Ada using GNAT?

I am trying to define a library in Ada (built on GNAT specifically) for x86 ISA extensions. (This question is specific to AVX/AVX2).

Here is some example code below:

-- 256-bit Vector of Single Precision Floating Point Numbers
type Vector_256_Float_32 is array (0 .. 7) of IEEE_Float_32 with
  Alignment => 32, Size => 256, Object_Size => 256;
pragma Machine_Attribute (Vector_256_Float_32, "vector_type");
pragma Machine_Attribute (Vector_256_Float_32, "may_alias");

-- 256-bit Vector of 32-bit Signed Integers
type Vector_256_Integer_32 is array (0 .. 7) of Integer_32 with
  Alignment => 32, Size => 256, Object_Size => 256;
pragma Machine_Attribute (Vector_256_Integer_32, "vector_type");
pragma Machine_Attribute (Vector_256_Integer_32, "may_alias");

-- 256-bit Vector of 32-bit Unsigned Integers
type Vector_256_Unsigned_32 is array (0 .. 7) of Unsigned_32 with
  Alignment => 32, Size => 256, Object_Size => 256;
pragma Machine_Attribute (Vector_256_Unsigned_32, "vector_type");
pragma Machine_Attribute (Vector_256_Unsigned_32, "may_alias");

function vblendvps
  (Left, Right, Mask : Vector_256_Float_32)
   return Vector_256_Float_32 with
  Inline_Always => True, Convention => Intrinsic, Import => True,
  External_Name => "__builtin_ia32_blendvps256";

For the sake of education, I want to know how to do this in assembly.

I have tried to define the vblendvps function using the Asm function from System.Machine_Code. However, as I am not knowledgeable about assembly programming, I am struggling to find resources on how to do this.

This is what I have so far:

with System.Machine_Code; use System.Machine_Code;

function vblendvps
(Left, Right, Mask : Vector_256_Float_32)
return Vector_256_Float_32
result : Vector_256_Float_32;
(Template => "vblendvps %3, %0, %1, %2",
 Outputs  => Vector_256_Float_32'Asm_Output ("=g", result),
 Inputs   =>
   (Vector_256_Float_32'Asm_Input ("g", Left),
    Vector_256_Float_32'Asm_Input ("g", Right),
    Vector_256_Unsigned_32'Asm_Input ("g", Mask)));
return result;
end vblendvps;

When compiling the complete code, I get

Error: too many memory references for `vblendvps'

I believe this means that I need to move the arguments from memory to registers, but I am not sure. If there are some helpful references that explain every instruction, I would greatly appreciate that. (I had quite some trouble looking up the arguments to vblendvps).

My understanding is that the instruction is of the form (from ymm registers in my case)


Please let me know how I would do this. Even if it is not in Ada, I'm sure I can figure out how to translate it.

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


Building GCC 12.2.0 on Ventura for aarch64

These are notes on building GCC 12.2.0 and GNAT tools for Apple silicon.

There were two main problems:

  • the base package was built on an Intel machine (lockheed - named after Shadowcat’s companion dragon), running Monterey (macOS 12).
  • the build machine, an M1 mac Mini (temeraire - named after Naomi Novik’s dragon) was by this time running Ventura (macOS 13), but I wanted to make sure that users could continue to run on Monterey.
Read more »

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).




A cell phone company is continually building and leasing communication towers. Each tower has one-way, direct communcation links to other tower [closed]

A cell phone company is continually building and leasing communication towers. Each tower has one-way, direct communcation links to other towers. The task is find if there is a communication link from one tower to another, possibly through other towers.

The input to the program is essentially a list of pairs of tower names. Each pair will appear on a single line and will contain distinct names. Some pairs represent one-way communcation links between towers, and other pairs represent queries. Links and queries may be interspersed.

All the communication links of the system are added one link at a time and no links are removed. Here is an example of a link:

Tower_A Tower_B. A link is terminated by a period.

A query asks if a communcation link is possible from one tower to another by any combination of one-way links. If another link is added to the system later in the input, then the answer to the same query may be different. In the output, a plus sign (+) represents an affirmative answer; a minus sign (-) says there is no such link.

Links are distinguished from queries by ending in a question mark and not a period.

Tower_A Tower_B? The program should read from the standard input and and write to the standard output. For each query in the input there should be exactly one line of output. If the query is true (there is a communication channel through the network), the output line should begin with a plus sign (+); otherwise with a minus sign (-). The rest of the output line repeats the towers in the query.

For the following input:

Tower_A Tower_B. Tower_B Tower_C . Tower_A Tower_C? # A query Tower_B Tower_D. Tower_A Tower_D ? # Another query Tower_F Tower_E. Tower_D Tower_B ? # A third query xxxx yyyy? # Unknown tower names Tower_D Tower_B . Tower_D Tower_B ? # Now there is a link the output should be

  • Tower_A -> Tower_C
  • Tower_A -> Tower_D
  • Tower_D -> Tower_B
  • xxxx -> yyyy
  • Tower_D -> Tower_B The names of the towers will contain only the characters [a-zA-Z_0-9], in particular they will have no spaces in them. Names will have at least 1 character and no more than 50 characters. Furthermore the capitialization of the names is significant. That is, WestMelbourneTower is not to be considered the same tower as wESTMeLbOuRnEtOwEr. Characters, if any, after the period (.) or question mark (?) on a line are to be ignored. No line will will contain more than 150 characters.

Please carefully observe spacing. There may, or may not, be a space before the period, the question mark, and the comment in the input. There will be one or more spaces between the tower names in the input. There must be a space after the plus and minus sign in the output. There must be a space before and after the arrow (->) in the output.

You are required to create your own graph package graph.ads graph.adb and name it Graph. The package can be generic or non-generic. The graph is to be a list of adajency lists. You are required to use the generic, doubly-linked list package from the standard library. These requirements are generally reasonable ones for the task anyway. There are more sophisticated approaches and less sophisticated approaches, but these requirements ensure the educational objectives of the assignment are met.

Ada Wireless Driver Progress

25 July 2022 at 07:00

A few weeks ago, Raspberry Pi released the Pico W, an update to the Pico development board with the addition of a wifi chip and trace antenna. As I’ve been using the Pico for many of my projects, I’m excited by the possibility of adding wireless connectivity.

I program in Ada, so I want to add support for the Pico’s wireless controller, CYW43439 to my driver library.

First, a reality check; Raspberry Pi is going to continue producing new microcontrollers and development boards with new features. They’ve put an immense amount of effort into their C/C++ SDK and MicroPython libraries. Do I really want to continue reimplementing their drivers in Ada? Would I be better off just generating a wrapper around their SDK? The Pico SDK is pretty heavily dependent on the CMake build infrastructure right now, so I’d have to figure out how to make that work with Ada. The generated Ada bindings from C code are usually pretty awkward to work with, so I’d have to write a fair bit of code either way. For now I’m going to keep going with my native Ada libraries, but I’m going to keep asking myself if this is a worthwhile effort when good vendor libraries exist.

The wireless chip they’ve chosen, CYW43439, is a beast. Infineon (formerly Cypress, formerly Broadcom) have a public datasheet, which contains information useful to PCB designers and test engineers as well as some rather confusing timing diagrams that contain no actual timing information. The Pico W has an RP2040 connected to the CYW43439 with the "gSPI" interface with both the transmit and receive signals multiplexed onto a single microcontroller pin.

The RP2040’s PIO should be perfect for implementing this sort of odd serial protocol, but I found it to be quite frustrating in this case. The CS, CLK, and DAT signals are not accessible from any test pad or trace that I can find on the Pico W, so I can’t get a logic analyzer connected while the RP2040 is communicating with the CYW43439. I considered buying a standalone module that uses this chip so that I could connect it to some pins I can probe, but I figured I’d try working blind first. I configured the PIO to use some of the Pico’s exposed pins and connected a logic analyzer. At the very least, I can get the CS, CLK and DAT transmit timing to look correct before trying to talk to the wireless controller.

The datasheet says that the device needs up to 50ms after pulling REG_ON high before it’ll respond to gSPI commands. The host should poll the registers beginning at address 0x14 for the value 0xFEEDBEAD. Once that value is read correctly, a test write/readback at address 0x18 verifies that the gSPI bus is working and the CYW43439 is powered up and ready to accept commands.

That 0xFEEDBEAD value led to some interesting search results; this protocol has been used in Broadcom wireless chipsets as far back as the venerable WRT54G router. There are many open source drivers of varying quality for this family of chips and it seems that Broadcom/Cypress/Infineon kept the host interface mostly the same over the years, only adding new commands when necessary. I found a very detailed writeup about reverse engineering the firmware for these chips, which was quite interesting, if not immediately useful.

The Pico SDK has a PIO driver for gSPI, so I spent a lot of time reading that code and trying to understand it. They use a single PIO SM to control the DAT signal, with CLK configured as a side-set. To begin a transfer, the host CPU resets the SM and executes set pindirs, 1 to configure DAT as an output, then sets the x register to the number of bits to write and y to the number of bits to read. These instructions are not included in the main PIO program as they’re not timing critical and executing them from the CPU saves on PIO memory, which is only 32 instructions. The PIO program shifts one bit out on the DAT pin, toggles the CLK sideset, then decrements the x register. Once x reaches zero, DAT is reconfigured as an input and the SM starts shifting in bits, decrementing y as it goes.

This seems fairly reasonable. We can control the number of bits per word by changing the x and y registers before beginning a transaction. The host CPU needs to get involved after each TX/RX cycle to reset the pindirs, x, and y registers and pull CS high if the transaction has completed. The driver code uses DMA to send data to the PIO, which doesn’t seem like a huge benefit when the CPU is going to intervene after every word transferred. The DMA controller can do byte swapping, which may be useful for big endian network data, but I’m not sure if it’s worth the trouble in this case.

I decided that I’d rather use up a bit more PIO memory and have separate programs for read and write that do their own setting of pindirs and the x register. The CPU still needs to control CS though, which is inconvenient. I really wish the PIO had just a few more Delay/Side-Set bits so that we could have longer delays in PIO programs for timing the CS "back porch."

The CYW43439 datasheet also illustrates a "Read-Write" transaction, where CS stays low between the Write and Read commands. The datasheet says there should be a "fixed delay" in between read and write in this mode. The diagram shows four clock edges during this delay time and there is a bus configuration register for delay timing, but I wasn’t able to get this working. As far as I know, this is just an optimization, not a required bus mode.

Speaking of optimizations, the CYW43439 defaults to 16-bit words on the gSPI interface, but the command to switch to 32-bit mode is 2 16-bit words long, so we can send that as the first command and never have to deal with changing word sizes. As far as I can tell, this is what every driver does.

After spending far too long trying to make my program block until the SM finished clocking bits and wondering if the idle polarity of the clock really matters, I got a logic analyzer trace that looked reasonably close to what the datasheet specifies. I changed my pin config to connect the PIO to the wireless controller and got some signs of life! Polling the 0x14 register returned 0xED 0xFE, which was half of my expected 0xFEEDBEAD with swapped bytes. I played with the PIO SHIFTCTRL register a bit and got a successful read of 0xFEEDBEAD. Surprisingly, the test write/readback worked too! I guess that means I have a working gSPI implementation on PIO! I noticed that the Pico SDK runs the PIO at 33 MHz for this interface, but my test program fails at anything faster than 20 MHz. I guess I still need to get a probe on those DAT, CLK, and CS traces to get the timing right. The datasheet says this interface can run at 50 MHz, but we can worry about that later.

Now that I can communicate with the CYW43439, I started looking at cyw43-driver more seriously. The datasheet makes no mention of most of the CYW43439’s internal registers and this is not a trivial driver, so I’m going to try to interoperate with this C driver from Ada, rather than trying to rewrite it. It looks like this driver calls a bunch of symbols like cyw43_hal_pin_config that we need to provide. Luckily, exporting Ada procedures as symbols that conform to the C ABI is easy.

procedure HAL_Pin_Config
  (Pin, Mode, Pull, Alt : Interfaces.C.int)
with Export, Convention => C, External_Name => "cyw43_hal_pin_config";

On the more complex side of things, we need a TCP/IP stack. cyw43 only contains bindings for LwIP and that’s what Pico SDK uses, so I went searching for Ada bindings for LwIP. Surely someone else has tried to do embedded networking in Ada before, right?

Right! I found a directory called ipstack buried in the SPARK unit tests. If the README is to be believed, this is a formally verified rewrite of a large chunk of LwIP in SPARK. Excellent! This code predates the Alire package manager by many years, so I spent some time understanding the existing Makefiles and hierarchy of GPRbuild projects and got the whole mess built as an Alire crate I can use as a dependency. There’s a lot of room for improvement here, but I want to get some packets flowing before I start trying to improve the IP implementation. If this works at all, I’ll be impressed.

The ipstack library only has two hardware drivers: a minimal TUN/TAP implementation for testing on a Linux host and a driver for the ancient NE2000 ISA card. I spent many hours learning about firewalls with OpenBSD on a 486 with a couple of NE2K cards in my formative years, so this brings back fond memories. Back in the day, the NE2000 was not the fastest network card you could buy, but it was cheap, reliable, and rock solid under Linux, which was far from a guarantee for any peripheral back then.

So now I have three bits of code to string together: my Ada/PIO gSPI implementation, the SPARK ipstack, and cyw43-driver.

Stay tuned for my next post, where I might actually get something working.

How can I install the ZFP (Zero Foot Print) RTS (Run Time System) for AVR with the Alire package manager for Ada?

How can I install the ZFP (Zero Foot Print) RTS (Run Time System) for AVR with the Alire package manager for Ada?

My project file, I think correctly, contains:

project Avr is
   for Runtime("Ada") use "zfp";
   for Target use "avr-elf";
end Avr;

alire.toml hopefully correction contains:

gnat_avr_elf = ">=11.2.4"

Unfortunately, when running alr build, I get:

gprconfig: can't find a toolchain for the following configuration:
gprconfig: language 'ada', target 'avr-elf', runtime 'zfp'

I found documentation for programming AVR with Ada, but this assumes that I build the tool-chain myself and not have a package manager at least providing the GNU tool-chain.

The same applies to Programming Arduino with Ada.

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:

  - 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.



Using Attribute Scalar_Storage_Order in ada with gcc 6.2.1

I'm currently trying to find a solution to control the storage order for elements within a record in ADA.

I'm using gcc 6.2.1 which doesnt recognize the Scalar_Storage_Order attribute ( even though the attribute is clearly referenced in the gcc 6.2 GNAT reference manual).

type Rec is record

      Data1 : T_Data;
      Data2 : T_Data;

   end record;

for Rec use

         Data1      at 0 range 0 .. 15;
         Data2      at 0 range 0 .. 15;

      end record;

for Rec'Bit_Order use System.High_Order_First;
for Rec'Scalar_Storage_Order use System.High_Order_First;

error: unrecognized attribute "Scalar_Storage_Order"

Is there an alternative that I can use to achieve my goal?

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.



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)

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:

  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:
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



Passing String from C to Ada via C Interpreter (VxWorks)

I'm trying to pass a string from C to Ada by using the C interpreter in a telnet window to a VxWorks box.


#pragma once

#ifdef _cplusplus
extern "C"

extern void Ada_SetNewAddress(char*);

extern "C" void SetNewAddrBroker(char* ipAddress);

#ifdef __cplusplus


#include "Interface.h"
#include <stdio>

extern "C" void SetNewAddrBroker(char* ipAddress)
    printf("We passed the value -> %s", ipAddress);
    printf("Ada was called!\n");


with Interfaces.C;
with Interfaces.C.Strings;

package Streamer is
    procedure Initialize;
    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr);
    pragma Export (C, SetNewAddress, "Ada_SetNewAddress");
end Streamer;


package body Streamer is
    Socket : Socket_Type;
    DefaultAddr : String := "";
    Address : Sock_Addr_Type := (Family_Inet, Inet_Addr(DefaultAddr), 1024);
    Buffer : Stream_Access;

    procedure Initialize is
        Create_Socket(Socket, Family_Inet, Socket_Datagram);
        Buffer := Stream(Socket, Address);

    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr)
        cstar : String := Interfaces.C.Strings.Value(str);
        Address := (Family_Inet, Inet_Addr(cstar), 1024);
        Buffer := Stream(socket, Address);
end Streamer;

When I call the C function SetNewAddrBroker("") I get a 'data access' error, this is via telnet to the VxWorks machine that this code exists on, the Ada program is the main task, so I know it's not the missing "adainit() and adafinal()" calls. I can't figure out why it's throwing a random data access error. I can use putty or teraterm for the telnet client if that matters, both throw the same error.


    We passed ->
    data access
    Exception current instruction address: 0x002e3ab0
    trcStack aborted: error in top frame
    Shell task 'tShellRem1' restarted...

Examining, the instruction that threw the error

    0x2e3ab0 stw r30,8(r9)

I do not know assembly but I imagine this is trying to store the string in a place that is too small?

I need to set the IP of the broker for the client at runtime, the Ada is the client, and the broker is just on my LAN. I want to be able to telnet to the Ada client and just update the ip address, but the only interface exposed to me is the C interpreter for the VxWorks box, so I'm stuck with interfacing with this.

VxWorks Version 6.3