-
Notifications
You must be signed in to change notification settings - Fork 138
/
ncidef2pir.pl
executable file
·239 lines (155 loc) · 4.45 KB
/
ncidef2pir.pl
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#! perl
# Copyright (C) 2003-2011, Parrot Foundation.
=head1 NAME
tools/dev/ncidef2pir.pl - Turn an NCI library definition file into PIR
=head1 SYNOPSIS
perl tools/dev/ncidef2pir.pl path/to/from_file [ path/to/to_file ]
=head1 DESCRIPTION
This program takes an NCI library definition file and creates a PIR file
which loads the described library.
An NCI library definition file provides the information needed to
generate a parrot wrapper for the named library (or libraries). Its
format is simple, and looks like:
[package]
ncurses
[lib]
libform.so
[defs]
p new_field i i i i i i
[lib]
libncurses.so
[defs]
i is_term_resized i i
Note that the assembly file is generated in the order you specify, so
if there are library dependencies, make sure you have them in the
correct order.
=head2 package
Declares the package that all subsequent sub PMCs will be put
into. Double colon is used to to delimit namespaces.
=head2 lib
The name of the library to be loaded. Should be as qualified as
necessary for your platform--generally the full filename is required,
though the directory generally isn't.
You may load multiple libraries here, but only the last one loaded
will be exposed to subsequent defs.
=head2 defs
This section holds the definitions of functions. Each function is
assumed to be in the immediate preceding library. The definition of
the function is:
return_type name [param [param [param ...]]]
The param and return_type parameters use the NCI standard, which for
reference is:
=over 4
=item p
Parameter is a void pointer, taken from the PMC's data pointer. PMC is
assumed to be an unmanagedstruct or child class.
Taken from a P register
=item c
Parameter is a character.
Taken from an I register
=item s
Parameter is a short
Taken from an I register
=item i
Parameter is an int
Taken from an I register
=item l
Parameter is a long
Taken from an I register
=item f
Parameter is a float
Taken from an N register.
=item d
Parameter is a double.
Taken from an N register.
=item t
Parameter is a char *, presumably a C string
Taken from an S register
=item v
Void. Only valid as a return type, noting that the function returns no data.
=item I
Interpreter pointer. The current interpreter pointer is passed in
=item P
PMC.
=item 2
Pointer to short.
Taken from an I register.
=item 3
Pointer to int.
Taken from an I register
=item 4
Pointer to long
Taken from an I register
=back
=cut
use strict;
use warnings;
my ( $from_file, $to_file ) = @ARGV;
# If there is no destination file, strip off the extension of the
# source file and add a .pasm to it
if ( !defined $to_file ) {
$to_file = $from_file;
$to_file =~ s/\.[^.]*$//;
$to_file .= ".pir";
}
open my $INPUT, '<', "$from_file" or die "Can't open up $from_file, error $!";
open my $OUTPUT, '>', "$to_file" or die "Can't open up $to_file, error $!";
# Have the library initialized on load
print $OUTPUT <<EOR;
.sub '' :anon :load
.local pmc lib, nci
EOR
my @libs;
my ( $cur_package, $line, $cur_section );
# Our dispatch table
my (%dispatch) = (
package => \&package_line,
lib => \&lib_line,
defs => \&def_line,
);
while ( $line = <$INPUT> ) {
# Throw away trailing newlines, comments, and whitespace. If the
# line's empty, then off to the next line
chomp $line;
$line =~ s/#.*//;
$line =~ s/\s*$//;
next unless $line;
# Is it a section line? If so, extract the section and set it.
if ( $line =~ /\[(\w+)\]/ ) {
$cur_section = $1;
next;
}
# Everything else goes to the handler
$dispatch{$cur_section}->($line);
}
# Put the registers back and end
print $OUTPUT ".end\n";
close $OUTPUT;
sub package_line {
my $line = shift;
# Trim leading and trailing spaces
$line =~ s/^\s*//;
$line =~ s/\s*$//;
# Set the global current package
$cur_package = [ split /::/, $line ];
}
sub lib_line {
my $line = shift;
print $OUTPUT " loadlib lib, '$line'\n";
}
sub def_line {
my $line = shift;
my ( $return_type, $name, @params ) = split ' ', $line;
unshift @params, $return_type;
my $signature = join( "", @params );
print $OUTPUT " dlfunc nci, lib, '$name', '$signature'\n";
print $OUTPUT " set_global " .
"[" . (join ";", (map {"'$_'"} @$cur_package)) . "]" .
", '${name}', nci\n";
}
# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4: