# $Id: g3.txt,v 1.14 2010/07/23 12:41:24 bronto Exp bronto $ AsIni: Line(s?) /\Z/ Line: CommentLine | BlankLine | SectionDeclaration | AssignmentLine | CommentLine: /^\s*/m ';' /.*$/m { print STDERR qq{\tSkipping comment: $item[4]\n} ; } BlankLine: /^\s+$/m { print STDERR qq{\tSkipping blank line\n} } SectionDeclaration: '[' /[^\]]+/ ']' { print STDERR qq{In section "$item[2]"\n} ; my $sectionname = $item[2] ; $AsIni::section = $sectionname ; } AssignmentLine: Parameter '=' Value(?) { my $distvalue = $item[3] ; my $parmname = $item[1] ; my $paramvalue ; ( $paramvalue ) = @$distvalue ; if ( not exists $AsIni::node{$AsIni::section}{$parmname} ) { $AsIni::node{$AsIni::section}{$parmname} = [] ; } # Get a reference to the current array of values for this parameter # in $current my $current = $AsIni::node{$AsIni::section}{$parmname} ; # We can update this safely, since we are using the reference push @$current,$paramvalue ; } Parameter: /\w[\w\s-]*/ { $return = $item[1] ; } Value: PikeStructure | ValueString { $return = $item[1] ; } ValueString: QuotedString | UnquotedString { $return = $item[1] ; } QuotedString: '"' /[^"]+/ '"' { $return = $item[2] ; } UnquotedString: /.+/ { $return = $item[1] ; } # This rule matches a number, but rejects null-length results Number: /[+-]?\d*(\.\d+)?/ { $return = $item[1] ; } PikeStructure: PikeArray | PikeMapping { # $item[1] is a reference to an array (PikeArray) or hash # (PikeMapping). We bubble it up as is $return = $item[1] ; } PikeArray: '({' PikeArrayContent '})' { # $item[2] is a PikeArrayContent, and since PikeArrayContent # bubbles up a reference to an array of PikeValues, this should be # an array reference that we can safely bubble up as is. $return = $item[2] ; } PikeMapping: '([' PikeMappingContent '])' { # $item[2] is a PikeMappingContent, and since PikeMappingContent # bubbles up an hash reference, this should be an hash reference that we # can safely bubble up as is. $return = $item[2] ; } PikeStructureSeparator: ',' PikeArrayContent: PikeArraySequence(?) PikeStructureSeparator(?) { # $item[1] comes from a repetition of PikeArraySequence, # so it is a reference to an array of 0 or 1 PikeArraySequence. # In turn, PikeArraySequence is a reference to an array of # PikeValue's. We don't want to change the PikeValue's but we need # to unroll $item[1] before bubbling it up. ( $return ) = @{ $item[1] } ; } PikeArraySequence: PikeValue PikeArrayFurtherValue(s?) { # $item[1] is a PikeValue, hence: # - a reference to an array or hash (if PikeStructure) # - a scalar (if QuotedString or Number) # # $item[2] comes from a repetition of PikeArrayFurtherValue, # so it is a reference to an array of 0 or 1 PikeArrayFurtherValue. # In turn, PikeArrayFurtherValue just returns a PikeValue. So, # we actually don't want to change $item[1], but we need to # unroll $item[2] before returning it. Actually, we return an # array reference with the whole thing. $return = [ $item[1], @{ $item[2] } ] ; } PikeArrayFurtherValue: PikeStructureSeparator PikeValue { # $item[2] is a PikeValue, hence: # - a reference to an array or hash (if PikeStructure) # - a scalar (if QuotedString or Number) # We bubble it up as is. $return = $item[2] ; } PikeMappingContent: PikeMappingSequence(?) PikeStructureSeparator(?) { # Since we have a repetition here, $item[1] is a reference to an # array which may contain 0 or 1 PikeMappingSequence's. # In turn, PikeMappingSequence returns an hash reference. # So, if we want the hash reference to bubble up, we have to # unwrap it and return it as is. ( $return ) = @{ $item[1] } ; } PikeMappingSequence: PikeMappingPair PikeMappingFurtherPair(s?) { # $item[1] is a PikeMappingPair, hence a reference to an array # of two elements: a string and a PikeValue, that is: # - a reference to an array or hash (if Pikevalue ~ PikeStructure) # - a scalar (if PikeValue ~ QuotedString or Number) # # $item[2] has a repetition, so it is a reference to an array of # PikeMappingFurtherPair's. Since PikeMappingFurtherPair just # returns a PikeMappingPair (see $item[1]), then $item[2] is # a reference to an array where each element is, in turn, a # reference to an array of two elements. # # Since we are going to return an hash here, we create a reference # to an hash; to correctly unroll the values of $item[1] and # $item[2] we: # - simply dereference $item[1], hence unrolling the only hash # pair the array contained # - we dereference $item[2], getting an array of arrays, and # then we use map to further unroll the key/value pairs # # We then bubble up the outcome $return = { @{ $item[1] } , map( @$_ , @{ $item[2] } ) } ; } PikeMappingPair: QuotedString ':' PikeValue { # $item[1] is a scalar (QuotedString) # $item[3] is a PikeValue, hence: # - a reference to an array or hash (if Pikevalue ~ PikeStructure) # - a scalar (if PikeValue ~ QuotedString or Number) # We throw them up together as a single entity: a reference to an array $return = [ $item[1], $item[3] ] ; } PikeMappingFurtherPair: PikeStructureSeparator PikeMappingPair { # $item[2] is a PikeMappingPair, hence a reference to an array # containing a QuotedString (the first) and a PikeValue, hence: # - a reference to an array or hash (if Pikevalue ~ PikeStructure) # - a scalar (if PikeValue ~ QuotedString or Number) $return = $item[2] ; } PikeValue: PikeStructure | QuotedString | Number { # $item[1] is: # - a reference to an array or hash (if PikeStructure) # - a scalar (if QuotedString or Number) $return = $item[1] ; }