diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 7903c6ee1..816902e1f 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -1841,13 +1841,92 @@ class Compiler : public ErrorSink { 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 @@ class Compiler : public ErrorSink { 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 @@ class Compiler : public ErrorSink { 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 @@ class Compiler : public ErrorSink { a = pGen->beginFunctionCallArguments(); next(); l = 0; - while (tok != ')') { + while (tok != ')' && tok != EOF) { expr(); pGen->storeR0ToArg(l); if (tok == ',') @@ -2184,7 +2265,7 @@ class Compiler : public ErrorSink { 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 000000000..230109a4e --- /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'); +}