diff --git a/doc/ca65.sgml b/doc/ca65.sgml
index 52e9634ae..bc22ba354 100644
--- a/doc/ca65.sgml
+++ b/doc/ca65.sgml
@@ -2831,6 +2831,24 @@ Here's a list of all control commands and a description, what they do:
removing the lines with the assignments may also be an option when porting
code written for older assemblers).
+ string_escapes
+
+ Allow C-style backslash escapes within string constants to embed
+ special characters. The following escapes are accepted:
+
+
+- \\ backslash ($5C)
+
- \' single quote ($27)
+
- \" double quote ($22)
+
- \t tab ($09)
+
- \r carriage return ($0D)
+
- \n newline ($0A)
+
- \xNN ($NN)
+
+
+ Note that \n maps to ASCII $0A, not a platform specific
+ line ending character.
+
ubiquitous_idents
Allow the use of instructions names as names for macros and symbols. This
diff --git a/src/ca65/feature.c b/src/ca65/feature.c
index 0fb766b6f..b11345338 100644
--- a/src/ca65/feature.c
+++ b/src/ca65/feature.c
@@ -65,6 +65,7 @@ static const char* const FeatureKeys[FEAT_COUNT] = {
"underline_in_numbers",
"addrsize",
"bracket_as_indirect",
+ "string_escapes",
};
@@ -123,6 +124,7 @@ feature_t SetFeature (const StrBuf* Key)
case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= 1; break;
case FEAT_ADDRSIZE: AddrSize = 1; break;
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = 1; break;
+ case FEAT_STRING_ESCAPES: StringEscapes = 1; break;
default: /* Keep gcc silent */ break;
}
diff --git a/src/ca65/feature.h b/src/ca65/feature.h
index 050c197f0..876f3c4a8 100644
--- a/src/ca65/feature.h
+++ b/src/ca65/feature.h
@@ -67,6 +67,7 @@ typedef enum {
FEAT_UNDERLINE_IN_NUMBERS,
FEAT_ADDRSIZE,
FEAT_BRACKET_AS_INDIRECT,
+ FEAT_STRING_ESCAPES,
/* Special value: Number of features available */
FEAT_COUNT
diff --git a/src/ca65/global.c b/src/ca65/global.c
index 31e599f00..a216fc406 100644
--- a/src/ca65/global.c
+++ b/src/ca65/global.c
@@ -66,6 +66,7 @@ unsigned char DbgSyms = 0; /* Add debug symbols */
unsigned char LineCont = 0; /* Allow line continuation */
unsigned char LargeAlignment = 0; /* Don't warn about large alignments */
unsigned char RelaxChecks = 0; /* Relax a few assembler checks */
+unsigned char StringEscapes = 0; /* Allow C-style escapes in strings */
/* Emulation features */
unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */
@@ -84,4 +85,3 @@ unsigned char ForceRange = 0; /* Force values into expected range */
unsigned char UnderlineInNumbers = 0; /* Allow underlines in numbers */
unsigned char AddrSize = 0; /* Allow .ADDRSIZE function */
unsigned char BracketAsIndirect = 0; /* Use '[]' not '()' for indirection */
-
diff --git a/src/ca65/global.h b/src/ca65/global.h
index 397d9221b..77d90beca 100644
--- a/src/ca65/global.h
+++ b/src/ca65/global.h
@@ -68,6 +68,7 @@ extern unsigned char DbgSyms; /* Add debug symbols */
extern unsigned char LineCont; /* Allow line continuation */
extern unsigned char LargeAlignment; /* Don't warn about large alignments */
extern unsigned char RelaxChecks; /* Relax a few assembler checks */
+extern unsigned char StringEscapes; /* Allow C-style escapes in strings */
/* Emulation features */
extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */
diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c
index 7c291666c..965fa3581 100644
--- a/src/ca65/scanner.c
+++ b/src/ca65/scanner.c
@@ -794,6 +794,43 @@ static void ReadStringConst (int StringTerm)
break;
}
+ if (C == '\\' && StringEscapes) {
+ NextChar ();
+
+ switch (C) {
+ case EOF:
+ Error ("Unterminated escape sequence in string constant");
+ break;
+ case '\\':
+ case '\'':
+ case '"':
+ break;
+ case 't':
+ C = '\x09';
+ break;
+ case 'r':
+ C = '\x0D';
+ break;
+ case 'n':
+ C = '\x0A';
+ break;
+ case 'x':
+ NextChar ();
+ if (IsXDigit (C)) {
+ char high_nibble = DigitVal (C) << 4;
+ NextChar ();
+ if (IsXDigit (C)) {
+ C = high_nibble | DigitVal (C);
+ break;
+ }
+ }
+ /* otherwise, fall through */
+ default:
+ Error ("Unsupported escape sequence in string constant");
+ break;
+ }
+ }
+
/* Append the char to the string */
SB_AppendChar (&CurTok.SVal, C);