static double parse_int_frac_exp(MVMThreadContext *tc, MVMCodepointIter *ci, MVMCodepoint *cp, MVMString* s, double radix, int leading_zero) { /* * What we do here is extract the digits from the original string, * effectively stripping off underscores and converting fancy Unicode * digits to regular ones. We then ASCII-fy those digits and stuff * them into digits_buf (along with double-ish things like the dot * and 'e'). At the end we give the resultant string to strtod() to * do all the dirty work for us, so we don't have to worry about * handling denormals or picking closest representable double */ int digits = 0; int frac_digits = 0; int digit; int ends_with_underscore = 0; char *digits_buf = (char *)MVM_malloc(1 + MVM_string_graphs(tc, s)); char *digits_buf_tail = digits_buf; double result; if (*cp == '_') parse_error(tc, s, "number can't start with _"); if (*cp != '.') { while (*cp == '_' || (digit = cp_value(tc, *cp)) != -1) { ends_with_underscore = *cp == '_'; if (*cp != '_') { if (digit >= radix) break; *digits_buf_tail++ = '0' + digit; digits++; } get_cp(tc, ci, cp); } if (ends_with_underscore) parse_error(tc, s, "a number can't end in underscore"); } if (*cp == '.') { *digits_buf_tail++ = '.'; get_cp(tc, ci, cp); if (*cp == '_') parse_error(tc, s, "radix point can't be followed by _"); while (*cp == '_' || (digit = cp_value(tc, *cp)) != -1) { ends_with_underscore = *cp == '_'; if (*cp != '_') { if (digit >= radix) break; *digits_buf_tail++ = '0' + digit; frac_digits++; } get_cp(tc, ci, cp); } if (frac_digits == 0) parse_error(tc, s, "radix point must be followed by one or more valid digits"); if (ends_with_underscore) parse_error(tc, s, "a number can't end in underscore"); } if (digits == 0 && frac_digits == 0 && !leading_zero) parse_error(tc, s, "expecting a number"); if (*cp == 'E' || *cp == 'e') { int e_digits = 0; *digits_buf_tail++ = 'e'; get_cp(tc, ci, cp); if (parse_sign(tc, ci, cp) == -1) *digits_buf_tail++ = '-'; if (*cp == '_') parse_error(tc, s, "'e' or 'E' can't be followed by _"); while (*cp == '_' || (digit = cp_value(tc, *cp)) != -1) { if (*cp != '_') { if (digit >= radix) break; *digits_buf_tail++ = '0' + digit; e_digits++; } get_cp(tc, ci, cp); } if (e_digits == 0) parse_error(tc, s, "'e' or 'E' must be followed by one or more valid digits"); } *digits_buf_tail = '\0'; result = strtod(digits_buf, NULL); MVM_free(digits_buf); return result; }
static double parse_simple_number(MVMThreadContext *tc, MVMCodepointIter *ci, MVMCodepoint *cp, MVMString *s) { double sign; /* Handle NaN here, to make later parsing simpler */ if (match_word(tc, ci, cp, "NaN", s)) { return MVM_num_nan(tc); } sign = parse_sign(tc, ci, cp); if (match_word(tc, ci, cp, "Inf", s)) { return sign * MVM_num_posinf(tc); } else if (*cp == ':') { int radix; double body; get_cp(tc, ci, cp); radix = (int) parse_int_frac_exp(tc, ci, cp, s, 10, 0); if (*cp == '<') { get_cp(tc, ci, cp); body = parse_int_frac_exp(tc, ci, cp, s, radix, 0); if (*cp == '>') { /* > */ get_cp(tc, ci, cp); return sign * body; } parse_error(tc, s, "malformed ':radix<>' style radix number, expecting '>' after the body"); } else if (*cp == 171) { /* « */ get_cp(tc, ci, cp); body = parse_int_frac_exp(tc, ci, cp, s, radix, 0); if (*cp == 187) { /* » */ get_cp(tc, ci, cp); return sign * body; } parse_error(tc, s, "malformed ':radix«»' style radix number, expecting '>' after the body"); } else if (*cp == '[') { double result = 0; get_cp(tc, ci, cp); while (*cp != ']' && MVM_string_ci_has_more(tc, ci)) { double digit = parse_decimal_integer(tc, ci, cp, s); result = result * radix + digit; if (*cp == ',') { get_cp(tc, ci, cp); } } if (*cp == ']') { get_cp(tc, ci, cp); return sign * result; } parse_error(tc, s, "malformed ':radix[]' style radix number, expecting ']' after the body"); } parse_error(tc, s, "malformed ':radix' style number. Expected <, [ or « after ':radix'"); } else if (*cp == '0') { int radix = 0; get_cp(tc, ci, cp); switch (*cp) { case 'b': radix = 2; break; case 'o': radix = 8; break; case 'd': radix = 10; break; case 'x': radix = 16; break; } if (radix) { get_cp(tc, ci, cp); if (*cp == '_') get_cp(tc, ci, cp); return sign * parse_int_frac_exp(tc, ci, cp, s, radix, 1); } return sign * parse_int_frac_exp(tc, ci, cp, s, 10, 1); } else { return sign * parse_int_frac_exp(tc, ci, cp, s, 10, 0); } }
Data* parse_term( char** p ) { Data* ret = NULL; while(1) { char op; int sign; if( ret ) { parse_ws(p); op = *((*p)); if( op != '*' && op != '/' ) { break; /*last chr should not be parsed*/ } else (*p)++; } sign=parse_sign(p); if( sign == 0 ) sign = 1; Data* factor = parse_factor(p); if( factor->type == TYPE_ERROR ) { dispose(ret); return factor; /*throw*/ } if( sign == -1 ) { if( factor->type == TYPE_STRING ) { dispose(factor); dispose(ret); return Raise(SYNTAX); } else if( factor->type == TYPE_REAL ) factor->storage.Real = -factor->storage.Real; else factor->storage.Integer = - factor->storage.Integer; } parse_ws(p); if( **p == '^' ) {/*exponent*/ (*p)++; Data* exponent = parse_factor(p); factor = temp_var(factor); if( exponent->type == TYPE_ERROR ) { dispose(ret); dispose(factor); return exponent; } if( exponent->type == TYPE_STRING || factor->type == TYPE_STRING) { dispose(ret); dispose(factor); dispose(exponent); return Data_new( TYPE_ERROR , (Storage)Error_new(TYPE_MISMATCH) , 1 ); } if( factor->type == TYPE_INTEGER ) { factor->storage.Real = factor->storage.Integer; factor->type = TYPE_REAL; } if( exponent->type == TYPE_INTEGER ) { factor->storage.Real = factor->storage.Integer; factor->type = TYPE_REAL; } factor->storage.Real = exp( log(factor->storage.Real) * exponent->storage.Real); dispose(exponent); } if( ret == NULL ) ret = factor; else { ret = temp_var(ret); if( ret->type == TYPE_STRING ) { dispose(ret); dispose(factor); return Raise(TYPE_MISMATCH); } else { if( op == '*' ) { if( ret->type == TYPE_REAL || factor->type == TYPE_REAL ) { if( ret->type == TYPE_INTEGER ) { ret->type = TYPE_REAL; ret->storage.Real = ret->storage.Integer; } if( factor->type == TYPE_INTEGER ) { factor->type = TYPE_REAL; factor->storage.Real = factor->storage.Integer; } ret->storage.Real *= factor->storage.Real; } else ret->storage.Integer *= factor->storage.Integer; } else { if( ret->type == TYPE_INTEGER ) { ret->type = TYPE_REAL; ret->storage.Real = ret->storage.Integer; } if( factor->type == TYPE_INTEGER ) { factor->type = TYPE_REAL; factor->storage.Real = factor->storage.Integer; } if( factor->storage.Real == 0 ) { dispose( ret ); dispose( factor ); return Raise(DIV_BY_ZERO); } ret->storage.Real /= factor->storage.Real; } } dispose(factor); } } return ret; }
Data* parse_aexpr(char** p) { Data* ret = NULL; while(parse_ws(p),**p) { int sign ; sign = parse_sign(p); if( !ret || sign ) { Data* term = parse_term(p); if( term->type == TYPE_ERROR ) { dispose(ret); return term; /*Throw the error*/ } else if( !ret ) /* First term */ { if( sign != 0 && term->type == TYPE_STRING ) /* There are one or more negitive/positive sign before A string*/ /* e.g. : +"illegal"*/ { dispose(term); dispose(ret); return Raise(SYNTAX); /*raise a syntax error*/ } else ret = term; if( sign < 0 ) {/*only INTEGER and REAL */ if( term->type == TYPE_INTEGER ) term->storage.Integer = -term->storage.Integer; else term->storage.Real = -term->storage.Real; } } else if( term->type == TYPE_STRING ) { ret = temp_var(ret); if( sign > 0 ) /* AC + STRING */ { if( ret->type != TYPE_STRING ) { /* non-string + string is illegal */ dispose(term); dispose(ret); return Raise(TYPE_MISMATCH); } /* do strcat */ char* A = ret->storage.String; char* B = term->storage.String; int lA = strlen(A); int lB = strlen(B); char* temp = (char*)malloc( lA + lB + 1); strcpy( temp , A ); strcpy( temp + lA , B ); ret->storage.String = temp; if( A != init_value[TYPE_STRING].String ) free(A); /*dispose old string*/ dispose(term); /*dispose this term*/ } else { /* AC - string is illegal */ dispose(term); dispose(ret); return Raise(TYPE_MISMATCH); } } else if( term->type == TYPE_INTEGER ) { ret = temp_var(ret); /*AC + INTEGER*/ if( ret->type == TYPE_STRING ) {/*Type Mismatch*/ dispose(ret); dispose(term); return Raise(TYPE_MISMATCH); } else if( ret->type == TYPE_INTEGER ) {/*Integer + Integer*/ ret->storage.Integer += sign * term->storage.Integer; dispose(term); } else if( ret->type == TYPE_REAL ) {/*Real + Integer*/ ret->storage.Real += sign * term->storage.Integer; dispose(term); } } else if( term->type == TYPE_REAL ) { double org; ret = temp_var(ret); /*AC + REAL */ if( ret->type == TYPE_STRING ) {/*Type Mismatch*/ dispose(ret); dispose(term); return Raise(TYPE_MISMATCH); } if( ret->type == TYPE_REAL ) org = ret->storage.Real; else org = ret->storage.Integer; ret->type = TYPE_REAL; ret->storage.Real = org + sign * term->storage.Real; dispose(term); } } else break; } if( ret == NULL ) ret=Raise(SYNTAX); return ret; }
void do_sign(CHAR_DATA *ch,char *argument) { parse_sign(ch,argument,NOTE_SIGN); }