diff options
author | Luis Ontanon <luis.ontanon@gmail.com> | 2005-09-27 20:48:48 +0000 |
---|---|---|
committer | Luis Ontanon <luis.ontanon@gmail.com> | 2005-09-27 20:48:48 +0000 |
commit | 72cbc6410b80e0ca8d8fc7fa5f7d49ea70c74398 (patch) | |
tree | 39da66825e2d2d6b506b9c604cde524df2b0451c /tools/tpg/tpg.yp | |
parent | 9a66525b71ff30396b80804406affa14de450e55 (diff) |
TPG TVB Parser Generator
Given a bnf-like grammar generate a set of helpers for a dissector
It's not working yet, however I need this checkin as a cheeckpoint
(I'll write the doc when it starts to be ready)
svn path=/trunk/; revision=16021
Diffstat (limited to 'tools/tpg/tpg.yp')
-rw-r--r-- | tools/tpg/tpg.yp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/tools/tpg/tpg.yp b/tools/tpg/tpg.yp new file mode 100644 index 0000000000..81bcb4137b --- /dev/null +++ b/tools/tpg/tpg.yp @@ -0,0 +1,320 @@ +%{ +#!/usr/bin/perl +# +# TPG TVB Parser Generator Grammar +# +# Given a bnf like grammar generate a parser for text based tvbs +# +# $Id $ +# +# Ethereal - Network traffic analyzer +# By Gerald Combs <gerald@ethereal.com> +# Copyright 2004 Gerald Combs +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + use V2P; + + my $parser_info; + +sub hj { + ${$_[0]}{$_} = ${$_[1]}{$_} for (keys %{$_[1]}); + return $_[0]; +} + +sub abort { + my $line = ${$_[0]->YYData->{DATA}}; + + die "$_[1] at $line"; +} + +sub from_to { + my $f = unpack "C", shift; + my $t = unpack "C", shift; + my $b = ''; + for ($f..$t) { + $b .= pack("C",$_); + } + $b; +} + +sub chars_control { + $_ = $_[0]; + s/([a-zA-Z0-9])-([a-zA-Z0-9])/from_to($1,$2)/ge; + "\"$_\""; +} + +%} + +%% + +start: statements {$parser_info} ; + +statements: + #empty { $parser_info = {}; } + | statements statement + ; + +statement: + rule_statement { + my $rulename = ${$_[1]}{name}; + + if (exists ${${$parser_info}{rules}}{$rulename}) { + + my $rule = ${${$parser_info}{rules}}{$rulename}; + if (exists ${${$parser_info}{rules}}{root}) { + # a root rule exists already add this to its subrules + push @{${${$parser_info}{rules}}{subrules}}, $_[1]; + } else { + # this rule becomes the first subrule of a choice + ${${$parser_info}{rules}}{$rulename} = { + root=>'', + type=>'choice', + subrules=>[$rule,\$_[1]], + name=>${$_[1]}{name}, + } + } + } else { + ${${$parser_info}{rules}}{$rulename} = $_[1]; + } + } + | parser_name_statement { + abort($_[0],"%parser_name already defined") if exists ${$parser_info}{name}; + ${$parser_info}{proto_name} = $_[1]; + } + | proto_desc_statement { + abort($_[0],"%proto_desc already defined") if exists ${$parser_info}{proto_desc}; + ${$parser_info}{proto_desc} = $_[1]; + } + | header_head_statement { + ${$parser_info}{header_head} .= $_[1]; + } + | code_head_statement { + ${$parser_info}{head} .= $_[1]; + } + | header_tail_statement { + ${$parser_info}{header_tail} .= $_[1]; + } + | code_tail_statement { + ${$parser_info}{tail} .= $_[1]; + } + | static_field_statement { + abort($_[0],"%field '${$_[1]}{name}' already defined") if (exists ${${$parser_info}{fields}}{${$_[1]}{name}}); + ${${$parser_info}{fields}}{${$_[1]}{name}} = $_[1]; + } + | parser_data_statement { + abort($_[0],"%tt_type already defined") if exists ${$parser_info}{pdata}; + ${$parser_info}{pdata} = $_[1]; + } + | export_statement { + abort($_[0],"%export already defined") if exists ${$parser_info}{export}; + ${$parser_info}{export} = $_[1]; + } + | value_string_statement { + my $name = ${$_[1]}{name}; + abort($_[0],"%value_string $name already defined") if exists ${${$parser_info}{vs}}{$name}; + ${${$parser_info}{vs}}{$name} = $_[1]; + } + ; + +rule_statement: +'%rule' LOWERCASE '=' rule '.' rule_body { + my $r = hj($_[4],$_[6]); + ${$r}{name} = $_[2]; + $r; + } + ; + +rule_body: + #empty {{}} + | '{' rule_const rule_item_type tree code '}' { + my $r = {}; + ${$r}{'const'} = $_[2] if $_[2]; + ${$r}{'item'} = $_[3] if $_[3]; + ${$r}{'tree'} = $_[4] if $_[4]; + ${$r}{'code'} = $_[5] if $_[5]; + $r; + } + ; + +rule_const: + #empty { "NULL" } + | '%const' CODE {$_[2]} + ; + +rule_item_type: + #empty { undef } + | '%item_type' CODE {$_[2]} + ; + +code: + #empty { undef } + | '%code' CODE {$_[2]} + ; + +tree: + #empty {undef} + | '%root' LOWERCASE {$_[2]} + ; + +rule: + complete_rule + | sequence {{subrules=>$_[1],type=>'seq'}}; + + +complete_rule: + base_rule cardinality qualification {hj($_[1],hj($_[2],$_[3]))} + ; + +base_rule: + '(' sequence ')' { {subrules=>$_[2],type=>'seq'}} + | '(' choice ')' {{subrules=>$_[2],type=>'choice'}} + | until_rule + | CHARS {{control=>chars_control($_[1]),type=>'chars'}} + | NOTCHARS {{control=>chars_control($_[1]),type=>'not_chars'}} + | DQUOTED {{control=>"$_[1]",type=>'string'}} + | SQUOTED {{control=>"\"$_[1]\"",type=>'caseless'}} + | LOWERCASE {{control=>$_[1],type=>'named'}} + ; + +until_rule: + '...' qualification '{' rule '}' { @{$_[2]}{'type','subrule'} = ('until',$_[4]); $_[2] } + ; + +choice: + complete_rule '|' complete_rule { [$_[1],$_[3]] } + | choice '|' complete_rule { push @{$_[1]}, $_[3]; $_[1] } + ; + +sequence: + complete_rule complete_rule { [$_[1],$_[2]] } + | sequence complete_rule { push @{$_[1]}, $_[2]; $_[1] } + ; + +cardinality: + #empty { my %c; @c{'min','max'} = (1,1); \%c } + | '+' { my %c; @c{'min','max'} = (1,"0xffffffff"); \%c } + | '?' { my %c; @c{'min','max'} = (0,1); \%c } + | '*' { my %c; @c{'min','max'} = (0,"0xffffffff"); \%c } + | '{' NUMBER ',' NUMBER '}' { my %c; @c{'min','max'} = ($_[2],$_[4]); \%c } + | '{' NUMBER '}' { my %c; @c{'min','max'} = ($_[2],$_[2]); \%c } + | '{' ',' NUMBER '}' { my %c; @c{'min','max'} = (0,$_[3]); \%c } + | '{' NUMBER ',' '}' { my %c; @c{'min','max'} = ($_[2],"0xffffffff"); \%c } + ; + +qualification: + #empty {{}} + | '<' qualifiers '>' {$_[2]} + ; + +qualifiers: + qualifier { my $p = {}; ${$p} { ${$_[1]}[0] } = ${$_[1]}[1]; $p } + | qualifiers ':' qualifier { ${$_[1]} { ${$_[3]}[0] } = ${$_[3]}[1]; $_[1] } + ; + +qualifier: + | LOWERCASE { ['field',$_[1]] } + | UPPERCASE { ['var',$_[1]] } + | '%plain_text' { ['plain_text',1] } + ; + +proto_desc_statement: + '%proto_desc' quoted '.' { "\"$_[2]\"" } + ; + +header_head_statement: + '%header_head' CODE { $_[2] } + ; + +header_tail_statement: + '%header_tail' CODE { $_[2] } + ; + +code_head_statement: + '%head' CODE { $_[2] } + ; + +code_tail_statement: + '%tail' CODE { $_[2] } + ; + +parser_name_statement: + '%parser_name' LOWERCASE '.' {$_[2]} + ; + +parser_data_statement: + '%tt_type' CODE { $_[2] } + ; + +export_statement: + '%export' exports '.' { $_[2] } + ; + +exports: + exports LOWERCASE { ${$_[1]}{$_[2]} = undef; $_[1] } + | LOWERCASE { my $e = {}; ${$e}{$_[1]} = undef; $e } + ; + +value_string_statement: + '%value_string' LOWERCASE value_string_items { my $v = {}; ${$v}{name} = $_[2]; ${$v}{items} = $_[3]; $v } + ; + +value_string_items: + value_string_items value_string_item { push @{$_[1]}, $_[2] } + | value_string_item { [$_[1]]} + ; + +value_string_item: + NUMBER QUOTED { [ $_[1], "\"$_[2]\"" ] } + ; + +static_field_statement: + '%field' LOWERCASE DOTEDNAME field_name field_type field_base field_value_string field_description '.' { + my $field = {}; + @{$field}{'name','abbr','pname','type','base','vs','desc'} = ($_[2],"\"$_[3]\"",$_[4],$_[5],$_[6],$_[7],$_[8]); + return $field; + } + ; + +field_name: + #empty {undef} + | DQUOTED + ; + +field_type: + #empty { 'FT_STRING' } + | FT + ; + +field_base: + #empty { 'BASE_NONE' } + | BASE + ; + +field_value_string: + #empty { 'NULL' } + | CODE { $_[1] =~ s/#line.*?\n//ms; $_[1] =~ s/\n//msg; $_[1] =~ s@/\*eocode\*/@@; $_[1] } + ; + +field_description: + #empty {'""'} + | SQUOTED + ; + +quoted: DQUOTED | SQUOTED ; + +%% + + |