This is relatively easy with PixelMath, but you need multiple expressions and symbols.
Let's define the 'shadows', 'midtones' and 'highlights' sets as a function of two variables, a and b, as follows:
x pertains to shadows if 0 <= x < a
x pertains to midtones if a <= x < b
x pertains to highlights if b <= x < 1
where we are working in the normalized real range [0,1] (0=black and 1=white). Now assume that we want to multiply the shadows set by a constant k1, the midtones set by k2, and the highlights set by k3. This allows us to implement a three-step linear function. The PixelMath implementation is the following:
1. Uncheck the ''Use a single RGB/K expression" option, so we can specify three per-channel expressions.
2. Uncheck the ''Rescale result" option.
3. Define a variable L and five constants: a, b, k1, k2 and k3. For example, we can write this in the Symbols slot of PixelMath:
L, a=0.25, b=0.60, k1=0.90, k2=1.02, k3=0.95
4. Enter the following expressions:
R/K:
L = CIEL( $T ); $T*iif( L < a, k1, iif( L < b, k2, k3 ) )
G:
$T
B:
$T
These PixelMath expressions implement hard sets, i.e. sets without intersections. An improvement is to implement fuzzy sets, where a pixel can be a member of more than one set at the same time, in different degrees. This implementation is more complex but more useful and flexible. Any takers? >:D
Another way to implement this color correction is with the CurvesTransformation tool, applying per-channel curves with a luminance mask.
Let me know if this helps.