예제 #1
0
GLECSVDataStatus GLECSVData::readCellString(GLEBYTE quote) {
	unsigned int cellSize = 1;
	unsigned int cellPos = lastCharPos();
	initWritePos();
	while (true) {
		GLEBYTE ch = readChar();
		writeChar(ch);
		cellSize++;
		if (ch == 0) {
			m_error.errorCode = GLECSVErrorUnterminatedString;
			m_error.errorLine = m_lines;
			m_error.errorColumn = getUTF8Column(cellPos);
			createErrorString("unterminated string");
			return GLECSVDataStatusEOF;
		} else if (isEol(ch)) {
			m_error.errorCode = GLECSVErrorUnterminatedString;
			m_error.errorLine = m_lines;
			m_error.errorColumn = getUTF8Column(cellPos);
			createErrorString("unterminated string");
			return readNewline(ch);
		} else if (ch == quote) {
			GLEBYTE ch = readChar();
			if (ch != quote) {
				writeChar(ch);
				createCell(cellSize, cellPos);
				return skipSpacesAndFirstDelim(ch);
			}
		}
	}
	return GLECSVDataStatusOK;
}
예제 #2
0
GLECSVDataStatus GLECSVData::skipTillEol() {
	while (true) {
		GLEBYTE ch = readChar();
		if (ch == 0) {
			return GLECSVDataStatusEOF;
		}
		if (isEol(ch)) {
			return readNewline(ch);
		}
	}
}
예제 #3
0
파일: readval.c 프로젝트: RobDeBagel/survex
extern void
read_string(char **pstr, int *plen)
{
   s_zero(pstr);

   skipblanks();
   if (ch == '\"') {
      /* String quoted in "" */
      nextch();
      while (1) {
	 if (isEol(ch)) {
	    compile_error(-/*Missing \"*/69);
	    LONGJMP(file.jbSkipLine);
	 }

	 if (ch == '\"') break;

	 s_catchar(pstr, plen, ch);
	 nextch();
      }
   } else {
      /* Unquoted string */
      while (1) {
	 if (isEol(ch) || isComm(ch)) {
	    if (!*pstr || !(*pstr)[0]) {
	       compile_error(-/*Expecting string field*/121);
	       LONGJMP(file.jbSkipLine);
	    }
	    return;
	 }

	 if (isBlank(ch)) break;

	 s_catchar(pstr, plen, ch);
	 nextch();
      }
   }

   nextch();
}
예제 #4
0
/* read word */
static void
get_word(void)
{
   s_zero(&buffer);
   skipblanks();
   while (!isBlank(ch) && !isEol(ch)) {
      s_catchar(&buffer, &buf_len, (char)ch);
      nextch();
   }

   if (!buffer) s_catchar(&buffer, &buf_len, '\0');
#if 0
   printf("get_word() got “%s”\n", buffer);
#endif
}
예제 #5
0
Token Lexer::nextToken()
{
    if (atEof_) {
        return Token(TokenType::END_OF_INPUT, "");
    }

    if (std::isdigit(next_)) {
        return parseNumber();
    } else if (isIdentifierStart(next_)) {
        return parseIdentifier();
    } else if (isEol(next_)) {
        return parseNewLine();
    } else {
        return parseOperator();
    }
}
예제 #6
0
GLECSVDataStatus GLECSVData::readNewline(GLEBYTE prevCh) {
	m_lines++;
	m_nextLine = true;
	GLEBYTE ch = readChar();
	if (ch == 0) {
		m_firstColumn = m_pos;
		return GLECSVDataStatusEOF;
	}
	if (isEol(ch) && (ch != prevCh)) {
		// Found, e.g., CR followed by LF (Windows encoding of new line)
		m_firstColumn = m_pos;
		return GLECSVDataStatusEOL;
	}
	// Found just CR or just LF (Unix / Mac encoding of new line)
	goBack();
	m_firstColumn = m_pos;
	return GLECSVDataStatusEOL;
}
예제 #7
0
GLECSVDataStatus GLECSVData::skipSpacesAndFirstDelim(GLEBYTE ch) {
	while (true) {
		if (!isSpace(ch)) {
			if (ch == 0) {
				return GLECSVDataStatusEOF;
			} else if (isEol(ch)) {
				return readNewline(ch);
			} else if (isDelim(ch)) {
				m_lastDelimWasSpace = isSpace(ch);
				return GLECSVDataStatusOK;
			} else {
				goBack();
				return GLECSVDataStatusOK;
			}
		}
		ch = readChar();
	}
	return GLECSVDataStatusOK;
}
예제 #8
0
GLECSVDataStatus GLECSVData::readCell() {
	GLEBYTE ch = readSignificantChar();
	if (ch == '"' || ch == '\'') {
		return readCellString(ch);
	}
	unsigned int cellCount = 0;
	unsigned int cellSize = 0;
	unsigned int cellPos = lastCharPos();
	while (true) {
		if (ch == 0) {
			if (isSizeCheckOKEndOfLine(cellSize)) {
				createCell(cellSize, cellPos);
			}
			return GLECSVDataStatusEOF;
		} else if (isEol(ch)) {
			if (isSizeCheckOKEndOfLine(cellSize)) {
				createCell(cellSize, cellPos);
			}
			return readNewline(ch);
		} else if (isDelim(ch)) {
			m_lastDelimWasSpace = isSpace(ch);
			if (isSizeCheckOKAtDelim(ch, cellSize)) {
				createCell(cellSize, cellPos);
			}
			return skipSpacesAndFirstDelim(ch);
		} else if (isComment(ch)) {
			if (isSizeCheckOKEndOfLine(cellSize)) {
				createCell(cellSize, cellPos);
			}
			return skipTillEol();
		}
		cellCount++;
		if (!isSpace(ch)) {
			cellSize = cellCount;
		}
		ch = readChar();
	}
	return GLECSVDataStatusOK;
}
예제 #9
0
void Lexer::skipSpaces()
{
    while (!atEof_ && !isEol(next_) && std::isspace(next_)) {
        advance();
    }
}
예제 #10
0
static void
cmd_fix(void)
{
   prefix *fix_name;
   node *stn = NULL;
   static node *stnOmitAlready = NULL;
   real x, y, z;
   int nx, ny, nz;
   filepos fp;

   fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
   fix_name->sflags |= BIT(SFLAGS_FIXED);

   get_pos(&fp);
   get_token();
   if (strcmp(ucbuffer, "REFERENCE") == 0) {
      /* suppress "unused fixed point" warnings for this station */
      fix_name->sflags |= BIT(SFLAGS_USED);
   } else {
      if (*ucbuffer) set_pos(&fp);
   }

   x = read_numeric(fTrue, &nx);
   if (x == HUGE_REAL) {
      /* If the end of the line isn't blank, read a number after all to
       * get a more helpful error message */
      if (!isEol(ch) && !isComm(ch)) x = read_numeric(fFalse, &nx);
   }
   if (x == HUGE_REAL) {
      if (stnOmitAlready) {
	 if (fix_name != stnOmitAlready->name) {
	    compile_error_skip(/*More than one FIX command with no coordinates*/56);
	 } else {
	    compile_warning(/*Same station fixed twice with no coordinates*/61);
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
      compile_warning(/*FIX command with no coordinates - fixing at (0,0,0)*/54);
      x = y = z = (real)0.0;
      stnOmitAlready = stn;
   } else {
      real sdx;
      y = read_numeric(fFalse, &ny);
      z = read_numeric(fFalse, &nz);
      sdx = read_numeric(fTrue, NULL);
      if (sdx != HUGE_REAL) {
	 real sdy, sdz;
	 real cxy = 0, cyz = 0, czx = 0;
	 sdy = read_numeric(fTrue, NULL);
	 if (sdy == HUGE_REAL) {
	    /* only one variance given */
	    sdy = sdz = sdx;
	 } else {
	    sdz = read_numeric(fTrue, NULL);
	    if (sdz == HUGE_REAL) {
	       /* two variances given - horizontal & vertical */
	       sdz = sdy;
	       sdy = sdx;
	    } else {
	       cxy = read_numeric(fTrue, NULL);
	       if (cxy != HUGE_REAL) {
		  /* covariances given */
		  cyz = read_numeric(fFalse, NULL);
		  czx = read_numeric(fFalse, NULL);
	       } else {
		  cxy = 0;
	       }
	    }
	 }
	 stn = StnFromPfx(fix_name);
	 if (!fixed(stn)) {
	    node *fixpt = osnew(node);
	    prefix *name;
	    name = osnew(prefix);
	    name->pos = osnew(pos);
	    name->ident = NULL;
	    name->shape = 0;
	    fixpt->name = name;
	    name->stn = fixpt;
	    name->up = NULL;
	    if (TSTBIT(pcs->infer, INFER_EXPORTS)) {
	       name->min_export = USHRT_MAX;
	    } else {
	       name->min_export = 0;
	    }
	    name->max_export = 0;
	    name->sflags = 0;
	    add_stn_to_list(&stnlist, fixpt);
	    POS(fixpt, 0) = x;
	    POS(fixpt, 1) = y;
	    POS(fixpt, 2) = z;
	    fix(fixpt);
	    fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL;
	    addfakeleg(fixpt, stn, 0, 0, 0,
		       sdx * sdx, sdy * sdy, sdz * sdz
#ifndef NO_COVARIANCES
		       , cxy, cyz, czx
#endif
		       );
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
   }

   if (!fixed(stn)) {
      POS(stn, 0) = x;
      POS(stn, 1) = y;
      POS(stn, 2) = z;
      fix(stn);
      return;
   }

   if (x != POS(stn, 0) || y != POS(stn, 1) || z != POS(stn, 2)) {
      compile_error(/*Station already fixed or equated to a fixed point*/46);
      return;
   }
   compile_warning(/*Station already fixed at the same coordinates*/55);
}
예제 #11
0
static void
cmd_set(void)
{
   static sztok chartab[] = {
	{"BLANK",     SPECIAL_BLANK },
/*FIXME	{"CLOSE",     SPECIAL_CLOSE }, */
	{"COMMENT",   SPECIAL_COMMENT },
	{"DECIMAL",   SPECIAL_DECIMAL },
	{"EOL",       SPECIAL_EOL }, /* EOL won't work well */
	{"KEYWORD",   SPECIAL_KEYWORD },
	{"MINUS",     SPECIAL_MINUS },
	{"NAMES",     SPECIAL_NAMES },
	{"OMIT",      SPECIAL_OMIT },
/*FIXME	{"OPEN",      SPECIAL_OPEN }, */
	{"PLUS",      SPECIAL_PLUS },
#ifndef NO_DEPRECATED
	{"ROOT",      SPECIAL_ROOT },
#endif
	{"SEPARATOR", SPECIAL_SEPARATOR },
	{NULL,	      SPECIAL_UNKNOWN }
   };
   int mask;
   int i;

   get_token();
   mask = match_tok(chartab, TABSIZE(chartab));

   if (mask == SPECIAL_UNKNOWN) {
      file.lpos += strlen(buffer);
      compile_error_skip(-/*Unknown character class “%s”*/42, buffer);
      return;
   }

#ifndef NO_DEPRECATED
   if (mask == SPECIAL_ROOT) {
      if (root_depr_count < 5) {
	 file.lpos += strlen(buffer);
	 compile_warning(-/*ROOT is deprecated*/25);
	 if (++root_depr_count == 5)
	    compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
      }
   }
#endif

   /* if we're currently using an inherited translation table, allocate a new
    * table, and copy old one into it */
   if (pcs->next && pcs->next->Translate == pcs->Translate) {
      short *p;
      p = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
      memcpy(p - 1, pcs->Translate - 1, sizeof(short) * 257);
      pcs->Translate = p;
   }

   skipblanks();

   /* clear this flag for all non-alphanums */
   for (i = 0; i < 256; i++)
      if (!isalnum(i)) pcs->Translate[i] &= ~mask;

   /* now set this flag for all specified chars */
   while (!isEol(ch)) {
      if (!isalnum(ch)) {
	 pcs->Translate[ch] |= mask;
      } else if (tolower(ch) == 'x') {
	 int hex;
	 filepos fp;
	 get_pos(&fp);
	 nextch();
	 if (!isxdigit(ch)) {
	    set_pos(&fp);
	    break;
	 }
	 hex = isdigit(ch) ? ch - '0' : tolower(ch) - 'a';
	 nextch();
	 if (!isxdigit(ch)) {
	    set_pos(&fp);
	    break;
	 }
	 hex = hex << 4 | (isdigit(ch) ? ch - '0' : tolower(ch) - 'a');
	 pcs->Translate[hex] |= mask;
      } else {
	 break;
      }
      nextch();
   }
}
예제 #12
0
/* if prefix is omitted: if PFX_OPT set return NULL, otherwise use longjmp */
extern prefix *
read_prefix(unsigned pfx_flags)
{
   bool f_optional = !!(pfx_flags & PFX_OPT);
   bool fSurvey = !!(pfx_flags & PFX_SURVEY);
   bool fSuspectTypo = !!(pfx_flags & PFX_SUSPECT_TYPO);
   prefix *back_ptr, *ptr;
   char *name;
   size_t name_len = 32;
   size_t i;
   bool fNew;
   bool fImplicitPrefix = fTrue;
   int depth = -1;
   filepos fp_firstsep;

   skipblanks();
#ifndef NO_DEPRECATED
   if (isRoot(ch)) {
      if (!(pfx_flags & PFX_ALLOW_ROOT)) {
	 compile_diagnostic(DIAG_ERR|DIAG_COL, /*ROOT is deprecated*/25);
	 LONGJMP(file.jbSkipLine);
      }
      if (root_depr_count < 5) {
	 compile_diagnostic(DIAG_WARN|DIAG_COL, /*ROOT is deprecated*/25);
	 if (++root_depr_count == 5)
	    compile_diagnostic(DIAG_WARN, /*Further uses of this deprecated feature will not be reported*/95);
      }
      nextch();
      ptr = root;
      if (!isNames(ch)) {
	 if (!isSep(ch)) return ptr;
	 /* Allow optional SEPARATOR after ROOT */
	 get_pos(&fp_firstsep);
	 nextch();
      }
      fImplicitPrefix = fFalse;
#else
   if (0) {
#endif
   } else {
      if ((pfx_flags & PFX_ANON) &&
	  (isSep(ch) || (pcs->dash_for_anon_wall_station && ch == '-'))) {
	 int first_ch = ch;
	 filepos here;
	 get_pos(&here);
	 nextch();
	 if (isBlank(ch) || isEol(ch)) {
	    if (!isSep(first_ch))
	       goto anon_wall_station;
	    /* A single separator alone ('.' by default) is an anonymous
	     * station which is on a point inside the passage and implies
	     * the leg to it is a splay.
	     */
	    if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
	       set_pos(&here);
	       compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
	       LONGJMP(file.jbSkipLine);
	    }
	    pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
	    return new_anon_station();
	 }
	 if (isSep(first_ch) && ch == first_ch) {
	    nextch();
	    if (isBlank(ch) || isEol(ch)) {
	       /* A double separator ('..' by default) is an anonymous station
		* which is on the wall and implies the leg to it is a splay.
		*/
	       prefix * pfx;
anon_wall_station:
	       if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
		  set_pos(&here);
		  compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
		  LONGJMP(file.jbSkipLine);
	       }
	       pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
	       pfx = new_anon_station();
	       pfx->sflags |= BIT(SFLAGS_WALL);
	       return pfx;
	    }
	    if (ch == first_ch) {
	       nextch();
	       if (isBlank(ch) || isEol(ch)) {
		  /* A triple separator ('...' by default) is an anonymous
		   * station, but otherwise not handled specially (e.g. for
		   * a single leg down an unexplored side passage to a station
		   * which isn't refindable).
		   */
		  if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
		     set_pos(&here);
		     compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
		     LONGJMP(file.jbSkipLine);
		  }
		  pcs->flags |= BIT(FLAGS_ANON_ONE_END);
		  return new_anon_station();
	       }
	    }
	 }
	 set_pos(&here);
      }
      ptr = pcs->Prefix;
   }

   i = 0;
   name = NULL;
   do {
      fNew = fFalse;
      if (name == NULL) {
	 /* Need a new name buffer */
	 name = osmalloc(name_len);
      }
      /* i==0 iff this is the first pass */
      if (i) {
	 i = 0;
	 nextch();
      }
      while (isNames(ch)) {
	 if (i < pcs->Truncate) {
	    /* truncate name */
	    name[i++] = (pcs->Case == LOWER ? tolower(ch) :
			 (pcs->Case == OFF ? ch : toupper(ch)));
	    if (i >= name_len) {
	       name_len = name_len + name_len;
	       name = osrealloc(name, name_len);
	    }
	 }
	 nextch();
      }
      if (isSep(ch)) {
	 fImplicitPrefix = fFalse;
	 get_pos(&fp_firstsep);
      }
      if (i == 0) {
	 osfree(name);
	 if (!f_optional) {
	    if (isEol(ch)) {
	       if (fSurvey) {
		  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting survey name*/89);
	       } else {
		  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting station name*/28);
	       }
	    } else {
	       /* TRANSLATORS: Here "station" is a survey station, not a train station. */
	       compile_diagnostic(DIAG_ERR|DIAG_COL, /*Character “%c” not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch);
	    }
	    LONGJMP(file.jbSkipLine);
	 }
	 return (prefix *)NULL;
      }

      name[i++] = '\0';

      back_ptr = ptr;
      ptr = ptr->down;
      if (ptr == NULL) {
	 /* Special case first time around at each level */
	 name = osrealloc(name, i);
	 ptr = osnew(prefix);
	 ptr->ident = name;
	 name = NULL;
	 ptr->right = ptr->down = NULL;
	 ptr->pos = NULL;
	 ptr->shape = 0;
	 ptr->stn = NULL;
	 ptr->up = back_ptr;
	 ptr->filename = file.filename;
	 ptr->line = file.line;
	 ptr->min_export = ptr->max_export = 0;
	 ptr->sflags = BIT(SFLAGS_SURVEY);
	 if (fSuspectTypo && !fImplicitPrefix)
	    ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
	 back_ptr->down = ptr;
	 fNew = fTrue;
      } else {
	 /* Use caching to speed up adding an increasing sequence to a
	  * large survey */
	 static prefix *cached_survey = NULL, *cached_station = NULL;
	 prefix *ptrPrev = NULL;
	 int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
	 if (cached_survey == back_ptr) {
	    cmp = strcmp(cached_station->ident, name);
	    if (cmp <= 0) ptr = cached_station;
	 }
	 while (ptr && (cmp = strcmp(ptr->ident, name))<0) {
	    ptrPrev = ptr;
	    ptr = ptr->right;
	 }
	 if (cmp) {
	    /* ie we got to one that was higher, or the end */
	    prefix *newptr;
	    name = osrealloc(name, i);
	    newptr = osnew(prefix);
	    newptr->ident = name;
	    name = NULL;
	    if (ptrPrev == NULL)
	       back_ptr->down = newptr;
	    else
	       ptrPrev->right = newptr;
	    newptr->right = ptr;
	    newptr->down = NULL;
	    newptr->pos = NULL;
	    newptr->shape = 0;
	    newptr->stn = NULL;
	    newptr->up = back_ptr;
	    newptr->filename = file.filename;
	    newptr->line = file.line;
	    newptr->min_export = newptr->max_export = 0;
	    newptr->sflags = BIT(SFLAGS_SURVEY);
	    if (fSuspectTypo && !fImplicitPrefix)
	       newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
	    ptr = newptr;
	    fNew = fTrue;
	 }
	 cached_survey = back_ptr;
	 cached_station = ptr;
      }
      depth++;
      f_optional = fFalse; /* disallow after first level */
      if (isSep(ch)) get_pos(&fp_firstsep);
   } while (isSep(ch));
   if (name) osfree(name);

   /* don't warn about a station that is referred to twice */
   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);

   if (fNew) {
      /* fNew means SFLAGS_SURVEY is currently set */
      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
      if (!fSurvey) {
	 ptr->sflags &= ~BIT(SFLAGS_SURVEY);
	 if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
      }
   } else {
      /* check that the same name isn't being used for a survey and station */
      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
	 /* TRANSLATORS: Here "station" is a survey station, not a train station.
	  *
	  * Here "survey" is a "cave map" rather than list of questions - it should be
	  * translated to the terminology that cavers using the language would use.
	  */
	 compile_diagnostic(DIAG_ERR, /*“%s” can’t be both a station and a survey*/27,
			    sprint_prefix(ptr));
      }
      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
   }

   /* check the export level */
#if 0
   printf("R min %d max %d depth %d pfx %s\n",
	  ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr));
#endif
   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
      if (depth > ptr->max_export) ptr->max_export = depth;
   } else if (ptr->max_export < depth) {
      prefix *survey = ptr;
      char *s;
      const char *p;
      int level;
      for (level = ptr->max_export + 1; level; level--) {
	 survey = survey->up;
	 SVX_ASSERT(survey);
      }
      s = osstrdup(sprint_prefix(survey));
      p = sprint_prefix(ptr);
      if (survey->filename) {
	 compile_diagnostic_pfx(DIAG_ERR, survey,
				/*Station “%s” not exported from survey “%s”*/26,
				p, s);
      } else {
	 compile_diagnostic(DIAG_ERR, /*Station “%s” not exported from survey “%s”*/26, p, s);
      }
      osfree(s);
#if 0
      printf(" *** pfx %s warning not exported enough depth %d "
	     "ptr->max_export %d\n", sprint_prefix(ptr),
	     depth, ptr->max_export);
#endif
   }
   if (!fImplicitPrefix && (pfx_flags & PFX_WARN_SEPARATOR)) {
      filepos fp_tmp;
      get_pos(&fp_tmp);
      set_pos(&fp_firstsep);
      compile_diagnostic(DIAG_WARN|DIAG_COL, /*Separator in survey name*/392);
      set_pos(&fp_tmp);
   }
   return ptr;
}

/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
static real
read_number(bool f_optional)
{
   bool fPositive, fDigits = fFalse;
   real n = (real)0.0;
   filepos fp;
   int ch_old;

   get_pos(&fp);
   ch_old = ch;
   fPositive = !isMinus(ch);
   if (isSign(ch)) nextch();

   while (isdigit(ch)) {
      n = n * (real)10.0 + (char)(ch - '0');
      nextch();
      fDigits = fTrue;
   }

   if (isDecimal(ch)) {
      real mult = (real)1.0;
      nextch();
      while (isdigit(ch)) {
	 mult *= (real).1;
	 n += (char)(ch - '0') * mult;
	 fDigits = fTrue;
	 nextch();
      }
   }

   /* !'fRead' => !fDigits so fDigits => 'fRead' */
   if (fDigits) return (fPositive ? n : -n);

   /* didn't read a valid number.  If it's optional, reset filepos & return */
   set_pos(&fp);
   if (f_optional) {
      return HUGE_REAL;
   }

   if (isOmit(ch_old)) {
      compile_diagnostic(DIAG_ERR|DIAG_COL, /*Field may not be omitted*/8);
   } else {
      compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found “%s”*/9);
   }
   LONGJMP(file.jbSkipLine);
   return 0.0; /* for brain-fried compilers */
}