Ada: Pragma List - ada

Can anybody tell me what Pragma List does (specifically, what is "listing of the compilation")? I don't understand the description from the LRM (2.8.25)
A pragma List takes one of the identifiers On or Off as the single argument. This pragma is allowed anywhere a pragma is allowed. It specifies that listing of the compilation is to be continued or suspended until a List pragma with the opposite argument is given within the same compilation. The pragma itself is always listed if the compiler is producing a listing.

A compiler can output, i.e. “list” its input, together with any messages that it will generate, such as error messages. This is useful when you want a clear, verbose view of what a message is about, in context. IDEs will normally link message to code, but even today, considering Jacob's hint at computing history, a list can literally point out. Using a pragma List, the programmer can exclude what does not need to be listed, if he or she knows. Or, exclude what should never be listed, for reasons of secrecy.
Listing first, then the original program text, with pragma List:
Compiling: /some/path/some_proc.adb
Source file time stamp: 2017-01-30 08:30:40
Compiled at: 2017-01-30 09:30:42
1. procedure Some_Proc is
2. procedure Inner;
3. -- Does this and that...
4.
5. pragma List (Off);
10. pragma List (On);
11.
12. begin
13. Inner (42);
|
>>> too many arguments in call to "Inner"
14. end Some_Proc;
14 lines: 1 error
gprbuild: *** compilation phase failed
(If your compiler is GNAT, specify -gnatl among the switches, for listing, and compile:)
procedure Some_Proc is
procedure Inner;
-- Does this and that...
pragma List (Off);
procedure Inner is
begin
null;
end Inner;
pragma List (On);
begin
Inner (42);
end Some_Proc;

You should think back to how compilers worked and were used in the late 1970'ies. I'm pretty sure the meaning is as simple as it is written (substitute "is producing" with "outputs", to get a more modern wording).
with Ada.Text_IO;
-- Now you see me.
pragma List (Off);
-- Now you do not.
private with Some_Secret_Package;
pragma List (On);
package Hello_World is
...

Related

Deep copy of function arguments for polymorphic types

I use an object based on a base package roughly defined as:
package Base is
type T_Base is abstract tagged null record;
-- This performs a deep copy. Shallow copies may lead to STORAGE_ERROR.
-- This shall be implemented by every derived type.
function Copy (From : in T_Base) return T_Base'Class is abstract;
end package Base;
This package is derived by several packages which are further derived
package Foo is
type T_Foo is new T_Base with record
A_Data : Natural; -- Of course, in the real code, these are types by far more complex.
end record;
procedure do_something (Foo_Object : in T_Foo);
-- This implements the deep copy
function Copy (From : in T_Foo) return T_Base'Class is abstract;
end package Foo;
On calling the procedure do_something, I do get a storage_error:
procedure handle_received_foo (Foo_In: in Foo.T_Foo) is
begin
Foo.do_something (Foo_Object => Foo_In); -- The storage error does happen here.
end main;
When running the code with gdb, I get a segfault on entering the function and I get:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 39 (LWP 39)]
0x033c9828 in foo.do_something (foo_object=...) at ./foo.adb:67
67 procedure do_something (Foo_Object : in T_Foo);
(gdb) p foo_object
$1 (null)
So I guess I get a storage_error when doing the shallow copy of the argument Foo_Object.
I am aware that this is no MWE and that there might be a mistake in one of the types present used in the derived types.
I can't find any good option:
Making T_Foo a Controlled type to call Copy in Adjust seems not to be possible without greatly changing its definition as I can't derive T_Foo both from T_Base and Ada.Finalization.Controlled since none of them is an interface types
Defining T_Base as
type T_Base is abstract new Ada.Finalization.Controlled with null record;
and override Adjust here seems to induce a hell lot too much modifications on the existing code base as gnat yields in multiple places
type of aggregate has private ancestor "Controlled" must use extension aggregate.
So I'm low on solutions to either investigate the problem further or to solve it with a hammer.
The problem was not in the Copy function. The comments I saw in the code base were misleading.
The fact that introducing new variables changed the location of the exception made me consider some stack overflow problems.
Indeed the Storage_Size allocated for the task was not sufficient. Increasing the pragma Storage_Size(<value>) solved the problem.
Since the code base is compiled with -fstack-check, this led to the aforementioned STORAGE_ERROR.
More infos on Adacore's documentation.
This could probably have been seen with Gem #95: Dynamic Stack Analysis in GNAT but I am not currently able to see any result with the binding option suggested therein.

Ada program to detect an end of line

I was assigned this task as my homework. I have a file which contains lines of text of varying lengths. The program is supposed to write the data onto the screen in precisely the same order in which it is written in the file, yet it fails to do so. To achieve the desired result I tried reading only one character per iteration so as to detect new line characters. What am I doing wrong?
WITH Ada.Text_IO;
WITH Ada.Characters.Latin_1;
USE Ada.Text_IO;
PROCEDURE ASCII_artwork IS
File : File_Type;
c : Character;
BEGIN
Open(File, In_File, "Winnie_The_Pooh.txt");
WHILE NOT End_Of_File(File) LOOP
Get(File, C);
IF (C = Ada.Characters.Latin_1.LF) THEN Put_Line(" "); ELSE
Put(C);
END IF;
END LOOP;
Close(File);
END ASCII_Artwork;
For each file, the Ada runtime maintains a fictitious "cursor". This is not the typical file position cursor (index), but one that indicates the position on a page, line, etc. (see also RM A.10 (7)). This is somewhat of an inheritance from the early versions of Ada.
Get stems from this same era and is expected to update the location of this cursor when some particular control characters are being read (e.g. an end-of-line mark). If Get reads such such a control character, it will only use it to update the cursor (internally) and then continue to read a next character (see also RM A.10.7 (3)). You'll therefore never detect an end-of-line mark when using Get.
This behavior, however, has some uncomfortable consequence: if a file ends with a sequence of control characters, then Get will keep reading those characters and hit the end of the file causing an End_Error exception.
You can, of course, catch this exception and handle it, but such a construct is dubious as having a sequence of control characters at the end of a file is actually not such an abnormal case (and hence dubious if worth an exception). As a programmer, however, you cannot change this behavior: it's defined by the language and the language will not be changed because it has been decided to keep Ada (highly) backwards compatible (which in itself is understandable given its field of application).
Hence, in your case, if you want stick to a character-by-character processing approach, I would suggest to move away from Get and instead use (for example) streams to perform I/O as in the example below.
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams;
procedure ASCII_artwork IS
File : File_Type;
Input : Stream_Access;
Output : Stream_Access;
C : Character;
begin
Open (File, In_File, "Winnie_The_Pooh.txt");
Input := Stream (File);
Output := Stream (Standard_Output);
while not End_Of_File (File) loop
Character'Read (Input, C);
Character'Write (Output, C);
end loop;
Close(File);
end ASCII_Artwork;
Output is as expected (i.e. the content of this the file at ascii-art.de).
NOTE: Check the source code of the GNAT runtime to actually see how Get works internally (focus on the loop at the end).
As explained by DeeDee, text inputs are buffered linewise in Ada. The idea is to be able to read two integers on the same line. For consistency sake (the designers of Ada are picky on that...), Get(File, C) does the same. It is not practical in your case. Fortunately, Ada 95 has introduced Get_Immediate, to solve precisely that issue.
Otherwise, as suggested by Frédéric, you could use the function Get_Line to absorb Winnie_The_Pooh.txt line by line seamlessly. By the way, the Get_Line method will convert the different end-of-line conventions automatically.
Line terminators in Ada.Text_IO are a concept, not a character or sequence of characters in the file. (Although most commonly used file systems implement them as characters or sequences of characters in the file, there exist file systems that do not.) Line terminators must therefore be manipulated using the operations in the package. For reading, End_Of_Line checks to see if the cursor is at a line terminator, Skip_Line skips the next line terminator, and Get_Line may skip a line terminator. For writing, New_Line and Put_Line write line terminators.
For your problem, the canonical solution is to use the Get_Line function to read lines, and Put_Line to output the lines read.

Ada.Containers.Vectors not working with GNAT GPL 2017

I am trying to compile this code:
with Ada.Containers.Vectors;
procedure Test is
type My_Type is range -1 .. Integer'Last;
package My_Vectors is new Ada.Containers.Vectors (Positive, My_Type);
Vector : My_Vectors.Vector;
begin
Vector.Append (-1);
end Test;
gnatmake test.adb gives this output:
gcc -c test.adb
a-convec.adb:1553:33: missing operand
gnatmake: "test.adb" compilation error
The error message leads to this procedure in the stdlib's implementation:
procedure Insert
(Container : in out Vector;
Before : Extended_Index;
Count : Count_Type := 1)
is
New_Item : Element_Type := <>; -- << here
pragma Warnings (Off, New_Item);
begin
Insert (Container, Before, New_Item, Count);
end Insert;
It looks fine. I don't understand the error message, what's wrong here? Is it a bug in the stdlib?
Looks like this file has been tampered with…
Summarizing the evidence,
Multiple comments report no problem with GNAT versions going back as far as 4.9.1.
The initialization marked << here is a compile-time error, as the compound delimiter <>, named box, is not valid in an expression used in assignment.
Based on How gnatmake Works, a-convec.adb would only be recompiled if it were modified after the corresponding .ali file.
Going forward, you might
Check the modification dates of a-convec.adb and a-convec.ali, found in the adainclude and adalib directories, respectively.
Reinstall the compiler.
Notify upstream maintainers if warranted.

Error instantiating generic procedure

Hello i m creating generic procedure which will swap 2 numbers below is my code please help me to fix it.. i am new ada programming please skip if any typo mistake because i m posting this questn frm mobile i dnt have net on my system
swap.ads
generic
type t is private;
procedure swap(l,r:in out t);
swap.adb
procedure swap(l,r:in out t) is
temp:t:=l;
begin
l:=r;
r:=temp;
end swap;
swap_main.adb
v with swap;
procedure swap_main is
procedure swap_i is new swap(t);
i1,i2:interger;
begin
swap_i(i1,i2):
end swap_main;
Leaving aside the simple typos (v with swap, interger, and the last colon): the thing about instantiating a generic is that you have to supply actuals for the formals.
In this case, you say (after adjusting case and spacing to the generally-accepted norm)
generic
type T is private;
procedure Swap (L, R : in out T);
in which T is the formal parameter, which expects assignment and the equality operator ”=“ to be available in the actual.
But in your instantiation you say
procedure Swap_I is new Swap (T);
and the compiler says
rahul.ada:12:34: "T" is undefined
rahul.ada:12:34: instantiation abandoned
rahul.ada:15:04: "Swap_I" is undefined
rahul.ada:15:04: possible misspelling of "Swap_"
gnatmake: "swap_main.adb" compilation error
The second message explains the third. The fourth message is a failed attempt by the compiler to be helpful (Swap_ isn’t a legal identifier, after all).
The first message is the key: there is no type T visible to Swap_Main that is satisfactory as an actual for Swap’s formal parameter T.
I think on the whole that you should have written
procedure Swap_I is new Swap (Integer);
to give you a procedure capable of swapping integers.
“Named association” (Ada 95 Quality and Style Guide, section 5.2.2) would make your intention clearer:
procedure Swap_I is new Swap (T => Integer);

Inconsistent argument passing mode

Consider the following code (which compile with GCC 4.7.4):
procedure Main is
procedure Sub_Proc(N : in out Integer) is
M : Integer;
begin
M := N;
end;
procedure Proc(N : out Integer) is
begin
Sub_Proc(N);
end;
N : Integer;
begin
Proc(N);
end Main;
The procedure Proc is supposed to ensure that the argument N which is an out argument will never be read inside his body. But it passes this argument to a procedure Sub_Proc which takes an in out argument, so potentially the previous argument will be read inside this procedure whereas the calling procedure ensured the opposite.
Is it a GCC bug or an Ada standard specificity ?
You’ll have received a warning on the Sub_Proc(N); call: "N" may be referenced before it has a value. So the compiler was trying to help!
In Ada 83, your program would have been illegal: 6.4.1(3) says "for the mode in out, the variable must not be a formal parameter of mode out”. Indeed, using -gnat83, and after a minor rearrangement of the code to allow it to compile, the equivalent to the above warning is the error (Ada 83) illegal reading of out parameter.
In Ada 95 and Ada 2012 it is OK to read the value of an out parameter after it has been assigned; in ARM95 6.4.1(15) we find that the value starts out uninitialized (as indicated by the warning message noted above), so using it is a Bad Idea.
So the answer is, GNAT’s behaviour conforms with the standard.

Resources