Subprogram contracts in Ada - ada

I'm reading a document on Ada programming to be more specific, Ada for C++ Java developer, or I'm in trouble and to understand and be able to use some of the examples given in the document, one of them is on pre- and postconditions
But, when I compile that program, I just got a +Inf**** message - I was expecting compilation to fail because I am trying to pass 0 as the divisor.
with Ada.Text_IO;
use Ada.Text_IO;
procedure main is
function Divisao(Left, Right : Float) return Float
with Pre => Right /= 0.0,
Post => Divisao'Result * Right < left + 0.0001
and then Divisao'Result * Right > Left - 0.0001
is
begin
return Left/Right;
end Divisao;
begin
Put_Line(Float'Image(Divisao(10.3,0.0)));
end main;

By ARM 11.4.2 (1.1), pre- and postconditions are assertions. GNAT doesn’t enable assertions by default: you need to enable them by compiling with -gnata.
If you are using gprbuild, you will need to add something like this to your project.gpr file:
package Compiler is
for Default_Switches ("Ada") use
("-gnata"); -- enable assertions
end Compiler;

Related

Prevent Ada 202x Use in GNAT

GNAT allows the following code due to Random(Generator, First, Last) being implemented in the runtime, but it's not part of Ada 2012. Can I cause this to generate a compile error since it shouldn't be available?
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
procedure Main is
package Positive_Random is new Ada.Numerics.Discrete_Random
(Result_Subtype => Positive);
Generator : Positive_Random.Generator;
-- This should fail, since function isn't part of Ada 2012.
Value : Positive := Positive_Random.Random (Generator, 1, 10);
begin
Put_Line (Value'Image);
end Main;
This is my gpr file:
project Default is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.adb");
package Compiler is
for Switches ("ada") use ("-gnat12");
end Compiler;
end Default;
In my point of view, the standard way to do this is to add a global restriction:
pragma Restrictions (No_Implementation_Identifiers);
No_Implementation_Identifiers
There are no usage names that denote declarations with implementation-defined identifiers that occur within language-defined packages or instances of language-defined generic packages.
But this doesn't work in GNAT Community Edition 2021 (nor in GCC 11, I guess).
You can create a custom GNAT run-time and delete this subprogram or mark it with aspect Implementation_Defined to make the restriction work.

How to stop console window from closing immediately | GNAT - GPS

I have Ada program that runs and compile perfectly using GNAT - GPS. When I run its exe file and provide user input then instead of saying "Press any key to continue", the exe closes immediately.
I have searched for it online alot but i only found info related to c/c++/visual studio console window using system('pause'); OR Console.Readline().
Is there any way around for this in Ada lanaguage?
Apart from using Get_Line or Get, you can also use Get_Immediate from the Ada.Text_IO package. The difference is that Get_Line and Get will continue to read user input until <Enter> has been hit, while Get_Immediate will block only until a single key has been pressed when standard input is connected to an interactive device (e.g. a keyboard).
Here's an example:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
begin
-- Do some interesting stuff here...
declare
User_Response : Character;
begin
Put_Line ("Press any key to continue...");
Get_Immediate (User_Response);
end;
end Main;
NOTES
You should run the program in an interactive terminal (Bash, PowerShell, etc.) to actually see the effect of Get_Immediate. When you run the program from within GPS, then you still have to press enter to actually exit the program.
This might be too much detail, but I think that Get still waits for <Enter> to be pressed because it uses fgetc from the C standard library (libc) under the hood (see here and here). The function fgetc reads from a C stream. C streams are initially line-buffered for interactive devices (source).
The answer from #DeeDee is more portable and only Ada and the preferable way to go, so my answer is just if you are looking for a "windows" way to do it.
I think there is a linker option for it, but I couldn't find it. A more manual way is to bind the system() command from C and give it a "pause" command and place it at the end of your program:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Strings;
procedure Main is
function System(Str : Interfaces.c.strings.chars_ptr) return Interfaces.C.int
with Import,
Convention => C,
External_Name => "system";
procedure Pause is
Command : Interfaces.c.Strings.chars_ptr
:= Interfaces.C.Strings.New_String("pause");
Result : Interfaces.C.int
:= System(Command);
begin
Interfaces.C.Strings.Free(Command);
end Pause;
begin
Put_Line("Hello World");
Pause;
end Main;
I know you mentioned seeing about pause already, but just wanted to show an example.
The same way you could use Console.Readline(), you can use Get_Line from the package Ada.Text_IO.
In this case, you will have to put the result into a String that you won't use.

Ada - Can't find library info for "check_positive.adb"

I have to learn Ada so I can write an interpreter for it. But I cannot find many resources on learning the language. I get the above message when attempting to compile the following code: I save the file as check_positive.adb. What else am I supposed to do? I ran gnatls Check_Positive.adb after I ran gnatchop -w Check_Positive.adb. I am using GNAT Community v5.1.0.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Check_Positive is
N : Integer;
begin
Put ("Enter an integer value: "); -- Put a String
Get (N); -- Read in an integer value
if N > 0 then
Put (N); -- Put an Integer
Put_Line (" is a positive number");
end if;
end Check_Positive;
gnatls and gnatchop will not compile your code, you should try gnatmake:
gnatmake check_positive.adb
be aware that GNAT expects lower-case filenames and one procedure/function/package spec/package body per file. If you organize your code that way, you won't need gnatchop.

Is there a way of instructing Ada compiler to select blocks of code?

I would like to instruct the Ada compiler to select between two different blocks of code, depending on predefined static compiler directives, such as for instance "DEBUG" or "RELEASE". I would like to do something like this:
if DEBUG then
< COMPILE THIS CODE >
end if;
if RELEASE then
< COMPILE THIS OTHER CODE >
end if;
C# and other languages offer the #define directive for this. Has Ada something similar to offer? And if not, how is this done in Ada?
Good Ada style is to write it exactly as you did, making sure that the entities Debug and Release are static.
One way to do that is to have a package, say Compilation_Mode, which exists in two variants:
package Compilation_Mode is
Debug : constant Boolean := False;
Release : constant Boolean := True;
end Compilation_Mode;
and
package Compilation_Mode is
Debug : constant Boolean := True;
Release : constant Boolean := False;
end Compilation_Mode;
You then let your build system select the appropriate package. (Using gprbuild, you could do it with a package Naming in the project file.)
It is not very straightforward, but a possible way is to use separate compilation units. For example, say that you are inside the body of a package named Pkg, and want some code that should do different things based on some scenario variable (this is a GNAT GPRBuild term, but the method can also be used with other build systems). You move that code into some subroutine, let's say, Do_Something, and declare it as separate:
package body Pkg is
-- ...
procedure Do_Something is separate;
-- ...
end Pkg;
This tells the compiler that this procedure is defined as separate compilation unit. Now, you put your two (or any number of) implementations in two separate files like this:
separate (Pkg) procedure Do_Something is
-- ...
begin
-- ...
end Do_Something;
This tells the compiler that this is the definition of a separate compilation unit from within Pkg. And yes, this means that for each bunch of code, you would need to write two (or n with n = number of differing implementations) additional files.
A good method for managing those files would be to put all debug implementations in a debug directory and likewise for release implementations. You then instruct your build system to load sources from one or the other directory. For example with GPRBuild:
project My_Project is
-- define legal modes
type Mode_Type is ("debug", "release");
-- load mode from environment variable `Mode`, defaulting to "debug"
Mode : Mode_Type = external ("Mode", "debug");
-- add directory with appropriate separate implementations
case Mode is
when "debug" => My_Sources := My_Sources & "src/debug";
when "release" => My_Sources := My_Sources & "src/release";
end case;
-- define where the compiler should load sources from
for Source_Dirs use My_Sources;
-- ...
end My_Project;
Your src folder would have a layout like this:
src
debug
pkg-do_something.adb
release
pkg-do_something.adb
pkg.adb
pkg.ads
This approach works well with multiple, orthogonal scenario values. It also forces you to separate scenario-specific code from general code, which may be seen as good thing, but ymmv.
Ada doesn’t, but the most popular Ada toolset (GNAT) includes a tool gnatprep (see here) to do this. Other toolsets may include equivalents.
For example,
RCC.RCC_Periph.AHB1ENR := ($SCL_Enable => 1, others => <>);
$SCL_GPIO.MODER.Arr ($SCL_Pin) := 2; -- alternate function
$SCL_GPIO.OTYPER.OT.Arr ($SCL_Pin) := 1; -- open drain
$SCL_GPIO.OSPEEDR.Arr ($SCL_Pin) := 1; -- medium speed
$SCL_GPIO.PUPDR.Arr ($SCL_Pin) := 0; -- nopullup, no pulldown
#if SCL_Pin < 8 then
$SCL_GPIO.AFRL.Arr ($SCL_Pin) := 4; -- DocID022152 Rev 6 Table 9
#else
$SCL_GPIO.AFRH.Arr ($SCL_Pin) := 4; -- DocID022152 Rev 6 Table 9
#end if;
if translated using this Makefile fragment
src/i2c1-device.adb: ../i2c/src/i2c-device.adb.pp $(DEFINITION)
gnatprep \
-c -v \
$< \
$# \
$(DEFINITION)
where the file $(DEFINITION) contains
SCL_Enable := GPIOBEN
SCL_GPIO := GPIO.GPIOB_Periph
SCL_Pin := 8
results in
RCC.RCC_Periph.AHB1ENR := (GPIOBEN => 1, others => <>);
GPIO.GPIOB_Periph.MODER.Arr (8) := 2; -- alternate function
GPIO.GPIOB_Periph.OTYPER.OT.Arr (8) := 1; -- open drain
GPIO.GPIOB_Periph.OSPEEDR.Arr (8) := 1; -- medium speed
GPIO.GPIOB_Periph.PUPDR.Arr (8) := 0; -- nopullup, no pulldown
--! #if SCL_Pin < 8 then
--! $SCL_GPIO.AFRL.Arr ($SCL_Pin) := 4; -- DocID022152 Rev 6 Table 9
--! #else
GPIO.GPIOB_Periph.AFRH.Arr (8) := 4; -- DocID022152 Rev 6 Table 9
--! #end if;

Ada object declarations "Unsigned Not Declared in System"

In some code that I inherited, I get the compile error "Unsigned" not declared in "System".
I'm trying to compile this using GNAT, but ultimately the code must compile with the original tools, which I don't have ready access to. So I'd like to understand how to resolve this from within the development environment (including the project file), and not modify the existing code.
I checked the file system.ads, and Unsigned is not defined there. Am I referring to the wrong libraries? How would I resolve this with the self imposed constraint mentioned above (to compile in the original environment)?
unsigned is the name of a predefined type in C. If what you need it an Ada type that matches the C type, what you need is Interfaces.C.unsigned. An older Ada implementation (before Interfaces.C was introduced by the 1995 standard) might have defined System.Unsigned for this purpose.
It would help to know what Ada implementation the code was originally written for.
You should examine the code to see whether it uses that type to interface to C code. If not (i.e., if it's just being used as a general unsigned integer type), you might instead consider defining your own modular type.
If I understand correctly, you need the code to compile both in the original environment and with GNAT. That might be difficult. One approach would be to define a new package with two different versions, one for the original environment and one for GNAT (or, ideally, for any modern Ada implementation). For example:
-- version for original environment
with System;
package Foo is
subtype Unsigned is System.Unsigned;
end foo;
and:
-- version for GNAT
with Interfaces.C;
package Foo is
subtype Unsigned is Interfaces.C.Unsigned;
end Foo;
Picking a better name than Foo is left as an exercise, as is determining automatically which version to use.
You could rebuild the GNAT runtime system (RTS) with a slightly modified system.ads.
There’s a Makefile.adalib in the system RTS (well, there is in GNAT GPL 2014) which lets you do this. It’s at the last directory indicated in the “Object Search Path” section of the output of gnatls -v.
The RTS source is similarly indicated in the “Source Search Path” section.
Create a directory say unsigned with subdirectories adainclude, adalib.
Copy the RTS source into unsigned/adainclude, and edit system.ads to include
type Unsigned is mod 2 ** 32;
(I’m guessing a bit, but this is probably what you want!)
Then, in unsigned/adalib,
make -f Makefile.adalib ADA_INCLUDE_PATH=../adainclude ROOT=/opt/gnat-gpl-2014
(ROOT is where you have the compiler installed; it will be different on your system, it’s one above the bin directory in which gnatls and friends are installed).
There will be several errors during this, all caused (when I tried it) by units that use System.Unsigned_Types;. Work round this by inserting this immediately after the package body in the .adb:
subtype Unsigned is System.Unsigned_Types.Unsigned;
The files I had to change were
s-expmod.adb
s-expuns.adb
s-imgbiu.adb
s-imgrea.adb
s-imguns.adb
s-imgwiu.adb
s-valint.adb
s-valuns.adb
s-vercon.adb
It may be best at this stage to remove all the .ali and .a files from unsigned/adalib and repeat, to get a clean build.
Now, you should be able to use System.Unsigned by
gnatmake --RTS=/location/of/unsigned t.adb
In my case, t.adb contained
with System;
with Ada.Text_IO; use Ada.Text_IO;
procedure T is
begin
Put_Line ("first: " & System.Unsigned'First'Img);
Put_Line ("last: " & System.Unsigned'Last'Img);
Put_Line ("42: " & System.Unsigned'Value ("42")'Img);
Put_Line ("16#42#:" & System.Unsigned'Value ("16#42#")'Img);
end T;
and the output was
$ ./t
first: 0
last: 4294967295
42: 42
16#42#: 66

Resources