Mercurial > hg > index.cgi
changeset 301:6f7fe78bb868 ccdev
Add string -> number conversion for preproc expression evaluator
Q&D conversion from string to signed number. It should be noted that this
really should be done during tokenization and the type of number be set by
the tokenizer, including parsing floating point values. Then the
preprocessor can decide what to do with non-integer numbers.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sun, 15 Sep 2013 14:22:10 -0600 |
parents | 8d6c47395653 |
children | f29bebc279a8 |
files | lwcc/preproc.c |
diffstat | 1 files changed, 131 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/lwcc/preproc.c Sun Sep 15 13:49:00 2013 -0600 +++ b/lwcc/preproc.c Sun Sep 15 14:22:10 2013 -0600 @@ -705,7 +705,7 @@ } static long eval_expr_real(struct preproc_info *, int); -static long preproc_numval(struct token *); +static long preproc_numval(struct preproc_info *, struct token *); static long eval_term_real(struct preproc_info *pp) { @@ -783,7 +783,7 @@ /* numbers */ case TOK_NUMBER: - return preproc_numval(ct); + return preproc_numval(pp, ct); default: preproc_throw_error(pp, "Bad expression"); @@ -930,10 +930,137 @@ return rv; } +static int eval_escape(char **t) +{ + int c; + int c2; + + if (**t == 0) + return 0; + c = *(*t)++; + int rv = 0; + + switch (c) + { + case 'n': + return 10; + case 'r': + return 13; + case 'b': + return 8; + case 'e': + return 27; + case 'f': + return 12; + case 't': + return 9; + case 'v': + return 11; + case 'a': + return 7; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + // octal constant + rv = c - '0'; + c2 = 1; + for (; c2 < 3; c2++) + { + c = *(*t)++; + if (c < '0' || c > '7') + break; + rv = (rv << 3) | (c - '0'); + } + return rv; + case 'x': + // hex constant + for (;;) + { + c = *(*t)++; + if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') + break; + c = c - '0'; + if (c > 9) + c -= 7; + if (c > 15) + c -= 32; + rv = (rv << 4) | c; + } + return rv & 0xff; + default: + return c; + } +} + /* convert a numeric string to a number */ -long preproc_numval(struct token *t) +long preproc_numval(struct preproc_info *pp, struct token *t) { - return 0; + unsigned long long rv = 0; + unsigned long long rv2 = 0; + char *tstr = t -> strval; + int radix = 10; + int c; + int ovf = 0; + union { long sv; unsigned long uv; } tv; + + if (t -> ttype == TOK_CHR_LIT) + { + tstr++; + while (*tstr && *tstr != '\'') + { + if (*tstr == '\\') + { + tstr++; + c = eval_escape(&tstr); + } + else + c = *tstr++; + rv = (rv << 8) | c; + if (rv / radix < rv2) + ovf = 1; + rv2 = rv; + + } + goto done; + } + + + if (*tstr == '0') + { + radix = 8; + tstr++; + if (*tstr == 'x') + { + radix = 16; + tstr++; + } + } + while (*tstr) + { + c = *tstr++; + if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') + break; + c -= '0'; + if (c > 9) + c -= 7; + if (c > 15) + c -= 32; + if (c >= radix) + break; + rv = rv * radix + c; + if (rv / radix < rv2) + ovf = 1; + rv2 = rv; + } + tstr--; + while (*tstr == 'l' || *tstr == 'L') + tstr++; + tv.uv = rv; + if (tv.sv < 0 && radix == 10) + ovf = 1; +done: + if (ovf) + preproc_throw_error(pp, "Constant out of range: %s", t -> strval); + return rv; } /*