+# the precedence actually doesn't matter at all for this grammer, but
+# by providing a precedence we reduce the number of conflicts
+# enormously
+%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
+
+
################
# grammer
%%
-idl: idl_interface
- | idl idl_interface { util::FlattenArray([$_[1],$_[2]]) }
+idl:
+ #empty { {} }
+ | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
+ | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
;
-idl_interface: module_header interface { [ $_[1], $_[2] ] }
-;
-
-module_header: '[' module_params ']'
- {{
- "TYPE" => "MODULEHEADER",
- "PROPERTIES" => util::FlattenHash($_[2])
+coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
+ {$_[3] => {
+ "TYPE" => "COCLASS",
+ "PROPERTIES" => $_[1],
+ "NAME" => $_[3],
+ "DATA" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
}}
;
-module_params:
- #empty
- | module_param { [ $_[1] ] }
- | module_params ',' module_param { push(@{$_[1]}, $_[3]); $_[1] }
+interface_names:
+ #empty { {} }
+ | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
;
-module_param: identifier '(' listtext ')'
-{ { "$_[1]" => "$_[3]" } }
+interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
+ {$_[3] => {
+ "TYPE" => "INTERFACE",
+ "PROPERTIES" => $_[1],
+ "NAME" => $_[3],
+ "BASE" => $_[4],
+ "DATA" => $_[6],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
;
-interface: 'interface' identifier '{' definitions '}'
- {{
- "TYPE" => "INTERFACE",
- "NAME" => $_[2],
- "DATA" => $_[4]
- }}
+base_interface:
+ #empty
+ | ':' identifier { $_[2] }
;
definitions:
;
-definition: function | const | typedef
+definition: function | const | typedef | declare
;
const: 'const' identifier identifier '=' anytext ';'
"TYPE" => "CONST",
"DTYPE" => $_[2],
"NAME" => $_[3],
- "VALUE" => $_[5]
+ "VALUE" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
+ | 'const' identifier identifier array_len '=' anytext ';'
+ {{
+ "TYPE" => "CONST",
+ "DTYPE" => $_[2],
+ "NAME" => $_[3],
+ "ARRAY_LEN" => $_[4],
+ "VALUE" => $_[6],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
}}
;
"NAME" => $_[3],
"RETURN_TYPE" => $_[2],
"PROPERTIES" => $_[1],
- "DATA" => $_[5]
- }}
+ "ELEMENTS" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
;
-typedef: 'typedef' type identifier array_len ';'
+declare: 'declare' property_list decl_type identifier';'
{{
- "TYPE" => "TYPEDEF",
- "NAME" => $_[3],
- "DATA" => $_[2],
- "ARRAY_LEN" => $_[4]
+ "TYPE" => "DECLARE",
+ "PROPERTIES" => $_[2],
+ "NAME" => $_[4],
+ "DATA" => $_[3],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
}}
;
-type: struct | union | enum | identifier
+decl_type: decl_enum | decl_bitmap
+;
+
+decl_enum: 'enum'
+ {{
+ "TYPE" => "ENUM"
+ }}
+;
+
+decl_bitmap: 'bitmap'
+ {{
+ "TYPE" => "BITMAP"
+ }}
+;
+
+typedef: 'typedef' property_list type identifier array_len ';'
+ {{
+ "TYPE" => "TYPEDEF",
+ "PROPERTIES" => $_[2],
+ "NAME" => $_[4],
+ "DATA" => $_[3],
+ "ARRAY_LEN" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
+;
+
+type: struct | union | enum | bitmap | identifier
| void { "void" }
;
enum: 'enum' '{' enum_elements '}'
{{
- "TYPE" => "ENUM",
+ "TYPE" => "ENUM",
"ELEMENTS" => $_[3]
}}
;
| identifier '=' anytext { "$_[1]$_[2]$_[3]" }
;
-struct: property_list 'struct' '{' element_list1 '}'
+bitmap: 'bitmap' '{' bitmap_elements '}'
+ {{
+ "TYPE" => "BITMAP",
+ "ELEMENTS" => $_[3]
+ }}
+;
+
+bitmap_elements:
+ bitmap_element { [ $_[1] ] }
+ | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
+;
+
+struct: 'struct' '{' element_list1 '}'
{{
"TYPE" => "STRUCT",
- "PROPERTIES" => $_[1],
- "ELEMENTS" => $_[4]
+ "ELEMENTS" => $_[3]
}}
;
-union: property_list 'union' '{' union_elements '}'
- {{
- "TYPE" => "UNION",
- "PROPERTIES" => $_[1],
- "DATA" => $_[4]
+empty_element: property_list ';'
+ {{
+ "NAME" => "",
+ "TYPE" => "EMPTY",
+ "PROPERTIES" => $_[1],
+ "POINTERS" => 0,
+ "ARRAY_LEN" => [],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
}}
;
+base_or_empty: base_element ';' | empty_element;
+
+optional_base_element:
+ property_list base_or_empty { $_[2]->{PROPERTIES} = util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
+;
+
union_elements:
- union_element { [ $_[1] ] }
- | union_elements union_element { push(@{$_[1]}, $_[2]); $_[1] }
+ #empty
+ | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
;
-union_element:
- '[' 'case' '(' anytext ')' ']' base_element ';'
- {{
- "TYPE" => "UNION_ELEMENT",
- "CASE" => $_[4],
- "DATA" => $_[7]
- }}
- | '[' 'case' '(' anytext ')' ']' ';'
- {{
- "TYPE" => "EMPTY",
- "CASE" => $_[4],
- }}
- | '[' 'default' ']' base_element ';'
- {{
- "TYPE" => "UNION_ELEMENT",
- "CASE" => "default",
- "DATA" => $_[4]
- }}
- | '[' 'default' ']' ';'
- {{
- "TYPE" => "EMPTY",
- "CASE" => "default",
- }}
+union: 'union' '{' union_elements '}'
+ {{
+ "TYPE" => "UNION",
+ "ELEMENTS" => $_[3]
+ }}
;
base_element: property_list type pointers identifier array_len
"TYPE" => $_[2],
"PROPERTIES" => $_[1],
"POINTERS" => $_[3],
- "ARRAY_LEN" => $_[5]
+ "ARRAY_LEN" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
}}
;
| pointers '*' { $_[1]+1 }
;
-
-
element_list1:
#empty
- | base_element ';' { [ $_[1] ] }
| element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
;
element_list2:
#empty
- | 'void'
- | base_element { [ $_[1] ] }
+ | 'void'
+ | base_element { [ $_[1] ] }
| element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
;
array_len:
- #empty
- | '[' ']' { "*" }
- | '[' '*' ']' { "*" }
- | '[' anytext ']' { "$_[2]" }
+ #empty { [] }
+ | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
+ | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
;
property_list:
- #empty
- | '[' properties ']' { $_[2] }
- | property_list '[' properties ']' { util::FlattenArray([$_[1],$_[3]]); }
+ #empty
+ | property_list '[' properties ']' { util::FlattenHash([$_[1],$_[3]]); }
;
-properties: property { [ $_[1] ] }
- | properties ',' property { push(@{$_[1]}, $_[3]); $_[1] }
+properties: property { $_[1] }
+ | properties ',' property { util::FlattenHash([$_[1], $_[3]]); }
;
-property: identifier
- | identifier '(' anytext ')' {{ "$_[1]" => "$_[3]" }}
+property: identifier {{ "$_[1]" => "1" }}
+ | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
;
listtext:
| listtext ',' anytext { "$_[1] $_[3]" }
;
+commalisttext:
+ anytext
+ | commalisttext ',' anytext { "$_[1],$_[3]" }
+;
+
anytext: #empty
{ "" }
| identifier | constant | text
| anytext '.' anytext { "$_[1]$_[2]$_[3]" }
| anytext '*' anytext { "$_[1]$_[2]$_[3]" }
| anytext '>' anytext { "$_[1]$_[2]$_[3]" }
+ | anytext '<' anytext { "$_[1]$_[2]$_[3]" }
| anytext '|' anytext { "$_[1]$_[2]$_[3]" }
| anytext '&' anytext { "$_[1]$_[2]$_[3]" }
| anytext '/' anytext { "$_[1]$_[2]$_[3]" }
| anytext '+' anytext { "$_[1]$_[2]$_[3]" }
- | anytext '(' anytext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+ | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
+ | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+ | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
;
identifier: IDENTIFIER
text: TEXT { "\"$_[1]\"" }
;
+optional_semicolon:
+ #empty
+ | ';'
+;
+
#####################################
# start code
%%
-use util;
+use pidl::util;
sub _Error {
- if (exists $_[0]->YYData->{ERRMSG}) {
+ if (exists $_[0]->YYData->{ERRMSG}) {
print $_[0]->YYData->{ERRMSG};
delete $_[0]->YYData->{ERRMSG};
return;
my $last_token = $_[0]->YYData->{LAST_TOKEN};
my $file = $_[0]->YYData->{INPUT_FILENAME};
- print "Syntax error at $file:$line near '$last_token'\n";
+ print "$file:$line: Syntax error near '$last_token'\n";
}
-sub _Lexer {
+sub _Lexer($)
+{
my($parser)=shift;
$parser->YYData->{INPUT}
$parser->YYData->{INPUT} =~ s/^[ \t]*//;
for ($parser->YYData->{INPUT}) {
- if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
- $parser->YYData->{LINE} = $1;
- $parser->YYData->{INPUT_FILENAME} = $2;
- goto again;
+ if (/^\#/) {
+ if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
+ $parser->YYData->{LINE} = $1-1;
+ $parser->YYData->{INPUT_FILENAME} = $2;
+ goto again;
+ }
+ if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
+ $parser->YYData->{LINE} = $1-1;
+ $parser->YYData->{INPUT_FILENAME} = $2;
+ goto again;
+ }
+ if (s/^(\#.*)$//m) {
+ goto again;
+ }
}
if (s/^(\n)//) {
$parser->YYData->{LINE}++;
if (s/^([\w_]+)//) {
$parser->YYData->{LAST_TOKEN} = $1;
if ($1 =~
- /^(interface|const|typedef|union
- |struct|enum|void|case|default)$/x) {
+ /^(coclass|interface|const|typedef|declare|union
+ |struct|enum|bitmap|void)$/x) {
return $1;
}
return('IDENTIFIER',$1);
my $saved_delim = $/;
undef $/;
- my $data = `cpp $filename`;
+ my $cpp = $ENV{CPP};
+ if (! defined $cpp) {
+ $cpp = "cpp"
+ }
+ my $data = `$cpp -D__PIDL__ -xc $filename`;
$/ = $saved_delim;
- $self->YYData->{INPUT} = $data;
- $self->YYData->{LINE} = 0;
- $self->YYData->{LAST_TOKEN} = "NONE";
- return $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+ $self->YYData->{INPUT} = $data;
+ $self->YYData->{LINE} = 0;
+ $self->YYData->{LAST_TOKEN} = "NONE";
+
+ my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+
+ return util::CleanData($idl);
}