use strict; use warnings; use Parse::RecDescent; use Data::Dumper; my $grammar = <<'EOG' VCSConfig: statement(s) statement: clause | def clause: "include" pathname # Include Clause # NOTE: May not have any attributes... def: "cluster" name "(" Attr(s?) ")" | "system" name "(" Attr(s?) ")" # Pathname may or may not be surrounded by double quotes pathname: dquote(?) /([^"]+)/ dquote(?) { $return = $1; } dquote: /"/ name: /\w+/ Attr: AttrScalar(s?) | AttrKeyList(s?) | AttrAssociation(s?) AttrScalar: attribute '=' string AttrKeyList: attribute '=' keylist AttrAssociation: attribute '=' association attribute: /[a-zA-Z][\w@]+/ # allow '@' in attr name # NOTE: separator can be either of ',' or ';' keylist: '{' '}' association: '{' '}' key_value: string '=' string string: /[a-zA-Z]\w+/ EOG my ($vcs_config); my ($vcs_parse) = Parse::RecDescent->new( $grammar ); my ($vcs_config) = do { local $/; ; }; my ($orig_config) = $vcs_parse->VCSConfig( $vcs_config ); print Dumper $orig_config; __DATA__ include "types.cf" include "LBSybase.cf" include "OracleTypes.cf" cluster vcs ( UserNames = { vcs = X1Nh6WIWs6ATQ } Administrators = { vcs } CounterInterval = 5 ) system njengsunvcs1 ( ) system njengsunvcs2 ( )