diff options
Diffstat (limited to 'source4/pidl/idl.yp')
-rw-r--r-- | source4/pidl/idl.yp | 434 |
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); +} |