File Coverage

blib/lib/DMTF/CIM/MOF.pm
Criterion Covered Total %
statement 21 898 2.3
branch 0 578 0.0
condition 0 60 0.0
subroutine 7 14 50.0
pod 1 7 14.2
total 29 1557 1.8


line stmt bran cond sub pod time code
1             package DMTF::CIM::MOF;
2            
3 1     1   27648 use warnings;
  1         3  
  1         32  
4 1     1   6 use strict;
  1         2  
  1         34  
5 1     1   1133 use Storable;
  1         3968  
  1         65  
6 1     1   1063 use DMTF::CIM;
  1         20603  
  1         38  
7 1     1   13 use Carp;
  1         3  
  1         103  
8 1     1   7 use version;
  1         8  
  1         6  
9             our $VERSION = qv('0.05');
10 1     1   100 use Exporter qw ( import );
  1         2  
  1         9596  
11            
12            
13             # Module implementation here
14             sub valid_MOF_integer
15             {
16 0     0 0   my $value=shift;
17             # Binary
18 0 0         if($value =~ /^[-+]?1[01]*[bB]$/) {
    0          
    0          
    0          
    0          
19 0           return 2;
20             }
21             # Octal
22             elsif($value =~ /^[-+]?0[0-7]*$/) {
23 0           return 8;
24             }
25             # Decimal
26             elsif($value =~ /^[-+]?[1-9][0-9]*$/) {
27 0           return 10;
28             }
29             # Hex
30             elsif($value =~ /^[-+]?0[Xx][0-9a-fA-F]*$/) {
31 0           return 16;
32             }
33             # Unknown
34             elsif($value =~ /^[-+]?$/) {
35 0           return 1;
36             }
37 0           return 0;
38             }
39            
40             sub parse_MOF_integer
41             {
42 0     0 0   my $value=shift;
43            
44             # Decimal
45 0 0         if($value =~ /^[-+]?[1-9][0-9]*$/) {
46 0           $value += 0;
47             }
48             else {
49             # Binary
50 0 0         if($value =~ /^([-+]?)(1[01]*)[bB]$/) {
    0          
    0          
51 0           $value = "0b$2";
52             }
53             # Octal
54             elsif($value =~ /^([-+]?)(0[0-7]*)$/) {
55 0           $value = $2;
56             }
57             elsif($value =~ /^([-+]?)(0[Xx][0-9a-fA-F]*)$/) {
58 0           $value=$2;
59             }
60 0           $value=oct($value);
61 0 0         $value=0-$value if($1 eq '-');
62             }
63 0           return $value;
64             }
65            
66             sub setdefaults
67             {
68 0     0 0   my $scope=shift;
69 0           my $qualifier=shift;
70            
71 0           foreach my $key (keys %$scope) {
72 0 0         if(!defined $scope->{$key}{qualifiers}{lc($qualifier->{name})}) {
73 0           $scope->{$key}{qualifiers}{lc($qualifier->{name})} = {type=>$qualifier->{type}};
74 0 0         if(defined $qualifier->{array}) {
75 0           $scope->{$key}{qualifiers}{lc($qualifier->{name})}{array}=$qualifier->{array};
76             }
77             }
78 0 0         if(defined $qualifier->{value}) {
79 0 0         if(ref($qualifier->{value}) eq '') {
80 0           $scope->{$key}{qualifiers}{lc($qualifier->{name})}{value}=$qualifier->{value};
81             }
82             else {
83 0           $scope->{$key}{qualifiers}{lc($qualifier->{name})}{value}=Storable::dclone($qualifier->{value});
84             }
85             }
86             }
87             }
88            
89             sub derive
90             {
91 0     0 0   my $target=shift;
92 0           my $super=shift;
93 0           my $qualifiers=shift;
94            
95             # First, Deal with qualifiers...
96 0           my $targetscope;
97 0 0 0       if(defined $target->{qualifiers}{association} && $target->{qualifiers}{association}{value} eq 'true') {
    0 0        
98 0           $targetscope='association';
99             }
100             elsif(defined $target->{qualifiers}{indication} && $target->{qualifiers}{indication}{value} eq 'true') {
101 0           $targetscope='indication';
102             }
103             else {
104 0           $targetscope='class';
105             }
106 0           foreach my $qualifier (keys %$qualifiers) {
107 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{$targetscope} || defined $qualifiers->{$qualifier}{scope}{all}) {
108 0 0         if(!defined $target->{qualifiers}{$qualifier}) {
109 0           $target->{qualifiers}{$qualifier} = {type=>$qualifiers->{$qualifier}{type}};
110 0 0         if(defined $qualifiers->{$qualifier}{array}) {
111 0           $target->{qualifiers}{$qualifier}{array}=$qualifiers->{$qualifier}{array};
112             }
113             }
114 0 0         if(!defined $target->{qualifiers}{$qualifier}{value}) {
115 0 0         if(defined $super->{qualifiers}{$qualifier}{value}) {
    0          
116 0 0         if(ref($super->{qualifiers}{$qualifier}{value}) eq '') {
117 0           $target->{qualifiers}{$qualifier}{value}=$super->{qualifiers}{$qualifier}{value};
118             }
119             else {
120 0           $target->{qualifiers}{$qualifier}{value}=Storable::dclone($super->{qualifiers}{$qualifier}{value});
121             }
122             }
123             elsif(defined $qualifiers->{$qualifier}{value}) {
124 0 0         if(ref($qualifiers->{$qualifier}{value}) eq '') {
125 0           $target->{qualifiers}{$qualifier}{value}=$qualifiers->{$qualifier}{value};
126             }
127             else {
128 0           $target->{qualifiers}{$qualifier}{value}=Storable::dclone($qualifiers->{$qualifier}{value});
129             }
130             }
131             }
132             }
133             }
134            
135             # Now copy properties, methods, and references
136 0 0         $target->{properties}=Storable::dclone($super->{properties}) if defined $super->{properties};
137 0 0         $target->{methods}=Storable::dclone($super->{methods}) if defined $super->{methods};
138 0 0         $target->{references}=Storable::dclone($super->{references}) if defined $super->{references};
139             # Now set any qualifiers that do not propogate to their default value...
140 0           foreach my $qualifier (keys %$qualifiers) {
141 0 0         if(defined $qualifiers->{$qualifier}{flavor}{restricted}) {
142 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{property} || defined $qualifiers->{$qualifier}{scope}{all}) {
143 0           setdefaults($target->{properties}, $qualifiers->{$qualifier});
144             }
145 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{reference} || defined $qualifiers->{$qualifier}{scope}{all}) {
146 0           setdefaults($target->{references}, $qualifiers->{$qualifier});
147             }
148 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{method} || defined $qualifiers->{$qualifier}{scope}{all}) {
149 0           setdefaults($target->{methods}, $qualifiers->{$qualifier});
150             }
151 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{parameter} || defined $qualifiers->{$qualifier}{scope}{all}) {
152 0           foreach my $method (keys %{$target->{methods}}) {
  0            
153 0           setdefaults($target->{methods}{$method}{parameters}, $qualifiers->{$qualifier});
154             }
155             }
156             }
157             }
158            
159             # Finally, set superclass
160 0           $target->{superclass}=$super->{name};
161             }
162            
163             sub fill_qualifiers
164             {
165 0     0 0   my $target=shift;
166 0           my $scope=shift;
167 0           my $qualifiers=shift;
168            
169 0           foreach my $qualifier (keys %$qualifiers) {
170 0 0 0       if(defined $qualifiers->{$qualifier}{scope}{$scope} || defined $qualifiers->{$qualifier}{scope}{all}) {
171 0 0         if(!defined $target->{$qualifier}) {
172 0           $target->{$qualifier} = {type=>$qualifiers->{$qualifier}{type}};
173 0 0         $target->{$qualifier}{array}=$qualifiers->{$qualifier}{array} if(defined $qualifiers->{$qualifier}{array});
174 0 0         if(defined $qualifiers->{$qualifier}{value}) {
175 0 0         if(ref($qualifiers->{$qualifier}{value}) eq '') {
176 0           $target->{$qualifier}{value}=$qualifiers->{$qualifier}{value};
177             }
178             else {
179 0 0         $target->{$qualifier}{value}=Storable::dclone($qualifiers->{$qualifier}{value}) if(defined $qualifiers->{$qualifier}{value});
180             }
181             }
182             }
183             }
184             }
185             }
186            
187             sub value_parser_state
188             {
189 0     0 0   my $type=shift;
190            
191 0 0         return 'INTEGER' if($type eq 'uint8');
192 0 0         return 'INTEGER' if($type eq 'uint16');
193 0 0         return 'INTEGER' if($type eq 'uint32');
194 0 0         return 'INTEGER' if($type eq 'uint64');
195 0 0         return 'INTEGER' if($type eq 'sint8');
196 0 0         return 'INTEGER' if($type eq 'sint16');
197 0 0         return 'INTEGER' if($type eq 'sint32');
198 0 0         return 'INTEGER' if($type eq 'sint64');
199 0 0         return 'REAL' if($type eq 'real32');
200 0 0         return 'REAL' if($type eq 'real64');
201 0 0         return 'PARSE_STRING' if($type eq 'string');
202 0 0         return 'CHAR' if($type eq 'char16');
203 0 0         return 'BOOLEAN' if($type eq 'boolean');
204 0 0         return 'DATETIME' if($type eq 'datetime');
205 0           return '';
206             }
207            
208             sub parse_MOF
209             {
210 0     0 1   my $fname=shift;
211 0           my $old=shift;
212 0           my $line='';
213 0           my @handles;
214             my @filenames;
215 0           my @linenums;
216 0           my @linepos;
217 0           my $state='SKIP_WHITESPACE';
218 0           my @state_stack=('OPEN');
219 0           my %production;
220             my %qualifiers;
221 0           my %classes;
222 0           my %instances;
223 0           my %associations;
224 0           my %indications;
225 0           my $token=''; # Used to capture tokens
226 0           my %string; # Used to capture strings
227 0           my $identifier=''; # Target of the IDENTIFIER state
228 0           my $value; # Target of the INTEGER, REAL, PARSE_STRING, CHAR, BOOLEAN, and DATETIME states
229             my $type; # Temporary storage for type until other details (such as name and property/method/reference) is known
230 0           my $array; # Temporary storage for the array subscript to a type
231 0           my $method=''; # Temorary storage of current method name
232 0           my $basepath=$fname;
233 0           $basepath =~ s|([/\\])[^/\\]*$|$1|;
234 0           my %dataTypes = (uint8=>'',sint8=>'',uint16=>'',sint16=>'',uint32=>'',sint32=>'',uint64=>'',sint64=>'',real32=>'',real64=>'',char16=>'',string=>'',boolean=>'',datetime=>'');
235 0           my %scopetypes = (class=>'', association=>'', indication=>'', qualifier=>'', property=>'', reference=>'', method=>'', parameter=>'', any=>'');
236 0           my %flavortypes = (enableoverride=>'', disableoverride=>'', restricted=>'', tosubclass=>'', translatable=>'');
237 0           my %declarationtypes = (association=>'', indication=>'');
238 0           my %qualifierlist;
239             my $char16;
240            
241 0 0         $old=$old->{DATA} if(defined $old->{DATA});
242 0 0         if(defined $old) {
243 0 0         %classes=%{$old->{classes}} if(ref($old->{classes}) eq 'HASH');
  0            
244 0 0         %associations=%{$old->{associations}} if(ref($old->{associations}) eq 'HASH');
  0            
245 0 0         %indications=%{$old->{indications}} if(ref($old->{indications}) eq 'HASH');
  0            
246 0 0         %qualifiers=%{$old->{qualifiers}} if(ref($old->{qualifiers}) eq 'HASH');
  0            
247 0 0         %instances=%{$old->{instances}} if(ref($old->{instances}) eq 'HASH');
  0            
248             }
249 0           $filenames[$#filenames+1] = $fname;
250 0           open($handles[$#handles+1], "<", $filenames[$#filenames]);
251 0           $linenums[$#handles]=0;
252 0           line:while($#handles >= 0) {
253 0           my $handle=$handles[$#handles];
254 0           while (my $line = <$handle>) {
255 0 0         last if(!defined $line);
256 0           $linenums[$#handles]++;
257 0           $linepos[$#handles]=0;
258 0           while($linepos[$#handles] < length($line)) {
259 0           my $char=substr($line, $linepos[$#handles]++, 1);
260 0 0         if($state eq 'OPEN') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
261 0 0         if($char eq '#') {
    0          
    0          
    0          
    0          
262 0           $state = 'PRAGMA_START';
263 0           $token=$char;
264 0           next;
265             }
266             elsif($char eq '[') {
267             # Can be a class or instance declaration
268 0           %production=();
269 0           push @state_stack, $state;
270 0           push @state_stack, 'SKIP_WHITESPACE';
271 0           push @state_stack, 'CLASS_QUALIFIER_LIST_END';
272 0           push @state_stack, 'QUALIFIER_LIST';
273 0           $identifier='';
274 0           $state='IDENTIFIER';
275 0           next;
276             }
277             elsif(lc($char) eq 'q') {
278 0           %production=();
279 0           push @state_stack, $state;
280 0           push @state_stack, 'SKIP_WHITESPACE';
281 0           $state = 'QUALIFIER_START';
282 0           $token=$char;
283 0           next;
284             }
285             elsif(lc($char) eq 'i') {
286 0           %production=();
287 0           push @state_stack, $state;
288 0           push @state_stack, 'SKIP_WHITESPACE';
289 0           $state = 'INSTANCE_START';
290 0           $token=$char;
291 0           next;
292             }
293             elsif(lc($char) eq 'c') {
294 0           %production=();
295 0           push @state_stack, $state;
296 0           push @state_stack, 'SKIP_WHITESPACE';
297 0           $state = 'CLASS_START';
298 0           $token=$char;
299 0           next;
300             }
301             }
302            
303             #####################
304             ## Comment Parsing ##
305             #####################
306             elsif($state eq 'ONE_SLASH') {
307 0 0         if($char eq '/') {
    0          
308 0           $state = 'LINE_COMMENT';
309 0           next;
310             }
311             elsif($char eq '*') {
312 0           $state = 'BLOCK_COMMENT';
313 0           next;
314             }
315             }
316             elsif($state eq 'LINE_COMMENT') {
317 0 0 0       if($char eq "\n" || $char eq "\r") {
318 0           $state = pop @state_stack;
319 0           $linepos[$#handles]--;
320             }
321 0           next;
322             }
323             elsif($state eq 'BLOCK_COMMENT') {
324 0 0         if($char eq '*') {
325 0           $state = 'BLOCK_COMMENT_END';
326             }
327 0           next;
328             }
329             elsif($state eq 'BLOCK_COMMENT_END') {
330 0 0         if($char eq '/') {
331 0           $state = pop @state_stack;
332             }
333             else {
334 0           $state = 'BLOCK_COMMENT';
335             }
336 0           next;
337             }
338            
339             ####################
340             ## Generic Parses ##
341             ####################
342             elsif($state eq 'PARSE_STRING') {
343 0 0         if(!defined $string{quotes}) {
344 0           %string=(quotes=>0, escape=>0, hval=>0, hex=>'', value=>'');
345             }
346 0 0         if(!$string{quotes}) {
347 0 0         if($char eq '"') {
    0          
    0          
348 0           $string{quotes}=1;
349 0           next;
350             }
351             elsif($char eq '/') {
352 0           push @state_stack, $state;
353 0           $state = 'ONE_SLASH';
354 0           next;
355             }
356             elsif($char =~ /\s/s) {
357 0           next;
358             }
359             else {
360 0           $linepos[$#handles]--;
361 0           $state = pop @state_stack;
362 0           $value=$string{value};
363 0           next;
364             }
365             }
366             else {
367 0 0         if($string{escape}) {
    0          
368 0 0         if($char eq 'b') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
369 0           $string{value} .= "\b";
370 0           $string{escape}=0;
371 0           next;
372             }
373             elsif($char eq 't') {
374 0           $string{value} .= "\t";
375 0           $string{escape}=0;
376 0           next;
377             }
378             elsif($char eq 'n') {
379 0           $string{value} .= "\n";
380 0           $string{escape}=0;
381 0           next;
382             }
383             elsif($char eq 'f') {
384 0           $string{value} .= "\f";
385 0           $string{escape}=0;
386 0           next;
387             }
388             elsif($char eq 'r') {
389 0           $string{value} .= "\r";
390 0           $string{escape}=0;
391 0           next;
392             }
393             elsif($char eq '"') {
394 0           $string{value} .= '"';
395 0           $string{escape}=0;
396 0           next;
397             }
398             elsif($char eq "'") {
399 0           $string{value} .= "'";
400 0           $string{escape}=0;
401 0           next;
402             }
403             elsif($char eq '\\') {
404 0           $string{value} .= '\\';
405 0           $string{escape}=0;
406 0           next;
407             }
408             elsif(lc($char) eq 'x') {
409 0           $string{escape}=0;
410 0           $string{hval}=1;
411 0           $string{hex}='';
412 0           next;
413             }
414             }
415             elsif($string{hval}) {
416 0 0         if($char =~ /[A-Fa-f0-9]/) {
417 0           $string{hex} .= $char;
418 0 0         if(length($string{hex})==4) {
419 0           $string{value} .= ord(hex($string{hex}));
420 0           $string{hval}=0;
421             }
422 0           next;
423             }
424             else {
425 0           $string{value} .= ord(hex($string{hex}));
426 0           $string{hval}=0;
427 0           next;
428             }
429             }
430             else {
431 0 0         if($char eq '\\') {
    0          
432 0           $string{escape}=1;
433 0           next;
434             }
435             elsif($char eq '"') {
436 0           $string{quotes}=0;
437 0           next;
438             }
439 0           $string{value} .= $char;
440 0           next;
441             }
442             }
443             }
444             elsif($state eq 'IDENTIFIER') {
445 0 0         if (length($identifier) == 0) {
446 0 0         if($char =~ /\s/s) {
    0          
447 0           next;
448             }
449             elsif($char =~ /[A-Za-z_]/) {
450 0           $identifier .= $char;
451 0           next;
452             }
453             }
454             else {
455 0 0         if($char =~ /[A-Za-z0-9_]/) {
    0          
456 0           $identifier .= $char;
457 0           next;
458             }
459             elsif($char =~ /\s/s) {
460 0           $state = 'SKIP_WHITESPACE';
461 0           next;
462             }
463             else {
464 0           $state = pop @state_stack;
465 0           $linepos[$#handles]--;
466 0           next;
467             }
468             }
469             }
470             elsif($state eq 'SKIP_WHITESPACE') {
471 0 0         if($char =~ /\s/s) {
    0          
472 0           next;
473             }
474             elsif($char eq '/') {
475 0           push @state_stack, $state;
476 0           $state='ONE_SLASH';
477 0           next;
478             }
479             else {
480 0           $state = pop @state_stack;
481 0           $linepos[$#handles]--;
482 0           next;
483             }
484             }
485             elsif($state eq 'DATETIME') {
486 0           $value ='';
487 0           $linepos[$#handles]--;
488 0           push @state_stack, 'DATETIME_PARSE';
489 0           $state='PARSE_STRING';
490 0           next;
491             }
492             elsif($state eq 'DATETIME_PARSE') {
493             #TODO Parse date/time types.
494 0           $linepos[$#handles]--;
495 0           $state=pop @state_stack;
496 0           next;
497             }
498             elsif($state eq 'BOOLEAN') {
499 0           $value .= $char;
500 0 0         if(lc($value) eq 'true') {
    0          
    0          
    0          
501 0           $state = pop @state_stack;
502 0           next;
503             }
504             elsif(lc($value) eq 'false') {
505             # TODO: Should this be logically false?
506 0           $state = pop @state_stack;
507 0           next;
508             }
509             elsif(substr("true", 0, length($value)) eq lc($value)) {
510 0           next;
511             }
512             elsif(substr("false", 0, length($value)) eq lc($value)) {
513 0           next;
514             }
515             }
516             elsif($state eq 'NULL') {
517 0           $value .= $char;
518 0 0         if(lc($value) eq 'null') {
    0          
519 0           $value=undef;
520 0           $state = pop @state_stack;
521 0           next;
522             }
523             elsif(substr("null", 0, length($value)) eq lc($value)) {
524 0           next;
525             }
526             }
527             elsif($state eq 'CHECK_NULL') {
528 0           $linepos[$#handles]--;
529 0 0         if($char eq 'n') {
530 0           pop @state_stack;
531 0           $state = 'NULL';
532 0           next;
533             }
534             else {
535 0           $state = pop @state_stack;
536 0           next;
537             }
538             }
539             elsif($state eq 'INTEGER') {
540 0           my $oldvalue=$value;
541 0           my $oldvalid=valid_MOF_integer($value);
542 0           $value .= $char;
543 0           my $valid=valid_MOF_integer($value);
544 0 0         if($valid) {
545 0           next;
546             }
547 0 0         if($oldvalid > 1) {
548 0           $linepos[$#handles]--;
549             # TODO Check range.
550 0           $value=parse_MOF_integer($oldvalue);
551 0           $state = pop @state_stack;
552 0           next;
553             }
554             }
555             elsif($state eq 'SEMICOLON_TERMINATER') {
556 0 0         if($char eq ';') {
557 0           $state = 'SKIP_WHITESPACE';
558 0           next;
559             }
560             }
561             elsif($state eq 'QUALIFIER_LIST') {
562 0 0 0       if(defined $declarationtypes{lc($identifier)} || defined $qualifiers{lc($identifier)}) {
563 0           $qualifierlist{lc($identifier)}{type}=$qualifiers{lc($identifier)}{type};
564 0 0         $qualifierlist{lc($identifier)}{array}=$qualifiers{lc($identifier)}{array} if(defined $qualifiers{lc($identifier)}{array});
565 0 0         if($qualifierlist{lc($identifier)}{type} eq 'boolean') {
    0          
566 0           $qualifierlist{lc($identifier)}{value}='true';
567             }
568             elsif(defined $qualifierlist{lc($identifier)}{array}) {
569 0           $qualifierlist{lc($identifier)}{value}=[];
570             }
571 0 0         if($char eq ',') {
    0          
    0          
    0          
572 0           push @state_stack, 'QUALIFIER_LIST';
573 0           $identifier='';
574 0           $state='IDENTIFIER';
575 0           next;
576             }
577             elsif($char eq '(') {
578             # Parse value
579 0           push @state_stack, 'QUALIFIER_LIST_VALUE_DONE';
580 0           push @state_stack, 'SKIP_WHITESPACE';
581            
582 0           my $newstate=value_parser_state($qualifiers{lc($identifier)}{type});
583 0 0         if($newstate eq '') {
584 0           pop @state_stack;
585             }
586             else {
587 0           %string=();
588 0           $value='';
589 0           push @state_stack, $newstate;
590 0           push @state_stack, 'CHECK_NULL';
591 0           $state = 'SKIP_WHITESPACE';
592 0           next;
593             }
594             }
595             elsif($char eq '{') {
596 0           push @state_stack, 'QUALIFIER_ARRAY_VALUE_DONE';
597 0           push @state_stack, 'SKIP_WHITESPACE';
598            
599 0           my $newstate=value_parser_state($qualifiers{lc($identifier)}{type});
600 0 0         if($newstate eq '') {
601 0           pop @state_stack;
602             }
603             else {
604 0           %string=();
605 0           $value='';
606 0           push @state_stack, $newstate;
607 0           push @state_stack, 'CHECK_NULL';
608 0           $state = 'SKIP_WHITESPACE';
609 0           next;
610             }
611             }
612             elsif($char eq ']') {
613 0           $token='';
614 0           $identifier='';
615 0           $state='SKIP_WHITESPACE';
616 0           next;
617             }
618             }
619             else {
620             # Implicitly defined qualifier
621 0           $qualifierlist{lc($identifier)}{value}=$qualifiers{lc($identifier)}{value};
622 0           $qualifierlist{lc($identifier)}{type}='string';
623 0 0         if($char eq ',') {
    0          
    0          
624 0           push @state_stack, 'QUALIFIER_LIST';
625 0           $identifier='';
626 0           $state='IDENTIFIER';
627 0           next;
628             }
629             elsif($char eq '(') {
630             # Parse value
631 0           push @state_stack, 'QUALIFIER_LIST_VALUE_DONE';
632 0           push @state_stack, 'SKIP_WHITESPACE';
633            
634 0           %string=();
635 0           push @state_stack, 'PARSE_STRING';
636 0           push @state_stack, 'CHECK_NULL';
637 0           $state = 'SKIP_WHITESPACE';
638 0           next;
639             }
640             elsif($char eq ':') {
641             # TODO: (deprecated) implicit qualifier flavours
642             }
643 0           print "Qualifier/Declaration $identifier is unknown!\n";
644             }
645             }
646             elsif($state eq 'QUALIFIER_ARRAY_VALUE_DONE') {
647 0           push @{$qualifierlist{lc($identifier)}{value}}, $value;
  0            
648 0           $value = '';
649 0 0         if($char eq ',') {
    0          
650 0           push @state_stack, 'QUALIFIER_ARRAY_VALUE_DONE';
651 0           push @state_stack, 'SKIP_WHITESPACE';
652            
653 0           my $newstate=value_parser_state($qualifiers{lc($identifier)}{type});
654 0 0         if($newstate eq '') {
655 0           pop @state_stack;
656             }
657             else {
658 0           %string=();
659 0           $value='';
660 0           push @state_stack, $newstate;
661 0           push @state_stack, 'CHECK_NULL';
662 0           $state = 'SKIP_WHITESPACE';
663 0           next;
664             }
665             }
666             elsif($char eq '}') {
667 0           push @state_stack, 'QUALIFIER_LIST_AFTER_VALUE_DONE';
668 0           $state='SKIP_WHITESPACE';
669 0           next;
670             }
671             }
672             elsif($state eq 'QUALIFIER_LIST_VALUE_DONE') {
673 0 0         if($char eq ')') {
674 0           $qualifierlist{lc($identifier)}{value}=$value;
675 0           $value='';
676 0           push @state_stack, 'QUALIFIER_LIST_AFTER_VALUE_DONE';
677 0           $state='SKIP_WHITESPACE';
678 0           next;
679             }
680             }
681             elsif($state eq 'QUALIFIER_LIST_AFTER_VALUE_DONE') {
682 0 0         if($char eq ',') {
    0          
    0          
683 0           push @state_stack, 'QUALIFIER_LIST';
684 0           $identifier='';
685 0           $state='IDENTIFIER';
686 0           next;
687             }
688             elsif($char eq ']') {
689 0           $token='';
690 0           $identifier='';
691 0           $state='SKIP_WHITESPACE';
692 0           next;
693             }
694             elsif($char eq ':') {
695             # TODO (Deprecated) implicit qualifier flavours.
696             }
697             }
698            
699             ###########################################
700             ## Class/Instance/Association/Indication ##
701             ###########################################
702             elsif($state eq 'CLASS_QUALIFIER_LIST_END') {
703             # TODO: Validate the scope and flavor of qualifiers.
704 0           $production{qualifiers}={%qualifierlist};
705 0           $linepos[$#handles]--;
706 0           $state = 'INSTANCE_OR_CLASS';
707 0           next;
708             }
709             elsif($state eq 'INSTANCE_OR_CLASS') {
710 0           $token .= $char;
711 0 0         if(lc($token) eq 'instance') {
    0          
    0          
    0          
712 0           $state = 'INSTANCE_OF';
713 0           next;
714             }
715             elsif(lc($token) eq 'class') {
716 0           $identifier='';
717 0           push @state_stack, 'CLASS_NAME';
718 0           $state = 'IDENTIFIER';
719 0           next;
720             }
721             elsif(substr("instance", 0, length($token)) eq lc($token)) {
722 0           next;
723             }
724             elsif(substr("class", 0, length($token)) eq lc($token)) {
725 0           next;
726             }
727             }
728            
729             ##########################################
730             ## Class/Association/Indication Parsing ##
731             ##########################################
732             elsif($state eq 'CLASS_START') {
733 0           $token .= $char;
734 0 0         if(lc($token) eq 'class') {
    0          
735 0           $token='';
736 0           $identifier='';
737 0           push @state_stack, 'CLASS_NAME';
738 0           $state = 'IDENTIFIER';
739 0           next;
740             }
741             elsif(substr("class", 0, length($token)) eq lc($token)) {
742 0           next;
743             }
744             }
745             elsif($state eq 'CLASS_NAME') {
746 0           $linepos[$#handles]--;
747 0 0 0       if(!defined $classes{lc($identifier)} && !defined $associations{lc($identifier)} && !defined $indications{lc($identifier)}) {
748 0 0         if($identifier =~ /^[A-Za-z][A-Za-z0-9]*_[A-Za-z_][A-Za-z0-9_]*$/) {
749 0           $production{name}=$identifier;
750 0           push @state_stack, 'CLASS_SUPERCLASS';
751 0           $state='SKIP_WHITESPACE';
752 0           next;
753             }
754             else {
755 0           print "Invalid class name $identifier\n";
756             }
757             }
758             else {
759 0           print "Redefinition of $identifier!\n";
760             }
761             }
762             elsif($state eq 'CLASS_SUPERCLASS') {
763 0 0         if($char eq ':') {
    0          
764 0           push @state_stack, 'CLASS_SUPERCLASS_NAME';
765 0           $identifier='';
766 0           $state='IDENTIFIER';
767 0           next;
768             }
769             elsif($char eq '{') {
770 0           $linepos[$#handles]--;
771 0           $state = 'CLASS_FEATURE';
772 0 0 0       if(defined $qualifierlist{association} && $qualifierlist{association}{value} eq 'true') {
    0 0        
773 0           fill_qualifiers($production{qualifiers}, 'association', \%qualifiers);
774             }
775             elsif(defined $qualifierlist{indication} && $qualifierlist{indication}{value} eq 'true') {
776 0           fill_qualifiers($production{qualifiers}, 'indication', \%qualifiers);
777             }
778             else {
779 0           fill_qualifiers($production{qualifiers}, 'class', \%qualifiers);
780             }
781 0           next;
782             }
783             }
784             elsif($state eq 'CLASS_SUPERCLASS_NAME') {
785 0 0         if(defined $classes{lc($identifier)}) {
    0          
    0          
786 0           derive(\%production, $classes{lc($identifier)}, \%qualifiers);
787 0           $linepos[$#handles]--;
788 0           push @state_stack, 'CLASS_FEATURE';
789 0           $state='SKIP_WHITESPACE';
790 0           next;
791             }
792             elsif(defined $associations{lc($identifier)}) {
793 0           derive(\%production, $associations{lc($identifier)}, \%qualifiers);
794 0           $linepos[$#handles]--;
795 0           push @state_stack, 'CLASS_FEATURE';
796 0           $state='SKIP_WHITESPACE';
797 0           next;
798             }
799             elsif(defined $indications{lc($identifier)}) {
800 0           derive(\%production, $indications{lc($identifier)}, \%qualifiers);
801 0           $linepos[$#handles]--;
802 0           push @state_stack, 'CLASS_FEATURE';
803 0           $state='SKIP_WHITESPACE';
804 0           next;
805             }
806             else {
807 0           print "Superclass $identifier not defined\n";
808             }
809             }
810             elsif($state eq 'CLASS_FEATURE') {
811 0 0         if($char eq '{') {
812 0           push @state_stack, 'CLASS_FEATURE_LIST';
813 0           $state='SKIP_WHITESPACE';
814 0           next;
815             }
816             }
817             elsif($state eq 'CLASS_FEATURE_LIST') {
818 0           %qualifierlist=();
819 0 0         if($char eq '[') {
    0          
820 0           push @state_stack, $state;
821 0           push @state_stack, 'CLASS_FEATURE_QUALIFIER_LIST_END';
822 0           push @state_stack, 'QUALIFIER_LIST';
823 0           $identifier='';
824 0           $state='IDENTIFIER';
825 0           next;
826             }
827             elsif($char eq '}') {
828 0 0 0       if(defined $production{qualifiers}{association} && $production{qualifiers}{association}{value} eq 'true') {
    0 0        
829 0           $associations{lc($production{name})}={%production};
830             }
831             elsif(defined $production{qualifiers}{indication} && $production{qualifiers}{indication}{value} eq 'true') {
832 0           $indications{lc($production{name})}={%production};
833             }
834             else {
835 0           $classes{lc($production{name})}={%production};
836             }
837 0           push @state_stack, 'SEMICOLON_TERMINATER';
838 0           $state='SKIP_WHITESPACE';
839 0           next;
840             }
841             else {
842 0           $linepos[$#handles]--;
843 0           push @state_stack, 'CLASS_FEATURE_TYPE';
844 0           $state='IDENTIFIER';
845 0           next;
846             }
847             }
848             elsif($state eq 'CLASS_FEATURE_QUALIFIER_LIST_END') {
849             # TODO: Validate the scope and flavor of qualifiers.
850 0           $linepos[$#handles]--;
851 0           push @state_stack, 'CLASS_FEATURE_TYPE';
852 0           $state='IDENTIFIER';
853 0           next;
854             }
855             elsif($state eq 'CLASS_FEATURE_TYPE') {
856 0 0 0       if(defined $dataTypes{lc($identifier)}) {
    0 0        
857 0           $type = lc($identifier);
858 0           $identifier='';
859 0           $linepos[$#handles]--;
860 0           push @state_stack, 'CLASS_FEATURE_NAME';
861 0           $state='IDENTIFIER';
862 0           next;
863             }
864             elsif(defined $classes{lc($identifier)} || defined $associations{lc($identifier)} || defined $indications{lc($identifier)}) {
865 0 0 0       if(defined $production{qualifiers}{association} && $production{qualifiers}{association}{value} eq 'true') {
866 0           $type = lc($identifier);
867 0           $identifier='';
868 0           $linepos[$#handles]--;
869 0           $state = 'CLASS_REFERENCE';
870 0           next;
871             }
872             }
873             else {
874 0           print "Unhandled type $identifier\n";
875             }
876             }
877             elsif($state eq 'CLASS_REFERENCE') {
878 0           $token .= $char;
879 0 0         if(lc($token) eq 'ref') {
    0          
880 0           $token = '';
881 0           push @state_stack, 'CLASS_REFERENCE_NAME';
882 0           $identifier='';
883 0           $state='IDENTIFIER';
884 0           next;
885             }
886             elsif(substr("ref", 0, length($token)) eq lc($token)) {
887 0           next;
888             }
889             }
890             elsif($state eq 'CLASS_REFERENCE_NAME') {
891 0           $linepos[$#handles]--;
892 0           $production{references}{lc($identifier)}{type}=$type;
893 0           $production{references}{lc($identifier)}{is_ref}='true';
894 0           fill_qualifiers(\%qualifierlist, 'reference', \%qualifiers);
895 0           $production{references}{lc($identifier)}{qualifiers}={%qualifierlist};
896 0           $production{references}{lc($identifier)}{name}=$identifier;
897 0           %qualifierlist=();
898 0           push @state_stack, 'SEMICOLON_TERMINATER';
899 0           $state = 'SKIP_WHITESPACE';
900             # TODO: Handle default value
901 0           next;
902             }
903             elsif($state eq 'CLASS_FEATURE_NAME') {
904 0 0         if($char eq '[') {
    0          
    0          
    0          
905 0           fill_qualifiers(\%qualifierlist, 'property', \%qualifiers);
906 0           $production{properties}{lc($identifier)}{qualifiers}={%qualifierlist};
907 0           %qualifierlist=();
908 0           $production{properties}{lc($identifier)}{type}=$type;
909 0           $production{properties}{lc($identifier)}{array}='';
910 0           $production{properties}{lc($identifier)}{name}=$identifier;
911 0           push @state_stack, 'CLASS_PROPERTY_NAME_ARRAY';
912 0           $state='SKIP_WHITESPACE';
913 0           next;
914             }
915             elsif($char eq '=') {
916 0           $production{properties}{lc($identifier)}{type}=$type;
917 0           fill_qualifiers(\%qualifierlist, 'property', \%qualifiers);
918 0           $production{properties}{lc($identifier)}{qualifiers}={%qualifierlist};
919 0           $production{properties}{lc($identifier)}{name}=$identifier;
920 0           %qualifierlist=();
921 0           $linepos[$#handles]--;
922 0           $state = 'CLASS_PROPERTY_DEFAULT';
923 0           next;
924             }
925             elsif($char eq '(') {
926             #Method...
927 0           fill_qualifiers(\%qualifierlist, 'method', \%qualifiers);
928 0           $production{methods}{lc($identifier)}{qualifiers}={%qualifierlist};
929 0           %qualifierlist=();
930 0           $production{methods}{lc($identifier)}{type}=$type;
931 0           $production{methods}{lc($identifier)}{name}=$identifier;
932 0           $method=lc($identifier);
933 0           $identifier='';
934 0           push @state_stack, 'CLASS_PARAMETER_LIST';
935 0           $state = 'SKIP_WHITESPACE';
936 0           next;
937             }
938             elsif($char eq ';') {
939 0           $linepos[$#handles]--;
940 0           fill_qualifiers(\%qualifierlist, 'property', \%qualifiers);
941 0           $production{properties}{lc($identifier)}{qualifiers}={%qualifierlist};
942 0           %qualifierlist=();
943 0           $production{properties}{lc($identifier)}{type}=$type;
944 0           $production{properties}{lc($identifier)}{name}=$identifier;
945 0           $state = 'SEMICOLON_TERMINATER';
946 0           next;
947             }
948             }
949             elsif($state eq 'CLASS_PARAMETER_LIST') {
950 0 0         if($char eq '[') {
    0          
951 0           %qualifierlist=();
952 0           push @state_stack, 'CLASS_PARAMETER_QUALIFIER_LIST_END';
953 0           push @state_stack, 'QUALIFIER_LIST';
954 0           $identifier='';
955 0           $state='IDENTIFIER';
956 0           next;
957             }
958             elsif($char eq ')') {
959 0           push @state_stack, 'SEMICOLON_TERMINATER';
960 0           $state='SKIP_WHITESPACE';
961 0           next;
962             }
963             else {
964 0           $linepos[$#handles]--;
965 0           push @state_stack, 'CLASS_PARAMETER_TYPE';
966 0           $identifier='';
967 0           $state='IDENTIFIER';
968 0           next;
969             }
970             }
971             elsif($state eq 'CLASS_PARAMETER_QUALIFIER_LIST_END') {
972             # TODO: Validate the scope and flavor of qualifiers.
973 0           $linepos[$#handles]--;
974 0           push @state_stack, 'CLASS_PARAMETER_TYPE';
975 0           $state='IDENTIFIER';
976 0           next;
977             }
978             elsif($state eq 'CLASS_PARAMETER_TYPE') {
979 0 0 0       if(defined $dataTypes{lc($identifier)}) {
    0 0        
980 0           $type = lc($identifier);
981 0           $identifier='';
982 0           $linepos[$#handles]--;
983 0           push @state_stack, 'CLASS_PARAMETER_NAME';
984 0           $state='IDENTIFIER';
985 0           next;
986             }
987             elsif(defined $classes{lc($identifier)} || defined $associations{lc($identifier)} || defined $indications{lc($identifier)}) {
988 0           $type = lc($identifier);
989 0           $identifier='';
990 0           $linepos[$#handles]--;
991 0           $state = 'PARAMETER_REFERENCE';
992 0           next;
993             }
994             }
995             elsif($state eq 'CLASS_PARAMETER_NAME') {
996 0           $production{methods}{$method}{parameters}{lc($identifier)}{type}=$type;
997 0           $production{methods}{$method}{parameters}{lc($identifier)}{name}=$identifier;
998 0           fill_qualifiers(\%qualifierlist, 'parameter', \%qualifiers);
999 0           $production{methods}{$method}{parameters}{lc($identifier)}{qualifiers}={%qualifierlist};
1000 0 0         if($char eq '[') {
    0          
    0          
1001 0           $token='';
1002 0           $production{methods}{$method}{parameters}{lc($identifier)}{array}='';
1003 0           $state = 'PARAMETER_NAME_ARRAY';
1004 0           next;
1005             }
1006             elsif($char eq ',') {
1007 0           push @state_stack, 'CLASS_PARAMETER_LIST';
1008 0           $state = 'SKIP_WHITESPACE';
1009 0           next;
1010             }
1011             elsif($char eq ')') {
1012 0           push @state_stack, 'SEMICOLON_TERMINATER';
1013 0           $state = 'SKIP_WHITESPACE';
1014 0           next;
1015             }
1016             }
1017             elsif($state eq 'PARAMETER_REFERENCE') {
1018 0           $token .= $char;
1019 0 0         if(lc($token) eq 'ref') {
    0          
1020 0           $token = '';
1021 0           push @state_stack, 'PARAMETER_REFERENCE_NAME';
1022 0           $identifier='';
1023 0           $state='IDENTIFIER';
1024 0           next;
1025             }
1026             elsif(substr("ref", 0, length($token)) eq lc($token)) {
1027 0           next;
1028             }
1029             }
1030             elsif($state eq 'PARAMETER_REFERENCE_NAME') {
1031 0           $production{methods}{$method}{parameters}{lc($identifier)}{type}='ref';
1032 0           fill_qualifiers(\%qualifierlist, 'parameter', \%qualifiers);
1033 0           $production{methods}{$method}{parameters}{lc($identifier)}{qualifiers}={%qualifierlist};
1034 0           $production{methods}{$method}{parameters}{lc($identifier)}{name}=$identifier;
1035 0 0         if($char eq '[') {
    0          
    0          
1036 0           $token='';
1037 0           $production{methods}{$method}{parameters}{lc($identifier)}{array}='';
1038 0           $state = 'PARAMETER_NAME_ARRAY';
1039 0           next;
1040             }
1041             elsif($char eq ',') {
1042 0           push @state_stack, 'CLASS_PARAMETER_LIST';
1043 0           $state = 'SKIP_WHITESPACE';
1044 0           next;
1045             }
1046             elsif($char eq ')') {
1047 0           push @state_stack, 'SEMICOLON_TERMINATER';
1048 0           $state = 'SKIP_WHITESPACE';
1049 0           next;
1050             }
1051             }
1052             elsif($state eq 'PARAMETER_NAME_ARRAY') {
1053 0 0         if($char =~ /[0-9]/) {
    0          
1054 0           $production{properties}{lc($identifier)}{array} .= $char;
1055 0           next;
1056             }
1057             elsif($char eq ']') {
1058 0           push @state_stack, 'PARAMETER_NAME_ARRAY_DONE';
1059 0           $state='SKIP_WHITESPACE';
1060 0           next;
1061             }
1062             }
1063             elsif($state eq 'PARAMETER_NAME_ARRAY_DONE') {
1064 0 0         if($char eq ',') {
    0          
1065 0           push @state_stack, 'CLASS_PARAMETER_LIST';
1066 0           $state = 'SKIP_WHITESPACE';
1067 0           next;
1068             }
1069             elsif($char eq ')') {
1070 0           push @state_stack, 'SEMICOLON_TERMINATER';
1071 0           $state = 'SKIP_WHITESPACE';
1072 0           next;
1073             }
1074             }
1075             elsif($state eq 'CLASS_PROPERTY_NAME_ARRAY') {
1076 0 0         if($char =~ /[0-9]/) {
    0          
1077 0           $production{properties}{lc($identifier)}{array} .= $char;
1078 0           next;
1079             }
1080             elsif($char eq ']') {
1081 0           push @state_stack, 'CLASS_PROPERTY_DEFAULT';
1082 0           $state='SKIP_WHITESPACE';
1083 0           next;
1084             }
1085             }
1086             elsif($state eq 'CLASS_PROPERTY_DEFAULT') {
1087 0 0         if($char eq '=') {
    0          
1088 0           push @state_stack, 'CLASS_PROPERTY_DEFAULT_VALUE';
1089 0           $state = 'SKIP_WHITESPACE';
1090 0           next;
1091             }
1092             elsif($char eq ';') {
1093 0           $linepos[$#handles]--;
1094 0           $state = 'SEMICOLON_TERMINATER';
1095 0           next;
1096             }
1097             }
1098             elsif($state eq 'CLASS_PROPERTY_DEFAULT_VALUE') {
1099 0 0         if(defined $production{properties}{lc($identifier)}{array}) {
1100 0 0         if($char eq '{') {
1101 0           push @state_stack, 'CLASS_PROPERTY_DEFAULT_ARRAY_VALUE_DONE';
1102 0           push @state_stack, 'SKIP_WHITESPACE';
1103            
1104 0           my $newstate=value_parser_state($production{properties}{lc($identifier)}{type});
1105 0 0         if($newstate eq '') {
1106 0           pop @state_stack;
1107             }
1108             else {
1109 0           $value='';
1110 0           %string=();
1111 0           push @state_stack, $newstate;
1112 0           push @state_stack, 'CHECK_NULL';
1113 0           $state = 'SKIP_WHITESPACE';
1114 0           next;
1115             }
1116             }
1117             }
1118             else {
1119             # Parse value
1120 0           $linepos[$#handles]--;
1121 0           push @state_stack, 'CLASS_PROPERTY_DEFAULT_VALUE_DONE';
1122 0           push @state_stack, 'SKIP_WHITESPACE';
1123            
1124 0           my $newstate=value_parser_state($production{properties}{lc($identifier)}{type});
1125 0 0         if($newstate eq '') {
1126 0           pop @state_stack;
1127             }
1128             else {
1129 0           $value='';
1130 0           %string=();
1131 0           push @state_stack, $newstate;
1132 0           push @state_stack, 'CHECK_NULL';
1133 0           $state = 'SKIP_WHITESPACE';
1134 0           next;
1135             }
1136             }
1137             }
1138             elsif($state eq 'CLASS_PROPERTY_DEFAULT_ARRAY_VALUE_DONE') {
1139 0           push @{$production{properties}{lc($identifier)}{default}}, $value;
  0            
1140 0           $value = '';
1141 0 0         if($char eq ',') {
    0          
1142 0           push @state_stack, 'CLASS_PROPERTY_DEFAULT_ARRAY_VALUE_DONE';
1143 0           push @state_stack, 'SKIP_WHITESPACE';
1144            
1145 0           my $newstate=value_parser_state($production{properties}{lc($identifier)}{type});
1146 0 0         if($newstate eq '') {
1147 0           pop @state_stack;
1148             }
1149             else {
1150 0           $value='';
1151 0           %string=();
1152 0           push @state_stack, $newstate;
1153 0           push @state_stack, 'CHECK_NULL';
1154 0           $state = 'SKIP_WHITESPACE';
1155 0           next;
1156             }
1157             }
1158             elsif($char eq '}') {
1159 0           push @state_stack, 'SEMICOLON_TERMINATER';
1160 0           $state = 'SKIP_WHITESPACE';
1161 0           next;
1162             }
1163             }
1164             elsif($state eq 'CLASS_PROPERTY_DEFAULT_VALUE_DONE') {
1165 0           $production{properties}{lc($identifier)}{default}=$value;
1166 0           $linepos[$#handles]--;
1167 0           push @state_stack, 'SEMICOLON_TERMINATER';
1168 0           $state = 'SKIP_WHITESPACE';
1169 0           next;
1170             }
1171            
1172             ####################
1173             ## Pragma Parsing ##
1174             ####################
1175             elsif($state eq 'PRAGMA_START') {
1176 0           $token .= $char;
1177 0 0         if(lc($token) eq '#pragma') {
    0          
1178 0           %production=(type=>'#pragma');
1179 0           $token = '';
1180 0           push @state_stack, 'PRAGMA_NAME';
1181 0           $identifier='';
1182 0           $state='IDENTIFIER';
1183 0           next;
1184             }
1185             elsif(substr("#pragma", 0, length($token)) eq lc($token)) {
1186 0           next;
1187             }
1188             }
1189             elsif($state eq 'PRAGMA_NAME') {
1190 0 0         if($char eq '(') {
1191 0           $production{name}=$identifier;
1192 0           $identifier='';
1193 0           push @state_stack, 'PRAGMA_PARAMETER';
1194 0           %string=();
1195 0           $state = 'PARSE_STRING';
1196 0           next;
1197             }
1198             }
1199             elsif($state eq 'PRAGMA_PARAMETER') {
1200 0 0         if($char =~ /\s/s) {
    0          
1201 0           next;
1202             }
1203             elsif($char eq ')') {
1204 0           $production{parameter} = $string{value};
1205 0           %string=();
1206 0           push @state_stack,'OPEN';
1207 0           $state = 'SKIP_WHITESPACE';
1208 0 0         if(lc($production{name}) eq 'include') {
1209 0           $filenames[$#filenames+1] = $basepath.$production{parameter};
1210 0 0         if(open($handles[$#handles+1], "<", $filenames[$#filenames])) {
1211 0           $linenums[$#handles]=0;
1212 0           next line;
1213             }
1214 0           pop @filenames;
1215 0           pop @handles;
1216 0           print "Error opening file $basepath$production{parameter}!\n";
1217             }
1218             else {
1219 0           next;
1220             }
1221             }
1222             }
1223            
1224             #######################
1225             ## Qualifier Parsing ##
1226             #######################
1227             elsif($state eq 'QUALIFIER_START') {
1228 0           $token .= $char;
1229 0 0         if(lc($token) eq 'qualifier') {
    0          
1230 0           $token = '';
1231 0           push @state_stack, 'QUALIFIER_NAME';
1232 0           $identifier='';
1233 0           $state='IDENTIFIER';
1234 0           next;
1235             }
1236             elsif(substr("qualifier", 0, length($token)) eq lc($token)) {
1237 0           next;
1238             }
1239             }
1240             elsif($state eq 'QUALIFIER_NAME') {
1241 0 0         if($char eq ':') {
1242 0           $production{name}=$identifier;
1243 0           $identifier='';
1244 0           push @state_stack, 'QUALIFIER_TYPE';
1245 0           $state='IDENTIFIER';
1246 0           next;
1247             }
1248             }
1249             elsif($state eq 'QUALIFIER_TYPE') {
1250 0 0         if(defined $dataTypes{lc($identifier)}) {
1251 0           $production{type}=lc($identifier);
1252 0           $identifier='';
1253 0 0         if($char eq '[') {
    0          
    0          
1254 0           push @state_stack, 'QUALIFIER_ARRAY';
1255 0           $state='SKIP_WHITESPACE';
1256 0           next;
1257             }
1258             elsif($char eq '=') {
1259 0           $state = 'QUALIFIER_DEFAULT_VALUE';
1260 0           $linepos[$#handles]--;
1261 0           next;
1262             }
1263             elsif($char eq ',') {
1264 0 0         if($production{type} eq 'boolean') {
    0          
1265 0           $production{value}='true';
1266             }
1267             elsif(defined $production{array}) {
1268 0           $production{value}=[];
1269             }
1270 0           $state = 'QUALIFIER_SCOPE';
1271 0           $linepos[$#handles]--;
1272 0           next;
1273             }
1274             }
1275             }
1276             elsif($state eq 'QUALIFIER_ARRAY') {
1277 0 0         if($char eq ']') {
    0          
1278 0           $production{array}='';
1279 0           push @state_stack, 'QUALIFIER_DEFAULT_VALUE';
1280 0           $state='SKIP_WHITESPACE';
1281 0           next;
1282             }
1283             elsif($char =~ /[1-9]/) {
1284 0           $token=$char;
1285 0           $state='QUALIFIER_ARRAY_VALUE';
1286 0           next;
1287             }
1288             }
1289             elsif($state eq 'QUALIFIER_ARRAY_VALUE') {
1290 0 0         if($char =~ /[0-9]/) {
    0          
1291 0           $token .= $char;
1292 0           next;
1293             }
1294             elsif($char eq ']') {
1295 0           $production{array}=$token+0;
1296 0           $token='';
1297 0           push @state_stack, 'QUALIFIER_DEFAULT_VALUE';
1298 0           $state='SKIP_WHITESPACE';
1299 0           next;
1300             }
1301             }
1302             elsif($state eq 'QUALIFIER_DEFAULT_VALUE') {
1303 0 0         if($char eq '=') {
    0          
1304 0           push @state_stack, 'QUALIFIER_DEFAULT_VALUE_SPEC';
1305 0           $state='SKIP_WHITESPACE';
1306 0           next;
1307             }
1308             elsif($char eq ',') {
1309 0 0         if($production{type} eq 'boolean') {
    0          
1310 0           $production{value}='true';
1311             }
1312             elsif(defined $production{array}) {
1313 0           $production{value}=[];
1314             }
1315 0           $state = 'QUALIFIER_SCOPE';
1316 0           $linepos[$#handles]--;
1317 0           next;
1318             }
1319             }
1320             elsif($state eq 'QUALIFIER_DEFAULT_VALUE_SPEC') {
1321 0           $value='';
1322 0           $linepos[$#handles]--;
1323 0 0         if(defined $production{array}) {
1324             # TODO - Parse arrays...
1325             }
1326             else {
1327 0           push @state_stack, 'QUALIFIER_DEFAULT_VALUE_DONE';
1328            
1329 0 0         if($char eq 'n') {
1330 0           $state='NULL';
1331 0           next;
1332             }
1333             else {
1334 0           my $newstate = value_parser_state($production{type});
1335 0 0         if($newstate eq '') {
1336 0           pop @state_stack;
1337             }
1338             else {
1339 0           $value='';
1340 0           %string=();
1341 0           push @state_stack, $newstate;
1342 0           $state = 'SKIP_WHITESPACE';
1343 0           next;
1344             }
1345             }
1346             }
1347             }
1348             elsif($state eq 'QUALIFIER_DEFAULT_VALUE_DONE') {
1349 0           $linepos[$#handles]--;
1350 0           $production{value}=$value;
1351 0           $value='';
1352 0           push @state_stack, 'QUALIFIER_SCOPE';
1353 0           $state='SKIP_WHITESPACE';
1354 0           next;
1355             }
1356             elsif($state eq 'QUALIFIER_SCOPE') {
1357 0 0         if($char eq ',') {
1358 0           push @state_stack, 'QUALIFIER_SCOPE_IDENTIFIER';
1359 0           $state='SKIP_WHITESPACE';
1360 0           $token='';
1361 0           next;
1362             }
1363             }
1364             elsif($state eq 'QUALIFIER_SCOPE_IDENTIFIER') {
1365 0           $token .= $char;
1366 0 0         if(lc($token) eq 'scope') {
    0          
1367 0           $token = '';
1368 0           push @state_stack, 'QUALIFIER_SCOPE_LIST_START';
1369 0           $state='SKIP_WHITESPACE';
1370 0           next;
1371             }
1372             elsif(substr("scope", 0, length($token)) eq lc($token)) {
1373 0           next;
1374             }
1375             }
1376             elsif($state eq 'QUALIFIER_SCOPE_LIST_START') {
1377 0 0         if($char eq '(') {
1378 0           push @state_stack, 'QUALIFIER_SCOPE_LIST';
1379 0           $identifier='';
1380 0           $state='IDENTIFIER';
1381 0           next;
1382             }
1383             }
1384             elsif($state eq 'QUALIFIER_SCOPE_LIST') {
1385 0 0         if(defined $scopetypes{lc($identifier)}) {
1386 0           $production{scope}{lc($identifier)}=1;
1387 0 0         if($char eq ',') {
    0          
1388 0           push @state_stack, 'QUALIFIER_SCOPE_LIST';
1389 0           $identifier='';
1390 0           $state='IDENTIFIER';
1391 0           next;
1392             }
1393             elsif($char eq ')') {
1394 0           push @state_stack, 'QUALIFIER_FLAVOR';
1395 0           $identifier='';
1396 0           $state='SKIP_WHITESPACE';
1397 0           next;
1398             }
1399             }
1400             }
1401             elsif($state eq 'QUALIFIER_FLAVOR') {
1402 0 0         if($char eq ',') {
    0          
1403 0           push @state_stack, 'QUALIFIER_FLAVOR_IDENTIFIER';
1404 0           $state='SKIP_WHITESPACE';
1405 0           $token='';
1406 0           next;
1407             }
1408             elsif($char eq ';') {
1409 0           $qualifiers{lc($production{name})}={%production};
1410 0           $state = pop @state_stack;
1411 0           next;
1412             }
1413             }
1414             elsif($state eq 'QUALIFIER_FLAVOR_IDENTIFIER') {
1415 0           $token .= $char;
1416 0 0         if(lc($token) eq 'flavor') {
    0          
1417 0           $token = '';
1418 0           push @state_stack, 'QUALIFIER_FLAVOR_LIST_START';
1419 0           $state='SKIP_WHITESPACE';
1420 0           next;
1421             }
1422             elsif(substr("flavor", 0, length($token)) eq lc($token)) {
1423 0           next;
1424             }
1425             }
1426             elsif($state eq 'QUALIFIER_FLAVOR_LIST_START') {
1427 0 0         if($char eq '(') {
1428 0           push @state_stack, 'QUALIFIER_FLAVOR_LIST';
1429 0           $identifier='';
1430 0           $state='IDENTIFIER';
1431 0           next;
1432             }
1433             }
1434             elsif($state eq 'QUALIFIER_FLAVOR_LIST') {
1435 0 0         if(defined $flavortypes{lc($identifier)}) {
1436 0           $production{flavor}{lc($identifier)}=1;
1437 0 0         if($char eq ',') {
    0          
1438 0           push @state_stack, 'QUALIFIER_FLAVOR_LIST';
1439 0           $identifier='';
1440 0           $state='IDENTIFIER';
1441 0           next;
1442             }
1443             elsif($char eq ')') {
1444 0           $qualifiers{lc($production{name})}={%production};
1445 0           push @state_stack, 'SEMICOLON_TERMINATER';
1446 0           $identifier='';
1447 0           $state='SKIP_WHITESPACE';
1448 0           next;
1449             }
1450             }
1451             }
1452             else {
1453 0           print "Unhandled state $state\n";
1454 0           next;
1455             }
1456            
1457 0           carp "Error in $state (",join("->",@state_stack),") at char '$char' in $filenames[$#filenames] line $linenums[$#handles]\n";
1458 0           $line =~ s/\t/ /g;
1459 0           carp sprintf("%s\n%*s^\n", $line, $linepos[$#handles]-1, '');
1460 0           return;
1461             }
1462             }
1463 0           close(pop @handles);
1464 0           pop @filenames;
1465 0           pop @linenums;
1466 0           pop @linepos;
1467             }
1468            
1469 0           return {classes=>{%classes}, associations=>{%associations}, indications=>{%indications}, qualifiers=>{%qualifiers}, instances=>{%instances}};
1470             }
1471            
1472             1; # Magic true value required at end of module
1473             __END__