GCC Code Coverage Report
Directory: emc/rs274ngc/ Exec Total Coverage
File: emc/rs274ngc/interp_internal.cc Lines: 123 155 79.4 %
Date: 2016-10-27 Branches: 101 180 56.1 %

Line Exec Source
1
/********************************************************************
2
* Description: interp_internal.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
#include <unistd.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <math.h>
18
#include <string.h>
19
#include <ctype.h>
20
#include <sys/types.h>
21
#include <sys/stat.h>
22
#include "rs274ngc.hh"
23
#include "rs274ngc_return.hh"
24
#include "interp_internal.hh"	// interpreter private definitions
25
#include "rs274ngc_interp.hh"
26
27
/****************************************************************************/
28
29
/*! close_and_downcase
30
31
Returned Value: int
32
   If any of the following errors occur, this returns the error code shown.
33
   Otherwise, it returns INTERP_OK.
34
   1. A left parenthesis is found inside a comment:
35
      NCE_NESTED_COMMENT_FOUND
36
   2. The line ends before an open comment is closed:
37
      NCE_UNCLOSED_COMMENT_FOUND
38
   3. A newline character is found that is not followed by null:
39
      NCE_NULL_MISSING_AFTER_NEWLINE
40
41
Side effects: See below
42
43
Called by:  read_text
44
45
To simplify handling upper case letters, spaces, and tabs, this
46
function removes spaces and and tabs and downcases everything on a
47
line which is not part of a comment.
48
49
Comments are left unchanged in place. Comments are anything
50
enclosed in parentheses. Nested comments, indicated by a left
51
parenthesis inside a comment, are illegal.
52
53
The line must have a null character at the end when it comes in.
54
The line may have one newline character just before the end. If
55
there is a newline, it will be removed.
56
57
Although this software system detects and rejects all illegal characters
58
and illegal syntax, this particular function does not detect problems
59
with anything but comments.
60
61
We are treating RS274 code here as case-insensitive and spaces and
62
tabs as if they have no meaning. [RS274D, page 6] says spaces and tabs
63
are to be ignored by control.
64
65
The KT and NGC manuals say nothing about case or spaces and tabs.
66
67
*/
68
69
11161
int Interp::close_and_downcase(char *line)       //!< string: one line of NC code
70
{
71
    int m;
72
    int n;
73
    int comment, semicomment;
74
    char item;
75
11161
    comment = semicomment = 0;
76
333788
    for (n = 0, m = 0; (item = line[m]) != '\0'; m++) {
77
322627
	if ((item == ';') && !comment)
78
177
	    semicomment = 1;
79
80
322627
	if (semicomment) {
81
5337
	    line[n++] = item; // pass literally
82
5337
	     continue;
83
	}
84
317290
	if (comment) {
85
36313
	    line[n++] = item;
86
36313
	    if (item == ')') {
87
		comment = 0;
88
34946
	    } else if (item == '(')
89
		ERS(NCE_NESTED_COMMENT_FOUND);
90
280977
	} else if ((item == ' ') || (item == '\t') || (item == '\r'));
91
	/* don't copy blank or tab or CR */
92
232335
	else if (item == '\n') {    /* don't copy newline            *//* but check null follows        */
93
	    CHKS((line[m + 1] != 0), NCE_NULL_MISSING_AFTER_NEWLINE);
94
232335
	} else if ((64 < item) && (item < 91)) {    /* downcase upper case letters */
95
22232
	    line[n++] = (32 + item);
96
210103
	} else if ((item == '(') && !semicomment) {   /* (comment is starting */
97
1367
	    comment = 1;
98
1367
	    line[n++] = item;
99
	} else {
100
208736
	    line[n++] = item;         /* copy anything else */
101
	}
102
    }
103
11161
    CHKS((comment), NCE_UNCLOSED_COMMENT_FOUND);
104
11161
    line[n] = 0;
105
11161
    return INTERP_OK;
106
}
107
108
109
/****************************************************************************/
110
111
/*! enhance_block
112
113
Returned Value:
114
   If any of the following errors occur, this returns the error shown.
115
   Otherwise, it returns INTERP_OK.
116
   1. A g80 is in the block, no modal group 0 code that uses axes
117
      is in the block, and one or more axis values is given:
118
      NCE_CANNOT_USE_AXIS_VALUES_WITH_G80
119
   2. A g52 g92 is in the block and no axis value is given:
120
      NCE_ALL_AXES_MISSING_WITH_G52_OR_G92
121
   3. One g-code from group 1 and one from group 0, both of which can use
122
      axis values, are in the block:
123
      NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES
124
   4. A g-code (other than 0 or 1, for which we are allowing all axes
125
      missing) from group 1 which can use axis values is in the block,
126
      but no axis value is given: NCE_ALL_AXES_MISSING_WITH_MOTION_CODE
127
   5. Axis values are given, but there is neither a g-code in the block
128
      nor an active previously given modal g-code that uses axis values:
129
      NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM
130
131
Side effects:
132
   The value of motion_to_be in the block is set.
133
134
Called by: parse_line
135
136
If there is a g-code for motion in the block (in g_modes[1]),
137
set motion_to_be to that. Otherwise, if there is an axis value in the
138
block and no g-code to use it (any such would be from group 0 in
139
g_modes[0]), set motion_to_be to be the last motion saved (in
140
settings->motion mode).
141
142
This also make the checks described above.
143
144
*/
145
146
6554
int Interp::enhance_block(block_pointer block,   //!< pointer to a block to be checked
147
                         setup_pointer settings)        //!< pointer to machine settings
148
{
149
  int axis_flag;
150
  int ijk_flag;
151
  int polar_flag;
152
  int mode_zero_covets_axes;
153
  int mode0;
154
  int mode1;
155
156
6554
  if(block->radius_flag || block->theta_flag) {
157
      // someday, tediously add polar support for other planes here:
158
      CHKS((!_readers[(int)'x'] || !_readers[(int)'y']), _("Cannot use polar coordinate on a machine lacking X or Y axes"));
159
      CHKS(((settings->plane != CANON_PLANE_XY)), _("Cannot use polar coordinate except in G17 plane"));
160
      CHKS(((block->x_flag)), _("Cannot specify both polar coordinate and X word"));
161
      CHKS(((block->y_flag)), _("Cannot specify both polar coordinate and Y word"));
162
  }
163
164
5302
  axis_flag = ((block->x_flag) || (block->y_flag) ||
165
5038
               (block->z_flag) || (block->a_flag) ||
166
5037
               (block->b_flag) || (block->c_flag) ||
167
11591
               (block->u_flag) || (block->v_flag) ||
168
6554
               (block->w_flag));
169
6554
  polar_flag = (block->radius_flag) || (block->theta_flag);
170
6554
  ijk_flag = ((block->i_flag) || (block->j_flag) ||
171
6554
              (block->k_flag));
172
6554
  mode0 = block->g_modes[0];
173
6554
  mode1 = block->g_modes[1];
174
  mode_zero_covets_axes =
175
13050
    ((mode0 == G_10) || (mode0 == G_28) || (mode0 == G_30)
176
13050
     || (mode0 == G_52) || (mode0 == G_92));
177
178
6554
  if (mode1 != -1) {
179
1437
    if (mode1 == G_80) {
180
1
      CHKS(((polar_flag || axis_flag) && (!mode_zero_covets_axes)),
181
          NCE_CANNOT_USE_AXIS_VALUES_WITH_G80);
182
1
      CHKS((polar_flag && mode0 == G_92), _("Polar coordinates can only be used for motion"));
183
1
      CHKS(((!axis_flag) && (mode0 == G_52 || mode0 == G_92)),
184
	   NCE_ALL_AXES_MISSING_WITH_G52_OR_G92);
185
    } else {
186
1436
      CHKS(mode_zero_covets_axes,
187
          NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES);
188
1436
      CHKS(((!axis_flag && !polar_flag) &&
189
            mode1 != G_0 && mode1 != G_1 &&
190
            mode1 != G_2 && mode1 != G_3 && mode1 != G_5_2 &&
191
	    ! IS_USER_GCODE(mode1)),
192
          NCE_ALL_AXES_MISSING_WITH_MOTION_CODE);
193
    }
194
1436
    block->motion_to_be = mode1;
195
5117
  } else if (mode_zero_covets_axes) {   /* other 3 can get by without axes but not G92 */
196
63
    CHKS((polar_flag && mode0 == G_92), _("Polar coordinates can only be used for motion"));
197
63
    CHKS(((!axis_flag) &&
198
	  (block->g_modes[0] == G_52 || block->g_modes[0] == G_92)),
199
	 NCE_ALL_AXES_MISSING_WITH_G52_OR_G92);
200
5054
  } else if (axis_flag || polar_flag) {
201
25
    CHKS(((settings->motion_mode == -1)
202
         || (settings->motion_mode == G_80)) && (block->g_modes[8] != G_43_1),
203
        NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM);
204
25
    if (block->g_modes[8] != G_43_1) {
205
25
       block->motion_to_be = settings->motion_mode;
206
    }
207
5029
  } else if (!axis_flag && !polar_flag && ijk_flag && (settings->motion_mode == G_2 || settings->motion_mode == G_3)) {
208
    // this is a block like simply "i1" which should be accepted if we're in arc mode
209
      block->motion_to_be = settings->motion_mode;
210
  }
211
6553
  CHKS((polar_flag && block->motion_to_be == -1), _("Polar coordinates can only be used for motion"));
212
  return INTERP_OK;
213
}
214
215
216
/****************************************************************************/
217
218
/*! init_block
219
220
Returned Value: int (INTERP_OK)
221
222
Side effects:
223
   Values in the block are reset as described below.
224
225
Called by: parse_line
226
227
This system reuses the same block over and over, rather than building
228
a new one for each line of NC code. The block is re-initialized before
229
each new line of NC code is read.
230
231
The block contains many slots for values which may or may not be present
232
on a line of NC code. For some of these slots, there is a flag which
233
is turned on (at the time time value of the slot is read) if the item
234
is present.  For slots whose values are to be read which do not have a
235
flag, there is always some excluded range of values. Setting the
236
initial value of these slot to some number in the excluded range
237
serves to show that a value for that slot has not been read.
238
239
The rules for the indicators for slots whose values may be read are:
240
1. If the value may be an arbitrary real number (which is always stored
241
   internally as a double), a flag is needed to indicate if a value has
242
   been read. All such flags are initialized to false.
243
   Note that the value itself is not initialized; there is no point in it.
244
2. If the value must be a non-negative real number (which is always stored
245
   internally as a double), a value of -1.0 indicates the item is not present.
246
3. If the value must be an unsigned integer (which is always stored
247
   internally as an int), a value of -1 indicates the item is not present.
248
   (RS274/NGC does not use any negative integers.)
249
4. If the value is a character string (only the comment slot is one), the
250
   first character is set to 0 (NULL).
251
252
*/
253
254
9455
int Interp::init_block(block_pointer block)      //!< pointer to a block to be initialized or reset
255
{
256
  int n;
257
9455
  block->breadcrumbs = 0; // clear execution trail
258
9455
  block->executing_remap = NULL;
259
9455
  block->param_cnt = 0;
260
9455
  block->remappings.clear();
261
9455
  block->builtin_used = false;
262
263
9455
  block->a_flag = false;
264
9455
  block->b_flag = false;
265
9455
  block->c_flag = false;
266
9455
  block->comment[0] = 0;
267
9455
  block->d_flag = false;
268
9455
  block->e_flag = false;
269
9455
  block->f_flag = false;
270
160735
  for (n = 0; n < 16; n++) {
271
151280
    block->g_modes[n] = -1;
272
  }
273
9455
  block->h_flag = false;
274
9455
  block->h_number = -1;
275
9455
  block->i_flag = false;
276
9455
  block->j_flag = false;
277
9455
  block->k_flag = false;
278
9455
  block->l_number = -1;
279
9455
  block->l_flag = false;
280
9455
  block->line_number = -1;
281
9455
  block->n_number = -1;
282
9455
  block->motion_to_be = -1;
283
9455
  block->m_count = 0;
284
113460
  for (n = 0; n < 11; n++) {
285
104005
    block->m_modes[n] = -1;
286
  }
287
9455
  block->user_m = 0;
288
9455
  block->p_number = -1.0;
289
9455
  block->p_flag = false;
290
9455
  block->q_flag = false;
291
9455
  block->q_number = -1.0;
292
9455
  block->r_flag = false;
293
9455
  block->s_flag = false;
294
9455
  block->t_flag = false;
295
9455
  block->u_flag = false;
296
9455
  block->v_flag = false;
297
9455
  block->w_flag = false;
298
9455
  block->x_flag = false;
299
9455
  block->y_flag = false;
300
9455
  block->z_flag = false;
301
302
9455
  block->theta_flag = false;
303
9455
  block->radius_flag = false;
304
305
9455
  block->o_type = O_none;
306
9455
  block->o_name = 0;
307
9455
  block->call_type = -1;
308
309
9455
  return INTERP_OK;
310
}
311
312
313
/****************************************************************************/
314
315
/*! parse_line
316
317
Returned Value: int
318
   If any of the following functions returns an error code,
319
   this returns that code.
320
     init_block
321
     read_items
322
     enhance_block
323
     check_items
324
   Otherwise, it returns INTERP_OK.
325
326
Side effects:
327
   One RS274 line is read into a block and the block is checked for
328
   errors. System parameters may be reset.
329
330
Called by:  Interp::read
331
332
*/
333
334
9455
int Interp::parse_line(char *line,       //!< array holding a line of RS274 code
335
                      block_pointer block,      //!< pointer to a block to be filled
336
                      setup_pointer settings)   //!< pointer to machine settings
337
{
338
9455
  CHP(init_block(block));
339
9455
  CHP(read_items(block, line, settings->parameters));
340
341
9445
  if(settings->skipping_o == 0)
342
  {
343
6554
    CHP(enhance_block(block, settings));
344
6553
    CHP(check_items(block, settings));
345
6551
    int n = find_remappings(block,settings);
346
6551
    if (n) logRemap("parse_line: found %d remappings",n);
347
  }
348
  return INTERP_OK;
349
}
350
351
/****************************************************************************/
352
353
/*! precedence
354
355
Returned Value: int
356
  This returns an integer representing the precedence level of an_operator
357
358
Side Effects: None
359
360
Called by: read_real_expression
361
362
To add additional levels of operator precedence, edit this function.
363
364
*/
365
366
14036
int Interp::precedence(int an_operator)
367
{
368
  switch(an_operator)
369
    {
370
      case RIGHT_BRACKET:
371
	return 1;
372
373
      case AND2:
374
      case EXCLUSIVE_OR:
375
      case NON_EXCLUSIVE_OR:
376
	return 2;
377
378
      case LT:
379
      case EQ:
380
      case NE:
381
      case LE:
382
      case GE:
383
      case GT:
384
	return 3;
385
386
      case MINUS:
387
      case PLUS:
388
	return 4;
389
390
      case NO_OPERATION:
391
      case DIVIDED_BY:
392
      case MODULO:
393
      case TIMES:
394
	return 5;
395
396
      case POWER:
397
	return 6;
398
    }
399
  // should never happen
400
  return 0;
401
}
402
403
404
9
int Interp::refresh_actual_position(setup_pointer settings)
405
{
406
9
  settings->current_x = GET_EXTERNAL_POSITION_X();
407
9
  settings->current_y = GET_EXTERNAL_POSITION_Y();
408
9
  settings->current_z = GET_EXTERNAL_POSITION_Z();
409
9
  settings->AA_current = GET_EXTERNAL_POSITION_A();
410
9
  settings->BB_current = GET_EXTERNAL_POSITION_B();
411
9
  settings->CC_current = GET_EXTERNAL_POSITION_C();
412
9
  settings->u_current = GET_EXTERNAL_POSITION_U();
413
9
  settings->v_current = GET_EXTERNAL_POSITION_V();
414
9
  settings->w_current = GET_EXTERNAL_POSITION_W();
415
416
9
  return INTERP_OK;
417
}
418
419
420
421
/****************************************************************************/
422
423
/*! set_probe_data
424
425
Returned Value: int (INTERP_OK)
426
427
Side effects:
428
  The current position is set.
429
  System parameters for probe position are set.
430
431
Called by:  Interp::read
432
433
*/
434
435
int Interp::set_probe_data(setup_pointer settings)       //!< pointer to machine settings
436
{
437
  double a, b, c;
438
  refresh_actual_position(settings);
439
  settings->parameters[5061] = GET_EXTERNAL_PROBE_POSITION_X();
440
  settings->parameters[5062] = GET_EXTERNAL_PROBE_POSITION_Y();
441
  settings->parameters[5063] = GET_EXTERNAL_PROBE_POSITION_Z();
442
443
  a = GET_EXTERNAL_PROBE_POSITION_A();
444
  if(settings->a_axis_wrapped) {
445
      a = fmod(a, 360.0);
446
      if(a<0) a += 360.0;
447
  }
448
  settings->parameters[5064] = a;
449
450
  b = GET_EXTERNAL_PROBE_POSITION_B();
451
  if(settings->b_axis_wrapped) {
452
      b = fmod(b, 360.0);
453
      if(b<0) b += 360.0;
454
  }
455
  settings->parameters[5065] = b;
456
457
  c = GET_EXTERNAL_PROBE_POSITION_C();
458
  if(settings->c_axis_wrapped) {
459
      c = fmod(c, 360.0);
460
      if(c<0) c += 360.0;
461
  }
462
  settings->parameters[5066] = c;
463
464
  settings->parameters[5067] = GET_EXTERNAL_PROBE_POSITION_U();
465
  settings->parameters[5068] = GET_EXTERNAL_PROBE_POSITION_V();
466
  settings->parameters[5069] = GET_EXTERNAL_PROBE_POSITION_W();
467
  settings->parameters[5070] = (double) GET_EXTERNAL_PROBE_TRIPPED_VALUE();
468
469
  // was an undocumented feature?: settings->parameters[5067] = GET_EXTERNAL_PROBE_VALUE();
470
  return INTERP_OK;
471
}
472
473
44
int Interp::call_level(void) { return _setup.call_level; }