mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
a34f848b02
This will also be required for supporting parsing pointers to arrays and arrays of pointers simultaneously.
397 lines
8.7 KiB
Plaintext
397 lines
8.7 KiB
Plaintext
########################
|
|
# 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 grammer, but
|
|
# by providing a precedence we reduce the number of conflicts
|
|
# enormously
|
|
%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
|
|
|
|
|
|
################
|
|
# grammer
|
|
%%
|
|
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
|
|
;
|
|
|
|
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},
|
|
}}
|
|
;
|
|
|
|
type: struct | union | enum | bitmap | identifier
|
|
| void { "void" }
|
|
;
|
|
|
|
|
|
enum: 'enum' '{' enum_elements '}'
|
|
{{
|
|
"TYPE" => "ENUM",
|
|
"ELEMENTS" => $_[3]
|
|
}}
|
|
;
|
|
|
|
enum_elements:
|
|
enum_element { [ $_[1] ] }
|
|
| enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
|
|
;
|
|
|
|
enum_element: identifier
|
|
| identifier '=' anytext { "$_[1]$_[2]$_[3]" }
|
|
;
|
|
|
|
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",
|
|
"ELEMENTS" => $_[3]
|
|
}}
|
|
;
|
|
|
|
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:
|
|
#empty
|
|
| union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
|
|
;
|
|
|
|
union: 'union' '{' union_elements '}'
|
|
{{
|
|
"TYPE" => "UNION",
|
|
"ELEMENTS" => $_[3]
|
|
}}
|
|
;
|
|
|
|
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 ']' { util::FlattenHash([$_[1],$_[3]]); }
|
|
;
|
|
|
|
properties: property { $_[1] }
|
|
| properties ',' property { 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 '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
|
|
| anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
|
|
;
|
|
|
|
identifier: IDENTIFIER
|
|
;
|
|
|
|
constant: CONSTANT
|
|
;
|
|
|
|
text: TEXT { "\"$_[1]\"" }
|
|
;
|
|
|
|
optional_semicolon:
|
|
#empty
|
|
| ';'
|
|
;
|
|
|
|
|
|
#####################################
|
|
# start code
|
|
%%
|
|
|
|
use util;
|
|
|
|
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 = shift;
|
|
my $filename = shift;
|
|
|
|
my $saved_delim = $/;
|
|
undef $/;
|
|
my $cpp = $ENV{CPP};
|
|
if (! defined $cpp) {
|
|
$cpp = "cpp"
|
|
}
|
|
my $data = `$cpp -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 util::CleanData($idl);
|
|
}
|