php - Parsing Preformatted Formula to Array Recursively -
i trying create formula parser , stuck on how recursively convert code array of expressions. take following formula example:
$formula = " @var[a, 3]; @if[ (a <= 3) & (a = 3) ]: @var[a, + 4]; @if[ > 5 ]: @use[a]; @endif @elseif[ > 4 ]: @var[a, 2]; @else: @var[a, 5]; @endif @var[a,5]; @use[a]; ";
should output:
{ "0": "var[a, 3];", "if[ (a <= 3) & (a = 3) ]:": { "0": "var[a, + 4];", "1": "endif", "if[ > 5 ]:": [ "use[a];" ] }, "elseif[ > 4 ]:": [ "var[a, 2];" ], "else:": [ "var[a, 5];" ], "1": "endif", "2": "var[a,5];", "3": "use[a];", }
so can iterate through each item , evaluate each expression.
i have following code, doesn't output expected format.
<?php $formula = " @var[a, 3]; @if[ (a <= 3) & (a = 3) ]: @var[a, + 4]; @if[ > 5 ]: @use[a]; @endif @elseif[ > 4 ]: @var[a, 2]; @else: @var[a, 5]; @endif @var[a,5]; @use[a]; "; $formulas = explode( "@", $formula ); $result = parse( $formulas ); echo json_encode( $result ); function parse( $lines ){ $exec_tree = array(); foreach( $lines $i => $block ){ unset( $lines[$i] ); $block = trim( str_replace( array(" ") , "" , preg_replace('/\s\s+/', ' ', $block) ) ); if( trim( $block ) != "" ){ // match variable assignments if( preg_match('/var\[(.*)\]\;?/', $block ) ){ $exec_tree[] = $block; } // match use statements if( preg_match('/use\[(.*)\]\;?/', $block ) ){ $exec_tree[] = $block; } // match ifs if( preg_match('/^if\[(.*)\]\:/', $block ) ){ $exec_tree[$block] = parse( $lines ); } // match elseifs if( preg_match('/^elseif\[(.*)\]\:/', $block ) ){ $exec_tree[$block] = parse( $lines ); } // match elses if( preg_match('/^else:/', $block ) ){ $exec_tree[$block] = parse( $lines ); } // match endifs if( preg_match('/^endif/', $block ) ){ break; } } } return $exec_tree; }
the code recursive in nature, think missing termination of recursion. it's supposed end on endif keywords. can point me right direction appreciated.
this output now: (json formatted)
[ "var[a,3];", [ "if[(a<=3)&(a=3)]:", [ "var[a,a+4];", [ "if[a>5]:", [ "use[a];" ] ], "use[a];" ] ], "var[a,a+4];", [ "if[a>5]:", [ "use[a];" ] ], "use[a];"
]
thanks,
jan
admittedly not entirely clean solution, working , easy refactor:
<?php $formula = " @var[a, 3]; @if[ (a <= 3) & (a = 3) ]: @var[a, + 4]; @if[ > 5 ]: @use[a]; @endif @elseif[ > 4 ]: @var[a, 2]; @else: @var[a, 5]; @endif @var[a,5]; @use[a]; "; $formulas = explode( "@", $formula ); $rec = false; $result = parse( $formulas, $rec ); echo json_encode( $result, json_pretty_print ); function parse( &$lines, &$rec ) { $exec_tree = array(); while ( (bool) $lines === true ) { $block = array_shift( $lines ); $block = trim( str_replace( array( " " ), "", preg_replace( '/\s\s+/', ' ', $block ) ) ); if ( trim( $block ) != "" ) { // match variable assignments if ( preg_match( '/var\[(.*)\]\;?/', $block ) ) { $exec_tree[] = $block; } elseif ( preg_match( '/use\[(.*)\]\;?/', $block ) ) { $exec_tree[] = $block; } elseif ( preg_match( '/^if\[(.*)\]\:/', $block ) ) { $rec = true; $exec_tree[ $block ] = parse( $lines, $rec ); } elseif ( preg_match( '/^elseif\[(.*)\]\:/', $block ) ) { $rec = !$rec; if ( $rec === false ) { array_unshift( $lines, $block ); break; } else { $exec_tree[ $block ] = parse( $lines, $rec ); } } elseif ( preg_match( '/^else:/', $block ) ) { $rec = !$rec; if ( $rec === false ) { array_unshift( $lines, $block ); break; } else { $exec_tree[ $block ] = parse( $lines, $rec ); } } elseif ( preg_match( '/^endif/', $block ) ) { $rec = !$rec; if ( $rec === false ) { array_unshift( $lines, $block ); break; } else { $exec_tree[] = $block; } } } } return $exec_tree; }
returns
{ "0": "var[a,3];", "if[(a<=3)&(a=3)]:": { "0": "var[a,a+4];", "if[a>5]:": [ "use[a];" ], "1": "endif" }, "elseif[a>4]:": [ "var[a,2];" ], "else:": [ "var[a,5];" ], "1": "endif", "2": "var[a,5];", "3": "use[a];" }
the trick somehow keep track of whether or not you're in block , break out on else,elseif , endif, though still appending values end result.
Comments
Post a Comment