ngspice/src/frontend/parser/numparse.c

171 lines
4.1 KiB
C

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/* This routine parses a number. */
#include "ngspice/ngspice.h"
#include "ngspice/bool.h"
#include "ngspice/ftedefs.h"
#include "numparse.h"
static double
power10(double num) /* Chris Inbody */
{
double d = 1.0;
while (num-- > 0)
d *= 10.0;
return (d);
}
bool ft_strictnumparse = FALSE;
/* Parse a number. This will handle things like 10M, etc... If the number
* must not end before the end of the string, then whole is TRUE.
* If whole is FALSE and there is more left to the number, the argument
* is advanced to the end of the word. Returns NULL
* if no number can be found or if there are trailing characters when
* whole is TRUE.
*
* If ft_strictnumparse is TRUE, and whole is FALSE, the first of the
* trailing characters must be a '_'. */
double *
ft_numparse(char **s, bool whole)
{
double mant = 0.0;
int sign = 1, exsign = 1, p;
double expo = 0.0;
static double num;
char *string = *s;
/* See if the number begins with + or -. */
if (*string == '+') {
string++;
} else if (*string == '-') {
string++;
sign = -1;
}
/* We don't want to recognise "P" as 0P, or .P as 0.0P... */
if ((!isdigit_c(*string) && *string != '.') ||
((*string == '.') && !isdigit_c(string[1])))
return (NULL);
/* Now accumulate a number. Note ascii dependencies here... */
while (isdigit_c(*string))
mant = mant * 10.0 + (*string++ - '0');
/* Now maybe a decimal point. */
if (*string == '.') {
string++;
p = 1;
while (isdigit_c(*string))
mant += (*string++ - '0') / power10(p++);
}
/* Now look for the scale factor or the exponent (can't have both). */
switch (*string) {
case 'e':
case 'E':
/* Parse another number. */
string++;
if (*string == '+') {
exsign = 1;
string++;
} else if (*string == '-') {
exsign = -1;
string++;
}
while (isdigit_c(*string))
expo = expo * 10.0 + (*string++ - '0');
if (*string == '.') {
string++;
p = 1;
while (isdigit_c(*string))
expo += (*string++ - '0') / power10(p++);
}
expo *= exsign;
break;
case 't':
case 'T':
expo = 12.0;
string++;
break;
case 'g':
case 'G':
expo = 9.0;
string++;
break;
case 'k':
case 'K':
expo = 3.0;
string++;
break;
case 'u':
case 'U':
expo = -6.0;
string++;
break;
case 'n':
case 'N':
expo = -9.0;
string++;
break;
case 'p':
case 'P':
expo = -12.0;
string++;
break;
case 'f':
case 'F':
expo = -15.0;
string++;
break;
case 'm':
case 'M':
/* Can be either m, mil, or meg. */
if (string[1] && string[2] &&
((string[1] == 'e') || (string[1] == 'E')) &&
((string[2] == 'g') || (string[2] == 'G')))
{
expo = 6.0;
string += 3;
} else if (string[1] && string[2] &&
((string[1] == 'i') || (string[1] == 'I')) &&
((string[2] == 'l') || (string[2] == 'L')))
{
expo = -6.0;
mant *= 25.4;
string += 3;
} else {
expo = -3.0;
string++;
}
break;
}
if (whole && *string != '\0') {
return (NULL);
} else if (ft_strictnumparse && *string && isdigit_c(string[-1])) {
if (*string == '_')
while (isalpha_c(*string) || (*string == '_'))
string++;
else
return (NULL);
} else {
while (isalpha_c(*string) || (*string == '_'))
string++;
}
*s = string;
num = sign * mant * pow(10.0, expo);
if (ft_parsedb)
fprintf(cp_err, "numparse: got %e, left = %s\n", num, *s);
return (&num);
}