summaryrefslogtreecommitdiff
path: root/source4/pidl/idl.yp
diff options
context:
space:
mode:
Diffstat (limited to 'source4/pidl/idl.yp')
-rw-r--r--source4/pidl/idl.yp434
1 files changed, 434 insertions, 0 deletions
diff --git a/source4/pidl/idl.yp b/source4/pidl/idl.yp
new file mode 100644
index 0000000000..d5838d0c43
--- /dev/null
+++ b/source4/pidl/idl.yp
@@ -0,0 +1,434 @@
+########################
+# IDL Parse::Yapp parser
+# Copyright (C) Andrew Tridgell <tridge@samba.org>
+# released under the GNU GPL version 2 or later
+
+
+
+# the precedence actually doesn't matter at all for this grammar, but
+# by providing a precedence we reduce the number of conflicts
+# enormously
+%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
+
+
+################
+# grammar
+%%
+idl:
+ #empty { {} }
+ | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
+ | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+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},
+ }}
+;
+
+interface_names:
+ #empty { {} }
+ | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+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},
+ }}
+;
+
+base_interface:
+ #empty
+ | ':' identifier { $_[2] }
+;
+
+definitions:
+ definition { [ $_[1] ] }
+ | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+
+definition: function | const | typedef | declare | typedecl
+;
+
+const: 'const' identifier identifier '=' anytext ';'
+ {{
+ "TYPE" => "CONST",
+ "DTYPE" => $_[2],
+ "NAME" => $_[3],
+ "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},
+ }}
+;
+
+
+function: property_list type identifier '(' element_list2 ')' ';'
+ {{
+ "TYPE" => "FUNCTION",
+ "NAME" => $_[3],
+ "RETURN_TYPE" => $_[2],
+ "PROPERTIES" => $_[1],
+ "ELEMENTS" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
+;
+
+declare: 'declare' property_list decl_type identifier';'
+ {{
+ "TYPE" => "DECLARE",
+ "PROPERTIES" => $_[2],
+ "NAME" => $_[4],
+ "DATA" => $_[3],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
+;
+
+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},
+ }}
+;
+
+usertype: struct | union | enum | bitmap;
+
+typedecl: usertype ';' { $_[1] };
+
+type: usertype | identifier
+ | void { "void" }
+;
+
+enum: 'enum' optional_identifier '{' enum_elements '}'
+ {{
+ "TYPE" => "ENUM",
+ "NAME" => $_[2],
+ "ELEMENTS" => $_[4]
+ }}
+;
+
+enum_elements:
+ enum_element { [ $_[1] ] }
+ | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+enum_element: identifier
+ | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
+;
+
+bitmap: 'bitmap' optional_identifier '{' bitmap_elements '}'
+ {{
+ "TYPE" => "BITMAP",
+ "NAME" => $_[2],
+ "ELEMENTS" => $_[4]
+ }}
+;
+
+bitmap_elements:
+ bitmap_element { [ $_[1] ] }
+ | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
+;
+
+struct: 'struct' optional_identifier '{' element_list1 '}'
+ {{
+ "TYPE" => "STRUCT",
+ "NAME" => $_[2],
+ "ELEMENTS" => $_[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} = Parse::Pidl::Util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
+;
+
+union_elements:
+ #empty
+ | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+union: 'union' optional_identifier '{' union_elements '}'
+ {{
+ "TYPE" => "UNION",
+ "NAME" => $_[2],
+ "ELEMENTS" => $_[4]
+ }}
+;
+
+base_element: property_list type pointers identifier array_len
+ {{
+ "NAME" => $_[4],
+ "TYPE" => $_[2],
+ "PROPERTIES" => $_[1],
+ "POINTERS" => $_[3],
+ "ARRAY_LEN" => $_[5],
+ "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+ "LINE" => $_[0]->YYData->{LINE},
+ }}
+;
+
+
+pointers:
+ #empty
+ { 0 }
+ | pointers '*' { $_[1]+1 }
+;
+
+element_list1:
+ #empty
+ | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+element_list2:
+ #empty
+ | 'void'
+ | base_element { [ $_[1] ] }
+ | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+array_len:
+ #empty { [] }
+ | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
+ | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
+;
+
+
+property_list:
+ #empty
+ | property_list '[' properties ']' { Parse::Pidl::Util::FlattenHash([$_[1],$_[3]]); }
+;
+
+properties: property { $_[1] }
+ | properties ',' property { Parse::Pidl::Util::FlattenHash([$_[1], $_[3]]); }
+;
+
+property: identifier {{ "$_[1]" => "1" }}
+ | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
+;
+
+listtext:
+ anytext
+ | 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 { "$_[1]$_[2]$_[3]" }
+ | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
+ | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+ | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+;
+
+identifier: IDENTIFIER
+;
+
+optional_identifier:
+ IDENTIFIER
+ | #empty { undef }
+;
+
+constant: CONSTANT
+;
+
+text: TEXT { "\"$_[1]\"" }
+;
+
+optional_semicolon:
+ #empty
+ | ';'
+;
+
+
+#####################################
+# start code
+%%
+
+use Parse::Pidl::Util;
+
+#####################################################################
+# traverse a perl data structure removing any empty arrays or
+# hashes and any hash elements that map to undef
+sub CleanData($)
+{
+ sub CleanData($);
+ my($v) = shift;
+ if (ref($v) eq "ARRAY") {
+ foreach my $i (0 .. $#{$v}) {
+ CleanData($v->[$i]);
+ if (ref($v->[$i]) eq "ARRAY" && $#{$v->[$i]}==-1) {
+ $v->[$i] = undef;
+ next;
+ }
+ }
+ # this removes any undefined elements from the array
+ @{$v} = grep { defined $_ } @{$v};
+ } elsif (ref($v) eq "HASH") {
+ foreach my $x (keys %{$v}) {
+ CleanData($v->{$x});
+ if (!defined $v->{$x}) { delete($v->{$x}); next; }
+ if (ref($v->{$x}) eq "ARRAY" && $#{$v->{$x}}==-1) { delete($v->{$x}); next; }
+ }
+ }
+ return $v;
+}
+
+sub _Error {
+ if (exists $_[0]->YYData->{ERRMSG}) {
+ print $_[0]->YYData->{ERRMSG};
+ delete $_[0]->YYData->{ERRMSG};
+ return;
+ };
+ my $line = $_[0]->YYData->{LINE};
+ my $last_token = $_[0]->YYData->{LAST_TOKEN};
+ my $file = $_[0]->YYData->{INPUT_FILENAME};
+
+ print "$file:$line: Syntax error near '$last_token'\n";
+}
+
+sub _Lexer($)
+{
+ my($parser)=shift;
+
+ $parser->YYData->{INPUT} or return('',undef);
+
+again:
+ $parser->YYData->{INPUT} =~ s/^[ \t]*//;
+
+ for ($parser->YYData->{INPUT}) {
+ 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}++;
+ goto again;
+ }
+ if (s/^\"(.*?)\"//) {
+ $parser->YYData->{LAST_TOKEN} = $1;
+ return('TEXT',$1);
+ }
+ if (s/^(\d+)(\W|$)/$2/) {
+ $parser->YYData->{LAST_TOKEN} = $1;
+ return('CONSTANT',$1);
+ }
+ if (s/^([\w_]+)//) {
+ $parser->YYData->{LAST_TOKEN} = $1;
+ if ($1 =~
+ /^(coclass|interface|const|typedef|declare|union
+ |struct|enum|bitmap|void)$/x) {
+ return $1;
+ }
+ return('IDENTIFIER',$1);
+ }
+ if (s/^(.)//s) {
+ $parser->YYData->{LAST_TOKEN} = $1;
+ return($1,$1);
+ }
+ }
+}
+
+sub parse_idl($$)
+{
+ my ($self,$filename) = @_;
+
+ my $saved_delim = $/;
+ undef $/;
+ 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";
+
+ my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+
+ return CleanData($idl);
+}