Blender V4.3
expr_pylike_eval.c File Reference
#include <ctype.h>
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"

Go to the source code of this file.

Classes

struct  ExprOp
 
struct  ExprPyLike_Parsed
 
struct  BuiltinConstDef
 
struct  BuiltinOpDef
 
struct  KeywordTokenDef
 
struct  ExprParseState
 

Macros

#define FAIL_IF(condition)
 

Functions

Public API
void BLI_expr_pylike_free (ExprPyLike_Parsed *expr)
 
bool BLI_expr_pylike_is_valid (const ExprPyLike_Parsed *expr)
 
bool BLI_expr_pylike_is_constant (const ExprPyLike_Parsed *expr)
 
bool BLI_expr_pylike_is_using_param (const ExprPyLike_Parsed *expr, int index)
 
Stack Machine Evaluation
eExprPyLike_EvalStatus BLI_expr_pylike_eval (ExprPyLike_Parsed *expr, const double *param_values, int param_values_len, double *r_result)
 
Recursive Descent Parser
static bool parse_expr (ExprParseState *state)
 
static int parse_function_args (ExprParseState *state)
 
static bool parse_unary (ExprParseState *state)
 
static bool parse_mul (ExprParseState *state)
 
static bool parse_add (ExprParseState *state)
 
static BinaryOpFunc parse_get_cmp_func (short token)
 
static bool parse_cmp_chain (ExprParseState *state, BinaryOpFunc cur_func)
 
static bool parse_cmp (ExprParseState *state)
 
static bool parse_not (ExprParseState *state)
 
static bool parse_and (ExprParseState *state)
 
static bool parse_or (ExprParseState *state)
 
Main Parsing Function
ExprPyLike_ParsedBLI_expr_pylike_parse (const char *expression, const char **param_names, int param_names_len)
 

Expression Parser State

#define MAKE_CHAR2(a, b)   (((a) << 8) | (b))
 
#define CHECK_ERROR(condition)
 
#define TOKEN_ID   MAKE_CHAR2('I', 'D')
 
#define TOKEN_NUMBER   MAKE_CHAR2('0', '0')
 
#define TOKEN_GE   MAKE_CHAR2('>', '=')
 
#define TOKEN_LE   MAKE_CHAR2('<', '=')
 
#define TOKEN_NE   MAKE_CHAR2('!', '=')
 
#define TOKEN_EQ   MAKE_CHAR2('=', '=')
 
#define TOKEN_AND   MAKE_CHAR2('A', 'N')
 
#define TOKEN_OR   MAKE_CHAR2('O', 'R')
 
#define TOKEN_NOT   MAKE_CHAR2('N', 'O')
 
#define TOKEN_IF   MAKE_CHAR2('I', 'F')
 
#define TOKEN_ELSE   MAKE_CHAR2('E', 'L')
 
typedef struct KeywordTokenDef KeywordTokenDef
 
typedef struct ExprParseState ExprParseState
 
static const char * token_eq_characters = "!=><"
 
static const char * token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'"
 
static KeywordTokenDef keyword_list []
 
static ExprOpparse_alloc_ops (ExprParseState *state, int count)
 
static ExprOpparse_add_op (ExprParseState *state, eOpCode code, int stack_delta)
 
static int parse_add_jump (ExprParseState *state, eOpCode code)
 
static void parse_set_jump (ExprParseState *state, int jump)
 
static int opcode_arg_count (eOpCode code)
 
static bool parse_add_func (ExprParseState *state, eOpCode code, int args, void *funcptr)
 
static bool parse_next_token (ExprParseState *state)
 

Internal Types

enum  eOpCode {
  OPCODE_CONST , OPCODE_FUNC1 , OPCODE_FUNC2 , OPCODE_FUNC3 ,
  OPCODE_PARAMETER , OPCODE_MIN , OPCODE_MAX , OPCODE_JMP ,
  OPCODE_JMP_ELSE , OPCODE_JMP_OR , OPCODE_JMP_AND , OPCODE_CMP_CHAIN
}
 
typedef enum eOpCode eOpCode
 
typedef double(* UnaryOpFunc) (double)
 
typedef double(* BinaryOpFunc) (double, double)
 
typedef double(* TernaryOpFunc) (double, double, double)
 
typedef struct ExprOp ExprOp
 

Built-In Operations

typedef struct BuiltinConstDef BuiltinConstDef
 
typedef struct BuiltinOpDef BuiltinOpDef
 
static BuiltinConstDef builtin_consts []
 
static BuiltinOpDef builtin_ops []
 
static double op_negate (double arg)
 
static double op_mul (double a, double b)
 
static double op_div (double a, double b)
 
static double op_add (double a, double b)
 
static double op_sub (double a, double b)
 
static double op_radians (double arg)
 
static double op_degrees (double arg)
 
static double op_log2 (double a, double b)
 
static double op_lerp (double a, double b, double x)
 
static double op_clamp (double arg)
 
static double op_clamp3 (double arg, double minv, double maxv)
 
static double op_smoothstep (double a, double b, double x)
 
static double op_not (double a)
 
static double op_eq (double a, double b)
 
static double op_ne (double a, double b)
 
static double op_lt (double a, double b)
 
static double op_le (double a, double b)
 
static double op_gt (double a, double b)
 
static double op_ge (double a, double b)
 

Detailed Description

Simple evaluator for a subset of Python expressions that can be computed using purely double precision floating point values.

Supported subset:

  • Identifiers use only ASCII characters.
  • Literals: floating point and decimal integer.
  • Constants: pi, True, False
  • Operators: +, -, *, /, ==, !=, <, <=, >, >=, and, or, not, ternary if
  • Functions: min, max, radians, degrees, abs, fabs, floor, ceil, trunc, int, sin, cos, tan, asin, acos, atan, atan2, exp, log, sqrt, pow, fmod

The implementation has no global state and can be used multi-threaded.

Definition in file expr_pylike_eval.c.

Macro Definition Documentation

◆ CHECK_ERROR

#define CHECK_ERROR ( condition)
Value:
if (!(condition)) { \
return false; \
} \
((void)0)

Definition at line 438 of file expr_pylike_eval.c.

Referenced by parse_add(), parse_add_func(), parse_and(), parse_cmp(), parse_cmp_chain(), parse_expr(), parse_mul(), parse_next_token(), parse_not(), parse_or(), and parse_unary().

◆ FAIL_IF

#define FAIL_IF ( condition)
Value:
if (condition) { \
} \
((void)0)
@ EXPR_PYLIKE_FATAL_ERROR

Referenced by BLI_expr_pylike_eval().

◆ MAKE_CHAR2

#define MAKE_CHAR2 ( a,
b )   (((a) << 8) | (b))

Definition at line 436 of file expr_pylike_eval.c.

Referenced by parse_next_token().

◆ TOKEN_AND

#define TOKEN_AND   MAKE_CHAR2('A', 'N')

Definition at line 452 of file expr_pylike_eval.c.

Referenced by parse_and().

◆ TOKEN_ELSE

#define TOKEN_ELSE   MAKE_CHAR2('E', 'L')

Definition at line 456 of file expr_pylike_eval.c.

Referenced by parse_expr().

◆ TOKEN_EQ

#define TOKEN_EQ   MAKE_CHAR2('=', '=')

Definition at line 451 of file expr_pylike_eval.c.

Referenced by parse_get_cmp_func().

◆ TOKEN_GE

#define TOKEN_GE   MAKE_CHAR2('>', '=')

Definition at line 448 of file expr_pylike_eval.c.

Referenced by parse_get_cmp_func().

◆ TOKEN_ID

#define TOKEN_ID   MAKE_CHAR2('I', 'D')

Definition at line 446 of file expr_pylike_eval.c.

Referenced by parse_next_token(), and parse_unary().

◆ TOKEN_IF

#define TOKEN_IF   MAKE_CHAR2('I', 'F')

Definition at line 455 of file expr_pylike_eval.c.

Referenced by parse_expr().

◆ TOKEN_LE

#define TOKEN_LE   MAKE_CHAR2('<', '=')

Definition at line 449 of file expr_pylike_eval.c.

Referenced by parse_get_cmp_func().

◆ TOKEN_NE

#define TOKEN_NE   MAKE_CHAR2('!', '=')

Definition at line 450 of file expr_pylike_eval.c.

Referenced by parse_get_cmp_func().

◆ TOKEN_NOT

#define TOKEN_NOT   MAKE_CHAR2('N', 'O')

Definition at line 454 of file expr_pylike_eval.c.

Referenced by parse_not().

◆ TOKEN_NUMBER

#define TOKEN_NUMBER   MAKE_CHAR2('0', '0')

Definition at line 447 of file expr_pylike_eval.c.

Referenced by parse_next_token(), and parse_unary().

◆ TOKEN_OR

#define TOKEN_OR   MAKE_CHAR2('O', 'R')

Definition at line 453 of file expr_pylike_eval.c.

Referenced by parse_or().

Typedef Documentation

◆ BinaryOpFunc

typedef double(* BinaryOpFunc) (double, double)

Definition at line 81 of file expr_pylike_eval.c.

◆ BuiltinConstDef

typedef struct BuiltinConstDef BuiltinConstDef

◆ BuiltinOpDef

typedef struct BuiltinOpDef BuiltinOpDef

◆ eOpCode

typedef enum eOpCode eOpCode

◆ ExprOp

typedef struct ExprOp ExprOp

◆ ExprParseState

typedef struct ExprParseState ExprParseState

◆ KeywordTokenDef

typedef struct KeywordTokenDef KeywordTokenDef

◆ TernaryOpFunc

typedef double(* TernaryOpFunc) (double, double, double)

Definition at line 82 of file expr_pylike_eval.c.

◆ UnaryOpFunc

typedef double(* UnaryOpFunc) (double)

Definition at line 80 of file expr_pylike_eval.c.

Enumeration Type Documentation

◆ eOpCode

enum eOpCode
Enumerator
OPCODE_CONST 
OPCODE_FUNC1 
OPCODE_FUNC2 
OPCODE_FUNC3 
OPCODE_PARAMETER 
OPCODE_MIN 
OPCODE_MAX 
OPCODE_JMP 
OPCODE_JMP_ELSE 
OPCODE_JMP_OR 
OPCODE_JMP_AND 
OPCODE_CMP_CHAIN 

Definition at line 53 of file expr_pylike_eval.c.

Function Documentation

◆ BLI_expr_pylike_eval()

◆ BLI_expr_pylike_free()

void BLI_expr_pylike_free ( struct ExprPyLike_Parsed * expr)

Free the parsed data; NULL argument is ok.

Definition at line 112 of file expr_pylike_eval.c.

References MEM_freeN(), and NULL.

Referenced by BKE_driver_invalidate_expression(), driver_compile_simple_expr(), and fcurve_free_driver().

◆ BLI_expr_pylike_is_constant()

bool BLI_expr_pylike_is_constant ( const ExprPyLike_Parsed * expr)

◆ BLI_expr_pylike_is_using_param()

bool BLI_expr_pylike_is_using_param ( const ExprPyLike_Parsed * expr,
int index )

◆ BLI_expr_pylike_is_valid()

bool BLI_expr_pylike_is_valid ( const ExprPyLike_Parsed * expr)

Definition at line 119 of file expr_pylike_eval.c.

References NULL, and ExprPyLike_Parsed::ops_count.

Referenced by BLI_expr_pylike_eval().

◆ BLI_expr_pylike_parse()

ExprPyLike_Parsed * BLI_expr_pylike_parse ( const char * expression,
const char ** param_names,
int param_names_len )

Compile the expression and return the result.

Parse the expression for evaluation later. Returns non-NULL even on failure; use is_valid to check.

Definition at line 1057 of file expr_pylike_eval.c.

References BLI_assert, ExprPyLike_Parsed::max_stack, MEM_callocN, MEM_freeN(), MEM_mallocN, ExprPyLike_Parsed::ops, ExprPyLike_Parsed::ops_count, parse_expr(), parse_next_token(), and state.

Referenced by driver_compile_simple_expr_impl(), expr_pylike_const_test(), expr_pylike_parse_fail_test(), parse_for_eval(), TEST(), and TEST().

◆ op_add()

static double op_add ( double a,
double b )
static

Definition at line 295 of file expr_pylike_eval.c.

References b.

Referenced by parse_add().

◆ op_clamp()

static double op_clamp ( double arg)
static

Definition at line 325 of file expr_pylike_eval.c.

References CLAMP.

◆ op_clamp3()

static double op_clamp3 ( double arg,
double minv,
double maxv )
static

Definition at line 331 of file expr_pylike_eval.c.

References CLAMP.

◆ op_degrees()

static double op_degrees ( double arg)
static

Definition at line 310 of file expr_pylike_eval.c.

References M_PI.

◆ op_div()

static double op_div ( double a,
double b )
static

Definition at line 290 of file expr_pylike_eval.c.

References b.

Referenced by parse_mul().

◆ op_eq()

static double op_eq ( double a,
double b )
static

Definition at line 349 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_ge()

static double op_ge ( double a,
double b )
static

Definition at line 374 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_gt()

static double op_gt ( double a,
double b )
static

Definition at line 369 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_le()

static double op_le ( double a,
double b )
static

Definition at line 364 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_lerp()

static double op_lerp ( double a,
double b,
double x )
static

Definition at line 320 of file expr_pylike_eval.c.

References b, and x.

◆ op_log2()

static double op_log2 ( double a,
double b )
static

Definition at line 315 of file expr_pylike_eval.c.

References b, and log().

◆ op_lt()

static double op_lt ( double a,
double b )
static

Definition at line 359 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_mul()

static double op_mul ( double a,
double b )
static

Definition at line 285 of file expr_pylike_eval.c.

References b.

Referenced by parse_mul().

◆ op_ne()

static double op_ne ( double a,
double b )
static

Definition at line 354 of file expr_pylike_eval.c.

References b.

Referenced by parse_get_cmp_func().

◆ op_negate()

static double op_negate ( double arg)
static

Definition at line 280 of file expr_pylike_eval.c.

Referenced by parse_unary().

◆ op_not()

static double op_not ( double a)
static

Definition at line 344 of file expr_pylike_eval.c.

Referenced by parse_not().

◆ op_radians()

static double op_radians ( double arg)
static

Definition at line 305 of file expr_pylike_eval.c.

References M_PI.

◆ op_smoothstep()

static double op_smoothstep ( double a,
double b,
double x )
static

Definition at line 337 of file expr_pylike_eval.c.

References b, and CLAMP.

◆ op_sub()

static double op_sub ( double a,
double b )
static

◆ opcode_arg_count()

static int opcode_arg_count ( eOpCode code)
static

Definition at line 539 of file expr_pylike_eval.c.

References BLI_assert_msg, OPCODE_FUNC1, OPCODE_FUNC2, and OPCODE_FUNC3.

Referenced by parse_unary().

◆ parse_add()

static bool parse_add ( ExprParseState * state)
static

◆ parse_add_func()

static bool parse_add_func ( ExprParseState * state,
eOpCode code,
int args,
void * funcptr )
static

◆ parse_add_jump()

static int parse_add_jump ( ExprParseState * state,
eOpCode code )
static

Definition at line 525 of file expr_pylike_eval.c.

References parse_add_op(), and state.

Referenced by parse_and(), parse_expr(), and parse_or().

◆ parse_add_op()

static ExprOp * parse_add_op ( ExprParseState * state,
eOpCode code,
int stack_delta )
static

◆ parse_alloc_ops()

static ExprOp * parse_alloc_ops ( ExprParseState * state,
int count )
static

Definition at line 497 of file expr_pylike_eval.c.

References count, MEM_reallocN, power_of_2_max_i(), and state.

Referenced by parse_add_op(), and parse_expr().

◆ parse_and()

static bool parse_and ( ExprParseState * state)
static

◆ parse_cmp()

static bool parse_cmp ( ExprParseState * state)
static

◆ parse_cmp_chain()

◆ parse_expr()

◆ parse_function_args()

static int parse_function_args ( ExprParseState * state)
static

Definition at line 740 of file expr_pylike_eval.c.

References parse_expr(), parse_next_token(), and state.

Referenced by parse_unary().

◆ parse_get_cmp_func()

static BinaryOpFunc parse_get_cmp_func ( short token)
static

Definition at line 902 of file expr_pylike_eval.c.

References NULL, op_eq(), op_ge(), op_gt(), op_le(), op_lt(), op_ne(), TOKEN_EQ, TOKEN_GE, TOKEN_LE, and TOKEN_NE.

Referenced by parse_cmp(), and parse_cmp_chain().

◆ parse_mul()

static bool parse_mul ( ExprParseState * state)
static

◆ parse_next_token()

◆ parse_not()

static bool parse_not ( ExprParseState * state)
static

◆ parse_or()

static bool parse_or ( ExprParseState * state)
static

◆ parse_set_jump()

static void parse_set_jump ( ExprParseState * state,
int jump )
static

Definition at line 532 of file expr_pylike_eval.c.

References jump(), and state.

Referenced by parse_and(), parse_cmp_chain(), parse_expr(), and parse_or().

◆ parse_unary()

Variable Documentation

◆ builtin_consts

BuiltinConstDef builtin_consts[]
static
Initial value:
= {
{"pi", M_PI}, {"True", 1.0}, {"False", 0.0}, {NULL, 0.0}}
#define M_PI
#define NULL

Definition at line 384 of file expr_pylike_eval.c.

Referenced by parse_unary().

◆ builtin_ops

BuiltinOpDef builtin_ops[]
static
Initial value:
= {
{"radians", OPCODE_FUNC1, op_radians},
{"degrees", OPCODE_FUNC1, op_degrees},
{"abs", OPCODE_FUNC1, fabs},
{"fabs", OPCODE_FUNC1, fabs},
{"floor", OPCODE_FUNC1, floor},
{"ceil", OPCODE_FUNC1, ceil},
{"trunc", OPCODE_FUNC1, trunc},
{"round", OPCODE_FUNC1, round},
{"int", OPCODE_FUNC1, trunc},
{"sin", OPCODE_FUNC1, sin},
{"cos", OPCODE_FUNC1, cos},
{"tan", OPCODE_FUNC1, tan},
{"asin", OPCODE_FUNC1, asin},
{"acos", OPCODE_FUNC1, acos},
{"atan", OPCODE_FUNC1, atan},
{"atan2", OPCODE_FUNC2, atan2},
{"exp", OPCODE_FUNC1, exp},
{"log", OPCODE_FUNC1, log},
{"log", OPCODE_FUNC2, op_log2},
{"sqrt", OPCODE_FUNC1, sqrt},
{"pow", OPCODE_FUNC2, pow},
{"fmod", OPCODE_FUNC2, fmod},
{"lerp", OPCODE_FUNC3, op_lerp},
{"clamp", OPCODE_FUNC1, op_clamp},
{"clamp", OPCODE_FUNC3, op_clamp3},
{"smoothstep", OPCODE_FUNC3, op_smoothstep},
}
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
static double op_clamp3(double arg, double minv, double maxv)
static double op_smoothstep(double a, double b, double x)
static double op_lerp(double a, double b, double x)
@ OPCODE_FUNC3
@ OPCODE_FUNC2
@ OPCODE_CONST
@ OPCODE_FUNC1
static double op_degrees(double arg)
static double op_log2(double a, double b)
static double op_clamp(double arg)
static double op_radians(double arg)
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float3 ceil(const float3 a)
ccl_device_inline float3 cos(float3 v)
ccl_device_inline float3 log(float3 v)
T acos(const T &a)
T atan(const T &a)
T atan2(const T &y, const T &x)
T asin(const T &a)
T sin(const AngleRadianBase< T > &a)
T tan(const AngleRadianBase< T > &a)
T round(const T &a)

Definition at line 400 of file expr_pylike_eval.c.

Referenced by parse_unary().

◆ keyword_list

KeywordTokenDef keyword_list[]
static
Initial value:
= {
{"and", TOKEN_AND},
{"or", TOKEN_OR},
{"not", TOKEN_NOT},
{"if", TOKEN_IF},
{"else", TOKEN_ELSE},
}
#define TOKEN_ID
#define TOKEN_NOT
#define TOKEN_ELSE
#define TOKEN_OR
#define TOKEN_IF
#define TOKEN_AND

Definition at line 466 of file expr_pylike_eval.c.

Referenced by denoise_func(), merge_func(), and parse_next_token().

◆ token_characters

const char* token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'"
static

Definition at line 459 of file expr_pylike_eval.c.

Referenced by parse_next_token().

◆ token_eq_characters

const char* token_eq_characters = "!=><"
static

Definition at line 458 of file expr_pylike_eval.c.

Referenced by parse_next_token().