diff options
Diffstat (limited to 'appl/lib')
| -rw-r--r-- | appl/lib/string.b | 243 |
1 files changed, 156 insertions, 87 deletions
diff --git a/appl/lib/string.b b/appl/lib/string.b index 16bc1940..fb123f7e 100644 --- a/appl/lib/string.b +++ b/appl/lib/string.b @@ -1,4 +1,5 @@ implement String; + include "string.m"; splitl(s: string, cl: string): (string, string) @@ -112,61 +113,56 @@ splitstrr(s: string, t: string): (string, string) prefix(pre: string, s: string): int { - ns := len s; - n := len pre; - if(ns < n) + if(len s < len pre) return 0; - for(k := 0; k < n; k++) { + for(k := 0; k < len pre; k++) if(pre[k] != s[k]) return 0; - } return 1; } tolower(s: string): string { - r := s; - for(i := 0; i < len r; i++) { - c := r[i]; - if(c >= int 'A' && c <= int 'Z') - r[i] = r[i] + (int 'a' - int 'A'); + for(i := 0; i < len s; i++) { + c := s[i]; + if(c >= 'A' && c <= 'Z') + s[i] += 'a' - 'A'; } - return r; + return s; } toupper(s: string): string { - r := s; - for(i := 0; i < len r; i++) { - c := r[i]; - if(c >= int 'a' && c <= int 'z') - r[i] = r[i] - (int 'a' - int 'A'); + for(i := 0; i < len s; i++) { + c := s[i]; + if(c >= 'a' && c <= 'z') + s[i] += 'A' - 'a'; } - return r; + return s; } -tobig(s: string, base: int): (big, string) +startnum(s: string, base: int): (int, int, int) { - if (s == nil || base < 0 || base > 36 || base == 1) - return (big 0, s); + if(s == nil || base != 0 && (base < 2 || base > 36)) + return (0, 0, 0); # skip possible leading white space - c: int; + c := ' '; for (i := 0; i < len s; i++) { c = s[i]; if(c != ' ' && c != '\t' && c != '\n') break; } - # skip possible sign character + # optional sign neg := 0; - if (c == '-' || c == '+') { + if(c == '-' || c == '+') { if(c == '-') neg = 1; i++; } - if (base == 0) { + if(base == 0) { # parse possible leading base designator start := i; base = -1; @@ -183,26 +179,30 @@ tobig(s: string, base: int): (big, string) i = start; base = 10; } else if (base == 0 || base > 36) - return (big 0, s); + return (0, 0, i); } + if(i >= len s) + return (0, 0, 0); + + return (base, neg, i); +} + +tobig(s: string, base: int): (big, string) +{ + neg, i: int; + + (base, neg, i) = startnum(s, base); + if(base == 0) + return (big 0, s); # parse number itself. - # perhaps this should check for overflow, and max out, as limbo op does? + # probably this should check for overflow, and max out, as limbo op does? start := i; - dig := '9'; - if (base < 10) - dig = '0' + base - 1; n := big 0; for (; i < len s; i++) { - c = s[i]; - if ('0' <= c && c <= dig) - n = (n * big base) + big(c - '0'); - else if ('a' <= c && c < 'a' + base - 10) - n = (n * big base) + big(c - 'a' + 10); - else if ('A' <= c && c < 'A' + base - 10) - n = (n * big base) + big(c - 'A' + 10); - else + if((d := digit(s[i], base)) < 0) break; + n = n*big base + big d; } if (i == start) return (big 0, s); @@ -213,62 +213,20 @@ tobig(s: string, base: int): (big, string) toint(s: string, base: int): (int, string) { - if (s == nil || base < 0 || base > 36 || base == 1) - return (0, s); - - # skip possible leading white space - c: int; - for (i := 0; i < len s; i++) { - c = s[i]; - if(c != ' ' && c != '\t' && c != '\n') - break; - } + neg, i: int; - # skip possible sign character - neg := 0; - if (c == '-' || c == '+') { - if(c == '-') - neg = 1; - i++; - } - - if (base == 0) { - # parse possible leading base designator - start := i; - base = -1; - for (; i < start+3 && i < len s; i++) { - c = s[i]; - if (c == 'r' && i > start) { - base = int s[start:i]; - i++; - break; - } else if (c < '0' || c > '9') - break; - } - if (base == -1) { - i = start; - base = 10; - } else if (base == 0 || base > 36) - return (0, s); - } + (base, neg, i) = startnum(s, base); + if(base == 0) + return (0, s); # parse number itself. - # perhaps this should check for overflow, and max out, as limbo op does? + # probably this should check for overflow, and max out, as limbo op does? start := i; - dig := '9'; - if (base < 10) - dig = '0' + base - 1; n := 0; - for (; i < len s; i++) { - c = s[i]; - if ('0' <= c && c <= dig) - n = (n * base) + (c - '0'); - else if ('a' <= c && c < 'a' + base - 10) - n = (n * base) + (c - 'a' + 10); - else if ('A' <= c && c < 'A' + base - 10) - n = (n * base) + (c - 'A' + 10); - else + for (; i < len s; i++){ + if((d := digit(s[i], base)) < 0) break; + n = n*base + d; } if (i == start) return (0, s); @@ -277,6 +235,117 @@ toint(s: string, base: int): (int, string) return (n, s[i:]); } +digit(c: int, base: int): int +{ + if ('0' <= c && c <= '0' + base - 1) + return c-'0'; + else if ('a' <= c && c < 'a' + base - 10) + return (c - 'a' + 10); + else if ('A' <= c && c < 'A' + base - 10) + return (c - 'A' + 10); + else + return -1; +} + +rpow(x: real, n: int): real +{ + inv := 0; + if(n < 0){ + n = -n; + inv = 1; + } + r := 1.0; + for(;;){ + if(n&1) + r *= x; + if((n >>= 1) == 0) + break; + x *= x; + } + if(inv) + r = 1.0/r; + return r; +} + +match(p: string, s: string, i: int): int +{ + if(i+len p > len s) + return 0; + for(j := 0; j < len p; j++){ + c := s[i++]; + if(c >= 'A' && c <= 'Z') + c += 'a'-'A'; + if(p[j] != c) + return 0; + } + return 1; +} + +toreal(s: string, base: int): (real, string) +{ + neg, i: int; + + (base, neg, i) = startnum(s, base); + if(base == 0) + return (0.0, s); + + c := s[i]; + if((c == 'i' || c == 'I') && match("infinity", s, i)) + return (real s, s[i+8:]); + if((c == 'n' || c == 'N') && match("nan", s, i)) + return (real s, s[i+3:]); + + if(digit(c, base) < 0) + return (0.0, s); + + num := 0.0; + for(; i < len s && (d := digit(s[i], base)) >= 0; i++) + num = num*real base + real d; + dig := 0; # digits in fraction + if(i < len s && s[i] == '.'){ + i++; + for(; i < len s && (d = digit(s[i], base)) >= 0; i++){ + num = num*real base + real d; + dig++; + } + } + exp := 0; + eneg := 0; + if(i < len s && ((c = s[i]) == 'e' || c == 'E')){ + start := i; # might still be badly formed + i++; + if(i < len s && ((c = s[i]) == '-' || c == '+')){ + i++; + if(c == '-'){ + dig = -dig; + eneg = 1; + } + } + if(i < len s && s[i] >= '0' && s[i] <= '9'){ # exponents are always decimal + for(; i < len s && (d = digit(s[i], 10)) >= 0; i++) + exp = exp*base + d; + }else + i = start; + } + if(base == 10) + return (real s[0: i], s[i:]); # conversion can be more accurate + exp -= dig; + if(exp < 0){ + exp = -exp; + eneg = !eneg; + } + if(exp < 0 || exp > 19999) + exp = 19999; # huge but otherwise arbitrary limit + dem := rpow(real base, exp); + if(eneg) + num /= dem; + else + num *= dem; + if(neg) + return (-num,s[i:]); + return (num, s[i:]); +} + append(s: string, l: list of string): list of string { t: list of string; |
