mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Implement CHARVAL function (#1701)
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#ifndef RGBDS_ASM_CHARMAP_HPP
|
#ifndef RGBDS_ASM_CHARMAP_HPP
|
||||||
#define RGBDS_ASM_CHARMAP_HPP
|
#define RGBDS_ASM_CHARMAP_HPP
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -22,6 +23,7 @@ void charmap_CheckStack();
|
|||||||
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
|
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
|
||||||
bool charmap_HasChar(std::string const &mapping);
|
bool charmap_HasChar(std::string const &mapping);
|
||||||
size_t charmap_CharSize(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);
|
std::vector<int32_t> charmap_Convert(std::string const &input);
|
||||||
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
|
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);
|
std::string charmap_Reverse(std::vector<int32_t> const &value, bool &unique);
|
||||||
|
|||||||
13
man/rgbasm.5
13
man/rgbasm.5
@@ -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 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 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 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
|
.El
|
||||||
.Pp
|
.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
|
.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 ,
|
.Em position 1 ,
|
||||||
not from index 0!
|
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)"
|
.Bl -column "STRSUB(str, pos, len)"
|
||||||
.It Sy Name Ta Sy Operation
|
.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 .
|
.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 .
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ bool charmap_HasChar(std::string const &mapping) {
|
|||||||
return charmap.nodes[nodeIdx].isTerminal();
|
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;
|
Charmap const &charmap = *currentCharmap;
|
||||||
size_t nodeIdx = 0;
|
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)];
|
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
|
||||||
|
|
||||||
if (!nodeIdx) {
|
if (!nodeIdx) {
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CharmapNode const &node = charmap.nodes[nodeIdx];
|
return &charmap.nodes[nodeIdx];
|
||||||
return node.isTerminal() ? node.value.size() : 0;
|
}
|
||||||
|
|
||||||
|
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) {
|
std::vector<int32_t> charmap_Convert(std::string const &input) {
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ static std::unordered_map<std::string, int, CaseInsensitive, CaseInsensitive> ke
|
|||||||
{"CHARLEN", T_(OP_CHARLEN) },
|
{"CHARLEN", T_(OP_CHARLEN) },
|
||||||
{"CHARSIZE", T_(OP_CHARSIZE) },
|
{"CHARSIZE", T_(OP_CHARSIZE) },
|
||||||
{"CHARSUB", T_(OP_CHARSUB) },
|
{"CHARSUB", T_(OP_CHARSUB) },
|
||||||
|
{"CHARVAL", T_(OP_CHARVAL) },
|
||||||
{"INCHARMAP", T_(OP_INCHARMAP) },
|
{"INCHARMAP", T_(OP_INCHARMAP) },
|
||||||
{"REVCHAR", T_(OP_REVCHAR) },
|
{"REVCHAR", T_(OP_REVCHAR) },
|
||||||
|
|
||||||
|
|||||||
@@ -287,6 +287,7 @@
|
|||||||
%token OP_CHARLEN "CHARLEN"
|
%token OP_CHARLEN "CHARLEN"
|
||||||
%token OP_CHARSIZE "CHARSIZE"
|
%token OP_CHARSIZE "CHARSIZE"
|
||||||
%token OP_CHARSUB "CHARSUB"
|
%token OP_CHARSUB "CHARSUB"
|
||||||
|
%token OP_CHARVAL "CHARVAL"
|
||||||
%token OP_COS "COS"
|
%token OP_COS "COS"
|
||||||
%token OP_DEF "DEF"
|
%token OP_DEF "DEF"
|
||||||
%token OP_FDIV "FDIV"
|
%token OP_FDIV "FDIV"
|
||||||
@@ -1580,6 +1581,24 @@ relocexpr_no_str:
|
|||||||
}
|
}
|
||||||
$$.makeNumber(charSize);
|
$$.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 {
|
| LPAREN relocexpr RPAREN {
|
||||||
$$ = std::move($2);
|
$$ = std::move($2);
|
||||||
}
|
}
|
||||||
|
|||||||
23
test/asm/charval.asm
Normal file
23
test/asm/charval.asm
Normal 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
11
test/asm/charval.err
Normal 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)!
|
||||||
Reference in New Issue
Block a user