@ -167,7 +167,7 @@ static double eval_expr(Parser * p, AVExpr * e) {
return NAN ;
}
static AVExpr * parse_expr ( Parser * p ) ;
static int parse_expr ( AVExpr * * e , Parser * p ) ;
void ff_free_expr ( AVExpr * e ) {
if ( ! e ) return ;
@ -176,20 +176,22 @@ void ff_free_expr(AVExpr * e) {
av_freep ( & e ) ;
}
static AVExpr * parse_primary ( Parser * p ) {
static int parse_primary ( AVExpr * * e , Parser * p )
{
AVExpr * d = av_mallocz ( sizeof ( AVExpr ) ) ;
char * next = p - > s ;
int i ;
int ret , i ;
if ( ! d )
return NULL ;
return AVERROR ( ENOMEM ) ;
/* number */
d - > value = av_strtod ( p - > s , & next ) ;
if ( next ! = p - > s ) {
d - > type = e_value ;
p - > s = next ;
return d ;
* e = d ;
return 0 ;
}
d - > value = 1 ;
@ -199,7 +201,8 @@ static AVExpr * parse_primary(Parser *p) {
p - > s + = strlen ( p - > const_name [ i ] ) ;
d - > type = e_const ;
d - > a . const_index = i ;
return d ;
* e = d ;
return 0 ;
}
}
@ -208,29 +211,34 @@ static AVExpr * parse_primary(Parser *p) {
av_log ( p , AV_LOG_ERROR , " undefined constant or missing ( \n " ) ;
p - > s = next ;
ff_free_expr ( d ) ;
return NULL ;
return AVERROR ( EINVAL ) ;
}
p - > s + + ; // "("
if ( * next = = ' ( ' ) { // special case do-nothing
av_freep ( & d ) ;
d = parse_expr ( p ) ;
if ( ( ret = parse_expr ( & d , p ) ) < 0 )
return ret ;
if ( p - > s [ 0 ] ! = ' ) ' ) {
av_log ( p , AV_LOG_ERROR , " missing ) \n " ) ;
ff_free_expr ( d ) ;
return NULL ;
return AVERROR ( EINVAL ) ;
}
p - > s + + ; // ")"
return d ;
* e = d ;
return 0 ;
}
if ( ( ret = parse_expr ( & ( d - > param [ 0 ] ) , p ) ) < 0 ) {
ff_free_expr ( d ) ;
return ret ;
}
d - > param [ 0 ] = parse_expr ( p ) ;
if ( p - > s [ 0 ] = = ' , ' ) {
p - > s + + ; // ","
d - > param [ 1 ] = parse_expr ( p ) ;
parse_expr ( & d - > param [ 1 ] , p ) ;
}
if ( p - > s [ 0 ] ! = ' ) ' ) {
av_log ( p , AV_LOG_ERROR , " missing ) \n " ) ;
ff_free_expr ( d ) ;
return NULL ;
return AVERROR ( EINVAL ) ;
}
p - > s + + ; // ")"
@ -265,7 +273,8 @@ static AVExpr * parse_primary(Parser *p) {
if ( strmatch ( next , p - > func1_name [ i ] ) ) {
d - > a . func1 = p - > func1 [ i ] ;
d - > type = e_func1 ;
return d ;
* e = d ;
return 0 ;
}
}
@ -273,16 +282,18 @@ static AVExpr * parse_primary(Parser *p) {
if ( strmatch ( next , p - > func2_name [ i ] ) ) {
d - > a . func2 = p - > func2 [ i ] ;
d - > type = e_func2 ;
return d ;
* e = d ;
return 0 ;
}
}
av_log ( p , AV_LOG_ERROR , " unknown function \n " ) ;
ff_free_expr ( d ) ;
return NULL ;
return AVERROR ( EINVAL ) ;
}
return d ;
* e = d ;
return 0 ;
}
static AVExpr * new_eval_expr ( int type , int value , AVExpr * p0 , AVExpr * p1 ) {
@ -296,67 +307,116 @@ static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){
return e ;
}
static AVExpr * parse_pow ( Parser * p , int * sign ) {
static int parse_pow ( AVExpr * * e , Parser * p , int * sign )
{
* sign = ( * p - > s = = ' + ' ) - ( * p - > s = = ' - ' ) ;
p - > s + = * sign & 1 ;
return parse_primary ( p ) ;
return parse_primary ( e , p ) ;
}
static AVExpr * parse_factor ( Parser * p ) {
int sign , sign2 ;
AVExpr * e = parse_pow ( p , & sign ) ;
static int parse_factor ( AVExpr * * e , Parser * p )
{
int sign , sign2 , ret ;
AVExpr * e0 , * e1 , * e2 ;
if ( ( ret = parse_pow ( & e0 , p , & sign ) ) < 0 )
return ret ;
while ( p - > s [ 0 ] = = ' ^ ' ) {
e1 = e0 ;
p - > s + + ;
e = new_eval_expr ( e_pow , 1 , e , parse_pow ( p , & sign2 ) ) ;
if ( ! e )
return NULL ;
if ( e - > param [ 1 ] ) e - > param [ 1 ] - > value * = ( sign2 | 1 ) ;
if ( ( ret = parse_pow ( & e2 , p , & sign2 ) ) < 0 ) {
ff_free_expr ( e1 ) ;
return ret ;
}
e0 = new_eval_expr ( e_pow , 1 , e1 , e2 ) ;
if ( ! e0 ) {
ff_free_expr ( e1 ) ;
ff_free_expr ( e2 ) ;
return AVERROR ( ENOMEM ) ;
}
if ( e0 - > param [ 1 ] ) e0 - > param [ 1 ] - > value * = ( sign2 | 1 ) ;
}
if ( e ) e - > value * = ( sign | 1 ) ;
return e ;
if ( e0 ) e0 - > value * = ( sign | 1 ) ;
* e = e0 ;
return 0 ;
}
static AVExpr * parse_term ( Parser * p ) {
AVExpr * e = parse_factor ( p ) ;
static int parse_term ( AVExpr * * e , Parser * p )
{
int ret ;
AVExpr * e0 , * e1 , * e2 ;
if ( ( ret = parse_factor ( & e0 , p ) ) < 0 )
return ret ;
while ( p - > s [ 0 ] = = ' * ' | | p - > s [ 0 ] = = ' / ' ) {
int c = * p - > s + + ;
e = new_eval_expr ( c = = ' * ' ? e_mul : e_div , 1 , e , parse_factor ( p ) ) ;
if ( ! e )
return NULL ;
e1 = e0 ;
if ( ( ret = parse_factor ( & e2 , p ) ) < 0 ) {
ff_free_expr ( e1 ) ;
return ret ;
}
e0 = new_eval_expr ( c = = ' * ' ? e_mul : e_div , 1 , e1 , e2 ) ;
if ( ! e0 ) {
ff_free_expr ( e1 ) ;
ff_free_expr ( e2 ) ;
return AVERROR ( ENOMEM ) ;
}
}
return e ;
* e = e0 ;
return 0 ;
}
static AVExpr * parse_subexpr ( Parser * p ) {
AVExpr * e = parse_term ( p ) ;
static int parse_subexpr ( AVExpr * * e , Parser * p )
{
int ret ;
AVExpr * e0 , * e1 , * e2 ;
if ( ( ret = parse_term ( & e0 , p ) ) < 0 )
return ret ;
while ( * p - > s = = ' + ' | | * p - > s = = ' - ' ) {
e = new_eval_expr ( e_add , 1 , e , parse_term ( p ) ) ;
if ( ! e )
return NULL ;
e1 = e0 ;
if ( ( ret = parse_term ( & e2 , p ) ) < 0 ) {
ff_free_expr ( e1 ) ;
return ret ;
}
e0 = new_eval_expr ( e_add , 1 , e1 , e2 ) ;
if ( ! e0 ) {
ff_free_expr ( e1 ) ;
ff_free_expr ( e2 ) ;
return AVERROR ( ENOMEM ) ;
}
} ;
return e ;
* e = e0 ;
return 0 ;
}
static AVExpr * parse_expr ( Parser * p ) {
AVExpr * e ;
static int parse_expr ( AVExpr * * e , Parser * p )
{
int ret ;
AVExpr * e0 , * e1 , * e2 ;
if ( p - > stack_index < = 0 ) //protect against stack overflows
return NULL ;
return AVERROR ( EINVAL ) ;
p - > stack_index - - ;
e = parse_subexpr ( p ) ;
if ( ( r et = parse_subexpr ( & e0 , p ) ) < 0 )
return ret ;
while ( * p - > s = = ' ; ' ) {
e1 = e0 ;
if ( ( ret = parse_subexpr ( & e2 , p ) ) < 0 ) {
ff_free_expr ( e1 ) ;
return ret ;
}
p - > s + + ;
e = new_eval_expr ( e_last , 1 , e , parse_subexpr ( p ) ) ;
if ( ! e )
return NULL ;
e0 = new_eval_expr ( e_last , 1 , e1 , e2 ) ;
if ( ! e0 ) {
ff_free_expr ( e1 ) ;
ff_free_expr ( e2 ) ;
return AVERROR ( ENOMEM ) ;
}
} ;
p - > stack_index + + ;
return e ;
* e = e0 ;
return 0 ;
}
static int verify_expr ( AVExpr * e ) {
@ -373,7 +433,7 @@ static int verify_expr(AVExpr * e) {
}
}
AVExpr * ff_parse_expr ( const char * s ,
int ff_parse_expr ( AVExpr * * expr , const char * s ,
const char * const * const_name ,
const char * const * func1_name , double ( * const * func1 ) ( void * , double ) ,
const char * const * func2_name , double ( * const * func2 ) ( void * , double , double ) ,
@ -383,9 +443,10 @@ AVExpr *ff_parse_expr(const char *s,
AVExpr * e = NULL ;
char * w = av_malloc ( strlen ( s ) + 1 ) ;
char * wp = w ;
int ret = 0 ;
if ( ! w )
goto end ;
return AVERROR ( ENOMEM ) ;
while ( * s )
if ( ! isspace ( * s + + ) ) * wp + + = s [ - 1 ] ;
@ -402,14 +463,17 @@ AVExpr *ff_parse_expr(const char *s,
p . log_offset = log_offset ;
p . log_ctx = log_ctx ;
e = parse_expr ( & p ) ;
if ( ( ret = parse_expr ( & e , & p ) ) < 0 )
goto end ;
if ( ! verify_expr ( e ) ) {
ff_free_expr ( e ) ;
e = NULL ;
ret = AVERROR ( EINVAL ) ;
goto end ;
}
* expr = e ;
end :
av_free ( w ) ;
return e ;
return r et ;
}
double ff_eval_expr ( AVExpr * e , const double * const_value , void * opaque ) {
@ -420,18 +484,22 @@ double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) {
return eval_expr ( & p , e ) ;
}
double ff_parse_and_eval_expr ( const char * s ,
int ff_parse_and_eval_expr ( double * d , const char * s ,
const char * const * const_name , const double * const_value ,
const char * const * func1_name , double ( * const * func1 ) ( void * , double ) ,
const char * const * func2_name , double ( * const * func2 ) ( void * , double , double ) ,
void * opaque , int log_offset , void * log_ctx )
{
AVExpr * e = ff_parse_expr ( s , const_name , func1_name , func1 , func2_name , func2 , log_offset , log_ctx ) ;
double d ;
if ( ! e ) return NAN ;
d = ff_eval_expr ( e , const_value , opaque ) ;
AVExpr * e = NULL ;
int ret = ff_parse_expr ( & e , s , const_name , func1_name , func1 , func2_name , func2 , log_offset , log_ctx ) ;
if ( ret < 0 ) {
* d = NAN ;
return ret ;
}
* d = ff_eval_expr ( e , const_value , opaque ) ;
ff_free_expr ( e ) ;
return d ;
return isnan ( * d ) ? AVERROR ( EINVAL ) : 0 ;
}
# ifdef TEST
@ -448,12 +516,15 @@ static const char *const_names[]={
} ;
int main ( void ) {
int i ;
printf ( " %f == 12.7 \n " , ff_parse_and_eval_expr ( " 1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1) " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , 0 , NULL ) ) ;
printf ( " %f == 0.931322575 \n " , ff_parse_and_eval_expr ( " 80G/80Gi " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , NULL ) ) ;
double d ;
ff_parse_and_eval_expr ( & d , " 1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1) " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , 0 , NULL ) ;
printf ( " %f == 12.7 \n " , d ) ;
ff_parse_and_eval_expr ( & d , " 80G/80Gi " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , NULL ) ;
printf ( " %f == 0.931322575 \n " , d ) ;
for ( i = 0 ; i < 1050 ; i + + ) {
START_TIMER
ff_parse_and_eval_expr ( " 1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1) " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , 0 , NULL ) ;
ff_parse_and_eval_expr ( & d , " 1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1) " , const_names , const_values , NULL , NULL , NULL , NULL , NULL , 0 , NULL ) ;
STOP_TIMER ( " ff_parse_and_eval_expr " )
}
return 0 ;