Implement string and character backslash constants.
Until now we only supported '\n'. Now we support everything, including
octal ('\033') and hex '\x27' constants.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 7903c6e..816902e 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1841,13 +1841,92 @@
return isalnum(ch) | (ch == '_');
}
- /* read a character constant */
- void getq() {
+ /* read a character constant, advances ch to after end of constant */
+ int getq() {
+ int val = ch;
if (ch == '\\') {
inp();
- if (ch == 'n')
- ch = '\n';
+ if (isoctal(ch)) {
+ // 1 to 3 octal characters.
+ val = 0;
+ for(int i = 0; i < 3; i++) {
+ if (isoctal(ch)) {
+ val = (val << 3) + ch - '0';
+ inp();
+ }
+ }
+ return val;
+ } else if (ch == 'x' || ch == 'X') {
+ // N hex chars
+ inp();
+ if (! isxdigit(ch)) {
+ error("'x' character escape requires at least one digit.");
+ } else {
+ val = 0;
+ while (isxdigit(ch)) {
+ int d = ch;
+ if (isdigit(d)) {
+ d -= '0';
+ } else if (d <= 'F') {
+ d = d - 'A' + 10;
+ } else {
+ d = d - 'a' + 10;
+ }
+ val = (val << 4) + d;
+ inp();
+ }
+ }
+ } else {
+ int val = ch;
+ switch (ch) {
+ case 'a':
+ val = '\a';
+ break;
+ case 'b':
+ val = '\b';
+ break;
+ case 'f':
+ val = '\f';
+ break;
+ case 'n':
+ val = '\n';
+ break;
+ case 'r':
+ val = '\r';
+ break;
+ case 't':
+ val = '\t';
+ break;
+ case 'v':
+ val = '\v';
+ break;
+ case '\\':
+ val = '\\';
+ break;
+ case '\'':
+ val = '\'';
+ break;
+ case '"':
+ val = '"';
+ break;
+ case '?':
+ val = '?';
+ break;
+ default:
+ error("Undefined character escape %c", ch);
+ break;
+ }
+ inp();
+ return val;
+ }
+ } else {
+ inp();
}
+ return val;
+ }
+
+ static bool isoctal(int ch) {
+ return ch >= '0' && ch <= '7';
}
void next() {
@@ -1908,10 +1987,12 @@
inp();
if (tok == '\'') {
tok = TOK_NUM;
- getq();
- tokc = ch;
- inp();
- inp();
+ tokc = getq();
+ if (ch != '\'') {
+ error("Expected a ' character, got %c", ch);
+ } else {
+ inp();
+ }
} else if ((tok == '/') & (ch == '*')) {
inp();
while (ch) {
@@ -2071,14 +2152,14 @@
int c;
String tString;
t = 0;
- n = 1; /* type of expression 0 = forward, 1 = value, other =
- lvalue */
+ n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
if (tok == '\"') {
pGen->li((int) glo);
- while (ch != '\"') {
- getq();
- *allocGlobalSpace(1) = ch;
- inp();
+ while (ch != '\"' && ch != EOF) {
+ *allocGlobalSpace(1) = getq();
+ }
+ if (ch != '\"') {
+ error("Unterminated string constant.");
}
*glo = 0;
/* align heap */
@@ -2176,7 +2257,7 @@
a = pGen->beginFunctionCallArguments();
next();
l = 0;
- while (tok != ')') {
+ while (tok != ')' && tok != EOF) {
expr();
pGen->storeR0ToArg(l);
if (tok == ',')
@@ -2184,7 +2265,7 @@
l = l + 4;
}
pGen->endFunctionCallArguments(a, l);
- next();
+ skip(')');
if (!n) {
/* forward reference */
t = t + 4;
diff --git a/libacc/tests/data/constants.c b/libacc/tests/data/constants.c
new file mode 100644
index 0000000..230109a
--- /dev/null
+++ b/libacc/tests/data/constants.c
@@ -0,0 +1,30 @@
+#define FOO 0x10
+
+int main() {
+ printf("0 = %d\n", 0);
+ printf("010 = %d\n", 010);
+ printf("0x10 = %d\n", FOO);
+ printf("'\\a' = %d\n", '\a');
+ printf("'\\b' = %d\n", '\b');
+ printf("'\\f' = %d\n", '\f');
+ printf("'\\n' = %d\n", '\n');
+ printf("'\\r' = %d\n", '\r');
+ printf("'\\t' = %d\n", '\t');
+ printf("'\\v' = %d\n", '\v');
+ // Undefined
+ // printf("'\\z' = %d\n", '\z');
+ printf("'\\\\' = %d\n", '\\');
+ printf("'\\'' = %d\n", '\'');
+ printf("'\\\"' = %d\n", '\"');
+ printf("'\\?' = %d\n", '\?');
+ printf("'\\0' = %d\n", '\0');
+ printf("'\\1' = %d\n", '\1');
+ printf("'\\12' = %d\n", '\12');
+ printf("'\\123' = %d\n", '\123');
+ printf("'\\x0' = %d\n", '\x0');
+ printf("'\\x1' = %d\n", '\x1');
+ printf("'\\x12' = %d\n", '\x12');
+ printf("'\\x123' = %d\n", '\x123');
+ printf("'\\x1f' = %d\n", '\x1f');
+ printf("'\\x1F' = %d\n", '\x1F');
+}