Refactor readString

Much more readable, and avoids `peek(nz)`
This commit is contained in:
ISSOtm
2020-12-19 13:02:05 +01:00
parent 255b8bf9ba
commit c20ac35074

View File

@@ -692,6 +692,11 @@ static void freeExpansion(struct Expansion *expansion)
free(expansion); free(expansion);
} }
static bool isMacroChar(char c)
{
return c == '@' || c == '#' || (c >= '0' && c <= '9');
}
static char const *readMacroArg(char name) static char const *readMacroArg(char name)
{ {
char const *str; char const *str;
@@ -795,7 +800,7 @@ restart:
/* If character is a backslash, check for a macro arg */ /* If character is a backslash, check for a macro arg */
lexerState->macroArgScanDistance++; lexerState->macroArgScanDistance++;
c = peekInternal(distance + 1); c = peekInternal(distance + 1);
if (c == '@' || c == '#' || (c >= '0' && c <= '9')) { if (isMacroChar(c)) {
char const *str = readMacroArg(c); char const *str = readMacroArg(c);
/* /*
@@ -1443,22 +1448,22 @@ static int appendMacroArg(char const *str, int i)
static void readString(void) static void readString(void)
{ {
size_t i = 0;
dbgPrint("Reading string\n"); dbgPrint("Reading string\n");
lexerState->disableMacroArgs = true; lexerState->disableMacroArgs = true;
lexerState->disableInterpolation = true; lexerState->disableInterpolation = true;
size_t i = 0;
bool multiline = false; bool multiline = false;
// We reach this function after reading a single quote, but we also support triple quotes
if (peek(0) == '"') { if (peek(0) == '"') {
shiftChars(1); shiftChars(1);
if (peek(0) == '"') { if (peek(0) == '"') {
/* """ begins a multi-line string */ // """ begins a multi-line string
shiftChars(1); shiftChars(1);
multiline = true; multiline = true;
} else { } else {
/* "" is an empty string */ // "" is an empty string, skip the loop
goto finish; goto finish;
} }
} }
@@ -1466,45 +1471,35 @@ static void readString(void)
for (;;) { for (;;) {
int c = peek(0); int c = peek(0);
if (c == '\r' || c == '\n') { // '\r', '\n' or EOF ends a single-line string early
if (!multiline) { if (c == EOF || (!multiline && (c == '\r' || c == '\n'))) {
/* '\r' or '\n' ends a single-line string early */ error("Unterminated string\n");
c = EOF; break;
} else if (c == '\r' && peek(1) == '\n') { }
/* '\r\n' becomes '\n' in multi-line strings */
shiftChars(1); // We'll be staying in the string, so we can safely consume the char
c = '\n'; shiftChars(1);
}
// Handle CRLF (in multiline strings only, already handled above otherwise)
if (c == '\r' && peek(0) == '\n') {
shiftChars(1);
c = '\n';
} }
switch (c) { switch (c) {
case '"': case '"':
if (multiline) { if (multiline) {
/* """ ends a multi-line string */ // Only """ ends a multi-line string
if (peek(1) != '"' || peek(2) != '"') if (peek(0) != '"' || peek(1) != '"')
break; break;
shiftChars(3); shiftChars(2);
} else {
shiftChars(1);
}
if (i == sizeof(yylval.tzString)) {
i--;
warning(WARNING_LONG_STR, "String constant too long\n");
} }
goto finish; goto finish;
case EOF: case '\\': // Character escape or macro arg
if (i == sizeof(yylval.tzString)) { c = peek(0);
i--;
warning(WARNING_LONG_STR, "String constant too long\n");
}
error("Unterminated string\n");
goto finish;
case '\\': /* Character escape or macro arg */
c = peek(1);
switch (c) { switch (c) {
case '\\': /* Return that character unchanged */ case '\\': // Return that character unchanged
case '"': case '"':
case '{': case '{':
case '}': case '}':
@@ -1523,15 +1518,14 @@ static void readString(void)
shiftChars(1); shiftChars(1);
break; break;
/* Line continuation */ // Line continuation
case ' ': case ' ':
case '\r': case '\r':
case '\n': case '\n':
shiftChars(1); /* Shift the backslash */
readLineContinuation(); readLineContinuation();
continue; continue;
/* Macro arg */ // Macro arg
case '@': case '@':
case '#': case '#':
case '0': case '0':
@@ -1544,13 +1538,13 @@ static void readString(void)
case '7': case '7':
case '8': case '8':
case '9': case '9':
shiftChars(2); shiftChars(1);
char const *str = readMacroArg(c); char const *str = readMacroArg(c);
i = appendMacroArg(str, i); i = appendMacroArg(str, i);
continue; /* Do not copy an additional character */ continue; // Do not copy an additional character
case EOF: /* Can't really print that one */ case EOF: // Can't really print that one
error("Illegal character escape at end of input\n"); error("Illegal character escape at end of input\n");
c = '\\'; c = '\\';
break; break;
@@ -1561,8 +1555,9 @@ static void readString(void)
} }
break; break;
case '{': /* Symbol interpolation */ case '{': // Symbol interpolation
shiftChars(1); // We'll be exiting the string scope, so re-enable expansions
// (Not interpolations, since they're handled by the function itself...)
lexerState->disableMacroArgs = false; lexerState->disableMacroArgs = false;
char const *ptr = readInterpolation(); char const *ptr = readInterpolation();
@@ -1570,16 +1565,20 @@ static void readString(void)
while (*ptr && i < sizeof(yylval.tzString)) while (*ptr && i < sizeof(yylval.tzString))
yylval.tzString[i++] = *ptr++; yylval.tzString[i++] = *ptr++;
lexerState->disableMacroArgs = true; lexerState->disableMacroArgs = true;
continue; /* Do not copy an additional character */ continue; // Do not copy an additional character
/* Regular characters will just get copied */ // Regular characters will just get copied
} }
if (i < sizeof(yylval.tzString)) /* Copy one extra to flag overflow */
if (i < sizeof(yylval.tzString)) // Copy one extra to flag overflow
yylval.tzString[i++] = c; yylval.tzString[i++] = c;
shiftChars(1);
} }
finish: finish:
if (i == sizeof(yylval.tzString)) {
i--;
warning(WARNING_LONG_STR, "String constant too long\n");
}
yylval.tzString[i] = '\0'; yylval.tzString[i] = '\0';
dbgPrint("Read string \"%s\"\n", yylval.tzString); dbgPrint("Read string \"%s\"\n", yylval.tzString);