/ src / emc / canterp / canterp.cc
canterp.cc
  1  /********************************************************************
  2  * Description:  canterp.cc
  3  *               This file, 'canterp.cc', implements an interpreter 
  4  *               of a file of printed canonical interfaces
  5  *
  6  * Author: proctor
  7  * License: GPL Version 2
  8  *    
  9  * Copyright (c) 2005 All rights reserved.
 10  *
 11  * Last change: 
 12  ********************************************************************/
 13  /*
 14    canterp.cc
 15  
 16    Straight-through interpreter of a file of printed canonical interface
 17    commands like these:
 18  
 19    1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
 20    2 N..... SET_ORIGIN_OFFSETS(0.0000, 0.0000, 0.0000)
 21    3 N..... SET_FEED_REFERENCE(CANON_XYZ)
 22    4 N..... COMMENT("Circle Diamond Square Program")
 23    5 N..... COMMENT("Tom Kramer")
 24    6 N..... COMMENT("26-Sep-1994")
 25    7 N..... COMMENT("Assumes 4"x4"x2" finished stock")
 26    8 N..... COMMENT("Top of stock at Z=2"")
 27    9 N..... COMMENT("Cutter does not descend more than 0.94" below top")
 28    10 N0080  MIST_OFF()
 29    11 N0080  FLOOD_OFF()
 30    12 N0090  USE_TOOL_LENGTH_OFFSET(1.0000)
 31    13 N0110  STRAIGHT_TRAVERSE(0.0000, 0.0000, 3.0000)
 32    14 N0140  SET_FEED_RATE(16.0000)
 33    15 N0140  SET_SPINDLE_SPEED(0, 3500.0000)
 34    16 N0140  START_SPINDLE_CLOCKWISE(0)
 35    17 N0150  COMMENT("MILLING AN ENCLOSED POCKET")
 36    18 N0160  STRAIGHT_TRAVERSE(0.0000, 3.9150, 3.0000)
 37    19 N0170  STRAIGHT_TRAVERSE(0.0000, 3.9150, 2.1000)
 38    20 N0180  COMMENT("start left circle zigzag")
 39    21 N0180  STRAIGHT_FEED(0.0000, 3.9150, 1.6875)
 40    22 N0190  STRAIGHT_FEED(4.0000, 3.9150, 1.6875)
 41    23 N0200  STRAIGHT_FEED(4.0000, 3.7250, 1.6875)
 42    24 N0210  STRAIGHT_FEED(0.0000, 3.7250, 1.6875)
 43    25 N0220  STRAIGHT_FEED(0.0000, 3.5350, 1.6875)
 44    26 N0230  STRAIGHT_FEED(1.4370, 3.5350, 1.6875)
 45    27 N0240  ARC_FEED(1.0704, 3.3450, 2.0000, 2.0000, 1, 1.6875)
 46  
 47    which typically come out of one of Tom Kramer's interpreters.
 48    The first two columns are ignored, the rest is converted to
 49    equivalent canonical calls.
 50  */
 51  
 52  #include <stdio.h>		// FILE, fopen(), fclose()
 53  #include <string.h>		// strcpy()
 54  #include <ctype.h>		// isspace()
 55  #include <limits.h>
 56  #include <algorithm>
 57  #include "config.h"
 58  #include "emc/nml_intf/interp_return.hh"
 59  #include "emc/nml_intf/canon.hh"
 60  #include "emc/rs274ngc/interp_base.hh"
 61  
 62  static char the_command[LINELEN] = { 0 };	// our current command
 63  static char the_command_name[LINELEN] = { 0 };	// just the name part
 64  static char the_command_args[LINELEN] = { 0 };	// just the args part
 65  
 66  class Canterp : public InterpBase {
 67  public:
 68      Canterp () : f(0) {}
 69      char *error_text(int errcode, char *buf, size_t buflen);
 70      char *stack_name(int index, char *buf, size_t buflen);
 71      char *line_text(char *buf, size_t buflen);
 72      char *file_name(char *buf, size_t buflen);
 73      size_t line_length();
 74      int sequence_number();
 75      int ini_load(const char *inifile);
 76      int init();
 77      int execute();
 78      int execute(const char *line);
 79      int execute(const char *line, int line_number);
 80      int synch();
 81      int exit();
 82      int open(const char *filename);
 83      int read();
 84      int read(const char *line);
 85      int close();
 86      int reset();
 87      int line();
 88      int call_level();
 89      char *command(char *buf, size_t buflen);
 90      char *file(char *buf, size_t buflen);
 91      int on_abort(int reason, const char *message);
 92      void active_g_codes(int active_gcodes[ACTIVE_G_CODES]);
 93      void active_m_codes(int active_mcodes[ACTIVE_M_CODES]);
 94      void active_settings(double active_settings[ACTIVE_SETTINGS]);
 95      void set_loglevel(int level);
 96      void set_loop_on_main_m99(bool state);
 97      FILE *f;
 98      char filename[PATH_MAX];
 99  };
100  
101  char *Canterp::error_text(int errcode, char *buf, size_t buflen) {
102      if(errcode < INTERP_MIN_ERROR) snprintf(buf, buflen, "OK %d", errcode);
103      else snprintf(buf, buflen, "ERROR %d", errcode);
104      return buf;
105  }
106  
107  char *Canterp::stack_name(int index, char *buf, size_t buflen) {
108      snprintf(buf, buflen, "<stack %d>", index);
109      return buf;
110  }
111  
112  int Canterp::ini_load(const char *inifile) {
113      return 0;
114  }
115  
116  /*
117    We expect lines like this:
118  
119    {ws}1<white>N1<ws>cmd{ws}({ws}{arg1{ws}}){extra}
120  
121   */
122  
123  static char *skipwhite(char *ptr)
124  {
125      while (isspace(*ptr))
126  	ptr++;
127      return ptr;
128  }
129  
130  static char *findwhite(char *ptr)
131  {
132      while (!isspace(*ptr) && 0 != *ptr)
133  	ptr++;
134      return ptr;
135  }
136  
137  static int canterp_parse(char *buffer)
138  {
139      char *ptr = buffer;
140      char *cmd_ptr = the_command;
141      char *name_ptr = the_command_name;
142      char *args_ptr = the_command_args;
143      char *last_quote_ptr;
144      int inquote;
145  
146      *cmd_ptr = 0;
147      *name_ptr = 0;
148      *args_ptr = 0;
149  
150      // skip leading white space, return if nothing else found
151      if (0 == *(ptr = skipwhite(ptr)))
152  	return 0;
153  
154      // ---cut here if no leading line number, N-number columns---
155  
156      // skip the first column, return if nothing else found
157      if (0 == *(ptr = findwhite(ptr)))
158  	return 0;
159  
160      // skip following white space, return if nothing else found
161      if (0 == *(ptr = skipwhite(ptr)))
162  	return 0;
163  
164      // skip the second column, return if nothing else found
165      if (0 == *(ptr = findwhite(ptr)))
166  	return 0;
167  
168      // skip following white space, return if nothing else found
169      if (0 == *(ptr = skipwhite(ptr)))
170  	return 0;
171  
172      // ---cut to here---
173  
174      // we got something; store the name, up to space or the '('
175      while (!isspace(*ptr) && '(' != *ptr && 0 != *ptr) {
176  	*name_ptr++ = *ptr;
177  	*cmd_ptr++ = *ptr++;
178      }
179      if (isspace(*ptr))
180  	ptr = skipwhite(ptr);
181  
182      if (0 == *ptr) {
183  	// no parens, just a command name
184  	*name_ptr = 0;
185  	*cmd_ptr = 0;
186  	return 0;
187      }
188  
189      if ('(' != *ptr) {
190  	// we're missing the '(', so flag an error
191  	*name_ptr = 0;
192  	*cmd_ptr = 0;
193  	return INTERP_ERROR;
194      }
195      // we got the '(', so keep going
196      *name_ptr = 0;		// terminate the name
197      *cmd_ptr++ = *ptr++;	// add the '(' to the full command
198  
199      /*
200         now we're at the args; skip first and last quotes when building
201         args_ptr, and make commas spaces for easy parsing later
202       */
203      last_quote_ptr = 0;
204      inquote = 0;
205      while (')' != *ptr && 0 != *ptr) {
206  	if ('"' == *ptr) {
207  	    if (!inquote) {
208  		// here's the first quote, so suppress it in args_ptr
209  		inquote = 1;
210  		*cmd_ptr++ = *ptr++;
211  		continue;
212  	    }
213  	    /*
214  	       else it's a quote-in-quote, so mark it as the last so we
215  	       can delete it, thus handling any internal quotes, perhaps
216  	       used for inch marks
217  	     */
218  	    last_quote_ptr = args_ptr;
219  	}
220  	*args_ptr++ = (*ptr == ',' ? ' ' : *ptr);
221  	*cmd_ptr++ = *ptr++;
222      }
223      if (0 == *ptr) {
224  	// finished args without ')', so error
225  	*args_ptr = 0;
226  	*cmd_ptr = 0;
227  	return INTERP_ERROR;
228      }
229      if (0 != last_quote_ptr)
230  	*last_quote_ptr = 0;
231      *args_ptr = 0;
232      *cmd_ptr++ = ')';
233      *cmd_ptr = 0;
234  
235      return 0;
236  }
237  
238  int Canterp::read(const char *line) {
239      return canterp_parse((char *) line);
240  }
241  
242  int Canterp::read() {
243      char buf[LINELEN];
244      if(!f) return INTERP_ERROR;
245      if(!fgets(buf, sizeof(buf), f)) return INTERP_ENDFILE;
246      return canterp_parse(buf);
247  }
248  
249  int Canterp::execute(const char *line) {
250      int retval;
251      double d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11;
252      int i1, i2, ln=-1;
253      char s1[256];
254  
255      if (line) {
256  	retval = canterp_parse((char *) line);
257  	if (retval)
258  	    return retval;
259      }
260  
261      // a blank line
262      if (strlen(the_command_name) == 0) return INTERP_OK;
263  
264      if (!strcmp(the_command_name, "STRAIGHT_FEED")) {
265  	if (9 != sscanf(the_command_args, "%lf %lf %lf %lf %lf %lf %lf %lf %lf",
266  			&d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9)) {
267  	    return INTERP_ERROR;
268  	}
269  	STRAIGHT_FEED(ln, d1, d2, d3, d4, d5, d6, d7, d8, d9);
270  	return 0;
271      }
272  
273      if (!strcmp(the_command_name, "ARC_FEED")) {
274  	if (12 != sscanf(the_command_args,
275  			"%lf %lf %lf %lf %d %lf %lf %lf %lf %lf %lf %lf",
276  			&d1, &d2, &d3, &d4, &i1, &d5, &d6, &d7, &d8, &d9, &d10, &d11)) {
277  	    return INTERP_ERROR;
278  	}
279  	ARC_FEED(ln, d1, d2, d3, d4, i1, d5, d6, d7, d8, d9, d10, d11);
280  	return 0;
281      }
282  
283      if (!strcmp(the_command_name, "STRAIGHT_TRAVERSE")) {
284  	if (9 != sscanf(the_command_args, "%lf %lf %lf %lf %lf %lf %lf %lf %lf",
285  			&d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9)) {
286  	    return INTERP_ERROR;
287  	}
288  	STRAIGHT_TRAVERSE(ln, d1, d2, d3, d4, d5, d6, d7, d8, d9);
289  	return 0;
290      }
291  
292      if (!strcmp(the_command_name, "STRAIGHT_PROBE")) {
293  	if (6 != sscanf(the_command_args, "%lf %lf %lf %lf %lf %lf %lf %lf %lf",
294  			&d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9)) {
295  	    return INTERP_ERROR;
296  	}
297  	STRAIGHT_PROBE(ln, d1, d2, d3, d4, d5, d6, d7, d8, d9, 0);
298  	return 0;
299      }
300  
301      if (!strcmp(the_command_name, "USE_LENGTH_UNITS")) {
302  	if (!strcmp(the_command_args, "CANON_UNITS_MM")) {
303  	    USE_LENGTH_UNITS(CANON_UNITS_MM);
304  	    return 0;
305  	}
306  	if (!strcmp(the_command_args, "CANON_UNITS_CM")) {
307  	    USE_LENGTH_UNITS(CANON_UNITS_MM);
308  	    return 0;
309  	}
310  	if (!strcmp(the_command_args, "CANON_UNITS_INCHES")) {
311  	    USE_LENGTH_UNITS(CANON_UNITS_INCHES);
312  	    return 0;
313  	}
314  	return INTERP_ERROR;
315      }
316  
317  #if 0
318      if (!strcmp(the_command_name, "SET_ORIGIN_OFFSETS")) {
319  	if (6 != sscanf(the_command_args, "%lf %lf %lf %lf %lf %lf %lf %lf %lf",
320  			&d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9)) {
321  	    return INTERP_ERROR;
322  	}
323  	SET_ORIGIN_OFFSETS(d1, d2, d3, d4, d5, d6, d7, d8, d9);
324  	return 0;
325      }
326  #endif
327  
328      if (!strcmp(the_command_name, "SET_FEED_REFERENCE")) {
329  	if (!strcmp(the_command_args, "CANON_WORKPIECE")) {
330  	    SET_FEED_REFERENCE(CANON_WORKPIECE);
331  	    return 0;
332  	}
333  	if (!strcmp(the_command_args, "CANON_XYZ")) {
334  	    SET_FEED_REFERENCE(CANON_XYZ);
335  	    return 0;
336  	}
337  	return INTERP_ERROR;
338      }
339  
340      if (!strcmp(the_command_name, "SELECT_PLANE")) {
341  	if (!strcmp(the_command_args, "CANON_PLANE_XY")) {
342  	    SELECT_PLANE(CANON_PLANE_XY);
343  	    return 0;
344  	}
345  	if (!strcmp(the_command_args, "CANON_PLANE_YZ")) {
346  	    SELECT_PLANE(CANON_PLANE_YZ);
347  	    return 0;
348  	}
349  	if (!strcmp(the_command_args, "CANON_PLANE_XZ")) {
350  	    SELECT_PLANE(CANON_PLANE_XZ);
351  	    return 0;
352  	}
353  	return INTERP_ERROR;
354      }
355  
356      if (!strcmp(the_command_name, "COMMENT")) {
357  	COMMENT(the_command_args);
358  	return 0;
359      }
360  
361      if (!strcmp(the_command_name, "MIST_OFF")) {
362  	MIST_OFF();
363  	return 0;
364      }
365  
366      if (!strcmp(the_command_name, "FLOOD_OFF")) {
367  	FLOOD_OFF();
368  	return 0;
369      }
370  
371      if (!strcmp(the_command_name, "MIST_ON")) {
372  	MIST_ON();
373  	return 0;
374      }
375  
376      if (!strcmp(the_command_name, "FLOOD_ON")) {
377  	FLOOD_ON();
378  	return 0;
379      }
380  
381  #if 0
382      if (!strcmp(the_command_name, "USE_TOOL_LENGTH_OFFSET")) {
383  	if (1 != sscanf(the_command_args, "%lf %lf %lf", &d1, &d2, &d3)) {
384  	    return INTERP_ERROR;
385  	}
386  	USE_TOOL_LENGTH_OFFSET(d1, d2, d3);
387  	return 0;
388      }
389  #endif
390  
391      if (!strcmp(the_command_name, "SET_FEED_RATE")) {
392  	if (1 != sscanf(the_command_args, "%lf", &d1)) {
393  	    return INTERP_ERROR;
394  	}
395  	SET_FEED_RATE(d1);
396  	return 0;
397      }
398  
399  #if 0
400      if (!strcmp(the_command_name, "SET_TRAVERSE_RATE")) {
401  	if (1 != sscanf(the_command_args, "%lf", &d1)) {
402  	    return INTERP_ERROR;
403  	}
404  	SET_TRAVERSE_RATE(d1);
405  	return 0;
406      }
407  #endif
408  
409      if (!strcmp(the_command_name, "SELECT_POCKET")) {
410  	if (1 != sscanf(the_command_args, "%d", &i1)) {
411  	    return INTERP_ERROR;
412  	}
413  	SELECT_POCKET(i1, i1);
414  	return 0;
415      }
416  
417      if (!strcmp(the_command_name, "CHANGE_TOOL")) {
418  	if (1 != sscanf(the_command_args, "%d", &i1)) {
419  	    return INTERP_ERROR;
420  	}
421  	CHANGE_TOOL(i1);
422  	return 0;
423      }
424  
425      if (!strcmp(the_command_name, "DWELL")) {
426  	if (1 != sscanf(the_command_args, "%lf", &d1)) {
427  	    return INTERP_ERROR;
428  	}
429  	DWELL(d1);
430  	return 0;
431      }
432  
433  #if 0
434      if (!strcmp(the_command_name, "SPINDLE_RETRACT")) {
435  	SPINDLE_RETRACT();
436  	return 0;
437      }
438  
439      if (!strcmp(the_command_name, "SPINDLE_RETRACT_TRAVERSE")) {
440  	SPINDLE_RETRACT_TRAVERSE();
441  	return 0;
442      }
443  
444      if (!strcmp(the_command_name, "LOCK_SPINDLE_Z")) {
445  	LOCK_SPINDLE_Z();
446  	return 0;
447      }
448  
449      if (!strcmp(the_command_name, "USE_SPINDLE_FORCE")) {
450  	USE_SPINDLE_FORCE();
451  	return 0;
452      }
453  
454      if (!strcmp(the_command_name, "USE_NO_SPINDLE_FORCE")) {
455  	USE_NO_SPINDLE_FORCE();
456  	return 0;
457      }
458  
459      if (!strcmp(the_command_name, "CLAMP_AXIS")) {
460  	if (!strcmp(the_command_args, "CANON_AXIS_X")) {
461  	    CLAMP_AXIS(CANON_AXIS_X);
462  	    return 0;
463  	}
464  	if (!strcmp(the_command_args, "CANON_AXIS_Y")) {
465  	    CLAMP_AXIS(CANON_AXIS_Y);
466  	    return 0;
467  	}
468  	if (!strcmp(the_command_args, "CANON_AXIS_Z")) {
469  	    CLAMP_AXIS(CANON_AXIS_Z);
470  	    return 0;
471  	}
472  	if (!strcmp(the_command_args, "CANON_AXIS_A")) {
473  	    CLAMP_AXIS(CANON_AXIS_A);
474  	    return 0;
475  	}
476  	if (!strcmp(the_command_args, "CANON_AXIS_B")) {
477  	    CLAMP_AXIS(CANON_AXIS_B);
478  	    return 0;
479  	}
480  	if (!strcmp(the_command_args, "CANON_AXIS_C")) {
481  	    CLAMP_AXIS(CANON_AXIS_C);
482  	    return 0;
483  	}
484  	return INTERP_ERROR;
485      }
486  
487      if (!strcmp(the_command_name, "UNCLAMP_AXIS")) {
488  	if (!strcmp(the_command_args, "CANON_AXIS_X")) {
489  	    UNCLAMP_AXIS(CANON_AXIS_X);
490  	    return 0;
491  	}
492  	if (!strcmp(the_command_args, "CANON_AXIS_Y")) {
493  	    UNCLAMP_AXIS(CANON_AXIS_Y);
494  	    return 0;
495  	}
496  	if (!strcmp(the_command_args, "CANON_AXIS_Z")) {
497  	    UNCLAMP_AXIS(CANON_AXIS_Z);
498  	    return 0;
499  	}
500  	if (!strcmp(the_command_args, "CANON_AXIS_A")) {
501  	    UNCLAMP_AXIS(CANON_AXIS_A);
502  	    return 0;
503  	}
504  	if (!strcmp(the_command_args, "CANON_AXIS_B")) {
505  	    UNCLAMP_AXIS(CANON_AXIS_B);
506  	    return 0;
507  	}
508  	if (!strcmp(the_command_args, "CANON_AXIS_C")) {
509  	    UNCLAMP_AXIS(CANON_AXIS_C);
510  	    return 0;
511  	}
512  	return INTERP_ERROR;
513      }
514  
515      if (!strcmp(the_command_name, "SET_CUTTER_RADIUS_COMPENSATION")) {
516  	if (1 != sscanf(the_command_args, "%lf", &d1)) {
517  	    return INTERP_ERROR;
518  	}
519  	SET_CUTTER_RADIUS_COMPENSATION(d1);
520  	return 0;
521      }
522  
523      if (!strcmp(the_command_name, "START_CUTTER_RADIUS_COMPENSATION")) {
524  	if (1 != sscanf(the_command_args, "%d", &i1)) {
525  	    return INTERP_ERROR;
526  	}
527  	START_CUTTER_RADIUS_COMPENSATION(i1);
528  	return 0;
529      }
530  
531      if (!strcmp(the_command_name, "STOP_CUTTER_RADIUS_COMPENSATION")) {
532  	STOP_CUTTER_RADIUS_COMPENSATION();
533  	return 0;
534      }
535  #endif
536  
537      if (!strcmp(the_command_name, "START_SPEED_FEED_SYNCH")) {
538  	if (3 != sscanf(the_command_args, "%d %lf %d", &i1, &d1, &i2)) {
539              return INTERP_ERROR;
540          }
541  	START_SPEED_FEED_SYNCH(i1, d1, i2);
542  	return 0;
543      }
544  
545      if (!strcmp(the_command_name, "STOP_SPEED_FEED_SYNCH")) {
546  	STOP_SPEED_FEED_SYNCH();
547  	return 0;
548      }
549  
550      if (!strcmp(the_command_name, "SET_SPINDLE_SPEED")) {
551  	if (2 != sscanf(the_command_args, "%i %lf", &i1, &d1)) {
552  	    return INTERP_ERROR;
553  	}
554  	SET_SPINDLE_SPEED(i1, d1);
555  	return 0;
556      }
557  
558      if (!strcmp(the_command_name, "START_SPINDLE_CLOCKWISE")) {
559      	if (1 != sscanf(the_command_args, "%d", &i1)) {
560      	    return INTERP_ERROR;
561      	}
562  	START_SPINDLE_CLOCKWISE(i1);
563  	return 0;
564      }
565  
566      if (!strcmp(the_command_name, "START_SPINDLE_COUNTERCLOCKWISE")) {
567      	if (1 != sscanf(the_command_args, "%d", &i1)) {
568      	    return INTERP_ERROR;
569      	}
570  	START_SPINDLE_COUNTERCLOCKWISE(i1);
571  	return 0;
572      }
573  
574      if (!strcmp(the_command_name, "STOP_SPINDLE_TURNING")) {
575      	if (1 != sscanf(the_command_args, "%d", &i1)) {
576      	    return INTERP_ERROR;
577      	}
578  	STOP_SPINDLE_TURNING(i1);
579  	return 0;
580      }
581  
582      if (!strcmp(the_command_name, "ORIENT_SPINDLE")) {
583  	if (3 != sscanf(the_command_args, "%d %lf %s", &i1, &d1, s1)) {
584  	    return INTERP_ERROR;
585  	}
586  	if (!strcmp(s1, "CANON_CLOCKWISE")) {
587  	    ORIENT_SPINDLE(i1, d2, CANON_CLOCKWISE);
588  	    return 0;
589  	}
590  	if (!strcmp(s1, "CANON_COUNTERCLOCKWISE")) {
591  	    ORIENT_SPINDLE(i1, d2, CANON_COUNTERCLOCKWISE);
592  	    return 0;
593  	}
594  	return INTERP_ERROR;
595      }
596  
597      if (!strcmp(the_command_name, "DISABLE_SPEED_OVERRIDE")) {
598      	if (1 != sscanf(the_command_args, "%d", &i1)) {
599      	    return INTERP_ERROR;
600      	}
601  	DISABLE_SPEED_OVERRIDE(i1);
602  	return 0;
603      }
604  
605      if (!strcmp(the_command_name, "DISABLE_FEED_OVERRIDE")) {
606  	DISABLE_FEED_OVERRIDE();
607  	return 0;
608      }
609  
610      if (!strcmp(the_command_name, "ENABLE_SPEED_OVERRIDE")) {
611      	if (1 != sscanf(the_command_args, "%d", &i1)) {
612      	    return INTERP_ERROR;
613      	}
614  	ENABLE_SPEED_OVERRIDE(i1);
615  	return 0;
616      }
617  
618      if (!strcmp(the_command_name, "ENABLE_FEED_OVERRIDE")) {
619  	ENABLE_FEED_OVERRIDE();
620  	return 0;
621      }
622  
623      if (!strcmp(the_command_name, "PROGRAM_STOP")) {
624  	PROGRAM_STOP();
625  	return 0;
626      }
627  
628      if (!strcmp(the_command_name, "OPTIONAL_PROGRAM_STOP")) {
629  	OPTIONAL_PROGRAM_STOP();
630  	return 0;
631      }
632  
633      if (!strcmp(the_command_name, "PROGRAM_END")) {
634  	PROGRAM_END();
635  	return 0;
636      }
637  
638      if (!strcmp(the_command_name, "PALLET_SHUTTLE")) {
639  	PALLET_SHUTTLE();
640  	return 0;
641      }
642  
643      if (!strcmp(the_command_name, "SET_MOTION_CONTROL_MODE")) {
644  	if (!strcmp(the_command_args, "CANON_EXACT_PATH")) {
645  	    SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH, 0);
646  	    return 0;
647  	}
648  	if (!strcmp(the_command_args, "CANON_EXACT_STOP")) {
649  	    SET_MOTION_CONTROL_MODE(CANON_EXACT_STOP, 0);
650  	    return 0;
651  	}
652  	if (!strcmp(the_command_args, "CANON_CONTINUOUS")) {
653  	    SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0);
654  	    return 0;
655  	}
656  	return INTERP_ERROR;
657      }
658  
659      if (!strcmp(the_command_name, "MESSAGE")) {
660  	MESSAGE(the_command_args);
661  	return 0;
662      }
663  
664      if (!strcmp(the_command_name, "INIT_CANON")) {
665  	INIT_CANON();
666  	return 0;
667      }
668  
669      if (!strcmp(the_command_name, "TURN_PROBE_OFF")) {
670  	TURN_PROBE_OFF();
671  	return 0;
672      }
673  
674      if (!strcmp(the_command_name, "TURN_PROBE_ON")) {
675  	TURN_PROBE_ON();
676  	return 0;
677      }
678  
679      fprintf(stderr, "canterp: unrecognized canonical command %s\n",
680  	    the_command);
681      return INTERP_ERROR;
682  }
683  
684  int Canterp::execute(const char *line, int line_number) {
685      return execute(line);
686  }
687  
688  int Canterp::execute() {
689      return execute(0);
690  }
691  
692  int Canterp::open(const char *newfilename) {
693      if(f) fclose(f);
694      f = fopen(newfilename, "r");
695      if(f) snprintf(filename, sizeof(filename), "%s", newfilename);
696      return f ? INTERP_OK : INTERP_ERROR;
697  }
698  
699  int Canterp::close() {
700      return INTERP_OK;
701  }
702  
703  int Canterp::exit() { return 0; }
704  int Canterp::synch() { return 0; }
705  int Canterp::reset() { return 0; }
706  int Canterp::line() { return 0; }
707  int Canterp::call_level() { return 0; }
708  
709  char *Canterp::line_text(char *buf, size_t bufsize) {
710     snprintf(buf, bufsize, "<Canterp::line_text>");
711     return buf;
712  }
713  char *Canterp::file_name(char *buf, size_t bufsize) {
714     snprintf(buf, bufsize, "%s", filename);
715     return buf;
716  }
717  char *Canterp::file(char *buf, size_t bufsize) {
718     snprintf(buf, bufsize, "%s", filename);
719     return buf;
720  }
721  int Canterp::on_abort(int reason, const char *message)
722  {
723      fprintf(stderr, "Canterp::on_abort reason=%d message='%s'", reason, message);
724      reset();
725      return INTERP_OK;
726  }
727  char *Canterp::command(char *buf, size_t bufsize) {
728     snprintf(buf, bufsize, "<Canterp::command>");
729     return buf;
730  }
731  size_t Canterp::line_length() {
732     return 0;
733  }
734  int Canterp::sequence_number() {
735     return -1;
736  }
737  int Canterp::init() { return INTERP_OK; }
738  void Canterp::active_g_codes(int gees[]) { std::fill(gees, gees + ACTIVE_G_CODES, 0); }
739  void Canterp::active_m_codes(int emms[]) { std::fill(emms, emms + ACTIVE_M_CODES, 0); }
740  void Canterp::active_settings(double sets[]) { std::fill(sets, sets + ACTIVE_SETTINGS, 0.0); }
741  void Canterp::set_loglevel(int level) {}
742  void Canterp::set_loop_on_main_m99(bool state) {}
743  
744  InterpBase *makeInterp() { return new Canterp; }