4
# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
6
# This file is part of the KDE project
8
# This library is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU Library General Public
10
# License as published by the Free Software Foundation; either
11
# version 2 of the License, or (at your option) any later version.
13
# This library is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
# Library General Public License for more details.
18
# You should have received a copy of the GNU Library General Public License
19
# aint with this library; see the file COPYING.LIB. If not, write to
20
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
# Boston, MA 02111-1307, USA.
28
use constant MODE_UNDEF => 0; # Default mode.
30
use constant MODE_MODULE => 10; # 'module' section
31
use constant MODE_INTERFACE => 11; # 'interface' section
32
use constant MODE_EXCEPTION => 12; # 'exception' section
33
use constant MODE_ALIAS => 13; # 'alias' section
36
my @temporaryContent = "";
38
my $parseMode = MODE_UNDEF;
39
my $preservedParseMode = MODE_UNDEF;
41
my $beQuiet; # Should not display anything on STDOUT?
42
my $document = 0; # Will hold the resulting 'idlDocument'
53
bless($reference, $object);
57
# Returns the parsed 'idlDocument'
63
my $preprocessor = shift;
66
$preprocessor = "/usr/bin/gcc -E -P -x c++";
73
print " | *** Starting to parse $fileName...\n |\n" unless $beQuiet;
75
open FILE, $preprocessor . " " . join(" ", (map { "-D$_" } split(/ /, $defines))) . " ". $fileName . "|" or die "Could not open $fileName";
76
my @documentContent = <FILE>;
79
my $dataAvailable = 0;
81
# Simple IDL Parser (tm)
82
foreach (@documentContent) {
83
my $newParseMode = $object->DetermineParseMode($_);
85
if ($newParseMode ne MODE_UNDEF) {
86
if ($dataAvailable eq 0) {
87
$dataAvailable = 1; # Start node building...
89
$object->ProcessSection();
93
# Update detected data stream mode...
94
if ($newParseMode ne MODE_UNDEF) {
95
$parseMode = $newParseMode;
98
push(@temporaryContent, $_);
101
# Check if there is anything remaining to parse...
102
if (($parseMode ne MODE_UNDEF) and ($#temporaryContent > 0)) {
103
$object->ProcessSection();
106
print " | *** Finished parsing!\n" unless $beQuiet;
108
$document->fileName($fileName);
116
my $dataNode = shift;
118
print " |- Trying to parse module...\n" unless $beQuiet;
120
my $data = join("", @temporaryContent);
121
$data =~ /$IDLStructure::moduleSelector/;
123
my $moduleName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
124
$dataNode->module($moduleName);
126
print " |----> Module; NAME \"$moduleName\"\n |-\n |\n" unless $beQuiet;
129
sub dumpExtendedAttributes
139
while (($name, $value) = each(%{$attrs})) {
140
push(@temp, "$name=$value");
143
return $padStr . "[" . join(", ", @temp) . "]";
146
sub parseExtendedAttributes
149
$str =~ s/\[\s*(.*)\]/$1/g;
153
foreach my $value (split(/\s*,\s*/, $str)) {
154
($name,$value) = split(/\s*=\s*/, $value, 2);
156
# Attributes with no value are set to be true
157
$value = 1 unless defined $value;
158
$attrs{$name} = $value;
167
my $dataNode = shift;
168
my $sectionName = shift;
170
my $data = join("", @temporaryContent);
172
# Look for end-of-interface mark
174
$data = substr($data, index($data, $sectionName), pos($data) - length($data));
176
$data =~ s/[\n\r]/ /g;
178
# Beginning of the regexp parsing magic
179
if ($sectionName eq "exception") {
180
print " |- Trying to parse exception...\n" unless $beQuiet;
182
my $exceptionName = "";
183
my $exceptionData = "";
184
my $exceptionDataName = "";
185
my $exceptionDataType = "";
187
# Match identifier of the exception, and enclosed data...
188
$data =~ /$IDLStructure::exceptionSelector/;
189
$exceptionName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
190
$exceptionData = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
192
('' =~ /^/); # Reset variables needed for regexp matching
194
# ... parse enclosed data (get. name & type)
195
$exceptionData =~ /$IDLStructure::exceptionSubSelector/;
196
$exceptionDataType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
197
$exceptionDataName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
199
# Fill in domClass datastructure
200
$dataNode->name($exceptionName);
202
my $newDataNode = new domAttribute();
203
$newDataNode->type("readonly attribute");
204
$newDataNode->signature(new domSignature());
206
$newDataNode->signature->name($exceptionDataName);
207
$newDataNode->signature->type($exceptionDataType);
209
my $arrayRef = $dataNode->attributes;
210
push(@$arrayRef, $newDataNode);
212
print " |----> Exception; NAME \"$exceptionName\" DATA TYPE \"$exceptionDataType\" DATA NAME \"$exceptionDataName\"\n |-\n |\n" unless $beQuiet;
213
} elsif ($sectionName eq "interface") {
214
print " |- Trying to parse interface...\n" unless $beQuiet;
216
my $interfaceName = "";
217
my $interfaceData = "";
219
# Match identifier of the interface, and enclosed data...
220
$data =~ /$IDLStructure::interfaceSelector/;
222
$interfaceExtendedAttributes = (defined($1) ? $1 : " "); chop($interfaceExtendedAttributes);
223
$interfaceName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
224
$interfaceBase = (defined($3) ? $3 : "");
225
$interfaceData = (defined($4) ? $4 : die("Parsing error!\nSource:\n$data\n)"));
227
# Fill in known parts of the domClass datastructure now...
228
$dataNode->name($interfaceName);
229
$dataNode->extendedAttributes(parseExtendedAttributes($interfaceExtendedAttributes));
231
# Inheritance detection
232
my @interfaceParents = split(/,/, $interfaceBase);
233
foreach(@interfaceParents) {
237
my $arrayRef = $dataNode->parents;
238
push(@$arrayRef, $line);
241
$interfaceData =~ s/[\n\r]/ /g;
242
my @interfaceMethods = split(/;/, $interfaceData);
244
foreach my $line (@interfaceMethods) {
245
if ($line =~ /attribute/) {
246
$line =~ /$IDLStructure::interfaceAttributeSelector/;
248
my $attributeType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
249
my $attributeExtendedAttributes = (defined($2) ? $2 : " "); chop($attributeExtendedAttributes);
251
my $attributeDataType = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
252
my $attributeDataName = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)"));
254
('' =~ /^/); # Reset variables needed for regexp matching
256
$line =~ /$IDLStructure::getterRaisesSelector/;
257
my $getterException = (defined($1) ? $1 : "");
259
$line =~ /$IDLStructure::setterRaisesSelector/;
260
my $setterException = (defined($1) ? $1 : "");
262
my $newDataNode = new domAttribute();
263
$newDataNode->type($attributeType);
264
$newDataNode->signature(new domSignature());
266
$newDataNode->signature->name($attributeDataName);
267
$newDataNode->signature->type($attributeDataType);
268
$newDataNode->signature->extendedAttributes(parseExtendedAttributes($attributeExtendedAttributes));
270
my $arrayRef = $dataNode->attributes;
271
push(@$arrayRef, $newDataNode);
273
print " | |> Attribute; TYPE \"$attributeType\" DATA NAME \"$attributeDataName\" DATA TYPE \"$attributeDataType\" GET EXCEPTION? \"$getterException\" SET EXCEPTION? \"$setterException\"" .
274
dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet;
276
$getterException =~ s/\s+//g;
277
$setterException =~ s/\s+//g;
278
@{$newDataNode->getterExceptions} = split(/,/, $getterException);
279
@{$newDataNode->setterExceptions} = split(/,/, $setterException);
280
} elsif (($line !~ s/^\s*$//g) and ($line !~ /^\s*const/)) {
281
$line =~ /$IDLStructure::interfaceMethodSelector/ or die "Parsing error!\nSource:\n$line\n)";
283
my $methodExtendedAttributes = (defined($1) ? $1 : " "); chop($methodExtendedAttributes);
284
my $methodType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
285
my $methodName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
286
my $methodSignature = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)"));
288
('' =~ /^/); # Reset variables needed for regexp matching
290
$line =~ /$IDLStructure::raisesSelector/;
291
my $methodException = (defined($1) ? $1 : "");
293
my $newDataNode = new domFunction();
295
$newDataNode->signature(new domSignature());
296
$newDataNode->signature->name($methodName);
297
$newDataNode->signature->type($methodType);
298
$newDataNode->signature->extendedAttributes(parseExtendedAttributes($methodExtendedAttributes));
300
print " | |- Method; TYPE \"$methodType\" NAME \"$methodName\" EXCEPTION? \"$methodException\"" .
301
dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet;
303
$methodException =~ s/\s+//g;
304
@{$newDataNode->raisesExceptions} = split(/,/, $methodException);
306
my @params = split(/,/, $methodSignature);
310
$line =~ /$IDLStructure::interfaceParameterSelector/;
311
my $paramExtendedAttributes = (defined($1) ? $1 : " "); chop($paramExtendedAttributes);
312
my $paramType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
313
my $paramName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
315
my $paramDataNode = new domSignature();
316
$paramDataNode->name($paramName);
317
$paramDataNode->type($paramType);
318
$paramDataNode->extendedAttributes(parseExtendedAttributes($paramExtendedAttributes));
320
my $arrayRef = $newDataNode->parameters;
321
push(@$arrayRef, $paramDataNode);
323
print " | |> Param; TYPE \"$paramType\" NAME \"$paramName\"" .
324
dumpExtendedAttributes("\n | ", $paramDataNode->extendedAttributes) . "\n" unless $beQuiet;
327
my $arrayRef = $dataNode->functions;
328
push(@$arrayRef, $newDataNode);
329
} elsif ($line =~ /^\s*const/) {
330
$line =~ /$IDLStructure::constantSelector/;
331
my $constType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
332
my $constName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
333
my $constValue = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
335
my $newDataNode = new domConstant();
336
$newDataNode->name($constName);
337
$newDataNode->type($constType);
338
$newDataNode->value($constValue);
340
my $arrayRef = $dataNode->constants;
341
push(@$arrayRef, $newDataNode);
343
print " | |> Constant; TYPE \"$constType\" NAME \"$constName\" VALUE \"$constValue\"\n" unless $beQuiet;
347
print " |----> Interface; NAME \"$interfaceName\"" .
348
dumpExtendedAttributes("\n | ", $dataNode->extendedAttributes) . "\n |-\n |\n" unless $beQuiet;
353
sub DetermineParseMode
358
my $mode = MODE_UNDEF;
359
if ($_ =~ /module/) {
361
} elsif ($_ =~ /interface/) {
362
$mode = MODE_INTERFACE;
363
} elsif ($_ =~ /exception/) {
364
$mode = MODE_EXCEPTION;
365
} elsif ($_ =~ /alias/) {
377
if ($parseMode eq MODE_MODULE) {
378
die ("Two modules in one file! Fatal error!\n") if ($document ne 0);
379
$document = new idlDocument();
380
$object->ParseModule($document);
381
} elsif ($parseMode eq MODE_INTERFACE) {
382
my $node = new domClass();
383
$object->ParseInterface($node, "interface");
385
die ("No module specified! Fatal Error!\n") if ($document eq 0);
386
my $arrayRef = $document->classes;
387
push(@$arrayRef, $node);
388
} elsif($parseMode eq MODE_EXCEPTION) {
389
my $node = new domClass();
390
$object->ParseInterface($node, "exception");
392
die ("No module specified! Fatal Error!\n") if ($document eq 0);
393
my $arrayRef = $document->classes;
394
push(@$arrayRef, $node);
395
} elsif($parseMode eq MODE_ALIAS) {
396
print " |- Trying to parse alias...\n" unless $beQuiet;
398
my $line = join("", @temporaryContent);
399
$line =~ /$IDLStructure::aliasSelector/;
401
my $interfaceName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
402
my $wrapperName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
404
print " |----> Alias; INTERFACE \"$interfaceName\" WRAPPER \"$wrapperName\"\n |-\n |\n" unless $beQuiet;
406
# FIXME: Check if alias is already in aliases
407
my $aliases = $document->aliases;
408
$aliases->{$interfaceName} = $wrapperName;
411
@temporaryContent = "";