/ src / emc / rs274ngc / interp_read.cc
interp_read.cc
   1  /********************************************************************
   2  * Description: interp_read.cc
   3  *
   4  *   Derived from a work by Thomas Kramer
   5  *
   6  * Author:
   7  * License: GPL Version 2
   8  * System: Linux
   9  *    
  10  * Copyright (c) 2004 All rights reserved.
  11  *
  12  * Last change:
  13  ********************************************************************/
  14  #ifndef _GNU_SOURCE
  15  #define _GNU_SOURCE
  16  #endif
  17  #include <unistd.h>
  18  #include <stdio.h>
  19  #include <stdlib.h>
  20  #include <math.h>
  21  #include <string.h>
  22  #include <ctype.h>
  23  #include <sys/types.h>
  24  #include <sys/stat.h>
  25  #include <sstream>
  26  #include "rs274ngc.hh"
  27  #include "rs274ngc_return.hh"
  28  #include "interp_internal.hh"
  29  #include "rs274ngc_interp.hh"
  30  #include "rtapi_math.h"
  31  #include <cmath>
  32  
  33  using namespace interp_param_global;
  34  
  35  /****************************************************************************/
  36  
  37  /*! read_a
  38  
  39  Returned Value: int
  40     If read_real_value returns an error code, this returns that code.
  41     If any of the following errors occur, this returns the error code shown.
  42     Otherwise, it returns INTERP_OK.
  43     1. The first character read is not a:
  44        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
  45     2. An a_coordinate has already been inserted in the block:
  46        NCE_MULTIPLE_A_WORDS_ON_ONE_LINE.
  47     3. A values are not allowed: NCE_CANNOT_USE_A_WORD.
  48  
  49  Side effects:
  50     counter is reset.
  51     The a_flag in the block is turned on.
  52     An a_number is inserted in the block.
  53  
  54  Called by: read_one_item
  55  
  56  When this function is called, counter is pointing at an item on the
  57  line that starts with the character 'a', indicating an a_coordinate
  58  setting. The function reads characters which tell how to set the
  59  coordinate, up to the start of the next item or the end of the line.
  60  The counter is then set to point to the character following.
  61  
  62  The value may be a real number or something that evaluates to a
  63  real number, so read_real_value is used to read it. Parameters
  64  may be involved.
  65  
  66  If the AA compiler flag is defined, the a_flag in the block is turned
  67  on and the a_number in the block is set to the value read. If the
  68  AA flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
  69  A values are not allowed, and an error value is returned, (ii) if the
  70  AXIS_ERROR flag is not defined, nothing is done.
  71  
  72  */
  73  
  74  int Interp::read_a(char *line,   //!< string: line of RS274/NGC code being processed
  75                    int *counter, //!< pointer to a counter for position on the line 
  76                    block_pointer block,  //!< pointer to a block being filled from the line 
  77                    double *parameters)   //!< array of system parameters                    
  78  {
  79    double value;
  80  
  81    CHKS((line[*counter] != 'a'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
  82    *counter = (*counter + 1);
  83    CHKS((block->a_flag), NCE_MULTIPLE_A_WORDS_ON_ONE_LINE);
  84    CHP(read_real_value(line, counter, &value, parameters));
  85    block->a_flag = true;
  86    block->a_number = value;
  87    return INTERP_OK;
  88  }
  89  
  90  
  91  /****************************************************************************/
  92  
  93  /*! read_atan
  94  
  95  Returned Value: int
  96     If read_real_expression returns an error code, this returns that code.
  97     If any of the following errors occur, this returns the error code shown.
  98     Otherwise, it returns INTERP_OK.
  99     1. The first character to read is not a slash:
 100        NCE_SLASH_MISSING_AFTER_FIRST_ATAN_ARGUMENT
 101     2. The second character to read is not a left bracket:
 102        NCE_LEFT_BRACKET_MISSING_AFTER_SLASH_WITH_ATAN
 103  
 104  Side effects:
 105     The computed value is put into what double_ptr points at.
 106     The counter is reset to point to the first character after the
 107     characters which make up the value.
 108  
 109  Called by:
 110     read_unary
 111  
 112  When this function is called, the characters "atan" and the first
 113  argument have already been read, and the value of the first argument
 114  is stored in double_ptr.  This function attempts to read a slash and
 115  the second argument to the atan function, starting at the index given
 116  by the counter and then to compute the value of the atan operation
 117  applied to the two arguments.  The computed value is inserted into
 118  what double_ptr points at.
 119  
 120  The computed value is in the range from -180 degrees to +180 degrees.
 121  The range is not specified in the RS274/NGC manual [NCMS, page 51],
 122  although using degrees (not radians) is specified.
 123  
 124  */
 125  
 126  int Interp::read_atan(char *line,        //!< string: line of RS274/NGC code being processed
 127                       int *counter,      //!< pointer to a counter for position on line     
 128                       double *double_ptr,        //!< pointer to double to be read                  
 129                       double *parameters)        //!< array of system parameters                    
 130  {
 131    double argument2;
 132  
 133    CHKS((line[*counter] != '/'), NCE_SLASH_MISSING_AFTER_FIRST_ATAN_ARGUMENT);
 134    *counter = (*counter + 1);
 135    CHKS((line[*counter] != '['),
 136        NCE_LEFT_BRACKET_MISSING_AFTER_SLASH_WITH_ATAN);
 137    CHP(read_real_expression(line, counter, &argument2, parameters));
 138    *double_ptr = atan2(*double_ptr, argument2);  /* value in radians */
 139    *double_ptr = ((*double_ptr * 180.0) / M_PIl);   /* convert to degrees */
 140    return INTERP_OK;
 141  }
 142  
 143  /****************************************************************************/
 144  
 145  /*! read_b
 146  
 147  Returned Value: int
 148     If read_real_value returns an error code, this returns that code.
 149     If any of the following errors occur, this returns the error code shown.
 150     Otherwise, it returns INTERP_OK.
 151     1. The first character read is not b:
 152        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 153     2. A b_coordinate has already been inserted in the block:
 154        NCE_MULTIPLE_B_WORDS_ON_ONE_LINE.
 155     3. B values are not allowed: NCE_CANNOT_USE_B_WORD
 156  
 157  Side effects:
 158     counter is reset.
 159     The b_flag in the block is turned on.
 160     A b_number is inserted in the block.
 161  
 162  Called by: read_one_item
 163  
 164  When this function is called, counter is pointing at an item on the
 165  line that starts with the character 'b', indicating a b_coordinate
 166  setting. The function reads characters which tell how to set the
 167  coordinate, up to the start of the next item or the end of the line.
 168  The counter is then set to point to the character following.
 169  
 170  The value may be a real number or something that evaluates to a
 171  real number, so read_real_value is used to read it. Parameters
 172  may be involved.
 173  
 174  If the BB compiler flag is defined, the b_flag in the block is turned
 175  on and the b_number in the block is set to the value read. If the
 176  BB flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
 177  B values are not allowed, and an error value is returned, (ii) if the
 178  AXIS_ERROR flag is not defined, nothing is done.
 179  
 180  */
 181  
 182  int Interp::read_b(char *line,   //!< string: line of RS274/NGC code being processed
 183                    int *counter, //!< pointer to a counter for position on the line 
 184                    block_pointer block,  //!< pointer to a block being filled from the line 
 185                    double *parameters)   //!< array of system parameters                    
 186  {
 187    double value;
 188  
 189    CHKS((line[*counter] != 'b'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 190    *counter = (*counter + 1);
 191    CHKS((block->b_flag), NCE_MULTIPLE_B_WORDS_ON_ONE_LINE);
 192    CHP(read_real_value(line, counter, &value, parameters));
 193    block->b_flag = true;
 194    block->b_number = value;
 195    return INTERP_OK;
 196  }
 197  
 198  /****************************************************************************/
 199  
 200  /*! read_c
 201  
 202  Returned Value: int
 203     If read_real_value returns an error code, this returns that code.
 204     If any of the following errors occur, this returns the error code shown.
 205     Otherwise, it returns INTERP_OK.
 206     1. The first character read is not c:
 207        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 208     2. An c_coordinate has already been inserted in the block:
 209        NCE_MULTIPLE_C_WORDS_ON_ONE_LINE
 210     3. C values are not allowed: NCE_CANNOT_USE_C_WORD
 211  
 212  Side effects:
 213     counter is reset.
 214     The c_flag in the block is turned on.
 215     A c_number is inserted in the block.
 216  
 217  Called by: read_one_item
 218  
 219  When this function is called, counter is pointing at an item on the
 220  line that starts with the character 'c', indicating an c_coordinate
 221  setting. The function reads characters which tell how to set the
 222  coordinate, up to the start of the next item or the end of the line.
 223  The counter is then set to point to the character following.
 224  
 225  The value may be a real number or something that evaluates to a
 226  real number, so read_real_value is used to read it. Parameters
 227  may be involved.
 228  
 229  If the CC compiler flag is defined, the c_flag in the block is turned
 230  on and the c_number in the block is set to the value read. If the
 231  CC flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
 232  C values are not allowed, and an error value is returned, (ii) if the
 233  AXIS_ERROR flag is not defined, nothing is done.
 234  
 235  */
 236  
 237  int Interp::read_c(char *line,   //!< string: line of RS274/NGC code being processed
 238                    int *counter, //!< pointer to a counter for position on the line 
 239                    block_pointer block,  //!< pointer to a block being filled from the line 
 240                    double *parameters)   //!< array of system parameters                    
 241  {
 242    double value;
 243  
 244    CHKS((line[*counter] != 'c'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 245    *counter = (*counter + 1);
 246    CHKS((block->c_flag), NCE_MULTIPLE_C_WORDS_ON_ONE_LINE);
 247    CHP(read_real_value(line, counter, &value, parameters));
 248    block->c_flag = true;
 249    block->c_number = value;
 250    return INTERP_OK;
 251  }
 252  
 253  /****************************************************************************/
 254  
 255  /*! read_comment
 256  
 257  Returned Value: int
 258    If any of the following errors occur, this returns the error code shown.
 259     Otherwise, it returns INTERP_OK.
 260     1. The first character read is not '(' ,
 261        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 262  
 263  Side effects:
 264     The counter is reset to point to the character following the comment.
 265     The comment string, without parentheses, is copied into the comment
 266     area of the block.
 267  
 268  Called by: read_one_item
 269  
 270  When this function is called, counter is pointing at an item on the
 271  line that starts with the character '(', indicating a comment is
 272  beginning. The function reads characters of the comment, up to and
 273  including the comment closer ')'.
 274  
 275  It is expected that the format of a comment will have been checked (by
 276  read_text or read_keyboard_line) and bad format comments will
 277  have prevented the system from getting this far, so that this function
 278  can assume a close parenthesis will be found when an open parenthesis
 279  has been found, and that comments are not nested.
 280  
 281  The "parameters" argument is not used in this function. That argument is
 282  present only so that this will have the same argument list as the other
 283  "read_XXX" functions called using a function pointer by read_one_item.
 284  
 285  */
 286  
 287  int Interp::read_comment(char *line,     //!< string: line of RS274 code being processed   
 288                          int *counter,   //!< pointer to a counter for position on the line
 289                          block_pointer block,    //!< pointer to a block being filled from the line
 290                          double *parameters)     //!< array of system parameters                   
 291  {
 292    int n;
 293  
 294    CHKS((line[*counter] != '('), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 295    (*counter)++;
 296    for (n = 0; line[*counter] != ')'; (*counter)++, n++) {
 297      block->comment[n] = line[*counter];
 298    }
 299    block->comment[n] = 0;
 300    (*counter)++;
 301    return INTERP_OK;
 302  }
 303  
 304  // A semicolon marks the beginning of a comment.  The comment goes to
 305  // the end of the line.
 306  
 307  int Interp::read_semicolon(char *line,     //!< string: line of RS274 code being processed   
 308                             int *counter,   //!< pointer to a counter for position on the line
 309                             block_pointer block,    //!< pointer to a block being filled from the line
 310                             double *parameters)     //!< array of system parameters                   
 311  {
 312      char *s;
 313      CHKS((line[*counter] != ';'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 314      (*counter) = strlen(line);
 315      // pass unmutilated line to convert_comment - FIXME access to _setup
 316      if (( s = strchr(_setup.linetext,';')) != NULL)
 317  	CHP(convert_comment(s+1, false));
 318      return INTERP_OK;
 319  }
 320  
 321  /****************************************************************************/
 322  
 323  /*! read_d
 324  
 325  Returned Value: int
 326     If read_integer_value returns an error code, this returns that code.
 327     If any of the following errors occur, this returns the error code shown.
 328     Otherwise, it returns INTERP_OK.
 329     1. The first character read is not d:
 330        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 331     2. A d_number has already been inserted in the block:
 332        NCE_MULTIPLE_D_WORDS_ON_ONE_LINE
 333  
 334  Side effects:
 335     counter is reset to the character following the tool number.
 336     A d_number is inserted in the block.
 337  
 338  Called by: read_one_item
 339  
 340  When this function is called, counter is pointing at an item on the
 341  line that starts with the character 'd', indicating an index into a
 342  table of tool diameters.  The function reads characters which give the
 343  (integer) value of the index. The value may not be more than
 344  _setup.tool_max and may not be negative, but it may be zero. The range
 345  is checked here.
 346  
 347  read_integer_value allows a minus sign, so a check for a negative value
 348  is made here, and the parameters argument is also needed.
 349  
 350  */
 351  
 352  int Interp::read_d(char *line,   //!< string: line of RS274 code being processed   
 353                    int *counter, //!< pointer to a counter for position on the line
 354                    block_pointer block,  //!< pointer to a block being filled from the line
 355                    double *parameters)   //!< array of system parameters                   
 356  {
 357    double value;
 358  
 359    CHKS((line[*counter] != 'd'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 360    *counter = (*counter + 1);
 361    CHKS((block->d_flag), NCE_MULTIPLE_D_WORDS_ON_ONE_LINE);
 362    CHP(read_real_value(line, counter, &value, parameters));
 363    block->d_number_float = value;
 364    block->d_flag = true;
 365    return INTERP_OK;
 366  }
 367  
 368  /****************************************************************************/
 369  
 370  /*! read_dollar
 371  
 372  Returned Value: int
 373     If read_integer_value returns an error code, this returns that code.
 374     If any of the following errors occur, this returns the error code shown.
 375     Otherwise, it returns INTERP_OK.
 376     1. The first character read is not d:
 377        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 378     2. A dollar_number has already been inserted in the block:
 379        NCE_MULTIPLE_$_WORDS_ON_ONE_LINE
 380  
 381  Side effects:
 382     counter is reset to the character following the tool number.
 383     A d_number is inserted in the block.
 384  
 385  Called by: read_one_item
 386  
 387  When this function is called, counter is pointing at an item on the
 388  line that starts with the character 'd', indicating an index into a
 389  table of tool diameters.  The function reads characters which give the
 390  (integer) value of the index. The value may not be more than
 391  _setup.tool_max and may not be negative, but it may be zero. The range
 392  is checked here.
 393  
 394  read_integer_value allows a minus sign, so a check for a negative value
 395  is made here, and the parameters argument is also needed.
 396  
 397  */
 398  
 399  int Interp::read_dollar(char *line,   //!< string: line of RS274 code being processed
 400                    int *counter, //!< pointer to a counter for position on the line
 401                    block_pointer block,  //!< pointer to a block being filled from the line
 402                    double *parameters)   //!< array of system parameters
 403  {
 404    double value;
 405    CHKS((line[*counter] != '$'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 406    *counter = (*counter + 1);
 407    CHKS((block->dollar_flag), NCE_MULTIPLE_$_WORDS_ON_ONE_LINE);
 408    CHP(read_real_value(line, counter, &value, parameters));
 409    block->dollar_number = value;
 410    block->dollar_flag = true;
 411    return INTERP_OK;
 412  }
 413  
 414  /****************************************************************************/
 415  
 416  /*! read_e
 417  
 418  Returned Value: int
 419     If read_real_value returns an error code, this returns that code.
 420     If any of the following errors occur, this returns the error code shown.
 421     Otherwise, it returns INTERP_OK.
 422     1. The first character read is not e:
 423        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 424     2. A e value has already been inserted in the block:
 425        NCE_MULTIPLE_E_WORDS_ON_ONE_LINE
 426  
 427  Side effects:
 428     counter is reset to point to the first character following the e value.
 429     The e value setting is inserted in block.
 430  
 431  Called by: read_one_item
 432  
 433  When this function is called, counter is pointing at an item on the
 434  line that starts with the character 'e', indicating a e value
 435  setting. The function reads characters which tell how to set the e
 436  value, up to the start of the next item or the end of the line. This
 437  information is inserted in the block.
 438  
 439  E codes are used for:
 440  Infeed/Outfeed angle specification with G76
 441  
 442  */
 443  
 444  int Interp::read_e(char *line,   //!< string: line of RS274/NGC code being processed
 445                    int *counter, //!< pointer to a counter for position on the line 
 446                    block_pointer block,  //!< pointer to a block being filled from the line 
 447                    double *parameters)   //!< array of system parameters                    
 448  {
 449    double value;
 450  
 451    CHKS((line[*counter] != 'e'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 452    *counter = (*counter + 1);
 453    CHKS((block->e_flag), NCE_MULTIPLE_E_WORDS_ON_ONE_LINE);
 454    CHP(read_real_value(line, counter, &value, parameters));
 455    block->e_flag = true;
 456    block->e_number = value;
 457    return INTERP_OK;
 458  }
 459  
 460  
 461  /****************************************************************************/
 462  
 463  /*! read_f
 464  
 465  Returned Value: int
 466     If read_real_value returns an error code, this returns that code.
 467     If any of the following errors occur, this returns the error code shown.
 468     Otherwise, it returns INTERP_OK.
 469     1. The first character read is not f:
 470        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 471     2. An f_number has already been inserted in the block:
 472        NCE_MULTIPLE_F_WORDS_ON_ONE_LINE
 473     3. The f_number is negative: NCE_NEGATIVE_F_WORD_USED
 474  
 475  Side effects:
 476     counter is reset to point to the first character following the f_number.
 477     The f_number is inserted in block and the f_flag is set.
 478  
 479  Called by: read_one_item
 480  
 481  When this function is called, counter is pointing at an item on the
 482  line that starts with the character 'f'. The function reads characters
 483  which tell how to set the f_number, up to the start of the next item
 484  or the end of the line. This information is inserted in the block.
 485  
 486  The value may be a real number or something that evaluates to a real
 487  number, so read_real_value is used to read it. Parameters may be
 488  involved, so the parameters argument is required. The value is always
 489  a feed rate.
 490  
 491  */
 492  
 493  int Interp::read_f(char *line,   //!< string: line of RS274 code being processed   
 494                    int *counter, //!< pointer to a counter for position on the line
 495                    block_pointer block,  //!< pointer to a block being filled from the line
 496                    double *parameters)   //!< array of system parameters                   
 497  {
 498    double value;
 499  
 500    CHKS((line[*counter] != 'f'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 501    *counter = (*counter + 1);
 502    CHKS((block->f_flag), NCE_MULTIPLE_F_WORDS_ON_ONE_LINE);
 503    CHP(read_real_value(line, counter, &value, parameters));
 504    CHKS((value < 0.0), NCE_NEGATIVE_F_WORD_USED);
 505    block->f_number = value;
 506    block->f_flag = true;
 507    return INTERP_OK;
 508  }
 509  
 510  /****************************************************************************/
 511  
 512  /*! read_g
 513  
 514  Returned Value: int
 515     If read_real_value returns an error code, this returns that code.
 516     If any of the following errors occur, this returns the error code shown.
 517     Otherwise, it returns INTERP_OK.
 518     1. The first character read is not g:
 519        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 520     2. The value is negative: NCE_NEGATIVE_G_CODE_USED
 521     3. The value differs from a number ending in an even tenth by more
 522        than 0.0001: NCE_G_CODE_OUT_OF_RANGE
 523     4. The value is greater than 99.9: NCE_G_CODE_OUT_OF_RANGE
 524     5. The value is not the number of a valid g code: NCE_UNKNOWN_G_CODE_USED
 525     6. Another g code from the same modal group has already been
 526        inserted in the block: NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP
 527  
 528  Side effects:
 529     counter is reset to the character following the end of the g_code.
 530     A g code is inserted as the value of the appropriate mode in the
 531     g_modes array in the block.
 532     The g code counter in the block is increased by 1.
 533  
 534  Called by: read_one_item
 535  
 536  When this function is called, counter is pointing at an item on the
 537  line that starts with the character 'g', indicating a g_code.  The
 538  function reads characters which tell how to set the g_code.
 539  
 540  The RS274/NGC manual [NCMS, page 51] allows g_codes to be represented
 541  by expressions and provide [NCMS, 71 - 73] that a g_code must evaluate
 542  to to a number of the form XX.X (59.1, for example). The manual does not
 543  say how close an expression must come to one of the allowed values for
 544  it to be legitimate. Is 59.099999 allowed to mean 59.1, for example?
 545  In the interpreter, we adopt the convention that the evaluated number
 546  for the g_code must be within 0.0001 of a value of the form XX.X
 547  
 548  To simplify the handling of g_codes, we convert them to integers by
 549  multiplying by 10 and rounding down or up if within 0.001 of an
 550  integer. Other functions that deal with g_codes handle them
 551  symbolically, however. The symbols are defined in rs274NGC.hh
 552  where G_1 is 10, G_83 is 830, etc.
 553  
 554  This allows any number of g_codes on one line, provided that no two
 555  are in the same modal group.
 556  
 557  This allows G80 on the same line as one other g_code with the same
 558  mode. If this happens, the G80 is simply ignored.
 559  
 560  */
 561  
 562  int Interp::read_g(char *line,   //!< string: line of RS274/NGC code being processed
 563                    int *counter, //!< pointer to a counter for position on the line 
 564                    block_pointer block,  //!< pointer to a block being filled from the line 
 565                    double *parameters)   //!< array of system parameters                    
 566  {
 567    double value_read;
 568    int value;
 569    int mode;
 570  
 571    CHKS((line[*counter] != 'g'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 572    *counter = (*counter + 1);
 573    CHP(read_real_value(line, counter, &value_read, parameters));
 574    value_read = (10.0 * value_read);
 575    value = (int) floor(value_read);
 576  
 577    if ((value_read - value) > 0.999)
 578      value = (int) ceil(value_read);
 579    else if ((value_read - value) > 0.001)
 580      ERS(NCE_G_CODE_OUT_OF_RANGE);
 581  
 582    CHKS((value > 999), NCE_G_CODE_OUT_OF_RANGE);
 583    CHKS((value < 0), NCE_NEGATIVE_G_CODE_USED);
 584    // mode = usercode_mgroup(&(_setup),value);
 585    // if (mode != -1) {
 586  
 587   remap_pointer r = _setup.g_remapped[value];
 588    if (r) {
 589        mode =  r->modal_group;
 590        CHKS ((mode < 0),"BUG: G remapping: modal group < 0"); // real bad
 591  
 592        CHKS((block->g_modes[mode] != -1),
 593  	   NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP);
 594        block->g_modes[mode] = value;
 595        return INTERP_OK;
 596    }
 597    mode = _gees[value];
 598    CHKS((mode == -1), NCE_UNKNOWN_G_CODE_USED);
 599    if ((value == G_80) && (block->g_modes[mode] != -1));
 600    else {
 601      if (block->g_modes[mode] == G_80);
 602      else {
 603        CHKS((block->g_modes[mode] != -1),
 604            NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP);
 605      }
 606      block->g_modes[mode] = value;
 607    }
 608    return INTERP_OK;
 609  }
 610  
 611  /****************************************************************************/
 612  
 613  /*! read_h
 614  
 615  Returned Value: int
 616     If read_integer_value returns an error code, this returns that code.
 617     If any of the following errors occur, this returns the error code shown.
 618     Otherwise, it returns INTERP_OK.
 619     1. The first character read is not h:
 620        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 621     2. An h_number has already been inserted in the block:
 622        NCE_MULTIPLE_H_WORDS_ON_ONE_LINE
 623     3. The value is negative: NCE_NEGATIVE_H_WORD_TOOL_LENGTH_OFFSET_INDEX_USED
 624     4. The value is greater than _setup.tool_max:
 625        NCE_TOOL_LENGTH_OFFSET_INDEX_TOO_BIG
 626  
 627  Side effects:
 628     counter is reset to the character following the h_number.
 629     An h_number is inserted in the block.
 630  
 631  Called by: read_one_item
 632  
 633  When this function is called, counter is pointing at an item on the
 634  line that starts with the character 'h', indicating a tool length
 635  offset index.  The function reads characters which give the (integer)
 636  value of the tool length offset index (not the actual distance of the
 637  offset).
 638  
 639  */
 640  
 641  int Interp::read_h(char *line,   //!< string: line of RS274/NGC code being processed
 642                    int *counter, //!< pointer to a counter for position on the line 
 643                    block_pointer block,  //!< pointer to a block being filled from the line 
 644                    double *parameters)   //!< array of system parameters                    
 645  {
 646    int value;
 647  
 648    CHKS((line[*counter] != 'h'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 649    *counter = (*counter + 1);
 650    CHKS((block->h_flag), NCE_MULTIPLE_H_WORDS_ON_ONE_LINE);
 651    CHP(read_integer_value(line, counter, &value, parameters));
 652    CHKS((value < -1), NCE_NEGATIVE_H_WORD_USED);
 653    block->h_flag = true;
 654    block->h_number = value;
 655    return INTERP_OK;
 656  }
 657  
 658  /****************************************************************************/
 659  
 660  /*! read_i
 661  
 662  Returned Value: int
 663     If read_real_value returns an error code, this returns that code.
 664     If any of the following errors occur, this returns the error code shown.
 665     Otherwise, it returns INTERP_OK.
 666     1. The first character read is not i:
 667        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 668     2. An i_coordinate has already been inserted in the block:
 669        NCE_MULTIPLE_I_WORDS_ON_ONE_LINE
 670  
 671  Side effects:
 672     counter is reset.
 673     The i_flag in the block is turned on.
 674     An i_coordinate setting is inserted in the block.
 675  
 676  Called by: read_one_item
 677  
 678  When this function is called, counter is pointing at an item on the
 679  line that starts with the character 'i', indicating a i_coordinate
 680  setting. The function reads characters which tell how to set the
 681  coordinate, up to the start of the next item or the end of the line.
 682  This information is inserted in the block. The counter is then set to
 683  point to the character following.
 684  
 685  The value may be a real number or something that evaluates to a
 686  real number, so read_real_value is used to read it. Parameters
 687  may be involved.
 688  
 689  */
 690  
 691  int Interp::read_i(char *line,   //!< string: line of RS274 code being processed    
 692                    int *counter, //!< pointer to a counter for position on the line 
 693                    block_pointer block,  //!< pointer to a block being filled from the line 
 694                    double *parameters)   //!< array of system parameters                    
 695  {
 696    double value;
 697  
 698    CHKS((line[*counter] != 'i'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 699    *counter = (*counter + 1);
 700    CHKS((block->i_flag), NCE_MULTIPLE_I_WORDS_ON_ONE_LINE);
 701    CHP(read_real_value(line, counter, &value, parameters));
 702    block->i_flag = true;
 703    block->i_number = value;
 704    return INTERP_OK;
 705  }
 706  
 707  /****************************************************************************/
 708  
 709  /*! read_integer_unsigned
 710  
 711  Returned Value: int
 712     If any of the following errors occur, this returns the error shown.
 713     Otherwise, INTERP_OK is returned.
 714     1. The first character is not a digit: NCE_BAD_FORMAT_UNSIGNED_INTEGER
 715     2. sscanf fails: NCE_SSCANF_FAILED
 716  
 717  Side effects:
 718     The number read from the line is put into what integer_ptr points at.
 719  
 720  Called by: read_n_number
 721  
 722  This reads an explicit unsigned (positive) integer from a string,
 723  starting from the position given by *counter. It expects to find one
 724  or more digits. Any character other than a digit terminates reading
 725  the integer. Note that if the first character is a sign (+ or -),
 726  an error will be reported (since a sign is not a digit).
 727  
 728  */
 729  
 730  int Interp::read_integer_unsigned(char *line,    //!< string: line of RS274 code being processed   
 731                                   int *counter,  //!< pointer to a counter for position on the line
 732                                   int *integer_ptr)      //!< pointer to the value being read              
 733  {
 734    int n;
 735    char c;
 736  
 737    for (n = *counter;; n++) {
 738      c = line[n];
 739      if ((c < 48) || (c > 57))
 740        break;
 741    }
 742    CHKS((n == *counter), NCE_BAD_FORMAT_UNSIGNED_INTEGER);
 743    if (sscanf(line + *counter, "%d", integer_ptr) == 0)
 744      ERS(NCE_SSCANF_FAILED);
 745    *counter = n;
 746    return INTERP_OK;
 747  }
 748  
 749  /****************************************************************************/
 750  
 751  /*! read_integer_value
 752  
 753  Returned Value: int
 754     If read_real_value returns an error code, this returns that code.
 755     If any of the following errors occur, this returns the error code shown.
 756     Otherwise, it returns INTERP_OK.
 757     1. The returned value is not close to an integer:
 758        NCE_NON_INTEGER_VALUE_FOR_INTEGER
 759  
 760  Side effects:
 761     The number read from the line is put into what integer_ptr points at.
 762  
 763  Called by:
 764     read_d
 765     read_l
 766     read_h
 767     read_m
 768     read_parameter
 769     read_parameter_setting
 770     read_t
 771  
 772  This reads an integer (positive, negative or zero) from a string,
 773  starting from the position given by *counter. The value being
 774  read may be written with a decimal point or it may be an expression
 775  involving non-integers, as long as the result comes out within 0.0001
 776  of an integer.
 777  
 778  This proceeds by calling read_real_value and checking that it is
 779  close to an integer, then returning the integer it is close to.
 780  
 781  */
 782  
 783  int Interp::read_integer_value(char *line,       //!< string: line of RS274/NGC code being processed
 784                                int *counter,     //!< pointer to a counter for position on the line 
 785                                int *integer_ptr, //!< pointer to the value being read               
 786                                double *parameters)       //!< array of system parameters                    
 787  {
 788    double float_value;
 789  
 790    CHP(read_real_value(line, counter, &float_value, parameters));
 791    *integer_ptr = (int) floor(float_value);
 792    if ((float_value - *integer_ptr) > 0.9999) {
 793      *integer_ptr = (int) ceil(float_value);
 794    } else if ((float_value - *integer_ptr) > 0.0001)
 795      ERS(NCE_NON_INTEGER_VALUE_FOR_INTEGER);
 796    return INTERP_OK;
 797  }
 798  
 799  /****************************************************************************/
 800  
 801  /*! read_items
 802  
 803  Returned Value: int
 804     If read_n_number or read_one_item returns an error code,
 805     this returns that code.
 806     Otherwise, it returns INTERP_OK.
 807  
 808  Side effects:
 809     One line of RS274 code is read and data inserted into a block.
 810     The counter which is passed around among the readers is initialized.
 811     System parameters may be reset.
 812  
 813  Called by: parse_line
 814  
 815  */
 816  
 817  int Interp::read_items(block_pointer block,      //!< pointer to a block being filled from the line 
 818                        char *line,       //!< string: line of RS274/NGC code being processed
 819                        double *parameters)   //!< array of system parameters 
 820  {
 821    int counter;
 822    int m_number, m_counter;  // for checking m98/m99 as o-words
 823    int length;
 824  
 825    length = strlen(line);
 826    counter = 0;
 827  
 828    if (line[counter] == '/')     /* skip the slash character if first */
 829      counter++;
 830  
 831    if (line[counter] == 'n') {
 832      CHP(read_n_number(line, &counter, block));
 833    }
 834  
 835    // Pre-check for M code, used in following logic
 836    if (! (line[counter] == 'm' &&
 837  	 read_integer_value(line, &(m_counter=counter+1), &m_number,
 838  			    parameters) == INTERP_OK))
 839        m_number = -1;
 840  
 841    if (line[counter] == 'o' || m_number == 98 ||
 842        (m_number == 99 && _setup.call_level > 0))
 843  
 844   /* Handle 'o', 'm98' and 'm99' sub return (but not 'm99' endless
 845      program) explicitly here. Default is to read letters via pointer
 846      calls to related reader functions. 'o' control lines have their
 847      own commands and command handlers. */
 848    {
 849        CHP(read_o(line, &counter, block, parameters));
 850  
 851        // if skipping, the conditionals are not evaluated and are therefore unconsumed
 852        // so we can't check the rest of the line.  but don't worry, we'll get it later
 853        if(_setup.skipping_o) return INTERP_OK;
 854  
 855        // after if [...], etc., nothing is allowed except comments
 856        for (; counter < length;) {
 857            if(line[counter] == ';') read_semicolon(line, &counter, block, parameters);
 858            else if (line[counter] == '(') read_comment(line, &counter, block, parameters);
 859            else ERS("Unexpected character after O-word");
 860        }
 861        return INTERP_OK;
 862    }
 863  
 864    // non O-lines
 865  
 866    if(_setup.skipping_o)
 867    {
 868        // if we are skipping, do NOT evaluate non-olines
 869        return INTERP_OK;
 870    }
 871  
 872    for (; counter < length;) {
 873      CHP(read_one_item(line, &counter, block, parameters));
 874    }
 875    return INTERP_OK;
 876  }
 877  
 878  /****************************************************************************/
 879  
 880  /*! read_j
 881  
 882  Returned Value: int
 883     If read_real_value returns an error code, this returns that code.
 884     If any of the following errors occur, this returns the error code shown.
 885     Otherwise, it returns INTERP_OK.
 886     1. The first character read is not j:
 887        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 888     2. A j_coordinate has already been inserted in the block.
 889        NCE_MULTIPLE_J_WORDS_ON_ONE_LINE
 890  
 891  Side effects:
 892     counter is reset.
 893     The j_flag in the block is turned on.
 894     A j_coordinate setting is inserted in the block.
 895  
 896  Called by: read_one_item
 897  
 898  When this function is called, counter is pointing at an item on the
 899  line that starts with the character 'j', indicating a j_coordinate
 900  setting. The function reads characters which tell how to set the
 901  coordinate, up to the start of the next item or the end of the line.
 902  This information is inserted in the block. The counter is then set to
 903  point to the character following.
 904  
 905  The value may be a real number or something that evaluates to a real
 906  number, so read_real_value is used to read it. Parameters may be
 907  involved.
 908  
 909  */
 910  
 911  int Interp::read_j(char *line,   //!< string: line of RS274 code being processed    
 912                    int *counter, //!< pointer to a counter for position on the line 
 913                    block_pointer block,  //!< pointer to a block being filled from the line 
 914                    double *parameters)   //!< array of system parameters                    
 915  {
 916    double value;
 917  
 918    CHKS((line[*counter] != 'j'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 919    *counter = (*counter + 1);
 920    CHKS((block->j_flag), NCE_MULTIPLE_J_WORDS_ON_ONE_LINE);
 921    CHP(read_real_value(line, counter, &value, parameters));
 922    block->j_flag = true;
 923    block->j_number = value;
 924    return INTERP_OK;
 925  }
 926  
 927  /****************************************************************************/
 928  
 929  /*! read_k
 930  
 931  Returned Value: int
 932     If read_real_value returns an error code, this returns that code.
 933     If any of the following errors occur, this returns the error code shown.
 934     Otherwise, it returns INTERP_OK.
 935     1. The first character read is not k:
 936        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 937     2. A k_coordinate has already been inserted in the block:
 938        NCE_MULTIPLE_K_WORDS_ON_ONE_LINE
 939  
 940  Side effects:
 941     counter is reset.
 942     The k_flag in the block is turned on.
 943     A k_coordinate setting is inserted in the block.
 944  
 945  Called by: read_one_item
 946  
 947  When this function is called, counter is pointing at an item on the
 948  line that starts with the character 'k', indicating a k_coordinate
 949  setting. The function reads characters which tell how to set the
 950  coordinate, up to the start of the next item or the end of the line.
 951  This information is inserted in the block. The counter is then set to
 952  point to the character following.
 953  
 954  The value may be a real number or something that evaluates to a real
 955  number, so read_real_value is used to read it. Parameters may be
 956  involved.
 957  
 958  */
 959  
 960  int Interp::read_k(char *line,   //!< string: line of RS274 code being processed    
 961                    int *counter, //!< pointer to a counter for position on the line 
 962                    block_pointer block,  //!< pointer to a block being filled from the line 
 963                    double *parameters)   //!< array of system parameters                    
 964  {
 965    double value;
 966  
 967    CHKS((line[*counter] != 'k'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
 968    *counter = (*counter + 1);
 969    CHKS((block->k_flag), NCE_MULTIPLE_K_WORDS_ON_ONE_LINE);
 970    CHP(read_real_value(line, counter, &value, parameters));
 971    block->k_flag = true;
 972    block->k_number = value;
 973    return INTERP_OK;
 974  }
 975  
 976  /****************************************************************************/
 977  
 978  /*! read_l
 979  
 980  Returned Value: int
 981     If read_integer_value returns an error code, this returns that code.
 982     If any of the following errors occur, this returns the error code shown.
 983     Otherwise, it returns INTERP_OK.
 984     1. The first character read is not l:
 985        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
 986     2. An l_number has already been inserted in the block:
 987        NCE_MULTIPLE_L_WORDS_ON_ONE_LINE
 988     3. the l_number is negative: NCE_NEGATIVE_L_WORD_USED
 989  
 990  Side effects:
 991     counter is reset to the character following the l number.
 992     An l code is inserted in the block as the value of l.
 993  
 994  Called by: read_one_item
 995  
 996  When this function is called, counter is pointing at an item on the
 997  line that starts with the character 'l', indicating an L code.
 998  The function reads characters which give the (integer) value of the
 999  L code.
1000  
1001  L codes are used for:
1002  1. the number of times a canned cycle should be repeated.
1003  2. a key with G10.
1004  
1005  */
1006  
1007  int Interp::read_l(char *line,   //!< string: line of RS274/NGC code being processed
1008                    int *counter, //!< pointer to a counter for position on the line 
1009                    block_pointer block,  //!< pointer to a block being filled from the line 
1010                    double *parameters)   //!< array of system parameters                    
1011  {
1012    int value;
1013  
1014    CHKS((line[*counter] != 'l'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1015    *counter = (*counter + 1);
1016    CHKS((block->l_number > -1), NCE_MULTIPLE_L_WORDS_ON_ONE_LINE);
1017    CHP(read_integer_value(line, counter, &value, parameters));
1018    CHKS((value < 0), NCE_NEGATIVE_L_WORD_USED);
1019    block->l_number = value;
1020    block->l_flag = true;
1021    return INTERP_OK;
1022  }
1023  
1024  /****************************************************************************/
1025  
1026  /*! read_n_number
1027  
1028  Returned Value: int
1029     If read_integer_unsigned returns an error code, this returns that code.
1030     If any of the following errors occur, this returns the error code shown.
1031     Otherwise, it returns INTERP_OK.
1032     1. The first character read is not n:
1033        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
1034     2. The line number is too large (more than 99999):
1035        NCE_LINE_NUMBER_GREATER_THAN_99999
1036  
1037  Side effects:
1038     counter is reset to the character following the line number.
1039     A line number is inserted in the block.
1040  
1041  Called by: read_items
1042  
1043  When this function is called, counter is pointing at an item on the
1044  line that starts with the character 'n', indicating a line number.
1045  The function reads characters which give the (integer) value of the
1046  line number.
1047  
1048  Note that extra initial zeros in a line number will not cause the
1049  line number to be too large.
1050  
1051  */
1052  
1053  int Interp::read_n_number(char *line, //!< string: line of RS274    code being processed 
1054                            int *counter,       //!< pointer to a counter for position on the line 
1055                            block_pointer block)        //!< pointer to a block being filled from the line 
1056  {
1057    int value;
1058  
1059    CHKS(((line[*counter] != 'n') && (line[*counter] != 'o')),
1060        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1061    *counter = (*counter + 1);
1062    CHP(read_integer_unsigned(line, counter, &value));
1063    /* This next test is problematic as many CAM systems will exceed this !
1064    CHKS((value > 99999), NCE_LINE_NUMBER_GREATER_THAN_99999); */
1065    block->n_number = value;
1066  
1067    // accept & ignore fractional line numbers
1068    if (line[*counter] == '.') {
1069        *counter = (*counter + 1);
1070        CHP(read_integer_unsigned(line, counter, &value));
1071    }
1072    return INTERP_OK;
1073  }
1074  
1075  /****************************************************************************/
1076  
1077  /*! read_m
1078  
1079  Returned Value:
1080     If read_integer_value returns an error code, this returns that code.
1081     If any of the following errors occur, this returns the error code shown.
1082     Otherwise, it returns INTERP_OK.
1083     1. The first character read is not m:
1084        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
1085     2. The value is negative: NCE_NEGATIVE_M_CODE_USED
1086     3. The value is greater than 199: NCE_M_CODE_GREATER_THAN_199
1087     4. The m code is not known to the system: NCE_UNKNOWN_M_CODE_USED
1088     5. Another m code in the same modal group has already been read:
1089        NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP
1090  
1091  Side effects:
1092     counter is reset to the character following the m number.
1093     An m code is inserted as the value of the appropriate mode in the
1094     m_modes array in the block.
1095     The m code counter in the block is increased by 1.
1096  
1097  Called by: read_one_item
1098  
1099  When this function is called, counter is pointing at an item on the
1100  line that starts with the character 'm', indicating an m code.
1101  The function reads characters which give the (integer) value of the
1102  m code.
1103  
1104  read_integer_value allows a minus sign, so a check for a negative value
1105  is needed here, and the parameters argument is also needed.
1106  
1107  */
1108  
1109  int Interp::read_m(char *line,   //!< string: line of RS274 code being processed   
1110                    int *counter, //!< pointer to a counter for position on the line
1111                    block_pointer block,  //!< pointer to a block being filled from the line
1112                    double *parameters)   //!< array of system parameters                   
1113  {
1114    int value;
1115    int mode;
1116  
1117    CHKS((line[*counter] != 'm'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1118    *counter = (*counter + 1);
1119    CHP(read_integer_value(line, counter, &value, parameters));
1120    CHKS((value < 0), NCE_NEGATIVE_M_CODE_USED);
1121  
1122    remap_pointer r = _setup.m_remapped[value];
1123    if (r) {
1124        mode =  r->modal_group;
1125        CHKS ((mode < 0),"BUG: M remapping: modal group < 0");
1126        CHKS ((mode > 10),"BUG: M remapping: modal group > 10");
1127  
1128        CHKS((block->m_modes[mode] != -1),
1129  	   NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP);
1130        block->m_modes[mode] = value;
1131        block->m_count++;
1132        return INTERP_OK;
1133    }
1134  
1135    CHKS((value > 199), NCE_M_CODE_GREATER_THAN_199,value);
1136    mode = _ems[value];
1137    CHKS((mode == -1), NCE_UNKNOWN_M_CODE_USED,value);
1138    CHKS((block->m_modes[mode] != -1),
1139        NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP);
1140    block->m_modes[mode] = value;
1141    block->m_count++;
1142    if (value >= 100 && value < 200) {
1143      block->user_m = 1;
1144    }
1145    return INTERP_OK;
1146  }
1147  
1148  /****************************************************************************/
1149  
1150  /*! read_one_item
1151  
1152  Returned Value: int
1153     If a reader function which is called returns an error code, that
1154     error code is returned.
1155     If any of the following errors occur, this returns the error code shown.
1156     Otherwise, it returns INTERP_OK.
1157     1. the first character read is not a known character for starting a
1158     word: NCE_BAD_CHARACTER_USED
1159  
1160  Side effects:
1161     This function reads one item from a line of RS274/NGC code and inserts
1162     the information in a block. System parameters may be reset.
1163  
1164  Called by: read_items.
1165  
1166  When this function is called, the counter is set so that the position
1167  being considered is the first position of a word. The character at
1168  that position must be one known to the system.  In this version those
1169  characters are: a,b,c,d,f,g,h,i,j,k,l,m,n,p,q,r,s,t,x,y,z,(,#,;.
1170  However, read_items calls read_n_number directly if the first word
1171  begins with n, so no read function is included in the "_readers" array
1172  for the letter n. Thus, if an n word is encountered in the middle of
1173  a line, this function reports NCE_BAD_CHARACTER_USED.
1174  
1175  The function looks for a letter or special character and matches it to
1176  a pointer to a function in _readers[] - The position of the function
1177  pointers in the array match their ASCII number.
1178  Once the character has been matched, the function calls a selected function
1179  according to what the letter or character is.  The selected function will
1180  be responsible to consider all the characters that comprise the remainder
1181  of the item, and reset the pointer so that it points to the next character
1182  after the end of the item (which may be the end of the line or the first
1183  character of another item).
1184  
1185  After an item is read, the counter is set at the index of the
1186  next unread character. The item data is stored in the block.
1187  
1188  It is expected that the format of a comment will have been checked;
1189  this is being done by close_and_downcase. Bad format comments will
1190  have prevented the system from getting this far, so that this function
1191  can assume a close parenthesis will be found when an open parenthesis
1192  has been found, and that comments are not nested.
1193  
1194  */
1195  
1196  int Interp::read_one_item(
1197      char *line,    //!< string: line of RS274/NGC code being processed
1198      int *counter,  //!< pointer to a counter for position on the line 
1199      block_pointer block,   //!< pointer to a block being filled from the line 
1200      double * parameters) /* array of system parameters  */
1201  {
1202    read_function_pointer function_pointer;
1203    char letter;
1204  
1205    letter = line[*counter];      /* check if in array range */
1206    CHKS(((letter < ' ') || (letter > 'z')),
1207  	_("Bad character '\\%03o' used"), (unsigned char)letter);
1208    function_pointer = _readers[(int) letter]; /* Find the function pointer in the array */
1209    CHKS((function_pointer == 0),
1210  	(!isprint(letter) || isspace(letter)) ?
1211  	    _("Bad character '\\%03o' used") : _("Bad character '%c' used"), letter);
1212    CHP((*this.*function_pointer)(line, counter, block, parameters)); /* Call the function */ 
1213    return INTERP_OK;
1214  }
1215  
1216  /****************************************************************************/
1217  
1218  /*! read_operation
1219  
1220  Returned Value: int
1221     If any of the following errors occur, this returns the error code shown.
1222     Otherwise, it returns INTERP_OK.
1223     1. The operation is unknown:
1224        NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_A
1225        NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_M
1226        NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_O
1227        NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_X
1228        NCE_UNKNOWN_OPERATION
1229     2. The line ends without closing the expression: NCE_UNCLOSED_EXPRESSION
1230  
1231  Side effects:
1232     An integer representing the operation is put into what operation points
1233     at.  The counter is reset to point to the first character after the
1234     operation.
1235  
1236  Called by: read_real_expression
1237  
1238  This expects to be reading a binary operation (+, -, /, *, **, and,
1239  mod, or, xor) or a right bracket (]). If one of these is found, the
1240  value of operation is set to the symbolic value for that operation.
1241  If not, an error is reported as described above.
1242  
1243  */
1244  
1245  int Interp::read_operation(char *line,   //!< string: line of RS274/NGC code being processed
1246                            int *counter, //!< pointer to a counter for position on the line 
1247                            int *operation)       //!< pointer to operation to be read               
1248  {
1249    char c;
1250  
1251    c = line[*counter];
1252    *counter = (*counter + 1);
1253    switch (c) {
1254    case '+':
1255      *operation = PLUS;
1256      break;
1257    case '-':
1258      *operation = MINUS;
1259      break;
1260    case '/':
1261      *operation = DIVIDED_BY;
1262      break;
1263    case '*':
1264      if (line[*counter] == '*') {
1265        *operation = POWER;
1266        *counter = (*counter + 1);
1267      } else
1268        *operation = TIMES;
1269      break;
1270    case ']':
1271      *operation = RIGHT_BRACKET;
1272      break;
1273    case 'a':
1274      if ((line[*counter] == 'n') && (line[(*counter) + 1] == 'd')) {
1275        *operation = AND2;
1276        *counter = (*counter + 2);
1277      } else
1278        ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_A);
1279      break;
1280    case 'm':
1281      if ((line[*counter] == 'o') && (line[(*counter) + 1] == 'd')) {
1282        *operation = MODULO;
1283        *counter = (*counter + 2);
1284      } else
1285        ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_M);
1286      break;
1287    case 'o':
1288      if (line[*counter] == 'r') {
1289        *operation = NON_EXCLUSIVE_OR;
1290        *counter = (*counter + 1);
1291      } else
1292        ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_O);
1293      break;
1294    case 'x':
1295      if ((line[*counter] == 'o') && (line[(*counter) + 1] == 'r')) {
1296        *operation = EXCLUSIVE_OR;
1297        *counter = (*counter + 2);
1298      } else
1299        ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_X);
1300      break;
1301  
1302        /* relational operators */
1303      case 'e':
1304        if(line[*counter] == 'q')
1305  	{
1306  	  *operation = EQ;
1307  	  *counter = (*counter + 1);
1308  	}
1309        else
1310          ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_E);
1311        break;
1312      case 'n':
1313        if(line[*counter] == 'e')
1314  	{
1315  	  *operation = NE;
1316  	  *counter = (*counter + 1);
1317  	}
1318        else
1319          ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_N);
1320        break;
1321      case 'g':
1322        if(line[*counter] == 'e')
1323  	{
1324  	  *operation = GE;
1325  	  *counter = (*counter + 1);
1326  	}
1327        else if(line[*counter] == 't')
1328  	{
1329  	  *operation = GT;
1330  	  *counter = (*counter + 1);
1331  	}
1332        else
1333          ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_G);
1334        break;
1335      case 'l':
1336        if(line[*counter] == 'e')
1337  	{
1338  	  *operation = LE;
1339  	  *counter = (*counter + 1);
1340  	}
1341        else if(line[*counter] == 't')
1342  	{
1343  	  *operation = LT;
1344  	  *counter = (*counter + 1);
1345  	}
1346        else
1347          ERS(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_L);
1348        break;
1349  
1350    case 0:
1351      ERS(NCE_UNCLOSED_EXPRESSION);
1352    default:
1353      ERS(NCE_UNKNOWN_OPERATION);
1354    }
1355    return INTERP_OK;
1356  }
1357  
1358  /****************************************************************************/
1359  
1360  /*! read_operation_unary
1361  
1362  Returned Value: int
1363     If the operation is not a known unary operation, this returns one of
1364     the following error codes:
1365     NCE_UNKNOWN_WORD_STARTING_WITH_A
1366     NCE_UNKNOWN_WORD_STARTING_WITH_C
1367     NCE_UNKNOWN_WORD_STARTING_WITH_E
1368     NCE_UNKNOWN_WORD_STARTING_WITH_F
1369     NCE_UNKNOWN_WORD_STARTING_WITH_L
1370     NCE_UNKNOWN_WORD_STARTING_WITH_R
1371     NCE_UNKNOWN_WORD_STARTING_WITH_S
1372     NCE_UNKNOWN_WORD_STARTING_WITH_T
1373     NCE_UNKNOWN_WORD_WHERE_UNARY_OPERATION_COULD_BE
1374     Otherwise, this returns INTERP_OK.
1375  
1376  Side effects:
1377     An integer code for the name of the operation read from the
1378     line is put into what operation points at.
1379     The counter is reset to point to the first character after the
1380     characters which make up the operation name.
1381  
1382  Called by:
1383     read_unary
1384  
1385  This attempts to read the name of a unary operation out of the line,
1386  starting at the index given by the counter. Known operations are:
1387  abs, acos, asin, atan, cos, exp, fix, fup, ln, round, sin, sqrt, tan.
1388  
1389  */
1390  
1391  int Interp::read_operation_unary(char *line,     //!< string: line of RS274/NGC code being processed
1392                                  int *counter,   //!< pointer to a counter for position on the line 
1393                                  int *operation) //!< pointer to operation to be read               
1394  {
1395    char c;
1396  
1397    c = line[*counter];
1398    *counter = (*counter + 1);
1399    switch (c) {
1400    case 'a':
1401      if ((line[*counter] == 'b') && (line[(*counter) + 1] == 's')) {
1402        *operation = ABS;
1403        *counter = (*counter + 2);
1404      } else if (strncmp((line + *counter), "cos", 3) == 0) {
1405        *operation = ACOS;
1406        *counter = (*counter + 3);
1407      } else if (strncmp((line + *counter), "sin", 3) == 0) {
1408        *operation = ASIN;
1409        *counter = (*counter + 3);
1410      } else if (strncmp((line + *counter), "tan", 3) == 0) {
1411        *operation = ATAN;
1412        *counter = (*counter + 3);
1413      } else
1414        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_A);
1415      break;
1416    case 'c':
1417      if ((line[*counter] == 'o') && (line[(*counter) + 1] == 's')) {
1418        *operation = COS;
1419        *counter = (*counter + 2);
1420      } else
1421        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_C);
1422      break;
1423    case 'e':
1424      if ((line[*counter] == 'x') && (line[(*counter) + 1] == 'p')) {
1425        *operation = EXP;
1426        *counter = (*counter + 2);
1427      } else if (    (line[*counter]     == 'x')
1428                  && (line[*counter + 1] == 'i')
1429                  && (line[*counter + 2] == 's')
1430                  && (line[*counter + 3] == 't')
1431                  && (line[*counter + 4] == 's')
1432               ) {
1433        *counter = (*counter + 5);
1434        *operation = EXISTS;
1435      } else {
1436        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_E);
1437      }
1438      break;
1439    case 'f':
1440      if ((line[*counter] == 'i') && (line[(*counter) + 1] == 'x')) {
1441        *operation = FIX;
1442        *counter = (*counter + 2);
1443      } else if ((line[*counter] == 'u') && (line[(*counter) + 1] == 'p')) {
1444        *operation = FUP;
1445        *counter = (*counter + 2);
1446      } else
1447        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_F);
1448      break;
1449    case 'l':
1450      if (line[*counter] == 'n') {
1451        *operation = LN;
1452        *counter = (*counter + 1);
1453      } else
1454        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_L);
1455      break;
1456    case 'r':
1457      if (strncmp((line + *counter), "ound", 4) == 0) {
1458        *operation = ROUND;
1459        *counter = (*counter + 4);
1460      } else
1461        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_R);
1462      break;
1463    case 's':
1464      if ((line[*counter] == 'i') && (line[(*counter) + 1] == 'n')) {
1465        *operation = SIN;
1466        *counter = (*counter + 2);
1467      } else if (strncmp((line + *counter), "qrt", 3) == 0) {
1468        *operation = SQRT;
1469        *counter = (*counter + 3);
1470      } else
1471        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_S);
1472      break;
1473    case 't':
1474      if ((line[*counter] == 'a') && (line[(*counter) + 1] == 'n')) {
1475        *operation = TAN;
1476        *counter = (*counter + 2);
1477      } else
1478        ERS(NCE_UNKNOWN_WORD_STARTING_WITH_T);
1479      break;
1480    default:
1481      ERS(NCE_UNKNOWN_WORD_WHERE_UNARY_OPERATION_COULD_BE);
1482    }
1483    return INTERP_OK;
1484  }
1485  
1486  /****************************************************************************/
1487  
1488  /* read_o
1489  
1490  Returned Value: int
1491     If read_real_value returns an error code, this returns that code.
1492     If any of the following errors occur, this returns the error code shown.
1493     Otherwise, it returns RS274NGC_OK.
1494     1. The first character read is not o:
1495        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
1496  
1497  Side effects:
1498     counter is reset to point to the first character following the p value.
1499     The p value setting is inserted in block.
1500  
1501  Called by: read_one_item
1502  
1503  When this function is called, counter is pointing at an item on the
1504  line that starts with the character 'o', indicating a o value
1505  setting. The function reads characters which tell how to set the o
1506  value, up to the start of the next item or the end of the line. This
1507  information is inserted in the block.
1508  
1509  O codes are used for:
1510  1.  sub
1511  2.  endsub
1512  3.  call
1513  4.  do
1514  5.  while
1515  6.  if
1516  7.  elseif
1517  8.  else
1518  9.  endif
1519  10. break
1520  11. continue
1521  12. endwhile
1522  13. return
1523  
1524  Labels (o-words) are of local scope except for sub, endsub, and call which
1525  are of global scope.
1526  
1527  Named o-words and scoping of o-words are implemented now.
1528  Numeric o-words get converted to strings. Global o-words are stored as
1529  just the string. Local o-words are stored as the name (o-word) of the
1530  sub containing the o-word, followed by a '#', followed by the local o-word.
1531  If the local o-word is not contained within a sub, then the sub name is null
1532  and the o-word just begins with a '#'.
1533  
1534  It has been a pain to do this because o-words are used as integers all over
1535  the place.
1536  !!!KL the code could use some cleanup.
1537  
1538  */
1539  
1540  int Interp::read_o(    /* ARGUMENTS                                     */
1541   char * line,         /* string: line of RS274/NGC code being processed */
1542   int * counter,       /* pointer to a counter for position on the line  */
1543   block_pointer block, /* pointer to a block being filled from the line  */
1544   double * parameters) /* array of system parameters                     */
1545  {
1546    static char name[] = "read_o";
1547    double value;
1548    int param_cnt;
1549    char oNameBuf[LINELEN+1];
1550    const char *subName;
1551    char fullNameBuf[2*LINELEN+1];
1552    int oNumber, n;
1553    extern const char *o_ops[];
1554  
1555    if (line[*counter] == 'm' &&
1556        read_integer_value(line, &(n=*counter+1), &oNumber,
1557  			 parameters) == INTERP_OK) {
1558        // m98 or m99 found
1559        if (oNumber == 98) {
1560  	  CHKS(_setup.disable_fanuc_style_sub,
1561  	       "DISABLE_FANUC_STYLE_SUB set in .ini file, but found m98");
1562  
1563  	  // Fanuc-style subroutine call with loop: "m98"
1564  	  block->o_type = M_98;
1565  	  *counter += 3;
1566  
1567  	  // Read P-word and L-word now
1568  	  n = strlen(line);
1569  	  while (*counter < n)
1570  	      CHP(read_one_item(line, counter, block, parameters));
1571  	  // P-word:  convert to int and put in oNameBuf
1572  	  CHKS(! block->p_flag, "Found 'm98' code with no P-word");
1573  	  // (conversion code from read_integer_value)
1574  	  n = (int) floor(block->p_number);
1575  	  if ((block->p_number - n) > 0.9999) {
1576  	      n = (int) ceil(block->p_number);
1577  	  } else
1578  	      CHKS((block->p_number - n) > 0.0001,
1579  		   NCE_NON_INTEGER_VALUE_FOR_INTEGER);
1580  	  sprintf(oNameBuf, "%d", n);
1581        } else if (oNumber == 99) {
1582  	  // Fanuc-style subroutine return: "m99"
1583  
1584  	  // Error checks:
1585  	  // - Fanuc-style subs disabled
1586  	  CHKS(_setup.disable_fanuc_style_sub,
1587  	       "DISABLE_FANUC_STYLE_SUB set in .ini file, but found m99");
1588  	  // - Empty stack M99 (endless program) handled in read_m()
1589  	  CHKS(_setup.defining_sub,
1590  	       "Found 'M99' instead of 'O endsub' after 'O sub'");
1591  
1592  	  // Fanuc-style subroutine return: "m99"
1593  	  block->o_type = M_99;
1594  	  *counter += 3;
1595  
1596  	  // Subroutine name not provided in Fanuc syntax, so pull from
1597  	  // context
1598  	  strncpy(oNameBuf, _setup.sub_context[_setup.call_level].subName,
1599  		  LINELEN+1);
1600        } else
1601  	  // any other m-code should have been handled by read_m()
1602  	  OERR(_("%d: Bug:  Non-m98/m99 M-code passed to read_o(): '%s'"),
1603  	       _setup.sequence_number, _setup.linetext);
1604  
1605    } else {
1606        CHKS((line[*counter] != 'o'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1607  
1608        // rs274-style O-word
1609  
1610        *counter += 1;
1611        if(line[*counter] == '<')
1612  	  {
1613  	      read_name(line, counter, oNameBuf);
1614  	  }
1615        else
1616  	  {
1617  	      CHP(read_integer_value(line, counter, &oNumber,
1618  				     parameters));
1619  	      sprintf(oNameBuf, "%d", oNumber);
1620  	  }
1621  
1622        // We stash the text the offset part of setup
1623  
1624  #define CMP(txt) (strncmp(line+*counter, txt, strlen(txt)) == 0 && (*counter += strlen(txt)))
1625        // characterize the type of o-word
1626  
1627        if(CMP("sub"))
1628  	  block->o_type = O_sub;
1629        else if(CMP("endsub"))
1630  	  block->o_type = O_endsub;
1631        else if(CMP("call"))
1632  	  block->o_type = O_call;
1633        else if(CMP("do"))
1634  	  block->o_type = O_do;
1635        else if(CMP("while"))
1636  	  block->o_type = O_while;
1637        else if(CMP("repeat"))
1638  	  block->o_type = O_repeat;
1639        else if(CMP("if"))
1640  	  block->o_type = O_if;
1641        else if(CMP("elseif"))
1642  	  block->o_type = O_elseif;
1643        else if(CMP("else"))
1644  	  block->o_type = O_else;
1645        else if(CMP("endif"))
1646  	  block->o_type = O_endif;
1647        else if(CMP("break"))
1648  	  block->o_type = O_break;
1649        else if(CMP("continue"))
1650  	  block->o_type = O_continue;
1651        else if(CMP("endwhile"))
1652  	  block->o_type = O_endwhile;
1653        else if(CMP("endrepeat"))
1654  	  block->o_type = O_endrepeat;
1655        else if(CMP("return"))
1656  	  block->o_type = O_return;
1657        else if((line+*counter)[0] == '(' || (line+*counter)[0] == ';'
1658  	      || (line+*counter)[0] == 0) {
1659  	  // Fanuc-style subroutine definition:  "O2000" with no following args
1660  	  CHKS(_setup.disable_fanuc_style_sub,
1661  	       "DISABLE_FANUC_STYLE_SUB disabled in .ini file, but found "
1662  	       "bare O-word");
1663  
1664  	  block->o_type = O_;
1665        } else
1666  	  block->o_type = O_none;
1667    }
1668  
1669    logDebug("In: %s line:%d |%s| subroutine=|%s|",
1670  	   name, block->line_number, line, oNameBuf);
1671  
1672    // we now have it characterized
1673    // now create the text of the oword
1674  
1675    switch(block->o_type)
1676      {
1677        // the global cases first
1678      case O_sub:
1679      case O_:
1680      case O_endsub:
1681      case O_call:
1682      case M_98:
1683      case O_return:
1684      case M_99:
1685  	block->o_name = strstore(oNameBuf);
1686  	logDebug("global case:|%s|", block->o_name);
1687  	break;
1688  
1689        // the remainder are local cases
1690      default:
1691        if(_setup.call_level)
1692  	{
1693  	  subName = _setup.sub_context[_setup.call_level].subName;
1694  	  logDebug("inside a call[%d]:|%s|", _setup.call_level, subName);
1695  	}
1696        else if(_setup.defining_sub)
1697  	{
1698  	  subName = _setup.sub_name;
1699  	  logDebug("defining_sub:|%s|", subName);
1700  	}
1701        else
1702  	{
1703  	  subName = "";
1704  	  logDebug("not defining_sub:|%s|", subName);
1705  	}
1706        sprintf(fullNameBuf, "%s#%s", subName, oNameBuf);
1707        block->o_name = strstore(fullNameBuf);
1708        logDebug("local case:|%s|", block->o_name);
1709      }
1710    logDebug("o_type:%s o_name: %s  line:%d %s", o_ops[block->o_type], block->o_name,
1711  	   block->line_number, line);
1712  
1713    if (block->o_type == O_sub || block->o_type == O_)
1714      {
1715  	// Check we're not already defining a main- or sub-program
1716  	CHKS((_setup.defining_sub == 1), NCE_NESTED_SUBROUTINE_DEFN);
1717      }
1718    // in terms of execution endsub and return do the same thing
1719    else if ((block->o_type == O_endsub) || (block->o_type == O_return) ||
1720  	   (block->o_type == M_99))
1721      {
1722  	if ((_setup.skipping_o != 0) &&
1723  	    (0 != strcmp(_setup.skipping_o, block->o_name))) {
1724  	    return INTERP_OK;
1725  	}
1726  
1727  	// optional return value expression
1728  	if (block->o_type != M_99 && line[*counter] == '[') {
1729  	    CHP(read_real_expression(line, counter, &value, parameters));
1730  	    logOword("%s %s value %lf",
1731  		     (block->o_type == O_endsub) ? "endsub" : "return",
1732  		     block->o_name,
1733  		     value);
1734  	    _setup.return_value = value;
1735  	    _setup.value_returned = 1;
1736  	} else {
1737  	    _setup.return_value = 0;
1738  	    _setup.value_returned = 0;
1739  	}
1740      }
1741    else if(_setup.defining_sub == 1)
1742      {
1743        // we can not evaluate expressions -- so just skip on out
1744        block->o_type = O_none;
1745      }
1746    else if(block->o_type == O_call)
1747      {
1748        // we need to NOT evaluate parameters if skipping
1749        // skipping never ends on a "call"
1750        if(_setup.skipping_o != 0)
1751        {
1752            block->o_type = O_none;
1753            return INTERP_OK;
1754        }
1755  
1756        // convey starting state for call_fsm() to handle this call
1757        // convert_remapped_code() might change this to CS_REMAP 
1758        block->call_type = is_pycallable(&_setup,  OWORD_MODULE, block->o_name) ?
1759  	  CT_PYTHON_OWORD_SUB : CT_NGC_OWORD_SUB;
1760  
1761        for(param_cnt=0;(line[*counter] == '[') || (line[*counter] == '(');)
1762  	{
1763  	  if(line[*counter] == '(')
1764  	    {
1765  	      CHP(read_comment(line, counter, block, parameters));
1766  	      continue;
1767  	    }
1768  	  logDebug("counter[%d] rest of line:|%s|", *counter,
1769  		   line+*counter);
1770  	  CHKS((param_cnt >= INTERP_SUB_PARAMS),
1771  	      NCE_TOO_MANY_SUBROUTINE_PARAMETERS);
1772  	  CHP(read_real_expression(line, counter, &value, parameters));
1773  	  block->params[param_cnt] = value;
1774  	  param_cnt++;
1775  	}
1776        logDebug("set arg params:%d", param_cnt);
1777        block->param_cnt = param_cnt;
1778  
1779        // zero the remaining params
1780        for(;param_cnt < INTERP_SUB_PARAMS; param_cnt++)
1781  	{
1782  	  block->params[param_cnt] = 0.0;
1783  	}
1784      }
1785    else if(block->o_type == M_98) {
1786        // No params in M98 block (this could also be 30!)
1787        block->param_cnt = 0;
1788        // Distinguish from 'O.... call'
1789        block->call_type = CT_NGC_M98_SUB;
1790    }
1791    else if(block->o_type == O_do)
1792      {
1793        block->o_type = O_do;
1794      }
1795    else if(block->o_type == O_while)
1796      {
1797        // TESTME !!!KL -- should not eval expressions if skipping ???
1798        if((_setup.skipping_o != 0) &&
1799  	 (0 != strcmp(_setup.skipping_o, block->o_name)))
1800        {
1801  	    return INTERP_OK;
1802        }
1803  
1804        block->o_type = O_while;
1805        CHKS((line[*counter] != '['),
1806  	    _("Left bracket missing after 'while'"));
1807        CHP(read_real_expression(line, counter, &value, parameters));
1808        _setup.test_value = value;
1809      }
1810    else if(block->o_type == O_repeat)
1811        {
1812            // TESTME !!!KL -- should not eval expressions if skipping ???
1813            if((_setup.skipping_o != 0) &&
1814  	     (0 != strcmp(_setup.skipping_o, block->o_name)))
1815            {
1816  	    return INTERP_OK;
1817            }
1818  
1819            block->o_type = O_repeat;
1820            CHKS((line[*counter] != '['),
1821                 _("Left bracket missing after 'repeat'"));
1822            CHP(read_real_expression(line, counter, &value, parameters));
1823            _setup.test_value = value;
1824        }
1825    else if(block->o_type == O_if)
1826      {
1827        // TESTME !!!KL -- should not eval expressions if skipping ???
1828        if((_setup.skipping_o != 0) &&
1829  	 (0 != strcmp(_setup.skipping_o, block->o_name)))
1830        {
1831  	    return INTERP_OK;
1832        }
1833  
1834        block->o_type = O_if;
1835        CHKS((line[*counter] != '['),
1836  	    _("Left bracket missing after 'if'"));
1837        CHP(read_real_expression(line, counter, &value, parameters));
1838        _setup.test_value = value;
1839      }
1840    else if(block->o_type == O_elseif)
1841      {
1842        // TESTME !!!KL -- should not eval expressions if skipping ???
1843        if((_setup.skipping_o != 0) &&
1844  	 (0 != strcmp(_setup.skipping_o, block->o_name)))
1845        {
1846  	    return INTERP_OK;
1847        }
1848  
1849        block->o_type = O_elseif;
1850        CHKS((line[*counter] != '['),
1851  	    _("Left bracket missing after 'elseif'"));
1852        CHP(read_real_expression(line, counter, &value, parameters));
1853        _setup.test_value = value;
1854      }
1855    else if(block->o_type == O_else)
1856      {
1857        block->o_type = O_else;
1858      }
1859    else if(block->o_type == O_endif)
1860      {
1861        block->o_type = O_endif;
1862      }
1863    else if(block->o_type == O_break)
1864      {
1865        block->o_type = O_break;
1866      }
1867    else if(block->o_type == O_continue)
1868      {
1869        block->o_type = O_continue;
1870      }
1871    else if(block->o_type == O_endwhile)
1872      {
1873        block->o_type = O_endwhile;
1874      }
1875    else if(block->o_type == O_endrepeat)
1876        {
1877            block->o_type = O_endrepeat;
1878        }
1879    else
1880      {
1881        // not legal
1882        block->o_type = O_none;
1883        ERS(NCE_UNKNOWN_COMMAND_IN_O_LINE);
1884      }
1885  
1886    return INTERP_OK;
1887  }
1888  
1889  
1890  /****************************************************************************/
1891  
1892  /*! read_p
1893  
1894  Returned Value: int
1895     If read_real_value returns an error code, this returns that code.
1896     If any of the following errors occur, this returns the error code shown.
1897     Otherwise, it returns INTERP_OK.
1898     1. The first character read is not p:
1899        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
1900     2. A p value has already been inserted in the block:
1901        NCE_MULTIPLE_P_WORDS_ON_ONE_LINE
1902  
1903  Side effects:
1904     counter is reset to point to the first character following the p value.
1905     The p value setting is inserted in block.
1906  
1907  Called by: read_one_item
1908  
1909  When this function is called, counter is pointing at an item on the
1910  line that starts with the character 'p', indicating a p value
1911  setting. The function reads characters which tell how to set the p
1912  value, up to the start of the next item or the end of the line. This
1913  information is inserted in the block.
1914  
1915  P codes are used for:
1916  1. Dwell time in canned cycles g82, G86, G88, G89 [NCMS pages 98 - 100].
1917  2. A key with G10 [NCMS, pages 9, 10].
1918  
1919  */
1920  
1921  int Interp::read_p(char *line,   //!< string: line of RS274/NGC code being processed
1922                    int *counter, //!< pointer to a counter for position on the line 
1923                    block_pointer block,  //!< pointer to a block being filled from the line 
1924                    double *parameters)   //!< array of system parameters                    
1925  {
1926    double value;
1927  
1928    CHKS((line[*counter] != 'p'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1929    *counter = (*counter + 1);
1930    CHKS((block->p_number > -1.0), NCE_MULTIPLE_P_WORDS_ON_ONE_LINE);
1931  
1932    CHP(read_real_value(line, counter, &value, parameters));
1933    // FMP removed check for negatives, since we may want them for
1934    // user-defined codes
1935    // CHKS((value < 0.0), NCE_NEGATIVE_P_WORD_USED);
1936    block->p_number = value;
1937    block->p_flag = true;
1938    return INTERP_OK;
1939  }
1940  
1941  int Interp::read_name(
1942      char *line,   //!< string: line of RS274/NGC code being processed
1943      int *counter, //!< pointer to a counter for position on the line 
1944      char *nameBuf)   //!< pointer to name to be read
1945  {
1946  
1947    int done = 0;
1948    int i;
1949  
1950    CHKS((line[*counter] != '<'),
1951        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
1952  
1953    // skip over the '<'
1954    *counter = (*counter + 1);
1955  
1956    for(i=0; (i<LINELEN) && (line[*counter]); i++)
1957    {
1958        if(line[*counter] == '>')
1959        {
1960            nameBuf[i] = 0; // terminate the name
1961            *counter = (*counter + 1);
1962            done = 1;
1963            break;
1964        }
1965        nameBuf[i] = line[*counter];
1966        *counter = (*counter + 1);
1967    }
1968  
1969    // !!!KL need to rename the error message and change text
1970    CHKS((!done), NCE_NAMED_PARAMETER_NOT_TERMINATED);
1971  
1972    return INTERP_OK;
1973  }
1974  
1975  
1976  
1977  
1978  /****************************************************************************/
1979  
1980  /*! read_parameter
1981  
1982  Returned Value: int
1983     If read_integer_value returns an error code, this returns that code.
1984     If any of the following errors occur, this returns the error code shown.
1985     Otherwise, this returns INTERP_OK.
1986     1. The first character read is not # :
1987        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
1988     2. The parameter number is out of bounds:
1989        NCE_PARAMETER_NUMBER_OUT_OF_RANGE
1990  
1991  Side effects:
1992     The value of the given parameter is put into what double_ptr points at.
1993     The counter is reset to point to the first character after the
1994     characters which make up the value.
1995  
1996  Called by:  read_real_value
1997  
1998  This attempts to read the value of a parameter out of the line,
1999  starting at the index given by the counter.
2000  
2001  According to the RS274/NGC manual [NCMS, p. 62], the characters following
2002  # may be any "parameter expression". Thus, the following are legal
2003  and mean the same thing (the value of the parameter whose number is
2004  stored in parameter 2):
2005    ##2
2006    #[#2]
2007  
2008  Parameter setting is done in parallel, not sequentially. For example
2009  if #1 is 5 before the line "#1=10 #2=#1" is read, then after the line
2010  is is executed, #1 is 10 and #2 is 5. If parameter setting were done
2011  sequentially, the value of #2 would be 10 after the line was executed.
2012  
2013  ADDED by K. Lerman
2014  Named parameters are now supported.
2015  #[abcd] is a parameter with name "abcd"
2016  #[#2] is NOT a named parameter.
2017  When a [ is seen after a #, if the next char is not a #, it is a named
2018  parameter.
2019  
2020  */
2021  
2022  int Interp::read_parameter(
2023      char *line,   //!< string: line of RS274/NGC code being processed
2024      int *counter, //!< pointer to a counter for position on the line 
2025      double *double_ptr,   //!< pointer to double to be read                  
2026      double *parameters,   //!< array of system parameters
2027      bool check_exists)    //!< test for existence, not value
2028  {
2029    int index;
2030  
2031    CHKS((line[*counter] != '#'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2032  
2033    *counter = (*counter + 1);
2034  
2035    // named parameters look like '<letter...>' or '<_.....>'
2036    if(line[*counter] == '<')
2037    {
2038        //_setup.stack_index = 0; -- reminder of variable we need
2039        // find the matching string (if any) -- or create it
2040        // then get the value and store it
2041        CHP(read_named_parameter(line, counter, double_ptr, parameters,
2042  	      check_exists));
2043    }
2044    else
2045    {
2046        CHP(read_integer_value(line, counter, &index, parameters));
2047        if(check_exists)
2048        {
2049        *double_ptr = index >= 1 && index < RS274NGC_MAX_PARAMETERS;
2050  	  return INTERP_OK;
2051        }
2052        CHKS(((index < 1) || (index >= RS274NGC_MAX_PARAMETERS)),
2053            NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
2054        CHKS(((index >= 5420) && (index <= 5428) && (_setup.cutter_comp_side)),
2055             _("Cannot read current position with cutter radius compensation on"));
2056        *double_ptr = parameters[index];
2057    }
2058    return INTERP_OK;
2059  }
2060  
2061  int Interp::read_bracketed_parameter(
2062      char *line,   //!< string: line of RS274/NGC code being processed
2063      int *counter, //!< pointer to a counter for position on the line
2064      double *double_ptr,   //!< pointer to double to be read
2065      double *parameters,   //!< array of system parameters
2066      bool check_exists)    //!< test for existence, not value
2067  {
2068    CHKS((line[*counter] != '['), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2069    *counter = (*counter + 1);
2070    CHKS((line[*counter] != '#'), _("Expected # reading parameter"));
2071    CHP(read_parameter(line, counter, double_ptr, parameters, check_exists));
2072    CHKS((line[*counter] != ']'), _("Expected ] reading bracketed parameter"));
2073    *counter = (*counter + 1);
2074    return INTERP_OK;
2075  }
2076  
2077  
2078  /****************************************************************************/
2079  
2080  /*! read_parameter_setting
2081  
2082  Returned Value: int
2083     If read_real_value or read_integer_value returns an error code,
2084     this returns that code.
2085     If any of the following errors occur, this returns the error code shown.
2086     Otherwise, it returns INTERP_OK.
2087     1. The first character read is not # :
2088        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2089     2. The parameter index is out of range: PARAMETER_NUMBER_OUT_OF_RANGE
2090     3. An equal sign does not follow the parameter expression:
2091        NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING
2092  
2093  Side effects:
2094     counter is reset to the character following the end of the parameter
2095     setting. The parameter whose index follows "#" is set to the
2096     real value following "=".
2097  
2098  Called by: read_one_item
2099  
2100  When this function is called, counter is pointing at an item on the
2101  line that starts with the character '#', indicating a parameter
2102  setting when found by read_one_item.  The function reads characters
2103  which tell how to set the parameter.
2104  
2105  Any number of parameters may be set on a line. If parameters set early
2106  on the line are used in expressions farther down the line, the
2107  parameters have their old values, not their new values. This is
2108  usually called setting parameters in parallel.
2109  
2110  Parameter setting is not clearly described in [NCMS, pp. 51 - 62]: it is
2111  not clear if more than one parameter setting per line is allowed (any
2112  number is OK in this implementation). The characters immediately following
2113  the "#" must constitute a "parameter expression", but it is not clear
2114  what that is. Here we allow any expression as long as it evaluates to
2115  an integer.
2116  
2117  Parameters are handled in the interpreter by having a parameter table
2118  and a parameter buffer as part of the machine settings. The parameter
2119  table is passed to the reading functions which need it. The parameter
2120  buffer is used directly by functions that need it. Reading functions
2121  may set parameter values in the parameter buffer. Reading functions
2122  may obtain parameter values; these come from parameter table.
2123  
2124  The parameter buffer has three parts: (i) a counter for how many
2125  parameters have been set while reading the current line (ii) an array
2126  of the indexes of parameters that have been set while reading the
2127  current line, and (iii) an array of the values for the parameters that
2128  have been set while reading the current line; the nth value
2129  corresponds to the nth index. Any given index will appear once in the
2130  index number array for each time the parameter with that index is set
2131  on a line. There is no point in setting the same parameter more than
2132  one on a line because only the last setting of that parameter will
2133  take effect.
2134  
2135  The syntax recognized by this this function is # followed by an
2136  integer expression (explicit integer or expression evaluating to an
2137  integer) followed by = followed by a real value (number or
2138  expression).
2139  
2140  Note that # also starts a bunch of characters which represent a parameter
2141  to be evaluated. That situation is handled by read_parameter.
2142  
2143  */
2144  
2145  int Interp::read_parameter_setting(
2146      char *line,   //!< string: line of RS274/NGC code being processed
2147      int *counter, //!< pointer to a counter for position on the line 
2148      block_pointer block,  //!< pointer to a block being filled from the line 
2149      double *parameters)   //!< array of system parameters
2150  {
2151    static char name[] = "read_parameter_setting";
2152    int index;
2153    double value;
2154    char *param;
2155    const char *dup;
2156  
2157    CHKS((line[*counter] != '#'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2158    *counter = (*counter + 1);
2159  
2160    // named parameters look like '<letter...>' or '<_letter.....>'
2161    if(line[*counter] == '<')
2162    {
2163        CHP(read_named_parameter_setting(line, counter, &param, parameters));
2164  
2165        CHKS((line[*counter] != '='),
2166            NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING);
2167        *counter = (*counter + 1);
2168        CHP(read_real_value(line, counter, &value, parameters));
2169  
2170        logDebug("setting up named param[%d]:|%s| value:%lf",
2171                 _setup.named_parameter_occurrence, param, value);
2172  
2173        dup = strstore(param); // no more need to free this
2174        if(dup == 0)
2175        {
2176            ERS(NCE_OUT_OF_MEMORY);
2177        }
2178        logDebug("%s |%s|", name,  dup);
2179        _setup.named_parameters[_setup.named_parameter_occurrence] = dup;
2180  
2181        _setup.named_parameter_values[_setup.named_parameter_occurrence] = value;
2182        _setup.named_parameter_occurrence++;
2183        logDebug("done setting up named param[%d]:|%s| value:%lf",
2184                 _setup.named_parameter_occurrence, param, value);
2185    }
2186    else
2187    {
2188        CHP(read_integer_value(line, counter, &index, parameters));
2189        CHKS(((index < 1) || (index >= RS274NGC_MAX_PARAMETERS)),
2190            NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
2191        CHKS((isreadonly(index)), NCE_PARAMETER_NUMBER_READONLY);
2192        CHKS((line[*counter] != '='),
2193            NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING);
2194        *counter = (*counter + 1);
2195        CHP(read_real_value(line, counter, &value, parameters));
2196        _setup.parameter_numbers[_setup.parameter_occurrence] = index;
2197        _setup.parameter_values[_setup.parameter_occurrence] = value;
2198        _setup.parameter_occurrence++;
2199    }
2200    return INTERP_OK;
2201  }
2202  
2203  /****************************************************************************/
2204  
2205  /*! read_named_parameter_setting
2206  
2207  Returned Value: int
2208     If read_real_value or read_integer_value returns an error code,
2209     this returns that code.
2210     If any of the following errors occur, this returns the error code shown.
2211     Otherwise, it returns INTERP_OK.
2212     1. The first character read is not # :
2213        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2214     2. The parameter index is out of range: PARAMETER_NUMBER_OUT_OF_RANGE
2215     3. An equal sign does not follow the parameter expression:
2216        NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING
2217  
2218  Side effects:
2219     counter is reset to the character following the end of the parameter
2220     setting. The parameter whose index follows "#" is set to the
2221     real value following "=".
2222  
2223  Called by: read_parameter_setting
2224  
2225  When this function is called, counter is pointing at an item on the
2226  line that starts with the character '#', indicating a parameter
2227  setting when found by read_one_item.  The function reads characters
2228  which tell how to set the parameter.
2229  
2230  Any number of parameters may be set on a line. If parameters set early
2231  on the line are used in expressions farther down the line, the
2232  parameters have their old values, not their new values. This is
2233  usually called setting parameters in parallel.
2234  
2235  Parameter setting is not clearly described in [NCMS, pp. 51 - 62]: it is
2236  not clear if more than one parameter setting per line is allowed (any
2237  number is OK in this implementation). The characters immediately following
2238  the "#" must constitute a "parameter expression", but it is not clear
2239  what that is. Here we allow any expression as long as it evaluates to
2240  an integer.
2241  
2242  Parameters are handled in the interpreter by having a parameter table
2243  and a parameter buffer as part of the machine settings. The parameter
2244  table is passed to the reading functions which need it. The parameter
2245  buffer is used directly by functions that need it. Reading functions
2246  may set parameter values in the parameter buffer. Reading functions
2247  may obtain parameter values; these come from parameter table.
2248  
2249  The parameter buffer has three parts: (i) a counter for how many
2250  parameters have been set while reading the current line (ii) an array
2251  of the indexes of parameters that have been set while reading the
2252  current line, and (iii) an array of the values for the parameters that
2253  have been set while reading the current line; the nth value
2254  corresponds to the nth index. Any given index will appear once in the
2255  index number array for each time the parameter with that index is set
2256  on a line. There is no point in setting the same parameter more than
2257  one on a line because only the last setting of that parameter will
2258  take effect.
2259  
2260  The syntax recognized by this this function is # followed by an
2261  integer expression (explicit integer or expression evaluating to an
2262  integer) followed by = followed by a real value (number or
2263  expression).
2264  
2265  Note that # also starts a bunch of characters which represent a parameter
2266  to be evaluated. That situation is handled by read_parameter.
2267  
2268  */
2269  
2270  int Interp::read_named_parameter_setting(
2271      char *line,   //!< string: line of RS274/NGC code being processed
2272      int *counter, //!< pointer to a counter for position on the line 
2273      char **param,  //!< pointer to the char * to be returned 
2274      double *parameters)   //!< array of system parameters
2275  {
2276    static char name[] = "read_named_parameter_setting";
2277    int status;
2278    static char paramNameBuf[LINELEN+1];
2279  
2280    *param = paramNameBuf;
2281  
2282    logDebug("entered %s", name);
2283    CHKS((line[*counter] != '<'),
2284        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2285  
2286    status=read_name(line, counter, paramNameBuf);
2287    CHP(status);
2288  
2289    logDebug("%s: returned(%d) from read_name:|%s|", name, status, paramNameBuf);
2290  
2291    status = add_named_param(paramNameBuf);
2292    CHP(status);
2293    logDebug("%s: returned(%d) from add_named_param:|%s|", name, status, paramNameBuf);
2294  
2295    // the rest of the work is done in read_parameter_setting
2296  
2297    return INTERP_OK;
2298  }
2299  
2300  /****************************************************************************/
2301  
2302  /*! read_q
2303  
2304  Returned Value: int
2305     If read_real_value returns an error code, this returns that code.
2306     If any of the following errors occur, this returns the error code shown.
2307     Otherwise, it returns INTERP_OK.
2308     1. The first character read is not q:
2309        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2310     2. A q value has already been inserted in the block:
2311        NCE_MULTIPLE_Q_WORDS_ON_ONE_LINE
2312  
2313  Side effects:
2314     counter is reset to point to the first character following the q value.
2315     The q value setting is inserted in block.
2316  
2317  Called by: read_one_item
2318  
2319  When this function is called, counter is pointing at an item on the
2320  line that starts with the character 'q', indicating a q value
2321  setting. The function reads characters which tell how to set the q
2322  value, up to the start of the next item or the end of the line. This
2323  information is inserted in the block.
2324  
2325  Q is used only in the G87 canned cycle [NCMS, page 98], where it must
2326  be positive.
2327  
2328  */
2329  
2330  int Interp::read_q(char *line,   //!< string: line of RS274/NGC code being processed
2331                    int *counter, //!< pointer to a counter for position on the line 
2332                    block_pointer block,  //!< pointer to a block being filled from the line 
2333                    double *parameters)   //!< array of system parameters                    
2334  {
2335    double value;
2336  
2337    CHKS((line[*counter] != 'q'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2338    *counter = (*counter + 1);
2339    CHKS((block->q_number > -1.0), NCE_MULTIPLE_Q_WORDS_ON_ONE_LINE);
2340    CHP(read_real_value(line, counter, &value, parameters));
2341    // FMP removed check for negatives, since we may want them for
2342    // user-defined codes
2343    // CHKS((value <= 0.0), NCE_NEGATIVE_OR_ZERO_Q_VALUE_USED);
2344    block->q_number = value;
2345    block->q_flag = true;
2346    return INTERP_OK;
2347  }
2348  
2349  /****************************************************************************/
2350  
2351  /*! read_r
2352  
2353  Returned Value: int
2354     If read_real_value returns an error code, this returns that code.
2355     If any of the following errors occur, this returns the error code shown.
2356     Otherwise, it returns INTERP_OK.
2357     1. The first character read is not r:
2358        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2359     2. An r_number has already been inserted in the block:
2360        NCE_MULTIPLE_R_WORDS_ON_ONE_LINE
2361  
2362  Side effects:
2363     counter is reset.
2364     The r_flag in the block is turned on.
2365     The r_number is inserted in the block.
2366  
2367  Called by: read_one_item
2368  
2369  When this function is called, counter is pointing at an item on the
2370  line that starts with the character 'r'. The function reads characters
2371  which tell how to set the coordinate, up to the start of the next item
2372  or the end of the line. This information is inserted in the block. The
2373  counter is then set to point to the character following.
2374  
2375  An r number indicates the clearance plane in canned cycles.
2376  An r number may also be the radius of an arc.
2377  
2378  The value may be a real number or something that evaluates to a
2379  real number, so read_real_value is used to read it. Parameters
2380  may be involved.
2381  
2382  */
2383  
2384  int Interp::read_r(char *line,   //!< string: line of RS274 code being processed   
2385                    int *counter, //!< pointer to a counter for position on the line
2386                    block_pointer block,  //!< pointer to a block being filled from the line
2387                    double *parameters)   //!< array of system parameters                   
2388  {
2389    double value;
2390  
2391    CHKS((line[*counter] != 'r'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2392    *counter = (*counter + 1);
2393    CHKS((block->r_flag), NCE_MULTIPLE_R_WORDS_ON_ONE_LINE);
2394    CHP(read_real_value(line, counter, &value, parameters));
2395    block->r_flag = true;
2396    block->r_number = value;
2397    return INTERP_OK;
2398  }
2399  
2400  /****************************************************************************/
2401  
2402  /*! read_real_expression
2403  
2404  Returned Value: int
2405     If any of the following functions returns an error code,
2406     this returns that code.
2407       read_real_value
2408       read_operation
2409       execute_binary
2410     If any of the following errors occur, this returns the error shown.
2411     Otherwise, it returns INTERP_OK.
2412     1. The first character is not [ :
2413        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2414  
2415  Side effects:
2416     The number read from the line is put into what value_ptr points at.
2417     The counter is reset to point to the first character after the real
2418     expression.
2419  
2420  Called by:
2421   read_atan
2422   read_real_value
2423   read_unary
2424  
2425  Example 1: [2 - 3 * 4 / 5] means [2 - [[3 * 4] / 5]] and equals -0.4.
2426  
2427  Segmenting Expressions -
2428  
2429  The RS274/NGC manual, section 3.5.1.1 [NCMS, page 50], provides for
2430  using square brackets to segment expressions.
2431  
2432  Binary Operations -
2433  
2434  The RS274/NGC manual, section 3.5.1.1, discusses expression evaluation.
2435  The manual provides for eight binary operations: the four basic
2436  mathematical operations (addition, subtraction, multiplication,
2437  division), three logical operations (non-exclusive ||, exclusive ||,
2438  and AND2) and the modulus operation. The manual does not explicitly call
2439  these "binary" operations, but implicitly recognizes that they are
2440  binary. We have added the "power" operation of raising the number
2441  on the left of the operation to the power on the right; this is
2442  needed for many basic machining calculations.
2443  
2444  There are two groups of binary operations given in the manual. If
2445  operations are strung together as shown in Example 1, operations in
2446  the first group are to be performed before operations in the second
2447  group. If an expression contains more than one operation from the same
2448  group (such as * and / in Example 1), the operation on the left is
2449  performed first. The first group is: multiplication (*), division (/),
2450  and modulus (MOD). The second group is: addition(+), subtraction (-),
2451  logical non-exclusive || (||), logical exclusive || (XOR), and logical
2452  && (AND2). We have added a third group with higher precedence than
2453  the first group. The third group contains only the power (**)
2454  operation.
2455  
2456  The logical operations and modulus are apparently to be performed on
2457  any real numbers, not just on integers or on some other data type.
2458  
2459  Unary Operations -
2460  
2461  The RS274/NGC manual, section 3.5.1.2, provides for fifteen unary
2462  mathematical operations. Two of these, BIN and BCD, are apparently for
2463  converting between decimal and hexadecimal number representation,
2464  although the text is not clear. These have not been implemented, since
2465  we are not using any hexadecimal numbers. The other thirteen unary
2466  operations have been implemented: absolute_value, arc_cosine, arc_sine,
2467  arc_tangent, cosine, e_raised_to, fix_down, fix_up, natural_log_of,
2468  round, sine, square_root, tangent.
2469  
2470  The manual section 3.5.1.2 [NCMS, page 51] requires the argument to
2471  all unary operations (except atan) to be in square brackets.  Thus,
2472  for example "sin[90]" is allowed in the interpreter, but "sin 90" is
2473  not. The atan operation must be in the format "atan[..]/[..]".
2474  
2475  Production Rule Definitions in Terms of Tokens -
2476  
2477  The following is a production rule definition of what this RS274NGC
2478  interpreter recognizes as valid combinations of symbols which form a
2479  recognized real_value (the top of this production hierarchy).
2480  
2481  The notion of "integer_value" is used in the interpreter. Below it is
2482  defined as a synonym for real_value, but in fact a constraint is added
2483  which cannot be readily written in a production language.  An
2484  integer_value is a real_value which is very close to an integer.
2485  Integer_values are needed for array and table indices and (when
2486  divided by 10) for the values of M codes and G codes. All numbers
2487  (including integers) are read as real numbers and stored as doubles.
2488  If an integer_value is required in some situation, a test for being
2489  close to an integer is applied to the number after it is read.
2490  
2491  
2492  arc_tangent_combo = arc_tangent expression divided_by expression .
2493  
2494  binary_operation1 = divided_by | modulo | power | times .
2495  
2496  binary_operation2 = and | exclusive_or | minus |  non_exclusive_or | plus .
2497  
2498  combo1 = real_value { binary_operation1 real_value } .
2499  
2500  digit = zero | one | two | three | four | five | six | seven |eight | nine .
2501  
2502  expression =
2503     left_bracket
2504     (unary_combo | (combo1 { binary_operation2 combo1 }))
2505     right_bracket .
2506  
2507  integer_value = real_value .
2508  
2509  ordinary_unary_combo =  ordinary_unary_operation expression .
2510  
2511  ordinary_unary_operation =
2512     absolute_value | arc_cosine | arc_sine | cosine | e_raised_to |
2513     fix_down | fix_up | natural_log_of | round | sine | square_root | tangent .
2514  
2515  parameter_index = integer_value .
2516  
2517  parameter_value = parameter_sign  parameter_index .
2518  
2519  real_number =
2520     [ plus | minus ]
2521     (( digit { digit } decimal_point {digit}) | ( decimal_point digit {digit})).
2522  
2523  real_value =
2524     real_number | expression | parameter_value | unary_combo.
2525  
2526  unary_combo = ordinary_unary_combo | arc_tangent_combo .
2527  
2528  
2529  Production Tokens in Terms of Characters -
2530  
2531  absolute_value   = 'abs'
2532  and              = 'and'
2533  arc_cosine       = 'acos'
2534  arc_sine         = 'asin'
2535  arc_tangent      = 'atan'
2536  cosine           = 'cos'
2537  decimal_point    = '.'
2538  divided_by       = '/'
2539  eight            = '8'
2540  exclusive_or     = 'xor'
2541  e_raised_to      = 'exp'
2542  five             = '5'
2543  fix_down         = 'fix'
2544  fix_up           = 'fup'
2545  four             = '4'
2546  left_bracket     = '['
2547  minus            = '-'
2548  modulo           = 'mod'
2549  natural_log_of   = 'ln'
2550  nine             = '9'
2551  non_exclusive_or = 'or'
2552  one              = '1'
2553  parameter_sign   = '#'
2554  plus             = '+'
2555  power            = '**'
2556  right_bracket    = ']'
2557  round            = 'round'
2558  seven            = '7'
2559  sine             = 'sin'
2560  six              = '6'
2561  square_root      = 'sqrt'
2562  tangent          = 'tan'
2563  three            = '3'
2564  times            = '*'
2565  two              = '2'
2566  zero             = '0'
2567  
2568  When this function is called, the counter should be set at a left
2569  bracket. The function reads up to and including the right bracket
2570  which closes the expression.
2571  
2572  The basic form of an expression is: [v1 bop v2 bop ... vn], where the
2573  vi are real_values and the bops are binary operations. The vi may be
2574  numbers, parameters, expressions, or unary functions. Because some
2575  bops are to be evaluated before others, for understanding the order of
2576  evaluation, it is useful to rewrite the general form collecting any
2577  subsequences of bops of the same precedence. For example, suppose the
2578  expression is: [9+8*7/6+5-4*3**2+1]. It may be rewritten as:
2579  [9+[8*7/6]+5-[4*[3**2]]+1] to show how it should be evaluated.
2580  
2581  The manual provides that operations of the same precedence should be
2582  processed left to right.
2583  
2584  The first version of this function is commented out. It is suitable
2585  for when there are only two precendence levels. It is an improvement
2586  over the version used in interpreters before 2000, but not as general
2587  as the second version given here.
2588  
2589  The first version of this function reads the first value and the first
2590  operation in the expression. Then it calls either read_rest_bop1 or
2591  read_rest_bop2 according to whether the first operation is a bop1 or a
2592  bop2.  Read_rest_bop1 resets the next_operation to either a right
2593  bracket or a bop2. If it is reset to a bop2, read_rest_bop2 is called
2594  when read_rest_bop1 returns.
2595  
2596  */
2597  
2598  #ifdef UNDEFINED
2599  int Interp::read_real_expression(char *line,     //!< string: line of RS274/NGC code being processed
2600                                  int *counter,   //!< pointer to a counter for position on the line 
2601                                  double *value,  //!< pointer to double to be read                  
2602                                  double *parameters)     //!< array of system parameters                    
2603  {
2604    static char name[] = "read_real_expression";
2605    int next_operation;
2606    int status;
2607  
2608    CHKS((line[*counter] != '['), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2609    *counter = (*counter + 1);
2610    CHP(read_real_value(line, counter, value, parameters));
2611    CHP(read_operation(line, counter, &next_operation));
2612    if (next_operation == RIGHT_BRACKET); /* nothing to do */
2613    else if (next_operation < AND2) {     /* next operation is a bop1, times-like */
2614      CHP(read_rest_bop1(line, counter, value, &next_operation, parameters));
2615      if (next_operation == RIGHT_BRACKET);       /* next_operation has been reset */
2616      else                        /* next_operation is now a bop2, plus-like */
2617        CHP(read_rest_bop2(line, counter, value, next_operation, parameters));
2618    } else                        /* next operation is a bop2, plus-like */
2619      CHP(read_rest_bop2(line, counter, value, next_operation, parameters));
2620    return INTERP_OK;
2621  }
2622  #endif
2623  
2624  /****************************************************************************/
2625  
2626  /*! read_real_expression
2627  
2628  The following version is stack-based and fully general. It is the
2629  classical stack-based version with left-to-right evaluation of
2630  operations of the same precedence. Separate stacks are used for
2631  operations and values, and the stacks are made with arrays
2632  rather than lists, but those are implementation details. Pushing
2633  and popping are implemented by increasing or decreasing the
2634  stack index.
2635  
2636  Additional levels of precedence may be defined easily by changing the
2637  precedence function. The size of MAX_STACK should always be at least
2638  as large as the number of precedence levels used. We are currently
2639  using four precedence levels (for right-bracket, plus-like operations,
2640  times-like operations, and power).
2641  
2642  N.B.: We are now using six levels (right-bracket, logical operations,
2643  relational operations, plus-like operations, times-like operations, and
2644  power).
2645  
2646  */
2647  
2648  #define MAX_STACK 7
2649  
2650  int Interp::read_real_expression(char *line,     //!< string: line of RS274/NGC code being processed
2651                                  int *counter,   //!< pointer to a counter for position on the line 
2652                                  double *value,  //!< pointer to double to be computed              
2653                                  double *parameters)     //!< array of system parameters                    
2654  {
2655    double values[MAX_STACK];
2656    int operators[MAX_STACK];
2657    int stack_index;
2658  
2659    CHKS((line[*counter] != '['), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2660    *counter = (*counter + 1);
2661    CHP(read_real_value(line, counter, values, parameters));
2662    CHP(read_operation(line, counter, operators));
2663    stack_index = 1;
2664    for (; operators[0] != RIGHT_BRACKET;) {
2665      CHP(read_real_value(line, counter, values + stack_index, parameters));
2666      CHP(read_operation(line, counter, operators + stack_index));
2667      if (precedence(operators[stack_index]) >
2668          precedence(operators[stack_index - 1]))
2669        stack_index++;
2670      else {                      /* precedence of latest operator is <= previous precedence */
2671  
2672        for (; precedence(operators[stack_index]) <=
2673             precedence(operators[stack_index - 1]);) {
2674          CHP(execute_binary((values + stack_index - 1),
2675                             operators[stack_index - 1],
2676                             (values + stack_index)));
2677          operators[stack_index - 1] = operators[stack_index];
2678          if ((stack_index > 1) &&
2679              (precedence(operators[stack_index - 1]) <=
2680               precedence(operators[stack_index - 2])))
2681            stack_index--;
2682          else
2683            break;
2684        }
2685      }
2686    }
2687    *value = values[0];
2688    return INTERP_OK;
2689  }
2690  
2691  
2692  /****************************************************************************/
2693  
2694  /*! read_real_number
2695  
2696  Returned Value: int
2697     If any of the following errors occur, this returns the error shown.
2698     Otherwise, it returns INTERP_OK.
2699     1. The first character is not "+", "-", "." or a digit:
2700        NCE_BAD_NUMBER_FORMAT
2701     2. No digits are found after the first character and before the
2702        end of the line or the next character that cannot be part of a real:
2703        NCE_NO_DIGITS_FOUND_WHERE_REAL_NUMBER_SHOULD_BE
2704     3. sscanf fails: NCE_SSCANF_FAILED
2705  
2706  Side effects:
2707     The number read from the line is put into what double_ptr points at.
2708     The counter is reset to point to the first character after the real.
2709  
2710  Called by:  read_real_value
2711  
2712  This attempts to read a number out of the line, starting at the index
2713  given by the counter. It stops when the first character that cannot
2714  be part of the number is found.
2715  
2716  The first character may be a digit, "+", "-", or "."
2717  Every following character must be a digit or "." up to anything
2718  that is not a digit or "." (a second "." terminates reading).
2719  
2720  This function is not called if the first character is NULL, so it is
2721  not necessary to check that.
2722  
2723  The temporary insertion of a NULL character on the line is to avoid
2724  making a format string like "%3lf" which the LynxOS compiler cannot
2725  handle.
2726  
2727  */
2728  
2729  int Interp::read_real_number(char *line, //!< string: line of RS274/NGC code being processed
2730                              int *counter,       //!< pointer to a counter for position on the line 
2731                              double *double_ptr) //!< pointer to double to be read                  
2732  {
2733    char *start;
2734    size_t after;
2735  
2736    start = line + *counter;
2737  
2738    after = strspn(start, "+-");
2739    after = strspn(start+after, "0123456789.") + after;
2740  
2741    std::string st(start, start+after);
2742    std::stringstream s(st);
2743    double val;
2744    if(!(s >> val)) ERS(_("bad number format (conversion failed) parsing '%s'"), st.c_str());
2745    if(s.get() != std::char_traits<char>::eof()) ERS(_("bad number format (trailing characters) parsing '%s'"), st.c_str());
2746  
2747    *double_ptr = val;
2748    *counter = start + after - line;
2749    //fprintf(stderr, "got %f   rest of line=%s\n", val, line+*counter);
2750    return INTERP_OK;
2751  }
2752  
2753  /****************************************************************************/
2754  
2755  /*! read_real_value
2756  
2757  Returned Value: int
2758     If one of the following functions returns an error code,
2759     this returns that code.
2760        read_real_expression
2761        read_parameter
2762        read_unary
2763        read_real_number
2764     If no characters are found before the end of the line this
2765     returns NCE_NO_CHARACTERS_FOUND_IN_READING_REAL_VALUE.
2766     Otherwise, this returns INTERP_OK.
2767  
2768  Side effects:
2769     The value read from the line is put into what double_ptr points at.
2770     The counter is reset to point to the first character after the
2771     characters which make up the value.
2772  
2773  Called by:
2774     read_a
2775     read_b
2776     read_c
2777     read_f
2778     read_g
2779     read_i
2780     read_integer_value
2781     read_j
2782     read_k
2783     read_p
2784     read_parameter_setting
2785     read_q
2786     read_r
2787     read_real_expression
2788     read_s
2789     read_x
2790     read_y
2791     read_z
2792  
2793  This attempts to read a real value out of the line, starting at the
2794  index given by the counter. The value may be a number, a parameter
2795  value, a unary function, or an expression. It calls one of four
2796  other readers, depending upon the first character.
2797  
2798  */
2799  
2800  int Interp::read_real_value(char *line,  //!< string: line of RS274/NGC code being processed
2801                             int *counter,        //!< pointer to a counter for position on the line 
2802                             double *double_ptr,  //!< pointer to double to be read                  
2803                             double *parameters)  //!< array of system parameters                    
2804  {
2805    char c, c1;
2806  
2807    c = line[*counter];
2808    CHKS((c == 0), NCE_NO_CHARACTERS_FOUND_IN_READING_REAL_VALUE);
2809  
2810    c1 = line[*counter+1];
2811  
2812    if (c == '[')
2813      CHP(read_real_expression(line, counter, double_ptr, parameters));
2814    else if (c == '#')
2815    {
2816      CHP(read_parameter(line, counter, double_ptr, parameters, false));
2817    }
2818    else if (c == '+' && c1 && !isdigit(c1) && c1 != '.')
2819    {
2820      (*counter)++;
2821      CHP(read_real_value(line, counter, double_ptr, parameters));
2822    }
2823    else if (c == '-' && c1 && !isdigit(c1) && c1 != '.')
2824    {
2825      (*counter)++;
2826      CHP(read_real_value(line, counter, double_ptr, parameters));
2827      *double_ptr = -*double_ptr;
2828    }
2829    else if ((c >= 'a') && (c <= 'z'))
2830      CHP(read_unary(line, counter, double_ptr, parameters));
2831    else
2832      CHP(read_real_number(line, counter, double_ptr));
2833  
2834    CHKS(std::isnan(*double_ptr),
2835            _("Calculation resulted in 'not a number'"));
2836    CHKS(std::isinf(*double_ptr),
2837            _("Calculation resulted in 'infinity'"));
2838  
2839    return INTERP_OK;
2840  }
2841  
2842  /****************************************************************************/
2843  
2844  /*! read_rest_bop1
2845  
2846  Returned Value: int
2847    If any of the following functions returns an error code,
2848    this returns that code.
2849       execute_binary1
2850       read_real_value
2851       read_operation
2852    Otherwise, it returns INTERP_OK.
2853  
2854  Side effects:
2855     The value argument is set to the value of the expression.
2856     The counter is reset to point to the first character after the real
2857     expression.
2858  
2859  Called by:
2860    read_real_expression
2861    read_rest_bop2
2862  
2863  The value argument has a value in it when this is called. This repeatedly
2864  gets the next_value and the next_operation, performs the last_operation
2865  on the value and the next_value and resets the last_operation to the
2866  next_operation. Observe that both the value and the last_operation
2867  are passed back to the caller.
2868  
2869  This is commented out since it is not used in the uncommented version
2870  of read_real_expression. It has been tested.
2871  
2872  */
2873  
2874  #ifdef UNDEFINED
2875  int Interp::read_rest_bop1(char *line,   //!< string: line of RS274/NGC code being processed
2876                            int *counter, //!< pointer to a counter for position on the line 
2877                            double *value,        //!< pointer to double to be calculated            
2878                            int *last_operation,  //!< last operation read, reset to next operation  
2879                            double *parameters)   //!< array of system parameters                    
2880  {
2881    static char name[] = "read_rest_bop1";
2882    double next_value;
2883    int next_operation;
2884    int status;
2885  
2886    for (;;) {
2887      CHP(read_real_value(line, counter, &next_value, parameters));
2888      CHP(read_operation(line, counter, &next_operation));
2889      CHP(execute_binary1(value, *last_operation, &next_value));
2890      *last_operation = next_operation;
2891      if (next_operation >= AND2) /* next op is a bop2 or right bracket */
2892        break;
2893    }
2894    return INTERP_OK;
2895  }
2896  #endif
2897  
2898  /****************************************************************************/
2899  
2900  /*! read_rest_bop2
2901  
2902  Returned Value: int
2903    If any of the following functions returns an error code,
2904    this returns that code.
2905       execute_binary2
2906       read_real_value
2907       read_operation
2908       read_rest_bop1
2909    Otherwise, it returns INTERP_OK.
2910  
2911  Side effects:
2912     The value argument is set to the value of the expression.
2913     The counter is reset to point to the first character after the real
2914     expression.
2915  
2916  Called by:  read_real_expression
2917  
2918  The value argument has a value in it when this is called. This repeatedly
2919  gets the next_value and the next_operation, performs the last_operation
2920  on the value and the next_value and resets the last_operation to the
2921  next_operation. If the next_operation is ever a bop1 read_rest_bop1 is
2922  called to set the next_value.
2923  
2924  This is commented out since it is not used in the uncommented version
2925  of read_real_expression. It has been tested.
2926  
2927  */
2928  
2929  #ifdef UNDEFINED
2930  int Interp::read_rest_bop2(char *line,   //!< string: line of RS274/NGC code being processed
2931                            int *counter, //!< pointer to a counter for position on the line 
2932                            double *value,        //!< pointer to double to be calculated            
2933                            int last_operation,   //!< last operation read                           
2934                            double *parameters)   //!< array of system parameters                    
2935  {
2936    static char name[] = "read_rest_bop2";
2937    double next_value;
2938    int next_operation;
2939    int status;
2940  
2941    for (;; last_operation = next_operation) {
2942      CHP(read_real_value(line, counter, &next_value, parameters));
2943      CHP(read_operation(line, counter, &next_operation));
2944      if (next_operation < AND2) {        /* next operation is a bop1 */
2945        CHP(read_rest_bop1(line, counter, &next_value,
2946                           &next_operation, parameters));
2947      }
2948      CHP(execute_binary2(value, last_operation, &next_value));
2949      if (next_operation == RIGHT_BRACKET)
2950        break;
2951    }
2952    return INTERP_OK;
2953  }
2954  #endif
2955  
2956  /****************************************************************************/
2957  
2958  /*! read_s
2959  
2960  Returned Value: int
2961     If read_real_value returns an error code, this returns that code.
2962     If any of the following errors occur, this returns the error code shown.
2963     Otherwise, it returns INTERP_OK.
2964     1. The first character read is not s:
2965        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
2966     2. A spindle speed has already been inserted in the block:
2967        NCE_MULTIPLE_S_WORDS_ON_ONE_LINE
2968     3. The spindle speed is negative: NCE_NEGATIVE_SPINDLE_SPEED_USED
2969  
2970  Side effects:
2971     counter is reset to the character following the spindle speed.
2972     A spindle speed setting is inserted in the block.
2973  
2974  Called by: read_one_item
2975  
2976  When this function is called, counter is pointing at an item on the
2977  line that starts with the character 's', indicating a spindle speed
2978  setting. The function reads characters which tell how to set the spindle
2979  speed.
2980  
2981  The value may be a real number or something that evaluates to a
2982  real number, so read_real_value is used to read it. Parameters
2983  may be involved.
2984  
2985  */
2986  
2987  int Interp::read_s(char *line,   //!< string: line of RS274NGC code being processed
2988                    int *counter, //!< pointer to a counter for position on the line
2989                    block_pointer block,  //!< pointer to a block being filled from the line
2990                    double *parameters)   //!< array of system parameters                   
2991  {
2992    double value;
2993  
2994    CHKS((line[*counter] != 's'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
2995    *counter = (*counter + 1);
2996    CHKS((block->s_flag), NCE_MULTIPLE_S_WORDS_ON_ONE_LINE);
2997    CHP(read_real_value(line, counter, &value, parameters));
2998    CHKS((value < 0.0), NCE_NEGATIVE_SPINDLE_SPEED_USED);
2999    block->s_number = value;
3000    block->s_flag = true;
3001    return INTERP_OK;
3002  }
3003  
3004  /****************************************************************************/
3005  
3006  /*! read_t
3007  
3008  Returned Value: int
3009     If read_integer_value returns an error code, this returns that code.
3010     If any of the following errors occur, this returns the error code shown.
3011     Otherwise, it returns INTERP_OK.
3012     1. The first character read is not t:
3013        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
3014     2. A t_number has already been inserted in the block:
3015        NCE_MULTIPLE_T_WORDS_ON_ONE_LINE
3016     3. The t_number is negative: NCE_NEGATIVE_TOOL_ID_USED
3017  
3018  Side effects:
3019     counter is reset to the character following the t_number.
3020     A t_number is inserted in the block.
3021  
3022  Called by: read_one_item
3023  
3024  When this function is called, counter is pointing at an item on the
3025  line that starts with the character 't', indicating a tool.
3026  The function reads characters which give the (integer) value of the
3027  tool code.
3028  
3029  The value must be an integer or something that evaluates to a
3030  real number, so read_integer_value is used to read it. Parameters
3031  may be involved.
3032  
3033  */
3034  
3035  int Interp::read_t(char *line,   //!< string: line of RS274/NGC code being processed
3036                    int *counter, //!< pointer to a counter for position on the line 
3037                    block_pointer block,  //!< pointer to a block being filled from the line 
3038                    double *parameters)   //!< array of system parameters                    
3039  {
3040    int value;
3041  
3042    CHKS((line[*counter] != 't'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3043    *counter = (*counter + 1);
3044    CHKS((block->t_flag), NCE_MULTIPLE_T_WORDS_ON_ONE_LINE);
3045    CHP(read_integer_value(line, counter, &value, parameters));
3046    CHKS((value < 0), NCE_NEGATIVE_TOOL_ID_USED);
3047    block->t_number = value;
3048    block->t_flag = true;
3049    return INTERP_OK;
3050  }
3051  
3052  /****************************************************************************/
3053  
3054  /*! read_text
3055  
3056  Returned Value: int
3057     If close_and_downcase returns an error code, this returns that code.
3058     If any of the following errors occur, this returns the error code shown.
3059     Otherwise, this returns:
3060         a. INTERP_ENDFILE if the percent_flag is true and the only
3061            non-white character on the line is %,
3062         b. INTERP_EXECUTE_FINISH if the first character of the
3063            close_and_downcased line is a slash, and
3064         c. INTERP_OK otherwise.
3065     1. The end of the file is found and the percent_flag is true:
3066        NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN
3067     2. The end of the file is found and the percent_flag is false:
3068        NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN_OR_PROGRAM_END
3069     3. The command argument is not null and is too long or the command
3070        argument is null and the line read from the file is too long:
3071        NCE_COMMAND_TOO_LONG
3072  
3073  Side effects: See below
3074  
3075  Called by:  Interp::read
3076  
3077  This reads a line of RS274 code from a command string or a file into
3078  the line array. If the command string is not null, the file is ignored.
3079  
3080  If the end of file is reached, an error is returned as described
3081  above. The end of the file should not be reached because (a) if the
3082  file started with a percent line, it must end with a percent line, and
3083  no more reading of the file should occur after that, and (b) if the
3084  file did not start with a percent line, it must have a program ending
3085  command (M2 or M30) in it, and no more reading of the file should
3086  occur after that.
3087  
3088  All blank space at the end of a line read from a file is removed and
3089  replaced here with NULL characters.
3090  
3091  This then calls close_and_downcase to downcase and remove tabs and
3092  spaces from everything on the line that is not part of a comment. Any
3093  comment is left as is.
3094  
3095  The length is set to zero if any of the following occur:
3096  1. The line now starts with a slash, but the second character is NULL.
3097  2. The first character is NULL.
3098  Otherwise, length is set to the length of the line.
3099  
3100  An input line is blank if the first character is NULL or it consists
3101  entirely of tabs and spaces and, possibly, a newline before the first
3102  NULL.
3103  
3104  Block delete is discussed in [NCMS, page 3] but the discussion makes
3105  no sense. Block delete is handled by having this function return
3106  INTERP_EXECUTE_FINISH if the first character of the
3107  close_and_downcased line is a slash. When the caller sees this,
3108  the caller is expected not to call Interp::execute if the switch
3109  is on, but rather call Interp::read again to overwrite and ignore
3110  what is read here.
3111  
3112  The value of the length argument is set to the number of characters on
3113  the reduced line.
3114  
3115  */
3116  
3117  int Interp::read_text(
3118      const char *command,       //!< a string which may have input text, or null
3119      FILE * inport,     //!< a file pointer for an input file, or null
3120      char *raw_line,    //!< array to write raw input line into
3121      char *line,        //!< array for input line to be processed in
3122      int *length)       //!< a pointer to an integer to be set
3123  {
3124    int index;
3125  
3126    if (command == NULL) {
3127      if (fgets(raw_line, LINELEN, inport) == NULL) {
3128        if(_setup.skipping_to_sub)
3129        {
3130          ERS(_("EOF in file:%s seeking o-word: o<%s> from line: %d"),
3131                   _setup.filename,
3132                   _setup.skipping_to_sub,
3133                   _setup.skipping_start);
3134        }
3135        if (_setup.percent_flag)
3136        {
3137          ERS(NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN);
3138        }
3139        else
3140        {
3141          ERS(NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN_OR_PROGRAM_END);
3142        }
3143      }
3144      _setup.sequence_number++;   /* moved from version1, was outside if */
3145      if (strlen(raw_line) == (LINELEN - 1)) { // line is too long. need to finish reading the line to recover
3146        for (; fgetc(inport) != '\n' && !feof(inport) ;) {
3147        }
3148        ERS(NCE_COMMAND_TOO_LONG);
3149      }
3150      for (index = (strlen(raw_line) - 1);        // index set on last char
3151           (index >= 0) && (isspace(raw_line[index]));
3152           index--) { // remove space at end of raw_line, especially CR & LF
3153        raw_line[index] = 0;
3154      }
3155      strcpy(line, raw_line);
3156      CHP(close_and_downcase(line));
3157      if ((line[0] == '%') && (line[1] == 0) && (_setup.percent_flag)) {
3158          FINISH();
3159          return INTERP_ENDFILE;
3160      }
3161    } else {
3162      CHKS((strlen(command) >= LINELEN), NCE_COMMAND_TOO_LONG);
3163      strcpy(raw_line, command);
3164      strcpy(line, command);
3165      CHP(close_and_downcase(line));
3166    }
3167  
3168    _setup.parameter_occurrence = 0;      /* initialize parameter buffer */
3169  
3170    if ((line[0] == 0) || ((line[0] == '/') && (GET_BLOCK_DELETE())))
3171      *length = 0;
3172    else
3173      *length = strlen(line);
3174  
3175    return INTERP_OK;
3176  }
3177  
3178  /****************************************************************************/
3179  
3180  /*! read_unary
3181  
3182  Returned Value: int
3183     If any of the following functions returns an error code,
3184     this returns that code.
3185       execute_unary
3186       read_atan
3187       read_operation_unary
3188       read_real_expression
3189     If any of the following errors occur, this returns the error code shown.
3190     Otherwise, it returns INTERP_OK.
3191     1. the name of the unary operation is not followed by a left bracket:
3192        NCE_LEFT_BRACKET_MISSING_AFTER_UNARY_OPERATION_NAME
3193  
3194  Side effects:
3195     The value read from the line is put into what double_ptr points at.
3196     The counter is reset to point to the first character after the
3197     characters which make up the value.
3198  
3199  Called by:  read_real_value
3200  
3201  This attempts to read the value of a unary operation out of the line,
3202  starting at the index given by the counter. The atan operation is
3203  handled specially because it is followed by two arguments.
3204  
3205  */
3206  
3207  int Interp::read_unary(char *line,       //!< string: line of RS274/NGC code being processed
3208                        int *counter,     //!< pointer to a counter for position on the line 
3209                        double *double_ptr,       //!< pointer to double to be read                  
3210                        double *parameters)       //!< array of system parameters                    
3211  {
3212    int operation;
3213  
3214    CHP(read_operation_unary(line, counter, &operation));
3215    CHKS((line[*counter] != '['),
3216        NCE_LEFT_BRACKET_MISSING_AFTER_UNARY_OPERATION_NAME);
3217  
3218    if (operation == EXISTS)
3219    {
3220        CHP(read_bracketed_parameter(line, counter, double_ptr, parameters, true));
3221        return INTERP_OK;
3222    }
3223  
3224    CHP(read_real_expression(line, counter, double_ptr, parameters));
3225  
3226    if (operation == ATAN)
3227      CHP(read_atan(line, counter, double_ptr, parameters));
3228    else
3229      CHP(execute_unary(double_ptr, operation));
3230    return INTERP_OK;
3231  }
3232  
3233  int Interp::read_u(char *line,   //!< string: line of RS274/NGC code being processed
3234                    int *counter, //!< pointer to a counter for position on the line 
3235                    block_pointer block,  //!< pointer to a block being filled from the line 
3236                    double *parameters)   //!< array of system parameters                    
3237  {
3238    double value;
3239  
3240    CHKS((line[*counter] != 'u'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3241    *counter = (*counter + 1);
3242    CHKS((block->u_flag), _("Multiple U words on one line"));
3243    CHP(read_real_value(line, counter, &value, parameters));
3244    block->u_flag = true;
3245    block->u_number = value;
3246    return INTERP_OK;
3247  }
3248  
3249  int Interp::read_v(char *line,   //!< string: line of RS274/NGC code being processed
3250                    int *counter, //!< pointer to a counter for position on the line 
3251                    block_pointer block,  //!< pointer to a block being filled from the line 
3252                    double *parameters)   //!< array of system parameters                    
3253  {
3254    double value;
3255  
3256    CHKS((line[*counter] != 'v'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3257    *counter = (*counter + 1);
3258    CHKS((block->v_flag), _("Multiple V words on one line"));
3259    CHP(read_real_value(line, counter, &value, parameters));
3260    block->v_flag = true;
3261    block->v_number = value;
3262    return INTERP_OK;
3263  }
3264  
3265  int Interp::read_w(char *line,   //!< string: line of RS274/NGC code being processed
3266                    int *counter, //!< pointer to a counter for position on the line 
3267                    block_pointer block,  //!< pointer to a block being filled from the line 
3268                    double *parameters)   //!< array of system parameters                    
3269  {
3270    double value;
3271  
3272    CHKS((line[*counter] != 'w'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3273    *counter = (*counter + 1);
3274    CHKS((block->w_flag), _("Multiple W words on one line"));
3275    CHP(read_real_value(line, counter, &value, parameters));
3276    block->w_flag = true;
3277    block->w_number = value;
3278    return INTERP_OK;
3279  }
3280  
3281  
3282  /****************************************************************************/
3283  
3284  /*! read_x
3285  
3286  Returned Value: int
3287     If read_real_value returns an error code, this returns that code.
3288     If any of the following errors occur, this returns the error code shown.
3289     Otherwise, it returns INTERP_OK.
3290     1. The first character read is not x:
3291        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
3292     2. A x_coordinate has already been inserted in the block:
3293        NCE_MULTIPLE_X_WORDS_ON_ONE_LINE
3294  
3295  Side effects:
3296     counter is reset.
3297     The x_flag in the block is turned on.
3298     An x_number is inserted in the block.
3299  
3300  Called by: read_one_item
3301  
3302  When this function is called, counter is pointing at an item on the
3303  line that starts with the character 'x', indicating a x_coordinate
3304  setting. The function reads characters which tell how to set the
3305  coordinate, up to the start of the next item or the end of the line.
3306  This information is inserted in the block. The counter is then set to
3307  point to the character following.
3308  
3309  The value may be a real number or something that evaluates to a
3310  real number, so read_real_value is used to read it. Parameters
3311  may be involved.
3312  
3313  */
3314  
3315  int Interp::read_x(char *line,   //!< string: line of RS274 code being processed    
3316                    int *counter, //!< pointer to a counter for position on the line 
3317                    block_pointer block,  //!< pointer to a block being filled from the line 
3318                    double *parameters)   //!< array of system parameters                    
3319  {
3320    double value;
3321  
3322    CHKS((line[*counter] != 'x'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3323    *counter = (*counter + 1);
3324    CHKS((block->x_flag), NCE_MULTIPLE_X_WORDS_ON_ONE_LINE);
3325    CHP(read_real_value(line, counter, &value, parameters));
3326    block->x_flag = true;
3327    if(_setup.lathe_diameter_mode)
3328    {
3329      block->x_number = value / 2;
3330    }else
3331    {
3332    block->x_number = value;
3333    }
3334    return INTERP_OK;
3335  }
3336  
3337  int Interp::read_atsign(char *line, int *counter, block_pointer block,
3338                          double *parameters) {
3339      CHKS((line[*counter] != '@'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3340      (*counter)++;
3341      CHP(read_real_value(line, counter, &block->radius, parameters));
3342      block->radius_flag = true;
3343      return INTERP_OK;
3344  }
3345  
3346  int Interp::read_carat(char *line, int *counter, block_pointer block,
3347                         double *parameters) {
3348      CHKS((line[*counter] != '^'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3349      (*counter)++;
3350      CHP(read_real_value(line, counter, &block->theta, parameters));
3351      block->theta_flag = true;
3352      return INTERP_OK;
3353  }
3354      
3355      
3356  
3357  /****************************************************************************/
3358  
3359  /*! read_y
3360  
3361  Returned Value: int
3362     If read_real_value returns an error code, this returns that code.
3363     If any of the following errors occur, this returns the error code shown.
3364     Otherwise, it returns INTERP_OK.
3365     1. The first character read is not y:
3366        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
3367     2. A y_coordinate has already been inserted in the block:
3368        NCE_MULTIPLE_Y_WORDS_ON_ONE_LINE
3369  
3370  Side effects:
3371     counter is reset.
3372     The y_flag in the block is turned on.
3373     A y_number is inserted in the block.
3374  
3375  Called by: read_one_item
3376  
3377  When this function is called, counter is pointing at an item on the
3378  line that starts with the character 'y', indicating a y_coordinate
3379  setting. The function reads characters which tell how to set the
3380  coordinate, up to the start of the next item or the end of the line.
3381  This information is inserted in the block. The counter is then set to
3382  point to the character following.
3383  
3384  The value may be a real number or something that evaluates to a
3385  real number, so read_real_value is used to read it. Parameters
3386  may be involved.
3387  
3388  */
3389  
3390  int Interp::read_y(char *line,   //!< string: line of RS274 code being processed    
3391                    int *counter, //!< pointer to a counter for position on the line 
3392                    block_pointer block,  //!< pointer to a block being filled from the line 
3393                    double *parameters)   //!< array of system parameters                    
3394  {
3395    double value;
3396  
3397    CHKS((line[*counter] != 'y'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3398    *counter = (*counter + 1);
3399    CHKS((block->y_flag), NCE_MULTIPLE_Y_WORDS_ON_ONE_LINE);
3400    CHP(read_real_value(line, counter, &value, parameters));
3401    block->y_flag = true;
3402    block->y_number = value;
3403    return INTERP_OK;
3404  }
3405  
3406  /****************************************************************************/
3407  
3408  /*! read_z
3409  
3410  Returned Value: int
3411     If read_real_value returns an error code, this returns that code.
3412     If any of the following errors occur, this returns the error code shown.
3413     Otherwise, it returns INTERP_OK.
3414     1. The first character read is not z:
3415        NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
3416     2. A z_coordinate has already been inserted in the block:
3417        NCE_MULTIPLE_Z_WORDS_ON_ONE_LINE
3418  
3419  Side effects:
3420     counter is reset.
3421     The z_flag in the block is turned on.
3422     A z_number is inserted in the block.
3423  
3424  Called by: read_one_item
3425  
3426  When this function is called, counter is pointing at an item on the
3427  line that starts with the character 'z', indicating a z_coordinate
3428  setting. The function reads characters which tell how to set the
3429  coordinate, up to the start of the next item or the end of the line.
3430  This information is inserted in the block. The counter is then set to
3431  point to the character following.
3432  
3433  The value may be a real number or something that evaluates to a
3434  real number, so read_real_value is used to read it. Parameters
3435  may be involved.
3436  
3437  */
3438  
3439  int Interp::read_z(char *line,   //!< string: line of RS274 code being processed    
3440                    int *counter, //!< pointer to a counter for position on the line 
3441                    block_pointer block,  //!< pointer to a block being filled from the line 
3442                    double *parameters)   //!< array of system parameters                    
3443  {
3444    double value;
3445  
3446    CHKS((line[*counter] != 'z'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
3447    *counter = (*counter + 1);
3448    CHKS((block->z_flag), NCE_MULTIPLE_Z_WORDS_ON_ONE_LINE);
3449    CHP(read_real_value(line, counter, &value, parameters));
3450    block->z_flag = true;
3451    block->z_number = value;
3452    return INTERP_OK;
3453  }
3454  
3455  bool Interp::isreadonly(int index)
3456  {
3457    int i;
3458    for (i=0; i< _n_readonly_parameters; i++) {
3459      if (_readonly_parameters[i] == index) return 1;
3460    }
3461    return 0;
3462  }