Mercurial > hg > index.cgi
comparison lwcc/preproc.c @ 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 | d85d173ba120 |
comparison
equal
deleted
inserted
replaced
300:8d6c47395653 | 301:6f7fe78bb868 |
---|---|
703 skip_eol(pp); | 703 skip_eol(pp); |
704 preproc_unget_token(pp, pp -> curtok); | 704 preproc_unget_token(pp, pp -> curtok); |
705 } | 705 } |
706 | 706 |
707 static long eval_expr_real(struct preproc_info *, int); | 707 static long eval_expr_real(struct preproc_info *, int); |
708 static long preproc_numval(struct token *); | 708 static long preproc_numval(struct preproc_info *, struct token *); |
709 | 709 |
710 static long eval_term_real(struct preproc_info *pp) | 710 static long eval_term_real(struct preproc_info *pp) |
711 { | 711 { |
712 long tval = 0; | 712 long tval = 0; |
713 struct token *ct; | 713 struct token *ct; |
781 /* unknown identifier - it's zero */ | 781 /* unknown identifier - it's zero */ |
782 return 0; | 782 return 0; |
783 | 783 |
784 /* numbers */ | 784 /* numbers */ |
785 case TOK_NUMBER: | 785 case TOK_NUMBER: |
786 return preproc_numval(ct); | 786 return preproc_numval(pp, ct); |
787 | 787 |
788 default: | 788 default: |
789 preproc_throw_error(pp, "Bad expression"); | 789 preproc_throw_error(pp, "Bad expression"); |
790 skip_eoe(pp); | 790 skip_eoe(pp); |
791 return 0; | 791 return 0; |
928 skip_eol(pp); | 928 skip_eol(pp); |
929 } | 929 } |
930 return rv; | 930 return rv; |
931 } | 931 } |
932 | 932 |
933 static int eval_escape(char **t) | |
934 { | |
935 int c; | |
936 int c2; | |
937 | |
938 if (**t == 0) | |
939 return 0; | |
940 c = *(*t)++; | |
941 int rv = 0; | |
942 | |
943 switch (c) | |
944 { | |
945 case 'n': | |
946 return 10; | |
947 case 'r': | |
948 return 13; | |
949 case 'b': | |
950 return 8; | |
951 case 'e': | |
952 return 27; | |
953 case 'f': | |
954 return 12; | |
955 case 't': | |
956 return 9; | |
957 case 'v': | |
958 return 11; | |
959 case 'a': | |
960 return 7; | |
961 case '0': case '1': case '2': case '3': case '4': | |
962 case '5': case '6': case '7': | |
963 // octal constant | |
964 rv = c - '0'; | |
965 c2 = 1; | |
966 for (; c2 < 3; c2++) | |
967 { | |
968 c = *(*t)++; | |
969 if (c < '0' || c > '7') | |
970 break; | |
971 rv = (rv << 3) | (c - '0'); | |
972 } | |
973 return rv; | |
974 case 'x': | |
975 // hex constant | |
976 for (;;) | |
977 { | |
978 c = *(*t)++; | |
979 if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') | |
980 break; | |
981 c = c - '0'; | |
982 if (c > 9) | |
983 c -= 7; | |
984 if (c > 15) | |
985 c -= 32; | |
986 rv = (rv << 4) | c; | |
987 } | |
988 return rv & 0xff; | |
989 default: | |
990 return c; | |
991 } | |
992 } | |
993 | |
933 /* convert a numeric string to a number */ | 994 /* convert a numeric string to a number */ |
934 long preproc_numval(struct token *t) | 995 long preproc_numval(struct preproc_info *pp, struct token *t) |
935 { | 996 { |
936 return 0; | 997 unsigned long long rv = 0; |
998 unsigned long long rv2 = 0; | |
999 char *tstr = t -> strval; | |
1000 int radix = 10; | |
1001 int c; | |
1002 int ovf = 0; | |
1003 union { long sv; unsigned long uv; } tv; | |
1004 | |
1005 if (t -> ttype == TOK_CHR_LIT) | |
1006 { | |
1007 tstr++; | |
1008 while (*tstr && *tstr != '\'') | |
1009 { | |
1010 if (*tstr == '\\') | |
1011 { | |
1012 tstr++; | |
1013 c = eval_escape(&tstr); | |
1014 } | |
1015 else | |
1016 c = *tstr++; | |
1017 rv = (rv << 8) | c; | |
1018 if (rv / radix < rv2) | |
1019 ovf = 1; | |
1020 rv2 = rv; | |
1021 | |
1022 } | |
1023 goto done; | |
1024 } | |
1025 | |
1026 | |
1027 if (*tstr == '0') | |
1028 { | |
1029 radix = 8; | |
1030 tstr++; | |
1031 if (*tstr == 'x') | |
1032 { | |
1033 radix = 16; | |
1034 tstr++; | |
1035 } | |
1036 } | |
1037 while (*tstr) | |
1038 { | |
1039 c = *tstr++; | |
1040 if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') | |
1041 break; | |
1042 c -= '0'; | |
1043 if (c > 9) | |
1044 c -= 7; | |
1045 if (c > 15) | |
1046 c -= 32; | |
1047 if (c >= radix) | |
1048 break; | |
1049 rv = rv * radix + c; | |
1050 if (rv / radix < rv2) | |
1051 ovf = 1; | |
1052 rv2 = rv; | |
1053 } | |
1054 tstr--; | |
1055 while (*tstr == 'l' || *tstr == 'L') | |
1056 tstr++; | |
1057 tv.uv = rv; | |
1058 if (tv.sv < 0 && radix == 10) | |
1059 ovf = 1; | |
1060 done: | |
1061 if (ovf) | |
1062 preproc_throw_error(pp, "Constant out of range: %s", t -> strval); | |
1063 return rv; | |
937 } | 1064 } |
938 | 1065 |
939 /* | 1066 /* |
940 Below here is the logic for expanding a macro | 1067 Below here is the logic for expanding a macro |
941 */ | 1068 */ |