Handle more numeric literal syntax errors in linker scripts

This commit is contained in:
Rangi
2026-06-09 18:44:03 -04:00
parent 0b91bf654b
commit fc7d9ad573
5 changed files with 69 additions and 38 deletions
+37 -30
View File
@@ -97,27 +97,39 @@ static std::string readKeyword(int initial) {
template<uint32_t Base>
requires ValidBaseV<Base>
static yy::parser::symbol_type readNumber(int initial, char const *prefix, char const *name) {
static yy::parser::symbol_type readNumber(int initial, char const *prefix) {
LexerStackEntry &context = lexerStack.back();
uint32_t number;
bool empty;
if constexpr (Base == 10) {
assume(prefix == nullptr && name == nullptr);
assume(prefix == nullptr);
number = parseDigit<Base>(initial);
empty = false;
} else {
assume(initial == 0 && prefix != nullptr && name != nullptr);
int c = context.file.sgetc();
if (!isDigit<Base>(c)) {
scriptError("No %s digits found after %s", name, prefix);
return yy::parser::make_number(0);
}
number = parseDigit<Base>(c);
context.file.sbumpc();
assume(initial == 0 && prefix != nullptr);
number = 0;
empty = true;
}
for (int c = context.file.sgetc(); isDigit<Base>(c) || c == '_'; c = context.file.snextc()) {
bool prevWasSeparator = false;
for (int c = context.file.sgetc();; c = context.file.snextc()) {
if (c == '_') {
if (prevWasSeparator) {
scriptError("Invalid integer constant, '_' after another '_'");
}
prevWasSeparator = true;
continue;
}
if (!isDigit<Base>(c)) {
break;
}
uint32_t digit = parseDigit<Base>(c);
empty = false;
prevWasSeparator = false;
if (number > (UINT32_MAX - digit) / Base) {
scriptWarning(WARNING_LARGE_CONSTANT, "Integer constant is too large");
// Discard any additional digits
@@ -127,21 +139,16 @@ static yy::parser::symbol_type readNumber(int initial, char const *prefix, char
}
number = number * Base + digit;
}
if (empty) {
scriptError("Invalid integer constant, no digits after %s", prefix);
}
if (prevWasSeparator) {
scriptError("Invalid integer constant, trailing '_'");
}
return yy::parser::make_number(number);
}
static yy::parser::symbol_type parseBinNumber(char const *prefix) {
return readNumber<2>(0, prefix, "binary");
}
static yy::parser::symbol_type parseOctNumber(char const *prefix) {
return readNumber<8>(0, prefix, "octal");
}
static yy::parser::symbol_type parseHexNumber(char const *prefix) {
return readNumber<16>(0, prefix, "hexadecimal");
}
static yy::parser::symbol_type parseAnyNumber(int initial) {
LexerStackEntry &context = lexerStack.back();
if (initial == '0') {
@@ -149,18 +156,18 @@ static yy::parser::symbol_type parseAnyNumber(int initial) {
case 'x':
case 'X':
context.file.sbumpc();
return parseHexNumber("\"0x\"");
return readNumber<16>(0, "\"0x\"");
case 'o':
case 'O':
context.file.sbumpc();
return parseOctNumber("\"0o\"");
return readNumber<8>(0, "\"0o\"");
case 'b':
case 'B':
context.file.sbumpc();
return parseBinNumber("\"0b\"");
return readNumber<2>(0, "\"0b\"");
}
}
return readNumber<10>(initial, nullptr, nullptr);
return readNumber<10>(initial, nullptr);
}
static yy::parser::symbol_type parseString() {
@@ -226,11 +233,11 @@ yy::parser::symbol_type yylex() {
} else if (c == '"') {
return parseString();
} else if (c == '$') {
return parseHexNumber("'$'");
return readNumber<16>(0, "'$'");
} else if (c == '%') {
return parseBinNumber("'%'");
return readNumber<2>(0, "'%'");
} else if (c == '&') {
return parseOctNumber("'&'");
return readNumber<8>(0, "'&'");
} else if (isDigit<10>(c)) {
return parseAnyNumber(c);
} else if (isLetter(c)) {
+1 -1
View File
@@ -1,3 +1,3 @@
error: No hexadecimal digits found after '$'
error: Invalid integer constant, no digits after '$'
at script-lone-dollar.link(1)
Linking failed with 1 error
+1 -1
View File
@@ -1,3 +1,3 @@
error: No binary digits found after '%'
error: Invalid integer constant, no digits after '%'
at script-lone-percent.link(1)
Linking failed with 1 error
+7 -5
View File
@@ -1,9 +1,11 @@
ROM0
org 4_2
org %10_10_10
org &52_
org $2A_
org 0b101_010
org 0o5_2
org &52_ ; trailing '_'
org $2A_ ; trailing '_'
org 0b101__010 ; '_' after another '_'
org 0o__5_2 ; '_' after another '_'
org 0x2_A
org 41 ; Error!
org 41 ; different value
org %_ ; no digits
org 0x__ ; no digits
+23 -1
View File
@@ -1,3 +1,25 @@
error: Invalid integer constant, trailing '_'
at script-num-fmt.link(4)
error: Invalid integer constant, trailing '_'
at script-num-fmt.link(5)
error: Invalid integer constant, '_' after another '_'
at script-num-fmt.link(6)
error: Invalid integer constant, '_' after another '_'
at script-num-fmt.link(7)
error: Cannot decrease the current address (from $002a to $0029)
at script-num-fmt.link(9)
Linking failed with 1 error
error: Invalid integer constant, no digits after '%'
at script-num-fmt.link(10)
error: Invalid integer constant, trailing '_'
at script-num-fmt.link(10)
error: Cannot decrease the current address (from $002a to $0000)
at script-num-fmt.link(10)
error: Invalid integer constant, '_' after another '_'
at script-num-fmt.link(11)
error: Invalid integer constant, no digits after "0x"
at script-num-fmt.link(11)
error: Invalid integer constant, trailing '_'
at script-num-fmt.link(11)
error: Cannot decrease the current address (from $002a to $0000)
at script-num-fmt.link(11)
Linking failed with 12 errors