Using `limited with` in Ada to avoid circular dependency - ada

I'm trying to get a couple of tasks to be able to call each other, but I don't seem very good with this limited with thing..
I have a spec sctrain-trains.ads
limited with SCTrain.Stations;
with SCTrain.Travellers, SCTrain.Tracks, Ada.Strings.Unbounded;
use SCTrain.Travellers, SCTrain.Tracks, Ada.Strings.Unbounded;
package SCTrain.Trains is
type my_station_access_t is access all Stations.Station;
task type Train is
entry Start(leaving: my_station_access_t; arriving: my_station_access_t);
end Train;
end SCTrain.Trains;
and its .adb
with SCTrain.Stations;
use SCTrain.Stations;
package body SCTrain.Trains is
task body Train is
destination: my_station_access_t;
begin
accept Start(leaving: my_station_access_t; arriving: my_station_access_t) do
destination := arriving;
end Start;
destination.Gogo(1);
end Train;
end SCTrain.Trains;
I found in the documents I've been reading that withing the "circular" package in the body would allow smooth executions, but apparently I still have an invalid prefix in selected component "destination" because dereference must not be of an incomplete type (RM 3.10.1), and those errors stay there even without the with and use in the package body.
I'm sure I'm missing something, possibly something very basic, and I'd really love to know what that is. The problem I'm trying to solve is that the Train needs a signal from the Station to be allowed to leave and still able to communicate its arrival time afterwards.
I'm using the latest GNAT-GPL.
Thank you very much.
edit: adding Station's code
limited with SCTrain.Trains;
with Ada.Calendar, Ada.Strings.Unbounded, Ada.Text_IO;
use Ada.Calendar, Ada.Strings.Unbounded, Ada.Text_IO;
package SCTrain.Stations is
task type Station is
entry Gogo(name_d : Integer := 0);
end Station;
end SCTrain.Stations;
and the body:
with SCTrain.Trains;
use SCTrain.Trains;
package body SCTrain.Stations is
task body Station is
name : Integer;
begin
accept Gogo (name_d : Integer := 0) do
name := name_d;
Put_Line("Station " & Integer'Image(name) & " is alive");
end Gogo;
end Station;
end SCTrain.Stations;

Use limited with in one direction only, and a normal with in the other.

Replace the declaration of destination by
destination: access Stations.Station;
or replace the offending line by
destination.all.Gogo(1);
I don't know whether this is a compiler bug or proper behaviour; it looks suspicious!
Later: I posted a still-more-cut-down example on comp.lang.ada and one of the resident experts agrees that it's a bug; I'll report it to AdaCore.

Related

Error with IStream.Seek()

I have a very old piece of code to handle Excel files in Delphi 5, which I adapted to work with Delphi 2005, which I used professionally until 2010. Since then, there was no reasonable free version of Delphi. Therefore, it is only now that using Delphi 10.2.3 Tokyo I would like to adapt it once again.
A problem that I was not able to solve is related to the use of OleStream.Seek(...) in the function given below, where I get a fatal error with all expressions in OleCheck(...).
Also, I didn't find any hint on a similar problem searching for the function OleStream.Seek(...) on the Internet.
The code is the following
function Streamseek(offset : longint; origin: word):string;
var
Pos : longInt ; // Pos: largeint;
begin
if FBIFFVersion > biff4 then begin
case Origin of
soFromBeginning:
OleCheck(OStream.Seek(Offset,STREAM_SEEK_SET,Pos)); // ENUM: set =0
soFromCurrent:
OleCheck(OStream.Seek(Offset,STREAM_SEEK_CUR,Pos)); /// 1 cur
soFromEnd:
OleCheck(OStream.Seek(Offset,STREAM_SEEK_END,Pos)); // 2 end
end;
Of course, it is just one function in a much bigger program, which is not relevant here.
My problem is: I searched for
OStream.Seek(Offset,STREAM_SEEK_SET,Pos) on the Internet, but I could only find OleStream.seek(offset : longint; origin: word):string; except for one webpage, but there the same types were used.
Working with IStream in Delphi
So, I wonder what parameter types need to be used.
In the German version of Delphi 10.2.3, I get the error:
[dcc32 Fehler] line(878): E2033 Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen
In English:
The types of the real and the formal var parameters must be the same.
It is clear that largeint is not a modern parameter type, and I only see the possibility that, instead of Integer, LongInt, Int64 or else is needed since the number of parameters should be OK.
LongInt instead of Integer for offset does not work, Longint instead of LargeInt does not work for pos.
Has anyone an idea what might be the reason for the error? What are the required types of this function in Delphi 10.2.3?

Error: cannot generate code for file random.ads (package spec)

I somehow cannot compile (neither run) my Ada code in GPS. I get an error:
cannot generate code for file random.ads (package spec)
gprbuild: *** compilation phase failed
The random.ads file looks like this:
with Ada.Numerics.Float_Random;
use Ada.Numerics.Float_Random;
package random is
protected randomOut is
procedure Inicializal;
entry Parcel(
randomout: out Positive;
from: in Positive;
to: in Positive := 1
);
private
G: Generator;
Inicializalt: Boolean := False;
end randomOut;
task print is
entry write(what: in String);
end print;
end random;
The .gpr file looks as follows:
project Default is
package Compiler is
for Default_Switches ("ada") use ("-g", "-O2");
end Compiler;
for Main use ("hunting.adb");
end Default;
What does this mean? How can I fix it? Thank you!
You can't generate code for a package specification.
This is normal and expected.
You can compile the package body, random.adb, and generate code for it - but there's usually no need.
Just compile your main program, (or your test harness if you're unit testing) and let the compiler find all its dependencies.
(If it can't, either you haven't written them yet, or it's looking in the wrong place. If you need help with that, add relevant info to the question).
The problem is caused by
task print is
entry write(what: in String);
end print;
As any task is specified as a body, the compiler had trouble deciding: it had a body, that has to be compiled, in a spec file, which does not. Moving the task to the .adb file solved the issue.

Is is possible to have a child package as a separate compilation unit in Ada

I have a main package with a normal spec and body file. I am trying to create child packages of the parent, but want them in a separate compilation file(s). I can easily get it done if it is just a package body, or if it is a subprogram/proc/func. However, I can't get it to let me make a child spec file.
The reason I am doing this is because I want to have information in a child that is available to other children of the same parent. I know I can do this by just including the spec portion in the parent, but that is making my parent file pretty big.
Is this even possible, or do I have no choice but to make another root unit? Or just leave everything spec wise in the parent?
I tried:
in parent:
package Child1 is separate; (also tried Parent.Child1 but that gave compiles errors
in child:
separate(Parent)
package Parent.Child1 is
....
end Parent.Child1;
Ideas? Just not possible?
Update: I am compiling with Green Hills Multi Compiler. Ada95 language version, non-OO project.
Noting that you're using the separate keyword I'm going to venture that your question is not about child units, but nested units.
Try the following:
Testing.adb
With
Ada.Text_IO,
Parent;
Procedure Testing is
Begin
Ada.Text_IO.Put_Line("Starting Test:");
Parent.Nested.Test_Procedure;
Ada.Text_IO.Put_Line("Testing complete.");
End Test;
Parent.ads
Package Parent is
Package Nested is
Procedure Test_Procedure;
End Nested;
End Parent;
Parent.adb
Package Body Parent is
Package Body Nested is separate;
End Parent;
Parent-Nested.adb
(Note: you may have to use something slightly different for the file-name, I'm using GNAT with the default settings for "dot replacement".)
with Ada.Text_IO;
separate (Parent)
package body Nested is
Procedure Test_Procedure is
Message : Constant string:= ASCII.HT &
"Hello from the separate, nested test-procedure.";
begin
Ada.Text_IO.Put_Line( Message );
end Test_Procedure;
End Nested;
You should be able to compile and the output should be three lines as follows:
Starting Test:
Hello from the separate, nested test-procedure.
Testing complete.
The problem here stems from a slight misunderstanding regarding the differences between nested and child packages. Both are accessed with the same method of dot-delimited-qualification: Parent.Nested and Parent.Child.
The subtle difference is that child-packages are always a separately compiled unit (in GNAT they are always in a different file, this is an implementation restriction due to how they [don't] implement the Library.. but some Ada compilers can put different compilation_units into the same file) -- but a nested-package must be compiled at the same time that its enclosing unit is compiled unless it is specifically tagged as separate.
In order to preserve the current nested structure and still use separates you can use the following method with a single Auxiliary package holding all the specs for the packages.
Parent.ads
Package Parent is
-- Here's the magic of renaming. --'
Package Nested renames Auxiliary.Delegate;
End Parent;
Auxiliary.ads
Package Auxiliary is
Package Delegate is
Procedure Test_Procedure;
End Delegate;
End Auxiliary;
Auxiliary.adb
package body Auxiliary is
Package Body Delegate is separate;
end Auxiliary;
Auxiliary-Delegate.adb
(Note: you may have to use something slightly different for the file-name, I'm using GNAT with the default settings for "dot replacement".)
with Ada.Text_IO;
separate (Auxiliary)
package body Delegate is
Procedure Test_Procedure is
Message : Constant string:= ASCII.HT &
"Hello from the separate, nested test-procedure.";
begin
Ada.Text_IO.Put_Line( Message );
end Test_Procedure;
End Delegate;
Yes, this is totally fine. You can have your parent and child packages in separate files:
parent.ads
package Parent is
-- ...
end Parent;
parent-child.ads
package Parent.Child is
-- ...
end Parent.Child;
parent-other.ads:
limited with Parent.Child; --Need Ada 2005
package Parent.Other is
-- ...
end Parent.Other;
The parent.child package and the parent.other package have access to definitions in parent (with some limitations).
Notice how parent.other "withs" parent.child so that it has access to the definitions in parent.child.
I have an example of how it can be done. Also, here is an example from wikibooks.

How to make a non-blocking pipe from the command-line in Solaris?

I'm trying to write a lua script that reads input from other processes and analyzes it. For this purpose I'm using io.popen and it works as expected in Windows, but on Unix(Solaris) reading from io.popen blocks, so the script just waits there until something comes along instead of returning immediately...
As far as I know I can't change the functionality of io.popen from within the script, and if at all possible I would rather not have to change the C code, because then the script will then need to be bound with the patched binary.
Does that leave me with any command-line solutions?
Ok got no answers so far, but for posterity if someone needs a similar solution I did the following more or less
function my_popen(name,cmd)
local process = {}
process.__proc = assert(io.popen(cmd..">"..name..".tmp", 'r'))
process.__file = assert(io.open(name..".tmp", 'r'))
process.lines = function(self)
return self.__file:lines()
end
process.close = function(self)
self.__proc:close()
self.__file:close()
end
return process
end
proc = my_popen("somename","some command")
while true
--do stuf
for line in proc:lines() do
print(line)
end
--do stuf
end
Your problems seems to be related to buffering. For some reason the pipe is waiting for some data to be read before it allows the opened program to write more to it, and it seems to be less than a line. What you can do is use io.popen(cmd):read"*a" to read everything. This should avoid the buffering problem. Then you can split the returned string in lines with for line in string.gmatch("[^\n]+") do someting_with(line) end.
Your solution consist in dumping the output of the process to a file, and reading that file. You can replace your use or io.popen with io.execute, and discard the return value (just check it's 0).

How can you print an Ada.Calendar.Time variable in Ada?

Need to know how to print a Time variable in Ada. I assume there is no portable way because Time is implementation defined. I've already seen the GNAT.Calendar.Formatting package available under GNAT, I'd also be interested in a GHS for VME.
See package "Ada.Calendar.Formatting" function "Image" for Ada2005. If you have an Ada95 compiler you could and this package isn't available, try my implementation from here
This was written using GNAT 3.15p, so pretty old.
Sure, time output can be portable, Ada.Calendar contains standard functions that extract the components of a time value, so it's straightforward to put together your own conversion package.
For example, here's one. One just needs to either create a minor addition to create a "Formatted_Time" record for a given Time value (see the package's Get_Time() function for guidance), or make Main_Formatter() visible in the package spec.
Generally what I do is use Calendar.Split and then do a 'image on the parts I care about.
Here's an example that displays the date and time using the GNAT.Calendar.Time_IO package:
with ada.calendar;
with gnat.calendar.time_io;
procedure display_time is
begin
gnat.calendar.time_io.put_time(ada.calendar.clock, "Date: %Y/%m/%d Time: %H:%M:%S");
end display_time;
Date/time format options are available here:
https://en.wikibooks.org/wiki/Ada_Programming/Libraries/GNAT.Calendar.Time_IO

Resources