Skip to content

Commit

Permalink
Consistent model for expanding macro args and interpolations,
Browse files Browse the repository at this point in the history
within macro args, string literals, and normal context

- "{S}" should always equal the contents of S
- "\1" should always act like quoting the value of \1

Fixes #691
  • Loading branch information
Rangi42 committed Jan 5, 2021
1 parent b65848c commit 14c1361
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 113 deletions.
158 changes: 56 additions & 102 deletions src/asm/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1364,93 +1364,37 @@ static char const *readInterpolation(void)
return NULL;
}

static size_t appendUnescapedString(char const *str, size_t i)
static size_t appendSubstring(char const *str, size_t i, bool keepLiteral)
{
/* Copy one extra to flag overflow */
while (*str && i < sizeof(yylval.tzString)) {
int c = *str++;

if (c != '\\') {
yylval.tzString[i++] = c;
continue;
}

c = *str++;

/* Interpret character escapes */
switch (c) {
case '\\':
case '"':
case '{':
case '}':
/* Return that character unchanged */
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;

case '\0': /* Can't really print that one */
error("Illegal character escape at end of macro arg\n");
yylval.tzString[i++] = '\\';
break;

/*
* Line continuations and macro args were already
* handled while reading the macro args, so '\@',
* '\#', and '\0'-'\9' should not occur here.
*/

default:
error("Illegal character escape '%s'\n", print(c));
c = '\\';
break;
/* Escape characters that need escaping */
if (keepLiteral) {
switch (c) {
case '\\':
case '"':
case '{':
yylval.tzString[i++] = '\\';
break;
case '\n':
yylval.tzString[i++] = '\\';
c = 'n';
break;
case '\r':
yylval.tzString[i++] = '\\';
c = 'r';
break;
case '\t':
yylval.tzString[i++] = '\\';
c = 't';
break;
}
}
yylval.tzString[i++] = c;
}

return i;
}

static size_t appendEscapedString(char const *str, size_t i)
{
/* Copy one extra to flag overflow */
while (*str && i < sizeof(yylval.tzString)) {
int c = *str++;

/* Escape characters that need escaping */
switch (c) {
case '\\':
case '"':
case '{':
yylval.tzString[i++] = '\\';
if (i < sizeof(yylval.tzString))
yylval.tzString[i++] = c;
break;
case '\n':
yylval.tzString[i++] = '\\';
if (i < sizeof(yylval.tzString))
yylval.tzString[i++] = 'n';
break;
case '\r':
yylval.tzString[i++] = '\\';
if (i < sizeof(yylval.tzString))
yylval.tzString[i++] = 'r';
break;
case '\t':
yylval.tzString[i++] = '\\';
if (i < sizeof(yylval.tzString))
yylval.tzString[i++] = 't';
break;
default:
if (i < sizeof(yylval.tzString))
yylval.tzString[i++] = c;
break;
}
}

return i;
Expand Down Expand Up @@ -1577,20 +1521,16 @@ static size_t appendStringLiteral(size_t i, bool keepLiteral)
shiftChars(1);
char const *str = readMacroArg(c);

if (keepLiteral)
i = appendEscapedString(str, i);
else
i = appendUnescapedString(str, i);

i = appendSubstring(str, i, keepLiteral);
continue; // Do not copy an additional character

case EOF: // Can't really print that one
error("Illegal character escape at end of input\n");
c = '\\';
break;

default:
error("Illegal character escape '%s'\n", print(c));
c = '\\';
break;
}
break;
Expand All @@ -1601,14 +1541,8 @@ static size_t appendStringLiteral(size_t i, bool keepLiteral)
lexerState->disableMacroArgs = false;
char const *ptr = readInterpolation();

if (ptr) {
if (keepLiteral)
i = appendEscapedString(ptr, i);
else
while (*ptr && i < sizeof(yylval.tzString))
yylval.tzString[i++] = *ptr++;
}

if (ptr)
i = appendSubstring(ptr, i, keepLiteral);
lexerState->disableMacroArgs = true;
continue; // Do not copy an additional character

Expand Down Expand Up @@ -1902,6 +1836,7 @@ static int yylex_NORMAL(void)
case EOF:
error("Illegal character escape at end of input\n");
break;

default:
shiftChars(1);
error("Illegal character escape '%s'\n", print(c));
Expand Down Expand Up @@ -1953,6 +1888,7 @@ static int yylex_RAW(void)
dbgPrint("Lexing in raw mode, line=%" PRIu32 ", col=%" PRIu32 "\n",
lexer_GetLineNo(), lexer_GetColNo());

/* This is essentially a modified `appendStringLiteral` */
size_t i = 0;

/* Trim left of string... */
Expand All @@ -1972,7 +1908,8 @@ static int yylex_RAW(void)
discardComment();
c = peek(0);
/* fallthrough */
case ',':

case ',': /* End of macro arg */
case '\r':
case '\n':
case EOF:
Expand All @@ -1998,28 +1935,45 @@ static int yylex_RAW(void)
return T_STRING;

case '\\': /* Character escape */
c = peek(1);
shiftChars(1); /* Shift the backslash */
c = peek(0);
switch (c) {
case '\\':
case '"':
case ';':
case ';': /* Macro-only character escapes */
case ',':
shiftChars(1); /* Shift the backslash */
case '\\': /* Escapes shared with string literals */
case '"':
case '{':
case '}':
break;

case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;

case ' ':
case '\r':
case '\n':
shiftChars(1); /* Shift the backslash */
readLineContinuation();
continue;

case EOF: /* Can't really print that one */
error("Illegal character escape at end of input\n");
c = '\\';
break;
default: /* Pass the rest as-is */
c = '\\';

/*
* Macro args were already handled by peek, so '\@',
* '\#', and '\0'-'\9' should not occur here.
*/

default:
error("Illegal character escape '%s'\n", print(c));
break;
}
if (i < sizeof(yylval.tzString))
Expand Down
5 changes: 4 additions & 1 deletion test/asm/macro-arg-in-string.asm
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
print1: MACRO
if _NARG == 2
assert !STRCMP("\1", \2)
endc
PRINTLN "\1"
ENDM

print1 John "Danger" Smith
print1 \\\\A\\nB\n
print1 \\\\A\\nB\n, "\\\\A\\nB\n"
print1 C\
D
print1 E\!F ; illegal character escape
Expand Down
2 changes: 1 addition & 1 deletion test/asm/macro-arg-in-string.err
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ERROR: macro-arg-in-string.asm(9) -> macro-arg-in-string.asm::print1(2):
ERROR: macro-arg-in-string.asm(12):
Illegal character escape '!'
error: Assembly aborted (1 errors)!
5 changes: 2 additions & 3 deletions test/asm/macro-arg-in-string.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
John "Danger" Smith
\A
B
\\A\nB

CD
E\F
E!F
hello
4 changes: 4 additions & 0 deletions test/asm/quine2.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
q: macro
println \1,"\1"
endm
q "q: macro\n\tprintln \\1,\"\\1\"\nendm\n\tq "
Empty file added test/asm/quine2.err
Empty file.
4 changes: 4 additions & 0 deletions test/asm/quine2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
q: macro
println \1,"\1"
endm
q "q: macro\n\tprintln \\1,\"\\1\"\nendm\n\tq "
6 changes: 3 additions & 3 deletions test/asm/raw-macro-args.asm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ printlit: MACRO
ENDM

NUM EQU 42
STR EQUS "string"
STR EQUS "str\"ing"

printargs NUM
printargs "{d:NUM}"
Expand All @@ -28,11 +28,11 @@ STR EQUS "string"
printlit NUM
printlit "{d:NUM}"
printlit "{STR}", 16 ; comment 3
println "\"literal \\\"\\\\\\\"\""
printlit "\"literal \\\"\\\\\\\"\""
printlit "literal \"\\\"", \ ; comment 4
"""multi-"line"
""string"" arg"""
printlit MUL(2.0\, 3.0)
printlit this\\n is\, not\; a\\\\n syntax\" error
printlit this\n is\, not\; a\\n syntax\" error
printlit "unclosed
printlit """EOF
6 changes: 3 additions & 3 deletions test/asm/raw-macro-args.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$2A
42
string
str"ing
$10
"literal \"\\\""
literal "\"
Expand All @@ -10,10 +10,10 @@ $60000
unclosed
NUM
"42"
"string"
"str\"ing"
16
"\"literal \\\"\\\\\\\"\""
"literal \"\\\""
"literal "\""
"""multi-"line"
""string"" arg"""
MUL(2.0, 3.0)
Expand Down

0 comments on commit 14c1361

Please sign in to comment.