Applying the Refined Model to *(ptr + 1) = *ptr;
Let's break it down with int arr[5] = {1, 2, 3, 4, 5}; and int *ptr = arr; (so ptr points to arr[0]).
Evaluate RHS (*ptr):
The expression *ptr is on the RHS, so we need its rvalue.
First, evaluate ptr. ptr is a variable (an lvalue). In an rvalue context, it undergoes lvalue conversion. ⟦ptr⟧ → <address of arr[0]>.
Now evaluate *<address of arr[0]>. The * operator (dereference) reads the value at the given address.
⟦*ptr⟧ → 1 (the value stored in arr[0]). So, value_R is 1.
Evaluate LHS (*(ptr + 1)):
The expression *(ptr + 1) is on the LHS, so we need to find the location it designates (an lvalue).
First, evaluate the expression inside the parentheses: ptr + 1.
ptr evaluates to its value: ⟦ptr⟧ → <address of arr[0]>.
1 evaluates to 1.
Pointer arithmetic: ⟦<address of arr[0]> + 1⟧ → <address of arr[1]>. (The address is incremented by 1 * sizeof(int)).
Now evaluate the * operator applied to this address, in an lvalue context. The expression *<address of arr[1]> designates the memory location at that address.
⟦*(ptr + 1)⟧ → location corresponding to arr[1]. So, location_L is the memory slot for arr[1].
Store:
Store value_R (which is 1) into location_L (the memory for arr[1]).
The effect is that arr[1] now contains the value 1. The array becomes {1, 1, 3, 4, 5}.
Your original model was mostly correct but incomplete regarding the LHS of assignment. The LHS isn't ignored; it is evaluated, but its evaluation yields a location (lvalue), not necessarily a data value like the RHS. Expressions like *p or arr[i] or *(ptr + 1) can be lvalues – they designate specific, modifiable memory locations. Evaluating them on the LHS means figuring out which location they designate, potentially involving calculations like pointer arithmetic.
Think of it this way:
RHS Evaluation: "What is the value?"
LHS Evaluation: "What is the destination address/location?"