Identify files by (device, inode), not by path, so that symlinks,
relative paths, case-insensitive paths, or other edge cases
do not result in double includes.
Part of that condition's purpose is to ensure that we read the correct
lexer state; but it's possible now for the fstack to be non-empty
*before* the lexer state is registered, i.e. if there is an error
in the function that registers it.
This causes a NULL pointer deref.
- The '#' component for type 's' now escapes the string characters
- The '#' component for type 'f' now prints a precision suffix
- The new 'q' component specifies a precision value
* Implement a '#' prefix for raw identifiers that may alias keywords
* Review comments
* Disallow hashless raw identifiers in interpolations
* Run clang-format
- FIX: `Label & const` was not actually doing the `& const` masking
(fixes#1446)
- ADD: `LOW(Label)` can be constant if `Label` is aligned to 8 or more bits
(resolves#1444)
- ADD: `!expr` can be constant 0 if `expr` has any non-zero bits
(resolves#1447)
- `LOW()` and `HIGH()` have their own RPN operator values
(resolves#1445)
The change to RPN values means that the object file version was incremented.
This also refactors unary operators and functions, combining their
evaluation similarly to binary ones.
- Fixed-point formulas are implemented using IEEE-754 floating-point
internally, which could give infinity or NaN values whose conversion
to fixed-point integer was platform-dependent.
- Formatting fixed-point $8000_0000 (INT32_MIN, -2147483648) was
not putting the negative sign in front.
This way, if a child context initializes `\@`, the parent won't
reset it. And if the child context did not initialize `\@`,
then resetting it would be redundant.
This allows us to control the order in which sections are iterated,
instead of it depending on the internals of `std::map`. (This order
is arbitrary, but should be deterministic regardless.)