Bug
memcmp(str, name, len); lets memcmp() compare the first len bytes of the data pointed to by str and name, yet some of those are pointers to a string less than len in size. What code needs is strncmp() (or perhaps even strcmp()) to not compare past the end of the string.
Bug
The *(const char **)strp += len relies on bsearch() to stop calling cmp() once a return value of 0 occurs. Although this is common, bsearch()is not specified that way. Instead the calling code should advance the pointer, not the compare function.
Pedantic Bug
str[len]-name[len] in compar() should be an unsigned char compare to well sort symbols that have a character outside the [0...CHAR_MAX] range. Yet since, presently, symbols[] only employs ASCII characters, it does not make a difference.
Non-standard macros
M_PI and its 13 friends are not part of the C standard. See Using M_PI. Consider
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
Lack of comments
Functions deserve at least a little description to indicate its role.
Consider long double
Consider using the most precise/widest range floating point type available.
Use a more precise output
Rather than only 6 digits, use the precision of the type:
// printf("%g\n", some_double)
printf("%.*g\n", DBL_DIG, some_double)
Missing break;
case '(': { .. deserves a break; at the end of the case or a comment indicating fall-through was desired.
double expr() missing return value;
TBD code needed to quiet "Problem description: No return, in function returning non-void".
Minor:
Excessive use of const object
object would simplify code presentation in many places where there is only a few lines of code.
Example:
// const double val = expr(str, 0);
double val = expr(str, 0);
if (*(*str)++ == ')')
return val;
Format to presentation width
Use an auto-formatter and present to the display width (e.g. ~82)
1 2 3 4 5 6 7 8 9
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
// const Symbol *const symbol = bsearch(str, symbols, sizeof(symbols)/sizeof(Symbol), sizeof(Symbol), compar);
const Symbol *const symbol = bsearch(str, symbols,
sizeof(symbols)/sizeof(Symbol), sizeof(Symbol), compar);
Note the () are not needed with sizeof object.
Avoid names that differ only in case
// v----v v----v
const Symbol *const symbol
Vertical spacing
Between functions, types, consider a blank line.