blob: 7c2b0f3c35c40ad5233b1de102a4b9979e212361 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001#!/usr/bin/env perl
2
3#
4#//===----------------------------------------------------------------------===//
5#//
6#// The LLVM Compiler Infrastructure
7#//
8#// This file is dual licensed under the MIT and the University of Illinois Open
9#// Source Licenses. See LICENSE.txt for details.
10#//
11#//===----------------------------------------------------------------------===//
12#
13
14# Some pragmas.
15use strict; # Restrict unsafe constructs.
16use warnings; # Enable all warnings.
17
18use FindBin;
19use lib "$FindBin::Bin/lib";
20
21use tools;
22
23our $VERSION = "0.004";
24
25#
26# Subroutines.
27#
28
29sub parse_input($\%) {
30
31 my ( $input, $defs ) = @_;
32 my @bulk = read_file( $input );
33 my %entries;
34 my %ordinals;
35 my @dirs;
36 my $value = 1;
37
38 my $error =
39 sub {
40 my ( $msg, $l, $line ) = @_;
41 runtime_error(
42 "Error parsing file \"$input\" line $l:\n" .
43 " $line" .
44 ( $msg ? $msg . "\n" : () )
45 );
46 }; # sub
47
48 my $n = 0; # Line number.
49 foreach my $line ( @bulk ) {
50 ++ $n;
51 if ( 0 ) {
52 } elsif ( $line =~ m{^\s*(?:#|\n)} ) {
53 # Empty line or comment. Skip it.
54 } elsif ( $line =~ m{^\s*%} ) {
55 # A directive.
56 if ( 0 ) {
57 } elsif ( $line =~ m{^\s*%\s*if(n)?def\s+([A-Za-z0-9_]+)\s*(?:#|\n)} ) {
58 my ( $negation, $name ) = ( $1, $2 );
59 my $dir = { n => $n, line => $line, name => $name, value => $value };
60 push( @dirs, $dir );
61 $value = ( $value and ( $negation xor $defs->{ $name } ) );
62 } elsif ( $line =~ m{^\s*%\s*endif\s*(?:#|\n)} ) {
63 if ( not @dirs ) {
64 $error->( "Orphan %endif directive.", $n, $line );
65 }; # if
66 my $dir = pop( @dirs );
67 $value = $dir->{ value };
68 } else {
69 $error->( "Bad directive.", $n, $line );
70 }; # if
71 } elsif ( $line =~ m{^\s*(-)?\s*([A-Za-z0-9_]+)(?:\s+(\d+|DATA))?\s*(?:#|\n)} ) {
72 my ( $obsolete, $entry, $ordinal ) = ( $1, $2, $3 );
73 if ( $value ) {
74 if ( exists( $entries{ $entry } ) ) {
75 $error->( "Entry \"$entry\" has already been specified.", $n, $line );
76 }; # if
77 $entries{ $entry } = { ordinal => $ordinal, obsolete => defined( $obsolete ) };
78 if ( defined( $ordinal ) and $ordinal ne "DATA" ) {
79 if ( $ordinal >= 1000 and $entry =~ m{\A[ok]mp_} ) {
80 $error->( "Ordinal of user-callable entry must be < 1000", $n, $line );
81 }; # if
82 if ( $ordinal >= 1000 and $ordinal < 2000 ) {
83 $error->( "Ordinals between 1000 and 1999 are reserved.", $n, $line );
84 }; # if
85 if ( exists( $ordinals{ $ordinal } ) ) {
86 $error->( "Ordinal $ordinal has already been used.", $n, $line );
87 }; # if
88 $ordinals{ $ordinal } = $entry;
89 }; # if
90 }; # if
91 } else {
92 $error->( "", $n, $line );
93 }; # if
94 }; # foreach
95
96 if ( @dirs ) {
97 my $dir = pop( @dirs );
98 $error->( "Unterminated %if direcive.", $dir->{ n }, $dir->{ line } );
99 }; # while
100
101 return %entries;
102
103}; # sub parse_input
104
105sub process(\%) {
106
107 my ( $entries ) = @_;
108
109 foreach my $entry ( keys( %$entries ) ) {
110 if ( not $entries->{ $entry }->{ obsolete } ) {
111 my $ordinal = $entries->{ $entry }->{ ordinal };
112 if ( $entry =~ m{\A[ok]mp_} ) {
113 if ( not defined( $ordinal ) or $ordinal eq "DATA" ) {
114 runtime_error(
115 "Bad entry \"$entry\": ordinal number is not specified."
116 );
117 }; # if
118 $entries->{ uc( $entry ) } = { ordinal => 1000 + $ordinal };
119 }; # if
120 }; # if
121 }; # foreach
122
123 return %$entries;
124
125}; # sub process
126
127sub generate_output(\%$) {
128
129 my ( $entries, $output ) = @_;
130 my $bulk;
131
132 $bulk = "EXPORTS\n";
133 foreach my $entry ( sort( keys( %$entries ) ) ) {
134 if ( not $entries->{ $entry }->{ obsolete } ) {
135 $bulk .= sprintf( " %-40s ", $entry );
136 my $ordinal = $entries->{ $entry }->{ ordinal };
137 if ( defined( $ordinal ) ) {
138 if ( $ordinal eq "DATA" ) {
139 $bulk .= "DATA";
140 } else {
141 $bulk .= "\@" . $ordinal;
142 }; # if
143 }; # if
144 $bulk .= "\n";
145 }; # if
146 }; # foreach
147 if ( defined( $output ) ) {
148 write_file( $output, \$bulk );
149 } else {
150 print( $bulk );
151 }; # if
152
153}; # sub generate_ouput
154
155#
156# Parse command line.
157#
158
159my $input; # The name of input file.
160my $output; # The name of output file.
161my %defs;
162
163get_options(
164 "output=s" => \$output,
165 "D|define=s" =>
166 sub {
167 my ( $opt_name, $opt_value ) = @_;
168 my ( $def_name, $def_value );
169 if ( $opt_value =~ m{\A(.*?)=(.*)\z} ) {
170 ( $def_name, $def_value ) = ( $1, $2 );
171 } else {
172 ( $def_name, $def_value ) = ( $opt_value, 1 );
173 }; # if
174 $defs{ $def_name } = $def_value;
175 },
176);
177
178if ( @ARGV == 0 ) {
179 cmdline_error( "Not enough arguments." );
180}; # if
181if ( @ARGV > 1 ) {
182 cmdline_error( "Too many arguments." );
183}; # if
184$input = shift( @ARGV );
185
186#
187# Work.
188#
189
190my %data = parse_input( $input, %defs );
191%data = process( %data );
192generate_output( %data, $output );
193exit( 0 );
194
195__END__
196
197#
198# Embedded documentation.
199#
200
201=pod
202
203=head1 NAME
204
205B<generate-def.pl> -- Generate def file for OpenMP RTL.
206
207=head1 SYNOPSIS
208
209B<generate-def.pl> I<OPTION>... I<file>
210
211=head1 OPTIONS
212
213=over
214
215=item B<--define=>I<name>[=I<value>]
216
217=item B<-D> I<name>[=I<value>]
218
Alp Toker8f2d3f02014-02-24 10:40:15 +0000219Define specified name. If I<value> is omitted, I<name> is defined to 1. If I<value> is 0 or empty,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000220name is B<not> defined.
221
222=item B<--output=>I<file>
223
224=item B<-o> I<file>
225
226Specify output file name. If option is not present, result is printed to stdout.
227
228=item B<--doc>
229
230=item B<--manual>
231
232Print full help message and exit.
233
234=item B<--help>
235
236Print short help message and exit.
237
238=item B<--usage>
239
240Print very short usage message and exit.
241
242=item B<--verbose>
243
244Do print informational messages.
245
246=item B<--version>
247
248Print version and exit.
249
250=item B<--quiet>
251
252Work quiet, do not print informational messages.
253
254=back
255
256=head1 ARGUMENTS
257
258=over
259
260=item I<file>
261
262A name of input file.
263
264=back
265
266=head1 DESCRIPTION
267
268The script reads input file, process conditional directives, checks content for consistency, and
269generates ouptput file suitable for linker.
270
271=head2 Input File Format
272
273=over
274
275=item Comments
276
277 # It's a comment.
278
279Comments start with C<#> symbol and continue to the end of line.
280
281=item Conditional Directives
282
283 %ifdef name
284 %ifndef name
285 %endif
286
Alp Toker8f2d3f02014-02-24 10:40:15 +0000287A part of file surrounded by C<%ifdef I<name>> and C<%endif> directives is a conditional part -- it
Jim Cownie5e8470a2013-09-27 10:38:44 +0000288has effect only if I<name> is defined in the comman line by B<--define> option. C<%ifndef> is a
289negated version of C<%ifdef> -- conditional part has an effect only if I<name> is B<not> defined.
290
291Conditional parts may be nested.
292
293=item Export Definitions
294
295 symbol
296 symbol ordinal
297 symbol DATA
298
299Symbols starting with C<omp_> or C<kmp_> must have ordinal specified. They are subjects for special
300processing: each symbol generates two output lines: original one and upper case version. The ordinal
301number of the second is original ordinal increased by 1000.
302
303=item Obsolete Symbols
304
305 - symbol
306 - symbol ordinal
307 - symbol DATA
308
309Obsolete symbols look like export definitions prefixed with minus sign. Obsolete symbols do not
310affect the output, but obsolete symbols and their ordinals cannot be (re)used in export definitions.
311
312=back
313
314=head1 EXAMPLES
315
316 $ generate-def.pl -D stub -D USE_TCHECK=0 -o libguide.def dllexport
317
318=cut
319
320# end of file #
321