Implement CHARVAL function (#1701)

This commit is contained in:
Rangi
2025-06-12 17:21:12 -04:00
committed by GitHub
parent fa9e29e4ce
commit 089e366ddc
7 changed files with 82 additions and 7 deletions

View File

@@ -3,6 +3,7 @@
#ifndef RGBDS_ASM_CHARMAP_HPP
#define RGBDS_ASM_CHARMAP_HPP
#include <optional>
#include <stdint.h>
#include <string>
#include <string_view>
@@ -22,6 +23,7 @@ void charmap_CheckStack();
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
bool charmap_HasChar(std::string const &mapping);
size_t charmap_CharSize(std::string const &mapping);
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx);
std::vector<int32_t> charmap_Convert(std::string const &input);
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
std::string charmap_Reverse(std::vector<int32_t> const &value, bool &unique);

View File

@@ -608,14 +608,21 @@ The following functions operate on string expressions, but return integers.
.It Fn CHARLEN str Ta Returns the number of charmap entries in Ar str No with the current charmap .
.It Fn CHARCMP str1 str2 Ta Compares Ar str1 No and Ar str2 No according to their charmap entry values with the current charmap. Returns -1 if Ar str1 No is lower than Ar str2 Ns , 1 if Ar str1 No is greater than Ar str2 Ns , or 0 if they match.
.It Fn CHARSIZE char Ta Returns how many values are in the charmap entry for Ar char No with the current charmap.
.It Fn CHARVAL char idx Ta Returns the value at Ar idx No of the charmap entry for Ar char Ns .
.El
.Pp
Note that the first character of a string is at index 0, and the last is at index -1.
Note that indexes count starting from 0 at the beginning, or from -1 at the end.
The characters of a string are counted by
.Ql STRLEN ;
the charmap entries of a string are counted by
.Ql CHARLEN ;
and the values of a charmap entry are counted by
.Ql CHARSIZE .
.Pp
The following legacy functions are similar to other functions that operate on string expressions, but for historical reasons, they count characters starting from
The following legacy functions are similar to other functions that operate on string expressions, but for historical reasons, they count starting from
.Em position 1 ,
not from index 0!
(Position -1 still counts from the last character.)
(Position -1 still counts from the end.)
.Bl -column "STRSUB(str, pos, len)"
.It Sy Name Ta Sy Operation
.It Fn STRSUB str pos len Ta Returns a substring of Ar str No starting at Ar pos No and Ar len No characters long. If Ar len No is not specified, the substring continues to the end of Ar str No .

View File

@@ -189,7 +189,7 @@ bool charmap_HasChar(std::string const &mapping) {
return charmap.nodes[nodeIdx].isTerminal();
}
size_t charmap_CharSize(std::string const &mapping) {
static CharmapNode const *charmapEntry(std::string const &mapping) {
Charmap const &charmap = *currentCharmap;
size_t nodeIdx = 0;
@@ -197,12 +197,24 @@ size_t charmap_CharSize(std::string const &mapping) {
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
if (!nodeIdx) {
return 0;
return nullptr;
}
}
CharmapNode const &node = charmap.nodes[nodeIdx];
return node.isTerminal() ? node.value.size() : 0;
return &charmap.nodes[nodeIdx];
}
size_t charmap_CharSize(std::string const &mapping) {
CharmapNode const *node = charmapEntry(mapping);
return node && node->isTerminal() ? node->value.size() : 0;
}
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx) {
if (CharmapNode const *node = charmapEntry(mapping);
node && node->isTerminal() && idx < node->value.size()) {
return node->value[idx];
}
return std::nullopt;
}
std::vector<int32_t> charmap_Convert(std::string const &input) {

View File

@@ -259,6 +259,7 @@ static std::unordered_map<std::string, int, CaseInsensitive, CaseInsensitive> ke
{"CHARLEN", T_(OP_CHARLEN) },
{"CHARSIZE", T_(OP_CHARSIZE) },
{"CHARSUB", T_(OP_CHARSUB) },
{"CHARVAL", T_(OP_CHARVAL) },
{"INCHARMAP", T_(OP_INCHARMAP) },
{"REVCHAR", T_(OP_REVCHAR) },

View File

@@ -287,6 +287,7 @@
%token OP_CHARLEN "CHARLEN"
%token OP_CHARSIZE "CHARSIZE"
%token OP_CHARSUB "CHARSUB"
%token OP_CHARVAL "CHARVAL"
%token OP_COS "COS"
%token OP_DEF "DEF"
%token OP_FDIV "FDIV"
@@ -1580,6 +1581,24 @@ relocexpr_no_str:
}
$$.makeNumber(charSize);
}
| OP_CHARVAL LPAREN string COMMA iconst RPAREN {
if (size_t len = charmap_CharSize($3); len != 0) {
uint32_t idx = adjustNegativeIndex($5, len, "CHARVAL");
if (std::optional<int32_t> val = charmap_CharValue($3, idx); val.has_value()) {
$$.makeNumber(*val);
} else {
warning(
WARNING_BUILTIN_ARG,
"CHARVAL: Index %" PRIu32 " is past the end of the character mapping\n",
idx
);
$$.makeNumber(0);
}
} else {
::error("CHARVAL: No character mapping for \"%s\"\n", $3.c_str());
$$.makeNumber(0);
}
}
| LPAREN relocexpr RPAREN {
$$ = std::move($2);
}

23
test/asm/charval.asm Normal file
View File

@@ -0,0 +1,23 @@
charmap "a", 1
charmap "b", 2, 3
charmap "cdef", 4
charmap "ghi", 5, 6, 7, 8, 9
charmap "jkl", 123, 456, 789
charmap "mno", 123456789
assert charval("a", 0) == 1
assert charval("a", -1) == 1
assert charval("b", 0) == 2
assert charval("b", 1) == 3
assert charval("b", -1) == 3
assert charval("b", -2) == 2
assert charval("cdef", 0) == 4
assert charval("ghi", 2) == charval("ghi", -3)
assert charval("jkl", -1) == 789
assert charval("mno", 0) == 123456789
assert charval("abc", 0) == 0
assert charval("cd", 1) == 0
assert charval("xyz", 2) == 0
assert charval("ghi", -10) == 5
assert charval("ghi", 10) == 0

11
test/asm/charval.err Normal file
View File

@@ -0,0 +1,11 @@
error: charval.asm(19):
CHARVAL: No character mapping for "abc"
error: charval.asm(20):
CHARVAL: No character mapping for "cd"
error: charval.asm(21):
CHARVAL: No character mapping for "xyz"
warning: charval.asm(22): [-Wbuiltin-args]
CHARVAL: Index starts at 0
warning: charval.asm(23): [-Wbuiltin-args]
CHARVAL: Index 10 is past the end of the character mapping
error: Assembly aborted (3 errors)!