Implement """triple-quoted""" multi-line strings

Fixes #589
This commit is contained in:
Rangi
2020-12-16 12:31:44 -05:00
committed by Eldred Habert
parent ad6f17cd93
commit 255b8bf9ba
5 changed files with 90 additions and 7 deletions

View File

@@ -1448,30 +1448,57 @@ static void readString(void)
dbgPrint("Reading string\n");
lexerState->disableMacroArgs = true;
lexerState->disableInterpolation = true;
bool multiline = false;
if (peek(0) == '"') {
shiftChars(1);
if (peek(0) == '"') {
/* """ begins a multi-line string */
shiftChars(1);
multiline = true;
} else {
/* "" is an empty string */
goto finish;
}
}
for (;;) {
int c = peek(0);
if (c == '\r' || c == '\n') {
if (!multiline) {
/* '\r' or '\n' ends a single-line string early */
c = EOF;
} else if (c == '\r' && peek(1) == '\n') {
/* '\r\n' becomes '\n' in multi-line strings */
shiftChars(1);
c = '\n';
}
}
switch (c) {
case '"':
if (multiline) {
/* """ ends a multi-line string */
if (peek(1) != '"' || peek(2) != '"')
break;
shiftChars(3);
} else {
shiftChars(1);
}
if (i == sizeof(yylval.tzString)) {
i--;
warning(WARNING_LONG_STR, "String constant too long\n");
}
yylval.tzString[i] = '\0';
dbgPrint("Read string \"%s\"\n", yylval.tzString);
goto finish;
case '\r':
case '\n': /* Do not shift these! */
case EOF:
if (i == sizeof(yylval.tzString)) {
i--;
warning(WARNING_LONG_STR, "String constant too long\n");
}
yylval.tzString[i] = '\0';
error("Unterminated string\n");
dbgPrint("Read string \"%s\"\n", yylval.tzString);
goto finish;
case '\\': /* Character escape or macro arg */
@@ -1553,6 +1580,9 @@ static void readString(void)
}
finish:
yylval.tzString[i] = '\0';
dbgPrint("Read string \"%s\"\n", yylval.tzString);
lexerState->disableMacroArgs = false;
lexerState->disableInterpolation = false;
}

View File

@@ -240,6 +240,14 @@ There are a number of escape sequences you can use within a string:
.El
(Note that some of those can be used outside of strings, when noted further in this document.)
.Pp
Multi-line strings are contained in triple quotes
.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
.Ql \[rs]r
or
.Ql \[rs]n .
.Pp
A funky feature is
.Ql {symbol}
within a string, called

View File

@@ -0,0 +1,32 @@
S EQUS "Hello"
PRINTT "\"\"\"\n"
PRINTT """{S}
world
"""
PRINTT """The multi-line string \ ; line continuations work
can contain:
- "single quotes"
- ""double quotes""
- even escaped \"""triple"\"" ""\"quotes\"\"\"
!"""
PRINTT """\n"""
printarg: MACRO
PRINTT "arg <\1>\n"
PRINTT """arg (\1)\n"""
ENDM
printarg "
printarg """
EMPTY1 EQUS ""
EMPTY2 EQUS "\ ; comment
"
EMPTY3 EQUS """"""
EMPTY4 EQUS """\ ; comment
"""
PRINTT STRCAT("(", "{EMPTY1}", "{EMPTY2}", "{EMPTY3}", "{EMPTY4}", ")\n")

View File

View File

@@ -0,0 +1,13 @@
"""
Hello
world
The multi-line string can contain:
- "single quotes"
- ""double quotes""
- even escaped """triple""" """quotes"""
!
arg <">
arg (")
arg <""">
arg (""")
()