1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/pidl/idl.yp
Jelmer Vernooij 69fff2d750 Revert "Fix errornos assumption that all compilers are gcc"
This breaks (some?) files with gcc.

This reverts commit 98a4327b19.
2009-02-09 23:29:41 +01:00

498 lines
11 KiB
Plaintext

########################
# IDL Parse::Yapp parser
# Copyright (C) Andrew Tridgell <tridge@samba.org>
# released under the GNU GPL version 3 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] }
| idl import { push(@{$_[1]}, $_[2]); $_[1] }
| idl include { push(@{$_[1]}, $_[2]); $_[1] }
| idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
| idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
;
import: 'import' commalist ';' {{
"TYPE" => "IMPORT",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE}
}}
;
include: 'include' commalist ';' {{
"TYPE" => "INCLUDE",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE}
}}
;
importlib: 'importlib' commalist ';' {{
"TYPE" => "IMPORTLIB",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE}
}}
;
commalist:
text { [ $_[1] ] }
| commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
;
coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
{{
"TYPE" => "COCLASS",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"DATA" => $_[5],
"FILE" => $_[0]->YYData->{FILE},
"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
{{
"TYPE" => "INTERFACE",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"BASE" => $_[4],
"DATA" => $_[6],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
base_interface:
#empty
| ':' identifier { $_[2] }
;
cpp_quote: 'cpp_quote' '(' text ')'
{{
"TYPE" => "CPP_QUOTE",
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
"DATA" => $_[3]
}}
;
definitions:
definition { [ $_[1] ] }
| definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
;
definition: function | const | typedef | typedecl
;
const: 'const' identifier pointers identifier '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"POINTERS" => $_[3],
"NAME" => $_[4],
"VALUE" => $_[6],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
| 'const' identifier pointers identifier array_len '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"POINTERS" => $_[3],
"NAME" => $_[4],
"ARRAY_LEN" => $_[5],
"VALUE" => $_[7],
"FILE" => $_[0]->YYData->{FILE},
"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->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
typedef: property_list 'typedef' type identifier array_len ';'
{{
"TYPE" => "TYPEDEF",
"PROPERTIES" => $_[1],
"NAME" => $_[4],
"DATA" => $_[3],
"ARRAY_LEN" => $_[5],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
usertype: struct | union | enum | bitmap;
typedecl: usertype ';' { $_[1] };
sign: 'signed' | 'unsigned';
existingtype:
sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
| identifier
;
type: usertype | existingtype | void { "void" } ;
enum_body: '{' enum_elements '}' { $_[2] };
opt_enum_body: | enum_body;
enum: property_list 'enum' optional_identifier opt_enum_body
{{
"TYPE" => "ENUM",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4]
}}
;
enum_elements:
enum_element { [ $_[1] ] }
| enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
;
enum_element: identifier
| identifier '=' anytext { "$_[1]$_[2]$_[3]" }
;
bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
opt_bitmap_body: | bitmap_body;
bitmap: property_list 'bitmap' optional_identifier opt_bitmap_body
{{
"TYPE" => "BITMAP",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4]
}}
;
bitmap_elements:
bitmap_element { [ $_[1] ] }
| bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
;
opt_bitmap_elements: | bitmap_elements;
bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
;
struct_body: '{' element_list1 '}' { $_[2] };
opt_struct_body: | struct_body;
struct: property_list 'struct' optional_identifier opt_struct_body
{{
"TYPE" => "STRUCT",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4]
}}
;
empty_element: property_list ';'
{{
"NAME" => "",
"TYPE" => "EMPTY",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
base_or_empty: base_element ';' | empty_element;
optional_base_element:
property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
;
union_elements:
#empty
| union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
;
union_body: '{' union_elements '}' { $_[2] };
opt_union_body: | union_body;
union: property_list 'union' optional_identifier opt_union_body
{{
"TYPE" => "UNION",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"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->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
pointers:
#empty
{ 0 }
| pointers '*' { $_[1]+1 }
;
element_list1:
{ [] }
| element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
;
optional_const:
#empty
| 'const'
;
element_list2:
#empty
| 'void'
| optional_const base_element { [ $_[2] ] }
| element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
;
array_len:
#empty { [] }
| '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
| '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
;
property_list:
#empty
| property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
;
properties: property { $_[1] }
| properties ',' property { FlattenHash([$_[1], $_[3]]); }
;
property: identifier {{ "$_[1]" => "1" }}
| identifier '(' commalisttext ')' {{ "$_[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 '=' 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 qw(error);
#####################################################################
# flatten an array of hashes into a single hash
sub FlattenHash($)
{
my $a = shift;
my %b;
for my $d (@{$a}) {
for my $k (keys %{$d}) {
$b{$k} = $d->{$k};
}
}
return \%b;
}
#####################################################################
# 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;
return undef if (not defined($v));
if (ref($v) eq "ARRAY") {
foreach my $i (0 .. $#{$v}) {
CleanData($v->[$i]);
}
# 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; }
}
}
return $v;
}
sub _Error {
if (exists $_[0]->YYData->{ERRMSG}) {
error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
delete $_[0]->YYData->{ERRMSG};
return;
}
my $last_token = $_[0]->YYData->{LAST_TOKEN};
error($_[0]->YYData, "Syntax error near '$last_token'");
}
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->{FILE} = $2;
goto again;
}
if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
$parser->YYData->{LINE} = $1-1;
$parser->YYData->{FILE} = $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|union|cpp_quote
|struct|enum|bitmap|void|unsigned|signed|import|include
|importlib)$/x) {
return $1;
}
return('IDENTIFIER',$1);
}
if (s/^(.)//s) {
$parser->YYData->{LAST_TOKEN} = $1;
return($1,$1);
}
}
}
sub parse_string
{
my ($data,$filename) = @_;
my $self = new Parse::Pidl::IDL;
$self->YYData->{FILE} = $filename;
$self->YYData->{INPUT} = $data;
$self->YYData->{LINE} = 0;
$self->YYData->{LAST_TOKEN} = "NONE";
my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
return CleanData($idl);
}
sub parse_file($$)
{
my ($filename,$incdirs) = @_;
my $saved_delim = $/;
undef $/;
my $cpp = $ENV{CPP};
if (! defined $cpp) {
$cpp = "cpp";
}
my $includes = join('',map { " -I$_" } @$incdirs);
my $data = `$cpp -D__PIDL__$includes -xc $filename`;
$/ = $saved_delim;
return parse_string($data, $filename);
}