siahsd/pidl/idl.yp
Wilco Baan Hofman ad758df90b Add pidl. Add preliminary work on SecIP.
Please note that the Alphatronics implementation does not follow the Vebon specification.
An extra padding byte had to be added to the idl..
2012-08-01 03:30:50 +02:00

694 lines
12 KiB
Text

########################
# 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",
"DATA" => $_[3],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
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 pointers identifier array_len ';'
{{
"TYPE" => "TYPEDEF",
"PROPERTIES" => $_[1],
"NAME" => $_[5],
"DATA" => $_[3],
"POINTERS" => $_[4],
"ARRAY_LEN" => $_[6],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
usertype:
struct
|
union
|
enum
|
bitmap
|
pipe
;
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:
#empty
|
enum_body
;
enum:
property_list 'enum' optional_identifier opt_enum_body
{{
"TYPE" => "ENUM",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
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:
#empty
|
bitmap_body
;
bitmap:
property_list 'bitmap' optional_identifier opt_bitmap_body
{{
"TYPE" => "BITMAP",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
bitmap_elements:
bitmap_element { [ $_[1] ] }
|
bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
;
opt_bitmap_elements:
#empty
|
bitmap_elements
;
bitmap_element:
identifier '=' anytext { "$_[1] ( $_[3] )" }
;
struct_body:
'{' element_list1 '}' { $_[2] }
;
opt_struct_body:
#empty
|
struct_body
;
struct:
property_list 'struct' optional_identifier opt_struct_body
{{
"TYPE" => "STRUCT",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
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:
#empty
|
union_body
;
union:
property_list 'union' optional_identifier opt_union_body
{{
"TYPE" => "UNION",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
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 }
;
pipe:
property_list 'pipe' type
{{
"TYPE" => "PIPE",
"PROPERTIES" => $_[1],
"NAME" => undef,
"DATA" => {
"TYPE" => "STRUCT",
"PROPERTIES" => $_[1],
"NAME" => undef,
"ELEMENTS" => [{
"NAME" => "count",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [],
"TYPE" => "uint3264",
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
},{
"NAME" => "array",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [ "count" ],
"TYPE" => $_[3],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
},
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
element_list1:
#empty
{ [] }
|
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:
#empty { undef }
|
IDENTIFIER
;
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|import|importlib
|include|cpp_quote|typedef
|union|struct|enum|bitmap|pipe
|void|const|unsigned|signed)$/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};
my $options = "";
if (! defined $cpp) {
if (defined $ENV{CC}) {
$cpp = "$ENV{CC}";
$options = "-E";
} else {
$cpp = "cpp";
}
}
my $includes = join('',map { " -I$_" } @$incdirs);
my $data = `$cpp $options -D__PIDL__$includes -xc "$filename"`;
$/ = $saved_delim;
return parse_string($data, $filename);
}