mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Implement ++ operator for string concatenation (#1698)
This commit is contained in:
13
man/rgbasm.5
13
man/rgbasm.5
@@ -548,7 +548,7 @@ There are a number of escape sequences you can use within a string:
|
|||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Multi-line strings are contained in triple quotes
|
Multi-line strings are contained in triple quotes
|
||||||
.Pq Ql \&"\&"\&"for instance\&"\&"\&" .
|
.Pq Ql \&"\&"\&"for instance""" .
|
||||||
Escape sequences work the same way in multi-line strings; however, literal newline characters will be included as-is, without needing to escape them with
|
Escape sequences work the same way in multi-line strings; however, literal newline characters will be included as-is, without needing to escape them with
|
||||||
.Ql \er
|
.Ql \er
|
||||||
or
|
or
|
||||||
@@ -560,10 +560,19 @@ Inside them, backslashes and braces are treated like regular characters, so they
|
|||||||
For example, the raw string
|
For example, the raw string
|
||||||
.Ql #"\et\e1{s}\e"
|
.Ql #"\et\e1{s}\e"
|
||||||
is equivalent to the regular string
|
is equivalent to the regular string
|
||||||
.Ql "\e\et\e\e1\e{s}\e\e" .
|
.Ql \&"\e\et\e\e1\e{s}\e\e" .
|
||||||
(Note that this prevents raw strings from including the double quote character.)
|
(Note that this prevents raw strings from including the double quote character.)
|
||||||
Raw strings also may be contained in triple quotes for them to be multi-line, so they can include literal newline or quote characters (although still not three quotes in a row).
|
Raw strings also may be contained in triple quotes for them to be multi-line, so they can include literal newline or quote characters (although still not three quotes in a row).
|
||||||
.Pp
|
.Pp
|
||||||
|
You can use the
|
||||||
|
.Sq ++
|
||||||
|
operator to concatenate two strings.
|
||||||
|
.Ql \&"str" ++ \&"ing"
|
||||||
|
is equivalent to
|
||||||
|
.Ql \&"string" ,
|
||||||
|
or to
|
||||||
|
.Ql STRCAT("str", \&"ing") .
|
||||||
|
.Pp
|
||||||
The following functions operate on string expressions, and return strings themselves.
|
The following functions operate on string expressions, and return strings themselves.
|
||||||
.Bl -column "STRSLICE(str, start, stop)"
|
.Bl -column "STRSLICE(str, start, stop)"
|
||||||
.It Sy Name Ta Sy Operation
|
.It Sy Name Ta Sy Operation
|
||||||
|
|||||||
@@ -1774,12 +1774,17 @@ static Token yylex_NORMAL() {
|
|||||||
|
|
||||||
// Handle ambiguous 1- or 2-char tokens
|
// Handle ambiguous 1- or 2-char tokens
|
||||||
|
|
||||||
case '+': // Either += or ADD
|
case '+': // Either +=, ADD, or CAT
|
||||||
if (peek() == '=') {
|
switch (peek()) {
|
||||||
|
case '=':
|
||||||
shiftChar();
|
shiftChar();
|
||||||
return Token(T_(POP_ADDEQ));
|
return Token(T_(POP_ADDEQ));
|
||||||
|
case '+':
|
||||||
|
shiftChar();
|
||||||
|
return Token(T_(OP_CAT));
|
||||||
|
default:
|
||||||
|
return Token(T_(OP_ADD));
|
||||||
}
|
}
|
||||||
return Token(T_(OP_ADD));
|
|
||||||
|
|
||||||
case '-': // Either -= or SUB
|
case '-': // Either -= or SUB
|
||||||
if (peek() == '=') {
|
if (peek() == '=') {
|
||||||
|
|||||||
@@ -125,6 +125,9 @@
|
|||||||
%token OP_MUL "*" OP_DIV "/" OP_MOD "%"
|
%token OP_MUL "*" OP_DIV "/" OP_MOD "%"
|
||||||
%token OP_EXP "**"
|
%token OP_EXP "**"
|
||||||
|
|
||||||
|
// String operators
|
||||||
|
%token OP_CAT "++"
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators
|
||||||
%token OP_LOGICEQU "==" OP_LOGICNE "!="
|
%token OP_LOGICEQU "==" OP_LOGICNE "!="
|
||||||
%token OP_LOGICLT "<" OP_LOGICGT ">"
|
%token OP_LOGICLT "<" OP_LOGICGT ">"
|
||||||
@@ -147,6 +150,7 @@
|
|||||||
%left OP_AND OP_OR OP_XOR
|
%left OP_AND OP_OR OP_XOR
|
||||||
%left OP_SHL OP_SHR OP_USHR
|
%left OP_SHL OP_SHR OP_USHR
|
||||||
%left OP_MUL OP_DIV OP_MOD
|
%left OP_MUL OP_DIV OP_MOD
|
||||||
|
%left OP_CAT
|
||||||
%precedence NEG // applies to unary OP_LOGICNOT, OP_ADD, OP_SUB, OP_NOT
|
%precedence NEG // applies to unary OP_LOGICNOT, OP_ADD, OP_SUB, OP_NOT
|
||||||
%right OP_EXP
|
%right OP_EXP
|
||||||
|
|
||||||
@@ -1613,6 +1617,10 @@ string_literal:
|
|||||||
STRING {
|
STRING {
|
||||||
$$ = std::move($1);
|
$$ = std::move($1);
|
||||||
}
|
}
|
||||||
|
| string OP_CAT string {
|
||||||
|
$$ = std::move($1);
|
||||||
|
$$.append($3);
|
||||||
|
}
|
||||||
| OP_STRSLICE LPAREN string COMMA iconst COMMA iconst RPAREN {
|
| OP_STRSLICE LPAREN string COMMA iconst COMMA iconst RPAREN {
|
||||||
size_t len = strlenUTF8($3, false);
|
size_t len = strlenUTF8($3, false);
|
||||||
uint32_t start = adjustNegativeIndex($5, len, "STRSLICE");
|
uint32_t start = adjustNegativeIndex($5, len, "STRSLICE");
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ warning: equs-newline.asm(3): [-Wuser]
|
|||||||
while expanding symbol "ACT"
|
while expanding symbol "ACT"
|
||||||
warning: equs-newline.asm(3): [-Wuser]
|
warning: equs-newline.asm(3): [-Wuser]
|
||||||
Second
|
Second
|
||||||
while expanding symbol "ACT"
|
|
||||||
warning: equs-newline.asm(4): [-Wuser]
|
warning: equs-newline.asm(4): [-Wuser]
|
||||||
Third
|
Third
|
||||||
|
|||||||
26
test/asm/string-concat.asm
Normal file
26
test/asm/string-concat.asm
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
SECTION "test", ROM0
|
||||||
|
|
||||||
|
MACRO test
|
||||||
|
assert !strcmp(\1, \2)
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test "a"++"b", "ab"
|
||||||
|
test "a"++""++"b", "ab"
|
||||||
|
test "a"++"b", strcat("a", "b")
|
||||||
|
test "a"++"b"++"c", strcat("a","b","c")
|
||||||
|
test "" ++ "", ""
|
||||||
|
test strupr("a") ++ strlwr("B"), "Ab"
|
||||||
|
|
||||||
|
def str equs "hi"
|
||||||
|
test #str ++ strupr(#str), "hiHI"
|
||||||
|
test "a" ++ """b""" ++ strupr("c") ++ strslice(#str, 0, 0), "abC"
|
||||||
|
|
||||||
|
charmap "a", 1
|
||||||
|
charmap "b", 2
|
||||||
|
charmap "ab", 12
|
||||||
|
assert "a" + "b" == 3
|
||||||
|
assert "a" ++ "b" == 12
|
||||||
|
|
||||||
|
; errors
|
||||||
|
assert 2 ++ 2 == 4
|
||||||
|
ld a, [hl++]
|
||||||
5
test/asm/string-concat.err
Normal file
5
test/asm/string-concat.err
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
error: string-concat.asm(25):
|
||||||
|
syntax error, unexpected ++
|
||||||
|
error: string-concat.asm(26):
|
||||||
|
syntax error, unexpected ++, expecting ] or + or -
|
||||||
|
error: Assembly aborted (2 errors)!
|
||||||
@@ -3,41 +3,30 @@ error: unique-id.asm(11):
|
|||||||
while expanding symbol "warn_unique"
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(11): [-Wuser]
|
warning: unique-id.asm(11): [-Wuser]
|
||||||
!
|
!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(4): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(4): [-Wuser]
|
||||||
_u1!
|
_u1!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
||||||
_u2!
|
_u2!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
||||||
_u3!
|
_u3!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(8): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(8): [-Wuser]
|
||||||
_u1!
|
_u1!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
error: unique-id.asm(13):
|
error: unique-id.asm(13):
|
||||||
'\@' cannot be used outside of a macro or REPT/FOR block
|
'\@' cannot be used outside of a macro or REPT/FOR block
|
||||||
while expanding symbol "warn_unique"
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(13): [-Wuser]
|
warning: unique-id.asm(13): [-Wuser]
|
||||||
!
|
!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(4): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(4): [-Wuser]
|
||||||
_u4!
|
_u4!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
||||||
_u5!
|
_u5!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
||||||
_u6!
|
_u6!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser]
|
||||||
_u4!
|
_u4!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
error: unique-id.asm(15):
|
error: unique-id.asm(15):
|
||||||
'\@' cannot be used outside of a macro or REPT/FOR block
|
'\@' cannot be used outside of a macro or REPT/FOR block
|
||||||
while expanding symbol "warn_unique"
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(15): [-Wuser]
|
warning: unique-id.asm(15): [-Wuser]
|
||||||
!
|
!
|
||||||
while expanding symbol "warn_unique"
|
|
||||||
error: Assembly aborted (3 errors)!
|
error: Assembly aborted (3 errors)!
|
||||||
|
|||||||
Reference in New Issue
Block a user