1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
-- Programmed by Jedidiah Barber
-- Released into the public domain
-- This is a tool that reads in a file with an exact template
-- and a file with sets of substitution rules with each rule
-- of the form X=Y and with each set of rules separated by
-- one or more blank lines.
-- It then applies each set of rules to a copy of the template
-- and puts the result to standard output.
-- The specific use this tool was written for was to deal with
-- very repetitive codegen such as binding static char get/set.
-- But of course, it can be useful for other things too.
with
Ada.Characters.Latin_1,
Ada.Command_Line,
Ada.Containers.Indefinite_Ordered_Maps,
Ada.Direct_IO,
Ada.Directories,
Ada.Strings.Maps,
Ada.Strings.Unbounded,
Ada.Text_IO;
procedure Template is
package Latin renames Ada.Characters.Latin_1;
package ACom renames Ada.Command_Line;
package ADir renames Ada.Directories;
package SMap renames Ada.Strings.Maps;
package SU renames Ada.Strings.Unbounded;
package TIO renames Ada.Text_IO;
package Char_IO is new Ada.Direct_IO (Character);
My_Template : Char_IO.File_Type;
My_Rule_List : TIO.File_Type;
Element_In : Character;
Template_Input, Copy_Input : SU.Unbounded_String;
Sub_Line : SU.Unbounded_String;
Cut_At : Natural;
package String_Maps is new Ada.Containers.Indefinite_Ordered_Maps
(Key_Type => String,
Element_Type => String);
Rule_Map : String_Maps.Map;
procedure Process
(Text : in out SU.Unbounded_String;
Rules : in String_Maps.Map)
is
Token_At : Natural;
begin
for C in Rules.Iterate loop
Token_At := 1;
while Token_At <= SU.Length (Text) loop
Token_At := SU.Index (Text, String_Maps.Key (C), Token_At);
exit when Token_At = 0;
SU.Replace_Slice
(Text,
Token_At,
Token_At + String_Maps.Key (C)'Length - 1,
String_Maps.Element (C));
Token_At := Token_At + String_Maps.Element (C)'Length;
end loop;
end loop;
end Process;
begin
if ACom.Argument_Count /= 2 then
TIO.Put_Line
(TIO.Standard_Error,
"ERROR: Need an input template file and a substitution list file");
ACom.Set_Exit_Status (ACom.Failure);
return;
end if;
if not ADir.Exists (ACom.Argument (1)) then
TIO.Put_Line
(TIO.Standard_Error,
"ERROR: Input template file does not exist");
ACom.Set_Exit_Status (ACom.Failure);
return;
end if;
if not ADir.Exists (ACom.Argument (2)) then
TIO.Put_Line
(TIO.Standard_Error,
"ERROR: Substitution list file does not exist");
ACom.Set_Exit_Status (ACom.Failure);
return;
end if;
Char_IO.Open (My_Template, Char_IO.In_File, ACom.Argument (1));
while not Char_IO.End_Of_File (My_Template) loop
Char_IO.Read (My_Template, Element_In);
SU.Append (Template_Input, Element_In);
end loop;
Char_IO.Close (My_Template);
TIO.Open (My_Rule_List, TIO.In_File, ACom.Argument (2));
while not TIO.End_Of_File (My_Rule_List) loop
SU.Set_Unbounded_String (Sub_Line, TIO.Get_Line (My_Rule_List));
Cut_At := SU.Index (Sub_Line, SMap.To_Set ('='));
if Cut_At = 0 and SU.Length (Sub_Line) > 0 then
TIO.Put_Line
(TIO.Standard_Error,
"WARNING: Malformed rule """ & SU.To_String (Sub_Line) & """ with no production");
end if;
if Cut_At = 0 and not Rule_Map.Is_Empty then
Copy_Input := Template_Input;
Process (Copy_Input, Rule_Map);
TIO.Put (SU.To_String (Copy_Input));
Rule_Map.Clear;
elsif Cut_At = 1 then
TIO.Put_Line
(TIO.Standard_Error,
"WARNING: Malformed rule """ & SU.To_String (Sub_Line) & """ with null pattern");
elsif Cut_At > 1 then
Rule_Map.Include
(SU.Slice (Sub_Line, 1, Cut_At - 1),
SU.Slice (Sub_Line, Cut_At + 1, SU.Length (Sub_Line)));
end if;
end loop;
if not Rule_Map.Is_Empty then
Process (Template_Input, Rule_Map);
TIO.Put (SU.To_String (Template_Input));
end if;
TIO.Close (My_Rule_List);
end Template;
|