Skip to content

Commit 089e366

Browse files
authored
Implement CHARVAL function (#1701)
1 parent fa9e29e commit 089e366

File tree

7 files changed

+82
-7
lines changed

7 files changed

+82
-7
lines changed

include/asm/charmap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef RGBDS_ASM_CHARMAP_HPP
44
#define RGBDS_ASM_CHARMAP_HPP
55

6+
#include <optional>
67
#include <stdint.h>
78
#include <string>
89
#include <string_view>
@@ -22,6 +23,7 @@ void charmap_CheckStack();
2223
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
2324
bool charmap_HasChar(std::string const &mapping);
2425
size_t charmap_CharSize(std::string const &mapping);
26+
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx);
2527
std::vector<int32_t> charmap_Convert(std::string const &input);
2628
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
2729
std::string charmap_Reverse(std::vector<int32_t> const &value, bool &unique);

man/rgbasm.5

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -608,14 +608,21 @@ The following functions operate on string expressions, but return integers.
608608
.It Fn CHARLEN str Ta Returns the number of charmap entries in Ar str No with the current charmap .
609609
.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.
610610
.It Fn CHARSIZE char Ta Returns how many values are in the charmap entry for Ar char No with the current charmap.
611+
.It Fn CHARVAL char idx Ta Returns the value at Ar idx No of the charmap entry for Ar char Ns .
611612
.El
612613
.Pp
613-
Note that the first character of a string is at index 0, and the last is at index -1.
614+
Note that indexes count starting from 0 at the beginning, or from -1 at the end.
615+
The characters of a string are counted by
616+
.Ql STRLEN ;
617+
the charmap entries of a string are counted by
618+
.Ql CHARLEN ;
619+
and the values of a charmap entry are counted by
620+
.Ql CHARSIZE .
614621
.Pp
615-
The following legacy functions are similar to other functions that operate on string expressions, but for historical reasons, they count characters starting from
622+
The following legacy functions are similar to other functions that operate on string expressions, but for historical reasons, they count starting from
616623
.Em position 1 ,
617624
not from index 0!
618-
(Position -1 still counts from the last character.)
625+
(Position -1 still counts from the end.)
619626
.Bl -column "STRSUB(str, pos, len)"
620627
.It Sy Name Ta Sy Operation
621628
.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 .

src/asm/charmap.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,20 +189,32 @@ bool charmap_HasChar(std::string const &mapping) {
189189
return charmap.nodes[nodeIdx].isTerminal();
190190
}
191191

192-
size_t charmap_CharSize(std::string const &mapping) {
192+
static CharmapNode const *charmapEntry(std::string const &mapping) {
193193
Charmap const &charmap = *currentCharmap;
194194
size_t nodeIdx = 0;
195195

196196
for (char c : mapping) {
197197
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
198198

199199
if (!nodeIdx) {
200-
return 0;
200+
return nullptr;
201201
}
202202
}
203203

204-
CharmapNode const &node = charmap.nodes[nodeIdx];
205-
return node.isTerminal() ? node.value.size() : 0;
204+
return &charmap.nodes[nodeIdx];
205+
}
206+
207+
size_t charmap_CharSize(std::string const &mapping) {
208+
CharmapNode const *node = charmapEntry(mapping);
209+
return node && node->isTerminal() ? node->value.size() : 0;
210+
}
211+
212+
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx) {
213+
if (CharmapNode const *node = charmapEntry(mapping);
214+
node && node->isTerminal() && idx < node->value.size()) {
215+
return node->value[idx];
216+
}
217+
return std::nullopt;
206218
}
207219

208220
std::vector<int32_t> charmap_Convert(std::string const &input) {

src/asm/lexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ static std::unordered_map<std::string, int, CaseInsensitive, CaseInsensitive> ke
259259
{"CHARLEN", T_(OP_CHARLEN) },
260260
{"CHARSIZE", T_(OP_CHARSIZE) },
261261
{"CHARSUB", T_(OP_CHARSUB) },
262+
{"CHARVAL", T_(OP_CHARVAL) },
262263
{"INCHARMAP", T_(OP_INCHARMAP) },
263264
{"REVCHAR", T_(OP_REVCHAR) },
264265

src/asm/parser.y

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
%token OP_CHARLEN "CHARLEN"
288288
%token OP_CHARSIZE "CHARSIZE"
289289
%token OP_CHARSUB "CHARSUB"
290+
%token OP_CHARVAL "CHARVAL"
290291
%token OP_COS "COS"
291292
%token OP_DEF "DEF"
292293
%token OP_FDIV "FDIV"
@@ -1580,6 +1581,24 @@ relocexpr_no_str:
15801581
}
15811582
$$.makeNumber(charSize);
15821583
}
1584+
| OP_CHARVAL LPAREN string COMMA iconst RPAREN {
1585+
if (size_t len = charmap_CharSize($3); len != 0) {
1586+
uint32_t idx = adjustNegativeIndex($5, len, "CHARVAL");
1587+
if (std::optional<int32_t> val = charmap_CharValue($3, idx); val.has_value()) {
1588+
$$.makeNumber(*val);
1589+
} else {
1590+
warning(
1591+
WARNING_BUILTIN_ARG,
1592+
"CHARVAL: Index %" PRIu32 " is past the end of the character mapping\n",
1593+
idx
1594+
);
1595+
$$.makeNumber(0);
1596+
}
1597+
} else {
1598+
::error("CHARVAL: No character mapping for \"%s\"\n", $3.c_str());
1599+
$$.makeNumber(0);
1600+
}
1601+
}
15831602
| LPAREN relocexpr RPAREN {
15841603
$$ = std::move($2);
15851604
}

test/asm/charval.asm

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
charmap "a", 1
2+
charmap "b", 2, 3
3+
charmap "cdef", 4
4+
charmap "ghi", 5, 6, 7, 8, 9
5+
charmap "jkl", 123, 456, 789
6+
charmap "mno", 123456789
7+
8+
assert charval("a", 0) == 1
9+
assert charval("a", -1) == 1
10+
assert charval("b", 0) == 2
11+
assert charval("b", 1) == 3
12+
assert charval("b", -1) == 3
13+
assert charval("b", -2) == 2
14+
assert charval("cdef", 0) == 4
15+
assert charval("ghi", 2) == charval("ghi", -3)
16+
assert charval("jkl", -1) == 789
17+
assert charval("mno", 0) == 123456789
18+
19+
assert charval("abc", 0) == 0
20+
assert charval("cd", 1) == 0
21+
assert charval("xyz", 2) == 0
22+
assert charval("ghi", -10) == 5
23+
assert charval("ghi", 10) == 0

test/asm/charval.err

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: charval.asm(19):
2+
CHARVAL: No character mapping for "abc"
3+
error: charval.asm(20):
4+
CHARVAL: No character mapping for "cd"
5+
error: charval.asm(21):
6+
CHARVAL: No character mapping for "xyz"
7+
warning: charval.asm(22): [-Wbuiltin-args]
8+
CHARVAL: Index starts at 0
9+
warning: charval.asm(23): [-Wbuiltin-args]
10+
CHARVAL: Index 10 is past the end of the character mapping
11+
error: Assembly aborted (3 errors)!

0 commit comments

Comments
 (0)