#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11147096 use warnings; my $testdata = < $2 } ] : /\G([^{}\s]+) \{/gc ? [ @$e, { "$1" => (expr(), /\G\}/gc || die pos($_), ' missing }', substr $_, pos($_))[0] } ] : /\G([^{}\s]+)/gc ? [ @$e, $1 ] : return $e while 1; } use List::AllUtils qw( all ); sub fixhash { local $_ = shift; return ref $_ eq 'ARRAY' ? ( all { ref $_ eq 'HASH' } @$_ ) ? { map fixhash($_), map %$_, @$_ } : [ map fixhash($_), @$_ ] : ref $_ eq 'HASH' ? { map fixhash($_), %$_ } : $_; } local $_ = $testdata; # NOTE expr() expects input in $_ my $parse = fixhash expr(); pos($_) < length $_ and die "incomplete parse ", substr $_, pos($_); use Data::Dump 'dd'; dd $parse;