4 # TPG TVB Parser Generator Grammar
6 # Given a bnf like grammar generate a parser for text based tvbs
10 # Wireshark - Network traffic analyzer
11 # By Gerald Combs <gerald@wireshark.org>
12 # Copyright 2004 Gerald Combs
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 ${$_[0]}{$_} = ${$_[1]}{$_} for (keys %{$_[1]});
38 my $line = ${$_[0]->YYData->{DATA}};
44 my $f = unpack "C", shift;
45 my $t = unpack "C", shift;
55 sprintf "\\x%.2x", unpack("C",$_[0]);
60 s/([a-zA-Z0-9])-([a-zA-Z0-9])/from_to($1,$2)/ge;
62 s/\\(.)/to_hexesc($1)/ge;
70 start: statements {$parser_info} ;
73 #empty { $parser_info = {}; }
74 | statements statement
79 my $rulename = ${$_[1]}{name};
81 abort($_[0],"%rule $rulename already defined") if exists ${${$parser_info}{rules}}{$rulename};
83 ${${$parser_info}{rules}}{$rulename} = $_[1];
85 | parser_name_statement {
86 abort($_[0],"%parser_name already defined") if exists ${$parser_info}{name};
87 ${$parser_info}{proto_name} = $_[1];
89 | proto_desc_statement {
90 abort($_[0],"%proto_desc already defined") if exists ${$parser_info}{proto_desc};
91 ${$parser_info}{proto_desc} = $_[1];
93 | header_head_statement {
94 ${$parser_info}{header_head} .= $_[1];
96 | code_head_statement {
97 ${$parser_info}{head} .= $_[1];
99 | header_tail_statement {
100 ${$parser_info}{header_tail} .= $_[1];
102 | code_tail_statement {
103 ${$parser_info}{tail} .= $_[1];
105 | static_field_statement {
106 abort($_[0],"%field '${$_[1]}{name}' already defined") if (exists ${${$parser_info}{fields}}{${$_[1]}{name}});
107 ${${$parser_info}{fields}}{${$_[1]}{name}} = $_[1];
109 | parser_data_statement {
110 abort($_[0],"%tt_type already defined") if exists ${$parser_info}{pdata};
111 ${$parser_info}{pdata} = $_[1];
114 abort($_[0],"%export already defined") if exists ${$parser_info}{export};
115 ${$parser_info}{export} = $_[1];
117 | value_string_statement {
118 my $name = ${$_[1]}{name};
119 abort($_[0],"%value_string $name already defined") if exists ${${$parser_info}{vs}}{$name};
120 ${${$parser_info}{vs}}{$name} = $_[1];
123 ${$parser_info}{ignore} = $_[1];
128 '%ignore' LOWERCASE {$_[2]}
132 '%sequence' tree LOWERCASE '=' sequence_rule '.' qualification code {
133 my $r = hj($_[5],$_[7]);
135 ${$r}{code} = $_[8] if defined $_[8];
136 ${$r}{tree} = 1 if defined $_[2];
139 | '%choice' tree LOWERCASE '=' choice_rule '.' qualification code {
140 my $r = hj($_[5],$_[7]);
142 ${$r}{code} = $_[8] if defined $_[8];
143 ${$r}{tree} = 1 if defined $_[2];
146 | '%rule' LOWERCASE '=' complete_rule '.' code {
149 ${$r}{code} = $_[6] if defined $_[6];
166 base_rule cardinality qualification {hj($_[1],hj($_[2],$_[3]))}
167 | named_rule cardinality { hj($_[1],$_[2]) }
171 named_rule: LOWERCASE {{control=>$_[1],type=>'named'}} ;
174 | CHARS {{control=>chars_control($_[1]),type=>'chars'}}
175 | NOTCHARS {{control=>chars_control($_[1]),type=>'not_chars'}}
176 | DQUOTED {{control=>"\"$_[1]\"",type=>'string'}}
177 | SQUOTED {{control=>"\"$_[1]\"",type=>'caseless'}}
181 '...' qualification '(' last_rule include_mode ')' { @{$_[2]}{'type','subrule','inc_mode'} = ('until',$_[4],$_[5]); $_[2] }
184 last_rule: base_rule | named_rule;
187 #empty { 'TP_UNTIL_SPEND' }
188 | '%spend' { 'TP_UNTIL_SPEND' }
189 | '%include' { 'TP_UNTIL_INCLUDE' }
190 | '%leave' { 'TP_UNTIL_LEAVE' }
193 choice_rule: choice {{subrules=>$_[1],type=>'choice'}} ;
196 complete_rule '|' complete_rule { [$_[1],$_[3]] }
197 | choice '|' complete_rule { push @{$_[1]}, $_[3]; $_[1] }
200 sequence_rule: sequence { {subrules=>$_[1],type=>'seq'}} ;
203 complete_rule { [$_[1]] }
204 | sequence '&' complete_rule { push @{$_[1]}, $_[3]; $_[1] }
208 #empty { my %c; @c{'min','max'} = (1,1); \%c }
209 | '+' { my %c; @c{'min','max'} = (1,"0xffffffff"); \%c }
210 | '?' { my %c; @c{'min','max'} = (0,1); \%c }
211 | '*' { my %c; @c{'min','max'} = (0,"0xffffffff"); \%c }
212 | '{' NUMBER ',' NUMBER '}' { my %c; @c{'min','max'} = ($_[2],$_[4]); \%c }
213 | '{' NUMBER '}' { my %c; @c{'min','max'} = ($_[2],$_[2]); \%c }
214 | '{' ',' NUMBER '}' { my %c; @c{'min','max'} = (0,$_[3]); \%c }
215 | '{' NUMBER ',' '}' { my %c; @c{'min','max'} = ($_[2],"0xffffffff"); \%c }
220 | '<' qualifiers '>' {$_[2]}
224 qualifier { my $p = {}; ${$p} { ${$_[1]}[0] } = ${$_[1]}[1]; $p }
225 | qualifiers ':' qualifier { ${$_[1]} { ${$_[3]}[0] } = ${$_[3]}[1]; $_[1] }
229 | LOWERCASE { ['field',$_[1]] }
230 | UPPERCASE { ['var',$_[1]] }
231 | '%plain_text' { ['plain_text',1] }
234 proto_desc_statement:
235 '%proto_desc' quoted '.' { "\"$_[2]\"" }
238 header_head_statement:
239 '%header_head' CODE { $_[2] }
242 header_tail_statement:
243 '%header_tail' CODE { $_[2] }
247 '%head' CODE { $_[2] }
251 '%tail' CODE { $_[2] }
254 parser_name_statement:
255 '%parser_name' LOWERCASE '.' {$_[2]}
258 parser_data_statement:
259 '%tt_type' CODE { $_[2] }
263 '%export' exports '.' { $_[2] }
267 exports LOWERCASE { ${$_[1]}{$_[2]} = 1; $_[1] }
268 | LOWERCASE { my $e = {}; ${$e}{$_[1]} = 1; $e }
271 value_string_statement:
272 '%value_string' LOWERCASE value_string_items { my $v = {}; ${$v}{name} = $_[2]; ${$v}{items} = $_[3]; $v }
276 value_string_items value_string_item { push @{$_[1]}, $_[2] }
277 | value_string_item { [$_[1]]}
281 NUMBER DQUOTED { [ $_[1], "\"$_[2]\"" ] }
284 static_field_statement:
285 '%field' LOWERCASE DOTEDNAME field_name field_type field_base field_value_string field_description '.' {
287 @{$field}{'name','abbr','pname','type','base','vs','desc'} = ($_[2],"\"$_[3]\"",$_[4],$_[5],$_[6],$_[7],$_[8]);
294 | DQUOTED { "\"$_[1]\""}
298 #empty { 'FT_STRING' }
303 #empty { 'BASE_NONE' }
309 | CODE { $_[1] =~ s/#line.*?\n//ms; $_[1] =~ s/\n//msg; $_[1] =~ s@/\*eocode\*/@@; $_[1] }
314 | SQUOTED { "\"$_[1]\""}
317 quoted: DQUOTED | SQUOTED ;