Adasubst is a tool for making semantic substitutions. This means that it does not replace text, but Ada elements (identifiers) in an Ada program by other identifiers. This substitution can therefore account for visibility rules, to make sure that only the intended element is replaced. But Adasubst goes far beyond that: it takes all Ada rules into consideration. Therefore, if you substitute a name defined in a generic, the same substitution will be applied for all instantiations (unless there is an explicit substitution for the instantiated element, of course). Similarly, if you substitute the name of a primitive operation of a type, the same substitution will be applied to the corresponding operation of all derived types (see Known Bugs for a limitation on this however).
Adasubst can also perform other kinds of semantic substitution; for the moment, it can also remove all representation clauses from a program. Other forms of substitutions may be added in the future; we are looking forward to user suggestions about what could be useful.
Adasubst can be used for a variety of usages. See Adasubst in practice to give you an idea about what it can do for you. It has already been used in an industrial context, and has processed succesfully many thousands of lines. It is another example of the nice things that can be made using ASIS.
Please send bug reports, remarks, notes, good ideas, improvements to the documentation, etc. to J-P. Rosen .
This software is © Adalog, 2002-2004. Adasubst is free software; you can redistribute it and/or modify it under terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This unit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License distributed with this program; see file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate generics from the units of this program, or if you link units provided with this program with other files to produce an executable, these units do not by themselves cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Public License.
This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
If for any reason your local lawyer expresses some concern about the terms of this license, please get in touch with us. Our intent is to allow anybody to do whatever they please with this code, and we'll be happy to clarify things if necessary.
This program is offered to the community with this very liberal license as a demonstration of Adalog's know-how; please do not remove the reference to Adalog in the header comment of each unit.
This version uses ASIS-for-GNAT. As a consequence, you must have GNAT installed before you install Adasubst. If you are using another compiler that provides an ASIS interface, you may recompile Adasubst with this compiler. GNAT will not be necessary any more (but your compiler will, of course). See Adasubst and ASIS.
If you downloaded an executable distribution of Adasubst, please note that it has been compiled with GNAT 3.15p, and will not work with any other version of GNAT. If you have an older version of GNAT, either upgrade your GNAT to 3.15p (recommended!), or recompile Adasubst from the source distribution.
If you downloaded the source version of Adasubst, you must make sure that ASIS is installed on your system, then simply gnatmake the file adasubst.adb, including appropriate options to access the ASIS library.
Adasubst needs no setup, no special rights. Simply copy the executable where you please.
This version has been tested under Windows9X/XP and Unix (SuSELinux 7.0 and above, Mandrake).
Files list
File | Description | Note |
adasubst-guide.htm | This file. | |
COPYING | The GNU General Public License file | |
*.ad[bs] | Source files | In the source distribution |
adasubst | Linux executable file | In the Linux executable distribution |
adasubst.exe | Windows executable file | In the Windows executable distribution |
Adasubst reads one or more Ada units, and produces output files obtained by performing a number of substitutions to the text of the corresponding source files. A dictionary file defines the substitutions to be performed. Note that source comments, character literals, character strings, and attribute designators are never substituted.
The dictionary file is a regular text file defining substitutions, one per line. Each line has one of the following formats:(elements between quotes must be typed as is):
<Original> "=>" <substitution> "not" <Original>
<Original> defines what kind of element is to be substituted (the original). Since the original is an Ada element, case is irrelevant, and you can even put spaces where they are allowed by Ada syntax.. Only one substitution is allowed for a given <Original>.
In the first form, <Substitution> describes how you want the Original to be modified. Note that the replacement is always taken "as is", i.e. the replacement uses the same casing as given in the substitution string.
The second form is an indication that the corresponding <Original> is not to be substituted. This is useful to make exceptions to a more general substitution rule. See Substitution with exceptions for examples of this.
In addition, empty lines and lines starting with a "#" character (comment lines) are ignored.
The syntax of the <Original> is as follows:
<Original> ::= <Full_Name> | "all" <Simple_Name>
<Full_Name> is the full name of the element to
be substituted, using normal Ada dot notation (with some
extension, see overloaded names).
Full name means that you give the full expanded name,
starting from a compilation unit. This name must be the actual
full name, i.e. it must not include any renaming. For example,
the usual Put_Line
must be given as Ada.Text_IO.Put_Line
,
not as Text_IO.Put_Line
. Predefined
elements (Integer
, Constraint_Error
)
must be given in the form Standard.Integer
or Standard.Constraint_Error
,
since they are logically declared in the package Standard.
<Simple_Name> is a single identifier, possibly followed by overloading information, see overloaded names. No qualification is allowed.
The first form designates a single element from an Ada program, and is therefore called "element substitution". Only this element will be substituted, i.e. if you want to replace the variable "V" declared in package "P", the original should be "P.V" , and no other "V" in the program will be substituted. The second form designates all identifiers with the given name in the program, irrespectively of where they appears, i.e. if you use the form "all V", all elements namesd "V" will be substituted. This form is called "identifier substitution".
In Ada, names can be overloaded. This means that you can have several procedures "P" in package "Pack", if they differ by the types of the parameters. If you just give the name "Pack.P" as the original, the corresponding substitution will be applied to all elements named "P" from package "Pack". If you want to distinguish between overloaded names, you can specify a profile after the element's name. A profile has the syntax:
"{" [ ["access"] <type-name> { ";" ["access"] <type-name> } ] ["return" <type-name>] "}"
You must specify the type name, even if the original declaration uses a subtype of the type; this is because Ada uses types for overloading resolution, not subtypes. Anonymous access parameters are specified by putting "access" in front of the type name. An overloaded name for a procedure without parameters uses just a pair of empty brackets. If the subprogram is a function, you must provide the "return <type-name>" part for the return type of the function. The types must also be given as a unique name, i.e. including the full path: if the type is "T" declared in package "Pack", you must specify it as "Pack.T". As a convenience, the "Standard." is optional for predefined types, so you can write "Standard.Integer" as "Integer". There is no ambiguity, since a type is always declared within some construct.
Overloaded names can be also be used with the "all <Simple_Name> form of the original. In this case, the substitution will be applied to all names that are subprograms with the given identifier and matching the given profile, irrespectively of where they appear.
Note that if you use an overloaded name, all names that are part of the original, including those of the profile, must use the overloaded syntax. For example, given the following program
procedure P is procedure Q (I : Integer) is ... end Q; procedure Q (F : Float) is ... end Q; begin ... end P;
If you want to distinguish between the two procedures "Q", you must specify them as "P{}.Q{Integer}" and "P{}.Q{Float}" (note the "P{}" which specifies an overloaded name for a procedure P without parameters).
Following normal Ada rules, an enumeration literal is considered a parameterless function. If you want to distinguish between overloaded enumeration literals, you can use overloaded names for them. For example, given:
package Pack is type T1 is (A, B); type T2 is (B, C); end Pack;
you can change the first "B" into "B_T1" and the second "B" into "B_T2" with the following dictionnary:
Pack.B{return Pack.T1} => B_T1 Pack.B{return Pack.T2} => B_T2
There is a special case for elements that are defined (directly or indirectly) within unnamed loops or block statements. Everything happens as if the unnamed construct was named "_anonymous_". So if you have the following program:
procedure P is begin for I in 1..10 loop declare J : Integer; begin ... end; end loop; end P;
You can refer to "I" as "P._anonymous_.I", and to "J" as "P._anonymous_._anonymous_.J".
You can substitute the name of a record or protected type component (a "field" name), but to identify it uniquely, you must precede its name in the dictionary by the name of the type. This is a small extension to Ada syntax, but it is the simplest and most natural way to deal with this case. For example, given:
procedure P is type T is record Bad_Name : Integer; end record; ...
you can replace every occurrence of "Bad_Name" by "Good_Name" with the following line in the dictionary:
P.T.Bad_Name => Good_Name
Adasubst handles operators (i.e. functions like "+") correctly. Of course, you must specify such operations using normal Ada syntax: if you define the integer type "T" in package "Pack", an overloaded name for the addition would be "Pack."+"{Pack.T; Pack.T return Pack.T}".
There is no problem in changing a regular function name into an operator, but the substitution will continue to use the prefixed call notation. If you do the opposite, i.e. changing an operator into a regular function, Adasubst will automatically transform any infixed call into a prefixed call. In short, if your dictionary says:
Plus => "+" "-" => Minus
the following sequence:
X := Plus (X, Y); X := X - Y; X := "-" (X, Y);
will become:
X := "+" (X, Y); X := Minus (X, Y); X := Minus (X, Y);
Note finally that "and then", "or else", "in" and "not in" are not operators (although they are operations) and cannot therefore be substituted. Similarly, operators between universal types have specifications that cannot be expressed in Ada, and therefore cannot be substituted.
The substitution can take one of the following forms:
["abs"] <Name> [<Name>] "in" <Package_Name> <Name> { [","] <Name> }
<Name> is the new name(s) of the entity, <Package_Name> is the place where it is now (if it has been moved). The idea is that the substitution describes how the element has been changed. If you simply changed the name of an entity, just give the new name. If you moved an entity into another package, just give "in" followed by the new package name. Of course, if you moved an entity and renamed it, you can give both.
If the substitution starts with an "abs", the element is replaced exactly by the <Name> (we call this an absolute substitution). Note that the element is replaced, irrespectively of how it was originally named (i.e. using a short name or a qualified name). This allows you to change short names into long names, i.e. if the element is "Pack.V" and the substitution is "abs Pack.V", then every occurrence of the former (even in short notation) will be changed into the full notation.
As a special case, you may provide several substitions for an element in the dictionary, separated by spaces or a comma (the third form). Such substitutions are always absolute. This is intended for the case when one element has been replaced by several ones, typically when a package has been split into several packages. For the purpose of the explanation, assume that package Pack has been split into Pack1 and Pack2. The dictionary will contain a line like "Pack => Pack1, Pack2". Normally, you should specify explicitely in the dictionary where each element of Pack has been moved (see Using Adasubst in preparation mode below for a mode that helps you do that). When Adasubst encounters a reference to Pack for which there is no explicit substitution, two things can happen:
For example, given a dictionary file containing the following lines:
Pack => Parent, Parent.Child Pack.X => New_X in Parent.Child Pack.V => abs Variable Pack.Z => Child.Z in Parent
Here is how the substitutions will happen:
Original | Substituted |
with Pack; procedure Example is A : Integer := Pack.X B : Integer := Pack.Y; use Pack; begin A := X + Y + V; B := Pack.V; B := Pack.Z + Z end Example; |
with Parent, Parent.Child; procedure Example is A : Integer := Parent.Child.New_X B : Integer := Parent? Parent.Child.Y; use Parent, Parent.Child; begin A := New_X + Y + Variable; B := Variable; B := Parent.Child.Z + Child.Z; end Example; |
Notes:
It may happen that several substitutions are possible for a given element. In this case, the rule is to use the most specific interpretation. This means that substitutions are considered in the following order:
The exact rule for substitution is that if an element has a substitution, then that substitution is applied; otherwise, if the element's name was given using a qualified notation, a substitution is attempted on the prefix (i.e. everything before the last dot), using this same rule.
For example, you may specify to replace "Pack" with "My_Package", and "Pack.X" with "Other_Package.X". In this case, the most specific substitution is applied (the later), but if you have a "Pack.Y" (no specific substitution specified), it will be replaced by "My_Package.Y".
In the design of Adasubst, we chose the most rigorous approach, hence the choice of ASIS. This means that we do not believe that Adasubst would generate a code that compiles and is wrong (provided the dictionary is correct, of course). If in doubt, it will produce code that does not compile, so you can fix it manually.
However, using ASIS has its drawback: the code must be compilable, and running Adasubst on it can take as long as it would need to fully compile it. Since Adasubst is used normally only once on any source file, it seems a sensible compromise.
In normal mode, adasubst is started by a command line of the form:
adasubst [-T] [-bcdhrsw] <dictionary-file> | <substitution> [-oO <output-prefix>] [-p <project-file>] [-l <line-length>] <unit-name>{+|-<unit-name>} | @<list-file> [-- <ASIS-options>]
Options:
As usual, options can be grouped or provided separately (i.e. "-b -s" is the same as "-bs"). Options can appear at any place on the command line.
-b | process body of unit |
-c | leave substituted lines as comments in output file |
-d | debug |
-h | help. Print usage message and exit |
-l | limits output line length to the given value. See below. |
-o | specify a prefix for output files. See below. |
-O | same as -o, but keep output files that have no changes. |
-p | use source directory indications from provided project file. See below. |
-r | recursive. Process the unit and (recursively) all user units it depends on (including parent units if the unit is a child or a subunit). Predefined Ada units and units belonging to the compiler's run-time library are never processed. |
-s | process specification of unit |
-w | overwrite output file if already existing |
The -T option means "translate", but it's the default mode for Adasubst and is therefore optional.
If the -h option is given, adasubst just prints a brief usage summary and exits. If neither -s or -b is given, -sb is assumed (i.e. both the specification and body are processed). The -d option adds extra messages for debugging purposes; there is no reason to use it, unles you encounter a bug in Adasubst.
<dictionary-file> is the name of the file to be used as the dictionary. If it is given as the single character "-", the dictionary is read from the standard input. Alternatively, you can give one substitution as a quoted string instead of a dictionary file; this avoids having to write a dictionary file for simple substitutions. For example:
adasubst "pack.x => A_Better_Name" My_Package
<unit-name> is the name of the Ada unit to translate; note that it is a unit name, not a file name: case is not significant, and there should be no extension! Of course, child units and subunits are allowed following normal Ada naming rules: "Parent.Child". Note that when a unit is processed, all its subunits are processed at the same time. Alternatively, you can give an "@" followed by the name of a file instead of a unit name. This file should contain a list of unit names, one on each line. All units whose names are given in the file will be processed. If a name in the file starts with "@", it will also be treated as an indirect file (i.e. the same process will be invoked recursively).
If no "-o <output-prefix>" option is given, the result of the substitutions is simply written to the standard output. This is useful to debug your dictionary, or if you want to have all the output in a single file. With Gnat, this file could be gnatchopped to rebuild the correct source file names. Otherwise, adasubst will output the result of processing each unit to a file whose name is obtained by prefixing the <output-prefix> to the original name of the corresponding source file. The <output-prefix> can be any string, and is not analyzed by adasubst. A prefix like "result/" will result in all the output going to the directory "result", with the same name as the original. Alternatively, a prefix like "new-" will result in all output files being in the same directory, with a "new-" prepended to the name. Adasubst will refuse to overwrite an existing file on output, unless the "-w" option is given. If no substitution were performed on a unit, the output file is not kept, unless you specified the <output-prefix> with the "-O" (capital O) option.
It may happen that a modified line is longer than the original, and therefore exceeds the maximum line length accepted by the compiler. The "-l" option sets an upper bound to the length of the output lines. If a line becomes longer than that, it is folded at an appropriate point. By convention, if the given <line-length> is zero (or if the "-l" option appears without a value), it means that lines should never be folded. If no "-l" option is given, the maximum line length is 200 (the minimum required by the Ada standard). A line length less than 80 is not accepted.
If the "-c" option is given, every changed line is kept in the output file, as a comment line starting with "--CHANGED: ". This makes it handy to retrieve changed lines with an editor, and to check the substitutions.
Everything that appears after "--" will be treated as an ASIS option, as described in the ASIS user manual. Normally, you don't have to care about this, except for the issue discussed below.
If the units that you are processing reference other units whose source is not in the same directory, Adasubst needs to know how to access these units (as GNAT would). You can do this in two ways (not exclusive):
Under control of special options, Adasubst helps you prepare the dictionary or list files.
This mode is intended to help you prepare the dictionary file when you want to split elements exported by a package into several other packages. This happens quite often when you start writing a package, then later decide to split it into child units.
adasubst -P [-bdrsw] [-o <output-file>] <unit-name>{+|-<unit-name>} | @<list-file> [-- <ASIS-options>]
Options are the same as in normal mode, except "-c" and "-l" which would mean nothing and are not accepted. The "-o <output-file>" option specifies the name of the file to which output is to be written (standard output if there is no "-o" option). Note that if an <output-file> is specified that already exists, new data is appended to it, unless the "-w" option is given (in which case it is overridden).
Adasubst will analyze the visible part (not the private part) of the units given by <unit-specification> (or the names of packages given in <list-file>, possibly recursively if a "-r" option is given), and produce a dictionary consisting of the full (overloaded) name of all elements declared within the visible parts of (generic) package units (others are ignored), followed by the simple identifier of the same element. Of course, if the visible part includes package, task or protected declarations, only their visible parts will be processed. In short, given the package:
package Pack is type T is range 0..100; E : exception; V : T; function F (X : Integer) return Float; task A_Task is entry Visible; private entry Not_Visible; end A_Task; private Hidden : Integer; end Pack;
Adasubst will produce a file containing:
# # Elements declared in package PACK # Pack.T => T Pack.E => E Pack.V => V Pack.F{Standard.Integer return Standard.Float} => F Pack.F{Standard.Integer return Standard.Float}.X => X Pack.A_Task => A_Task Pack.A_Task.Visible{} => Visible
Assuming that you have moved elements declared in Pack to other packages, all you have to do is take your favorite text editor and add after each identifier from the second column an "in" plus the name of the package where it is now. You can then use this dictionary to update all units that depended on Pack.
Note that the generated dictionary is a "no-op", i.e. each element is substituted by itself. Adasubst recognizes no-ops, so that lines that contain identical substitutions are not considered modifications (no "--CHANGED:" line is generated if you put the "-c" option). Therefore, if you just want to change some names of elements declared in a package, you can use the -P option to generate the dictionary, then modify only the lines for the identifiers you want to change. You can then run Adasubst in normal mode on the package itself as well as on any unit that uses the package to perform the substitutions.
Note also that if the original element does not use the same casing as the substitution, substitution does occur. This means that the "raw" dictionary can be used to change the casing of all identifiers to the one of the original declaration in the package specification.
This mode is intended to help you prepare the list of files you want to process by finding all the dependents of a set of units.
adasubst -D [-bdrsw] [<-o output-file>] <unit-name>{+|-<unit-name>} | @<list-file> [-- <ASIS-options>]
Options are the same as in normal mode, except "-c" and "-l" which would mean nothing and are not accepted. The "-r" option is assumed by default; it is accepted on the command line, but has no effect. The "-o <output-file>" option specifies the name of the file to which output is to be written (standard output if no "-o" option is given). Note that if an <output-file> is specified that already exists, new data is appended to it, unless the -w option is given (in which case it is overridden).
Adasubst will scan all units given by <unit-name> (or the names of packages given in <list-file>), and produce a list of the unit names, and (transitively) all units that are withed by these units, except predefined units. Especially, if you give it the name of your main program, this will build the list of all units that make up the program.
In addition, a special mode of Adasubst allows you to remove (or comment out) all representation clauses from a set of units. This can be useful if you want to assess the impact of representation clauses on your program, especially efficiency. Thanks to Adasubst, you can easily compare two versions of your program, with or without representation clauses.
adasubst -R [-bdrsw] [<-o output-file>] <unit-name>{+|-<unit-name>} | @<list-file> [-- <ASIS-options>]
Options are the same as in normal mode.
Adasubst will operate like in normal mode, except that instead of translating identifiers (there is no dictionary), the output files will have all representation clauses removed (or commented out if the "-c" option is given)..
Adasubst can be used for a number of purposes. The logic behind the format of the dictionary is:
Here are some typical usages.
You simply want to change every occurrence of an identifier, irrespectively of where it appears. For example, you misspelled an identifer. Just make a dictionary like this :
Wrong_Spelling => Right_Spelling
and run Adasubst on your program.
If you don't want to create a dictionary file, you can also use the following command:
echo Wrong_Spelling => Right_Spelling | adasubst - main_program -r
Note that here, we run Adasubst on the main program with the "-r" option to make sure that every occurrence of "Wrong_Spelling" in the whole program is replaced by "Right_Spelling". You can also avoid the "echo" command, and just type the dictionary line on the keyboard, don't forget to input the end-of-file in that case.
The following case illustrates another use of absolute substitutions. Imagine you had the following package, from an Ada83 project:
package Missing_Ada83_Functions is function Min (L, R : Integer) return Integer; function Max (L, R : Integer) return Integer; -- etc. end Missing_Ada83_Functions;
Now, you'd rather use the Ada95 'Min and 'Max attributes. Make a dictionary like this:
Missing_Ada83_Functions.Min => abs Integer'Min Missing_Ada83_Functions.Min.L => Left Missing_Ada83_Functions.Min.R => Right Missing_Ada83_Functions.Max => abs Integer'Max Missing_Ada83_Functions.Max.L => Left Missing_Ada83_Functions.Max.R => Right
Note the use of "abs". Therefore, even if the original was written as "Missing_Ada83_Functions.Min", it will be replaced by "Integer'Min", not "Missing_Ada83_Functions.Integer'Min". Note also the translation for the formal parameter names, to ensure correct translation of calls using named notation.
As another example, suppose you defined several "Put" operations for types defined in various packages, but someone decides that they should rather be called "Print". Of course, the substitution should not be applied to the "Put" defined in Ada.Text_IO. The following dictionary will do the trick:
all Put => Print not Ada.Text_IO.Put
Overloaded names can be used with all forms of substitution. If you decide in addition that all "Put" on type My_Int should be called "Print_Int" and that all "Put" on type My_Float should stay the same, the dictionary would become (assuming that the types are defined in package "My_Data"):
all Put => Print not Ada.Text_IO.Put all Put {My_Data.My_Int} => Print_Int not all Put {My_Data.My_Float}
Here you have a big package (possibly from an old Ada83 project) and you want to take advantage of the hierarchical units feature of Ada95 to split it into several child units.
package Old is Ident1 : Integer; Ident2 : Integer; end Old;
Running Adasubst -P on this package will produce:
Old.Ident1 => Ident1 Old.Ident2 => Ident2
If you want to change this package into the following:
package Parent is Good_Variable_Name : Integer; end Parent; package Parent.Child is Another_Good_Name : Integer; end Parent.Child;
change the dictionary to:
Old => Parent, Parent.Child Old.Ident1 => Good_Variable_Name in Parent Old.Ident2 => Another_Good_Name in Parent.Child
The first line expresses that package "Old" has been replaced by "Parent" and "Parent.Child". Any "with" or "use" for "Old" will be replaced with the corresponding clause for both packages. Alternatively, you could use the following dictionary:
Old => Parent Old.Ident1 => Good_Variable_Name in Parent Old.Ident2 => Child.Another_Good_Name in Parent
Here, "Old" would be systematically replaced by "Parent" and any use of "Ident2" would be replaced by "Child.Another_Good_Name", therefore producing also a correct code.
Run Adasubst on all units that used the old package with this dictionary. You can also run Adasubst with the same dictionary on the body of the packages you have modified, all required modifications will be performed automatically.
NB: if you plan to split a package into child units, it is often useful to know which parts of the package are used by various modules. Adadep, another utility provided with Adasubst, can be instrumental for that.
Adasubst has been tested only with ASIS-for-gnat; however, the
only (known) dependency is for the implementation-dependent
parameters used to open an ASIS context. These parameters are
defined as strings in the package Implementation_Options
(file implementation_options.ads
), so all you have
to do if you want to port Adasubst to another implementation is
adjust these definitions. If you ever do so, please keep us
informed by sending a note to rosen@adalog.fr.
It is a consequence of the way ASIS works that tree files (with
a .adt
extension) are created as part of the process.
Currently, these file are not erased by Adasubst after execution.
This speeds up execution if you run Adasubst several times, as is
often the case when you are designing the dictionary file.
However, if you change your source files, the trees are no more
consistent with the sources. Simply remove the adt
files and rerun Adasubst; new tree files will be created.
There are many subtile special cases when analysing Ada code, so it may happen that you find a context that we didn't think about. There are also some cases where the error comes from a bug in ASIS-for-Gnat. Normally, Adasubst will print "!! internal error, continuing" and will try to proceed, without processing the failing element. It will output a " ???? " string in the output file (something that will certainly not compile), for you to check manually if a substitution has been missed. Since such a case is very rare in practice, a bug will not prevent you from using Adasubst. Note however that if you run Adasubst with the "-d" (debug) option, it will halt on the failing element and print the full ASIS context.
If you encounter a bug while using Adasubst , please rerun it with the "-d" option and save the output to a file, then send this file together with the dictionary and the file you are processing to rosen@adalog.fr. We will do our best to fix it. Of course, you are welcome to try and fix it yourself; we made every attempt to make the source of Adasubst quite readable, but be aware that you will need a good understanding of ASIS and Ada syntax to understand how it works.
There is one slow operation in Adasubst, known as "opening the context" in ASIS. This happens only once per run - but happens in every run. This means that if you use a shell script to run Adasubst multiple times, with one file at a time, it will take you quite a while. On the other hand, if you provide a list of files, or provide several files at the same time on the command line, or just provide a main program with the "-r" option, Adasubst will be much faster (some users have reported going from several hours to a couple of minutes!), since the context is opened only once.
Look at your dictionary: they are actually doubly defined. Remember that if you run Adasubst in preparation mode and the output dictionary exists, new elements are appended to it (unless you use the "-w" option). Therefore, if you run by mistake twice the same "adasubst -P" command, all definitions will appear twice in the dictionary.
In the case of cascaded derivations with several substitutions, there is a case where Adasubst does not behave as expected. Consider:
package Pack is type T is ...; procedure Primitive (X : T); type D1 is new T; type D2 is new D1; end Pack;
with the following dictionary:
Pack.Primitive{Pack.T} => T_Primitive Pack.Primitive{Pack.D1} => D1_Primitive
We give different substitutions for "Primitive" on "T" and "D1", but we do not specify the substitution for "D2". Since D2 derives from D1, any occurrence of a call to "Primitive" with a "D2" parameter should be substituted as a "D1_Primitive", however it will be substituted as a "T_Primitive". In other words, the implicit substitution uses the ultimate ancestor, not the direct ancestor. This is due to a bug in Asis-for-Gnat, so there is not much we can do until the bug is fixed.
There is one very special case of a terminating identifier which is not handled properly by Adasubst:
THEN the closing name will not be substituted at all. In short, if you write:
procedure Parent.Child is -- Never a problem here ... end Parent -- Crazy comment . -- and crazy way of writing Child -- an identifier ;
substitution will not occur on the final name. It is unlikely that we fix this bug in any foreseeable future since:
The structure of this programs allows it to be extended very easily. Here is a brief overview of our to-do list:
Send good ideas, bug reports, suggestions of improvements to the program or to the documentation, etc. to rosen@adalog.fr (J-P. Rosen).
If you want commercial support for this product, or need any support or assistance for your Ada projects, please visit our Web site or send us a mail .