File Coverage

blib/lib/CORBA/IDL/Lexer.pm
Criterion Covered Total %
statement 12 209 5.7
branch 0 248 0.0
condition 0 24 0.0
subroutine 4 18 22.2
pod 0 2 0.0
total 16 501 3.1


line stmt bran cond sub pod time code
1             #
2             # Interface Definition Language (OMG IDL CORBA v3.0)
3             #
4             # Lexer module
5             #
6            
7             package CORBA::IDL::Lexer;
8            
9 1     1   5 use strict;
  1         1  
  1         33  
10 1     1   6 use warnings;
  1         1  
  1         31  
11            
12             our $VERSION = '2.64';
13            
14 1     1   23700 use Math::BigInt;
  1         25615  
  1         6  
15 1     1   38701 use Math::BigFloat;
  1         40203  
  1         6  
16            
17             sub _StringLexer {
18 0     0     my ($parser, $token) = @_;
19 0           my $str = q{};
20            
21 0           while ($parser->YYData->{line}) {
22            
23 0           for ($parser->YYData->{line}) {
24            
25 0 0         s/^\"//
26             and return ($token, $str);
27            
28 0 0         s/^([^"\\]+)//
29             and $str .= $1, # any character except single quote or backslash
30             last;
31            
32 0 0         s/^\\a//
33             and $str .= "\a", # alert
34             last;
35 0 0         s/^\\b//
36             and $str .= "\b", # backspace
37             last;
38 0 0         s/^\\f//
39             and $str .= "\f", # form feed
40             last;
41 0 0         s/^\\n//
42             and $str .= "\n", # new line
43             last;
44 0 0         s/^\\r//
45             and $str .= "\r", # carriage return
46             last;
47 0 0         s/^\\t//
48             and $str .= "\t", # horizontal tab
49             last;
50 0 0         s/^\\v//
51             and $str .= "\013", # vertical tab
52             last;
53 0 0         s/^\\([\?'"])//
54             and $str .= $1, # backslash, question mark, single quote, double quote
55             last;
56            
57 0 0         s/^\\([0-7]{1,3})//
    0          
58             and $str .= chr oct $1,
59             (oct $1) ? 1 : $parser->Error("null character in a string.\n"),
60             last;
61 0 0         s/^\\x([0-9A-Fa-f]{1,2})//
    0          
62             and $str .= chr hex $1,
63             (hex $1) ? 1 : $parser->Error("null character in a string.\n"),
64             last;
65 0 0         if ($token eq 'WIDE_STRING_LITERAL') {
66 0 0         s/^\\u([0-9A-Fa-f]{1,4})//
    0          
67             and $str .= chr hex $1,
68             (hex $1) ? 1 : $parser->Error("null character in a string.\n"),
69             last;
70             }
71             s/^\\//
72 0 0         and $parser->Error("invalid escape sequence.\n"),
73             last
74             }
75             }
76            
77 0           $parser->Error("untermined string.\n");
78 0           $parser->YYData->{lineno} ++;
79 0           return ($token, $str);
80             }
81            
82             sub _CharLexer {
83 0     0     my ($parser, $token) = @_;
84            
85 0           $_ = $parser->YYData->{line};
86 0 0         s/^([^'\\])\'//
87             and return ($token, $1); # any character except single quote or backslash
88            
89 0 0         s/^\\n\'//
90             and return ($token, "\n"); # new line
91 0 0         s/^\\t\'//
92             and return ($token, "\t"); # horizontal tab
93 0 0         s/^\\v\'//
94             and return ($token, "\013"); # vertical tab
95 0 0         s/^\\b\'//
96             and return ($token, "\b"); # backspace
97 0 0         s/^\\r\'//
98             and return ($token, "\r"); # carriage return
99 0 0         s/^\\f\'//
100             and return ($token, "\f"); # form feed
101 0 0         s/^\\a\'//
102             and return ($token, "\a"); # alert
103 0 0         s/^\\([\?'"])\'//
104             and return ($token, $1); # backslash, question mark, single quote, double quote
105 0 0         s/^\\([0-7]{1,3})\'//
106             and return ($token, chr oct $1);
107 0 0         s/^\\x([0-9A-Fa-f]{1,2})\'//
108             and return ($token, chr hex $1);
109 0 0         if ($token eq 'WIDE_STRING_LITERAL') {
110 0 0         s/^\\u([0-9A-Fa-f]{1,4})\'//
111             and return ($token, chr hex $1);
112             }
113            
114             s/^\\([^\s\(\)\[\]\{\}<>,;:="]*)//
115 0 0         and $parser->Error("invalid escape sequence $1.\n"),
116             return ($token, ' ');
117            
118 0 0         s/^([^\s\(\)\[\]\{\}<>,;:="]*)//
119             and $parser->Error("invalid character $1.\n"),
120             return ($token, q{ });
121            
122 0           print "INTERNAL_ERROR:_CharLexer $_\n";
123 0           return ($token, q{ });
124             }
125            
126             sub _Identifier {
127 0     0     my ($parser, $ident) = @_;
128            
129 0           my $key = uc $ident;
130 0 0         if (exists $parser->YYData->{keyword}{$key}) {
131 0           my ($keywd, $version, $lang) = @{$parser->YYData->{keyword}{$key}};
  0            
132 0 0         if ($CORBA::IDL::Parser::IDL_VERSION ge $version) {
133 0 0         if ($ident eq $keywd) {
134 0           return ($key, $ident);
135             }
136             else {
137 0           $parser->Error("'$ident' collides with keyword '$keywd'.\n");
138 0           return ('IDENTIFIER', $ident);
139             }
140             }
141             else {
142 0 0         if (defined $lang) {
143 0 0         if ($ident eq $keywd) {
144 0           $parser->Info("'$ident' is a keyword of $lang.\n");
145             }
146             else {
147 0           $parser->Info("'$ident' collides with keyword '$keywd' of $lang.\n");
148             }
149             }
150             else {
151 0 0         if ($ident eq $keywd) {
152 0           $parser->Info("'$ident' is a future keyword.\n");
153             }
154             else {
155 0           $parser->Info("'$ident' collides with future keyword '$keywd'.\n");
156             }
157             }
158             }
159             }
160 0           return ('IDENTIFIER', $ident);
161             }
162            
163             sub _EscIdentifier {
164 0     0     my ($parser, $ident) = @_;
165            
166 0 0         if ($CORBA::IDL::Parser::IDL_VERSION ge '2.3') {
167 0           my $key = uc $ident;
168 0 0         unless (exists $parser->YYData->{keyword}{$key}) {
169 0           Info("Unnecessary escaped identifier '$ident'.\n");
170             }
171             }
172             else {
173 0           $parser->Warning("Escaped identifier is not allowed.\n");
174             }
175 0           return ('IDENTIFIER', $ident);
176             }
177            
178             sub _OctInteger {
179 0     0     my ($parser, $str) = @_;
180            
181 0           my $val = new Math::BigInt(0);
182 0           foreach (split //, $str) {
183 0           $val = $val * new Math::BigInt(8) + new Math::BigInt(oct $_);
184             }
185 0           return ('INTEGER_LITERAL', $val);
186             }
187            
188             sub _HexInteger {
189 0     0     my ($parser, $str) = @_;
190            
191 0           my $val = new Math::BigInt(0);
192 0           foreach (split //, $str) {
193 0           $val = $val * new Math::BigInt(16) + new Math::BigInt(hex $_);
194             }
195 0           return ('INTEGER_LITERAL', $val);
196             }
197            
198             sub _CommentLexer {
199 0     0     my ($parser) = @_;
200            
201 0           while (1) {
202 0 0 0       $parser->YYData->{line}
203             or $parser->YYData->{line} = readline $parser->YYData->{fh}
204             or return;
205            
206 0           for ($parser->YYData->{line}) {
207 0 0         s/^\n//
208             and $parser->YYData->{lineno} ++,
209             last;
210 0 0         s/^\*\///
211             and return;
212 0 0         s/^.[^*\n]*//
213             and last;
214             }
215             }
216             }
217            
218             sub _DocLexer {
219 0     0     my ($parser) = @_;
220            
221 0           $parser->YYData->{doc} = q{};
222 0           my $flag = 1;
223 0           while (1) {
224 0 0 0       $parser->YYData->{line}
225             or $parser->YYData->{line} = readline $parser->YYData->{fh}
226             or return;
227            
228 0           for ($parser->YYData->{line}) {
229 0 0         s/^(\n)//
230             and $parser->YYData->{lineno} ++,
231             $parser->YYData->{doc} .= $1,
232             $flag = 0,
233             last;
234 0 0         s/^\r//
235             and last;
236 0 0         s/^\*\///
237             and return;
238 0 0         unless ($flag) {
239 0 0         s/^\*//
240             and $flag = 1,
241             last;
242             }
243             s/^([ \t\f\013]+)//
244 0 0         and $parser->YYData->{doc} .= $1,
245             last;
246 0 0         s/^(.[\w \t]*)//
247             and $parser->YYData->{doc} .= $1,
248             $flag = 1,
249             last;
250             }
251             }
252             }
253            
254             sub _DocAfterLexer {
255 0     0     my ($parser) = @_;
256            
257 0 0         unless (defined $parser->YYData->{curr_node}) {
258 0           $parser->_DocLexer();
259 0           return;
260             }
261            
262 0 0         unless (exists $parser->YYData->{curr_node}->{doc}) {
263 0           $parser->YYData->{curr_node}->{doc} = q{};
264             }
265 0           my $flag = 1;
266 0           while (1) {
267 0 0 0       $parser->YYData->{line}
268             or $parser->YYData->{line} = readline $parser->YYData->{fh}
269             or return;
270            
271 0           for ($parser->YYData->{line}) {
272 0 0         s/^(\n)//
273             and $parser->YYData->{lineno} ++,
274             $parser->YYData->{curr_node}->{doc} .= $1,
275             $flag = 0,
276             last;
277 0 0         s/^\r//
278             and last;
279 0 0         s/^\*\///
280             and return;
281 0 0         unless ($flag) {
282 0 0         s/^\*//
283             and $flag = 1,
284             last;
285             }
286             s/^([ \t\f\013]+)//
287 0 0         and $parser->YYData->{curr_node}->{doc} .= $1,
288             last;
289 0 0         s/^(.[\w \t]*)//
290             and $parser->YYData->{curr_node}->{doc} .= $1,
291             $flag = 1,
292             last;
293             }
294             }
295             }
296            
297             sub _CodeLexer {
298 0     0     my ($parser) = @_;
299 0           my $frag = q{};
300            
301 0           while (1) {
302 0 0 0       $parser->YYData->{line}
303             or $parser->YYData->{line} = readline $parser->YYData->{fh}
304             or return;
305            
306 0           for ($parser->YYData->{line}) {
307 0 0         s/^(\n)//
308             and $parser->YYData->{lineno} ++,
309             $frag .= $1,
310             last;
311 0 0         s/^%\}.*//
312             and return ('CODE_FRAGMENT', $frag);
313 0 0         s/^(.[^%\n]*)//
314             and $frag .= $1,
315             last;
316             }
317             }
318             }
319            
320             sub _PragmaLexer { # 10.6.5 Pragma Directives for RepositoryId
321 0     0     my ($parser, $line) = @_;
322            
323 0           for ($line) {
324 0 0         s/^ID[ \t]+([0-9A-Za-z_:]+)[ \t]+\"([^\s">]+)\"//
325             and $parser->YYData->{symbtab}->PragmaID($1,$2),
326             return;
327 0 0         s/^prefix[ \t]+\"([0-9A-Za-z_:\.\/\-]*)\"//
328             and $parser->YYData->{symbtab}->PragmaPrefix($1),
329             return;
330 0 0         s/^version[ \t]+([0-9A-Za-z_:]+)[ \t]+([0-9]+)\.([0-9]+)//
331             and $parser->YYData->{symbtab}->PragmaVersion($1,$2,$3),
332             return;
333            
334 0           $parser->Info("Non standard pragma.\n");
335 0           return;
336             }
337             }
338            
339             sub _AttachDoc {
340 0     0     my ($parser, $comment) = @_;
341            
342 0 0         if (defined $parser->YYData->{curr_node}) {
343 0 0         if (exists $parser->YYData->{curr_node}->{doc}) {
344 0           $parser->YYData->{curr_node}->{doc} .= $comment;
345             }
346             else {
347 0           $parser->YYData->{curr_node}->{doc} = $comment;
348             }
349             }
350             }
351            
352             sub Lexer {
353 0     0 0   my ($parser) = @_;
354            
355 0           while (1) {
356 0 0 0       $parser->YYData->{line}
357             or $parser->YYData->{line} = readline $parser->YYData->{fh}
358             or return (q{}, undef);
359            
360 0 0         unless (exists $parser->YYData->{srcname}) {
361 0 0         if ($parser->YYData->{line} =~ /^#\s*(line\s+)?\d+\s+["<]([^\s">]+)[">]\s*\n/ ) {
362 0           $parser->YYData->{srcname} = $2;
363             }
364             else {
365 0           print "INTERNAL_ERROR:_Lexer\n";
366             }
367 0 0         if (defined $parser->YYData->{srcname}) {
368 0           my @st = stat($parser->YYData->{srcname});
369 0           $parser->YYData->{srcname_size} = $st[7];
370 0           $parser->YYData->{srcname_mtime} = $st[9];
371             }
372             }
373            
374 0           for ($parser->YYData->{line}) {
375 0 0         s/^#\s+[\d]+\s+"<[^>]+>"\s*\d*\s*\n// # cpp 3.2.3 ("", " [\d]")
376             and last;
377            
378 0 0         s/^#\s+([\d]+)\s+["<]([^\s">]+)[">]\s+([\d]+)\s*\n// # cpp
379             and $parser->YYData->{lineno} = $1,
380             $parser->YYData->{filename} = $2,
381             $parser->YYData->{doc} = q{},
382             $parser->YYData->{curr_node} = undef,
383             last;
384            
385 0 0         s/^#\s+([\d]+)\s+["<]([^\s">]+)[">]\s*\n// # cpp
386             and $parser->YYData->{lineno} = $1,
387             $parser->YYData->{filename} = $2,
388             $parser->YYData->{doc} = q{},
389             $parser->YYData->{curr_node} = undef,
390             last;
391 0 0         s/^#\s*line\s+([\d]+)\s+["<]([^\s">]+)[">]\s*\n// # CL.EXE Microsoft VC
392             and $parser->YYData->{lineno} = $1,
393             $parser->YYData->{filename} = $2,
394             $parser->YYData->{doc} = q{},
395             $parser->YYData->{curr_node} = undef,
396             last;
397            
398 0           s/^[ \r\t\f\013]+//; # whitespaces
399 0 0         s/^\n//
400             and $parser->YYData->{lineno} ++,
401             $parser->YYData->{curr_node} = undef,
402             last;
403            
404 0 0         s/^#pragma\s+(.*)\n//
405             and _PragmaLexer($parser, $1),
406             $parser->YYData->{lineno} ++,
407             $parser->YYData->{curr_node} = undef,
408             last;
409            
410 0 0         s/^\/\*\*
411             and _DocAfterLexer($parser),
412             last;
413 0 0         s/^\/\*\*// # documentation
414             and _DocLexer($parser),
415             last;
416 0 0 0       s/^\/\/\/(.*)\n// # single line documentation
417             and _AttachDoc($parser, $1),
418             and $parser->YYData->{lineno} ++,
419             last;
420            
421 0 0         s/^\/\*// # multiple line comment
422             and _CommentLexer($parser),
423             last;
424 0 0         s/^\/\/.*\n// # single line comment
425             and $parser->YYData->{lineno} ++,
426             $parser->YYData->{curr_node} = undef,
427             last;
428            
429 0 0         s/^%\{// # code fragment
430             and return _CodeLexer($parser);
431            
432 0 0         if ($parser->YYData->{prop}) {
433 0 0         s/^([A-Za-z][0-9A-Za-z_]*)//
434             and return ('PROP_KEY', $1);
435            
436 0 0         s/^\(([^\)]+)\)//
437             and return ('PROP_VALUE', $1);
438             }
439            
440 0 0         if ($parser->YYData->{native}) {
441 0 0         s/^([^\)]+)\)//
442             and return ('NATIVE_TYPE', $1);
443             }
444            
445             s/^__declspec\s*\(\s*([A-Za-z]*)\s*\)//
446 0 0         and return ('DECLSPEC', $1);
447            
448 0 0         s/^([0-9]+)([Dd])//
449             and $parser->YYData->{lexeme} = $1 . $2,
450             return ('FIXED_PT_LITERAL', new Math::BigFloat($1));
451 0 0         s/^([0-9]+\.)([Dd])//
452             and $parser->YYData->{lexeme} = $1 . $2,
453             return ('FIXED_PT_LITERAL', new Math::BigFloat($1));
454 0 0         s/^(\.[0-9]+)([Dd])//
455             and $parser->YYData->{lexeme} = $1 . $2,
456             return ('FIXED_PT_LITERAL', new Math::BigFloat($1));
457 0 0         s/^([0-9]+\.[0-9]+)([Dd])//
458             and $parser->YYData->{lexeme} = $1 . $2,
459             return ('FIXED_PT_LITERAL', new Math::BigFloat($1));
460            
461 0 0         s/^([0-9]+\.[0-9]+[Ee][+\-]?[0-9]+)//
462             and $parser->YYData->{lexeme} = $1,
463             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
464 0 0         s/^([0-9]+[Ee][+\-]?[0-9]+)//
465             and $parser->YYData->{lexeme} = $1,
466             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
467 0 0         s/^(\.[0-9]+[Ee][+\-]?[0-9]+)//
468             and $parser->YYData->{lexeme} = $1,
469             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
470 0 0         s/^([0-9]+\.[0-9]+)//
471             and $parser->YYData->{lexeme} = $1,
472             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
473 0 0         s/^([0-9]+\.)//
474             and $parser->YYData->{lexeme} = $1,
475             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
476 0 0         s/^(\.[0-9]+)//
477             and $parser->YYData->{lexeme} = $1,
478             return ('FLOATING_PT_LITERAL', new Math::BigFloat($1));
479            
480 0 0         s/^0([0-7]+)//
481             and $parser->YYData->{lexeme} = '0' . $1,
482             return _OctInteger($parser, $1);
483 0 0         s/^(0[Xx])([A-Fa-f0-9]+)//
484             and $parser->YYData->{lexeme} = $1 . $2,
485             return _HexInteger($parser, $2);
486 0 0         s/^(0)//
487             and $parser->YYData->{lexeme} = $1,
488             return ('INTEGER_LITERAL', new Math::BigInt($1));
489 0 0         s/^([1-9][0-9]*)//
490             and $parser->YYData->{lexeme} = $1,
491             return ('INTEGER_LITERAL', new Math::BigInt($1));
492            
493 0 0         s/^\"//
494             and return _StringLexer($parser, 'STRING_LITERAL');
495            
496 0 0         if ($CORBA::IDL::Parser::IDL_VERSION ge '2.3') {
497 0 0         s/^L\"//
498             and return _StringLexer($parser, 'WIDE_STRING_LITERAL');
499             }
500             else {
501 0 0 0       s/^L\"//
502             and $parser->Warning("literal 'wstring' is not allowed.\n")
503             and return _StringLexer($parser, 'STRING_LITERAL');
504             }
505            
506 0 0         s/^\'//
507             and return _CharLexer($parser, 'CHARACTER_LITERAL');
508            
509 0 0         if ($CORBA::IDL::Parser::IDL_VERSION ge '2.3') {
510 0 0         s/^L\'//
511             and return _CharLexer($parser, 'WIDE_CHARACTER_LITERAL');
512             }
513             else {
514 0 0 0       s/^L\'//
515             and $parser->Warning("literal 'wchar' is not allowed.\n")
516             and return _CharLexer($parser, 'CHARACTER_LITERAL');
517             }
518            
519 0 0         s/^([A-Za-z][0-9A-Za-z_]*)//
520             and return _Identifier($parser, $1);
521 0 0         s/^_([A-Za-z][0-9A-Za-z_]*)//
522             and return _EscIdentifier($parser, $1);
523            
524 0 0         s/^(<<)//
525             and return ($1, $1);
526 0 0         s/^(>>)//
527             and return ($1, $1);
528 0 0         s/^(::)//
529             and return ($1, $1);
530 0 0         s/^(\.\.\.)//
531             and return ($1, $1);
532            
533 0 0         s/^([\+&\/%\*~\|\-\^\(\)\[\]\{\}<>,;:=])//
534             and return ($1, $1); # punctuators
535            
536 0 0         s/^([\S]+)//
537             and $parser->Error("lexer error $1.\n"),
538             last;
539             }
540             }
541             }
542            
543             sub InitLexico {
544 0     0 0   my ($parser) = @_;
545            
546             # 3.2.4 Keywords
547 0           my %keywords = (
548             'ABSTRACT' => [ 'abstract', '2.3' ],
549             'ANY' => [ 'any', '2.0' ],
550             'ATTRIBUTE' => [ 'attribute', '2.0' ],
551             'BOOLEAN' => [ 'boolean', '2.0' ],
552             'BYTE' => [ 'byte', '9.9', 'MIDL/MODL' ],
553             'CASE' => [ 'case', '2.0' ],
554             'CHAR' => [ 'char', '2.0' ],
555             'COMPONENT' => [ 'component', '3.0' ],
556             'CONST' => [ 'const', '2.0' ],
557             'CONSUMES' => [ 'consumes', '3.0' ],
558             'CONTEXT' => [ 'context', '2.0' ],
559             'CUSTOM' => [ 'custom', '2.3' ],
560             'DEFAULT' => [ 'default', '2.0' ],
561             'DOUBLE' => [ 'double', '2.0' ],
562             'EMITS' => [ 'emits', '3.0' ],
563             'ENUM' => [ 'enum', '2.0' ],
564             'EVENTTYPE' => [ 'eventtype', '3.0' ],
565             'EXCEPTION' => [ 'exception', '2.0' ],
566             'FACTORY' => [ 'factory', '2.3' ],
567             'FALSE' => [ 'FALSE', '2.0' ],
568             'FINDER' => [ 'finder', '3.0' ],
569             'FIXED' => [ 'fixed', '2.1' ],
570             'FLOAT' => [ 'float', '2.0' ],
571             'GETRAISES' => [ 'getraises', '3.0' ],
572             'HOME' => [ 'home', '3.0' ],
573             'IMPORT' => [ 'import', '3.0' ],
574             'IN' => [ 'in', '2.0' ],
575             'INOUT' => [ 'inout', '2.0' ],
576             'INTERFACE' => [ 'interface', '2.0' ],
577             'LOCAL' => [ 'local', '2.4' ],
578             'LONG' => [ 'long', '2.0' ],
579             'MODULE' => [ 'module', '2.0' ],
580             'MULTIPLE' => [ 'multiple', '3.0' ],
581             'NATIVE' => [ 'native', '2.2' ],
582             'OBJECT' => [ 'Object', '2.0' ],
583             'OCTET' => [ 'octet', '2.0' ],
584             'ONEWAY' => [ 'oneway', '2.0' ],
585             'OUT' => [ 'out', '2.0' ],
586             'PRIMARYKEY' => [ 'primarykey', '3.0' ],
587             'PRIVATE' => [ 'private', '2.3' ],
588             'PROVIDES' => [ 'provides', '3.0' ],
589             'PUBLIC' => [ 'public', '2.3' ],
590             'PUBLISHES' => [ 'publishes', '3.0' ],
591             'RAISES' => [ 'raises', '2.0' ],
592             'READONLY' => [ 'readonly', '2.0' ],
593             'SEQUENCE' => [ 'sequence', '2.0' ],
594             'SETRAISES' => [ 'setraises', '3.0' ],
595             'SHORT' => [ 'short', '2.0' ],
596             'STRING' => [ 'string', '2.0' ],
597             'STRUCT' => [ 'struct', '2.0' ],
598             'SUPPORTS' => [ 'supports', '2.3' ],
599             'SWITCH' => [ 'switch', '2.0' ],
600             'TRUE' => [ 'TRUE', '2.0' ],
601             'TRUNCATABLE' => [ 'truncatable', '2.3' ],
602             'TYPEDEF' => [ 'typedef', '2.0' ],
603             'TYPEID' => [ 'typeid', '3.0' ],
604             'TYPEPREFIX' => [ 'typeprefix', '3.0' ],
605             'UNION' => [ 'union', '2.0' ],
606             'UNSIGNED' => [ 'unsigned', '2.0' ],
607             'USES' => [ 'uses', '3.0' ],
608             'VALUEBASE' => [ 'ValueBase', '2.3' ],
609             'VALUETYPE' => [ 'valuetype', '2.3' ],
610             'VOID' => [ 'void', '2.0' ],
611             'WCHAR' => [ 'wchar', '2.1' ],
612             'WSTRING' => [ 'wstring', '2.1' ]
613             );
614            
615 0           $parser->YYData->{keyword} = \%keywords;
616             }
617            
618             1;
619