📄 idl.yp
字号:
######################### 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 '{' definitions '}' optional_semicolon {{ "TYPE" => "INTERFACE", "PROPERTIES" => $_[1], "NAME" => $_[3], "DATA" => $_[5], "FILE" => $_[0]->YYData->{FILE}, "LINE" => $_[0]->YYData->{LINE}, }};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] };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 ']' { 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 hashsub 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 undefsub 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -