diff --git a/compiler/src/main/pascal/uSemantic.pas b/compiler/src/main/pascal/uSemantic.pas index d3909ba..0a720c4 100644 --- a/compiler/src/main/pascal/uSemantic.pas +++ b/compiler/src/main/pascal/uSemantic.pas @@ -4008,6 +4008,18 @@ var begin Result := AElem; if AElem = '' then Exit; + { Radix-prefixed integer literal — $hex, %binary, &octal (with optional + leading sign). The lexer keeps the prefixed form in the token text, but + the rest of the const-array pipeline (codegen, OPDF) expects a plain + decimal string. Fold through ParseIntLiteral, the same canonical parser + the parser uses for scalar/typed consts, so all three radixes behave + identically inside an array initialiser. } + if AElem[0] = '$' then Exit(IntToStr(ParseIntLiteral(AElem))); + if AElem[0] = '%' then Exit(IntToStr(ParseIntLiteral(AElem))); + if AElem[0] = '&' then Exit(IntToStr(ParseIntLiteral(AElem))); + if (Length(AElem) > 1) and (AElem[0] = '-') and + ((AElem[1] = '$') or (AElem[1] = '%') or (AElem[1] = '&')) then + Exit(IntToStr(-ParseIntLiteral(StrCopyTail(AElem, 1)))); { Already a numeric literal (int, negative int, or float) — leave as is. } if IsPlainInt(AElem) then Exit; if (AElem[0] >= '0') and (AElem[0] <= '9') then Exit; diff --git a/docs/language-rationale.adoc b/docs/language-rationale.adoc index e313e12..a86ff96 100644 --- a/docs/language-rationale.adoc +++ b/docs/language-rationale.adoc @@ -583,6 +583,32 @@ The bit pattern is preserved in every case; the literal type only selects which signed/unsigned interpretation the surrounding expression sees. +==== Radix prefixes + +Integer literals may be written in four radixes, following FPC (not +Delphi): + +* decimal — `42` +* hexadecimal — `$2A` (also Delphi) +* binary — `%101010` (Delphi 11+ also accepts this) +* octal — `&52` (FPC only; Delphi has never supported octal — there `&` + is the identifier-escape prefix) + +Underscore digit separators are permitted in any radix (`$FF_FF`, +`%1010_1010`). All four forms are accepted everywhere an integer literal +is — scalar and typed constants, expressions, static-array bounds, and +*array-constant element lists*. The last was the gap behind issue #129: +`array[0..1] of Int64 = ($1, $2)` rejected the hex elements while the +scalar form `= $1` accepted them. Array-constant elements now fold +through the same `ParseIntLiteral` radix parser the rest of the compiler +uses, so every radix behaves identically inside an initialiser. + +The decision to keep FPC's `&` octal (rather than Delphi's no-octal / +`&`-as-escape) follows the project rule of preferring FPC syntax where the +two dialects diverge; the lexer already tokenised all four radixes, so the +fix only made the array-constant path consistent with the rest of the +language. + ==== Built-in constant `MaxInt: Integer = 2147483647` is a compiler built-in constant. It