Appendix D. Interpreter Software
This section describes the Interpreter software. NC programmers and machine operators should never need to use this section. SAI installers should not need it but may find it helpful. Developers and researchers should find the section useful.
The Interpreter has four interfaces, as shown in Figure 9. These are all function call interfaces. The direction of function calling is indicated by arrows. The flow of information in the reverse direction from the arrows differs in the different interfaces.
The Interpreter-do-it functions tell the Interpreter to do something, such as read a line of NC code or execute the line last read. These functions all return an integer status code as described in Appendix A.1. The functions themselves are described in Appendix D.4. They are declared in rs274ngc.hh and defined in rs274ngc_pre.cc. The names of these functions all begin with "rs274ngc_".
The Interpreter-give-information functions ask the Interpreter to give information. Some of these functions pass from the driver a pointer to a place to put information. The Interpreter provides the information either as a returned value, or by putting it into the place pointed at by the pointer. The functions are described in Appendix D.5. They are declared in rs274ngc.hh and defined in rs274ngc_pre.cc. The names of these functions all begin with "rs274ngc_".
The canonical machining functions tell the rest of the system to do something. These functions do not return anything. They are described in Section 4. They are declared in canon.hh and defined in canon.cc. The names of these functions do not all have the same prefix.
The world-give-information functions ask the world outside the Interpreter to give the Interpreter information. Some of these function pass from the Interpreter a pointer to a place to put information. The world provides the information either as a returned value, or by putting it into the place pointed at by the pointer. The functions are described in Appendix D.6. They are declared in canon.hh and defined in canon.cc. The names of these functions all begin with "GET_EXTERNAL_".
The Interpreter software is written in C++.
The files for the Interpreter and the rest of the SAI are:
The rs274ngc_pre.cc file is a bit over 12,000 lines. The other files are all in the range of 100 to 1100 lines.
The organization of the software by file is shown in Figure 10. The SAI uses the files shown in the left and middle columns. The EMC Controller uses the files shown in the right and middle columns. In the figure, arrows show the direction of function calls.
The rs274ngc_pre.cc file includes interface functions (the Interpreter-do-it and Interpreter-give-information functions) and other functions. In the file itself, the interface functions are given after the other functions. As shown in Figure 10, other functions are called only by interface functions, while interface functions are called by driver functions (in the SAI or EMC Controller). Both interface functions and other functions call canonical machining functions and world-give-information functions.
Different versions of the canonical machining functions are used in the SAI and the EMC Controller. The canonical machining functions used with the SAI print themselves and manipulate an emulated environment, while those used in the EMC controller send messages which ultimately lead to controlling the machine. The same header file, canon.hh, is used with both versions of the functions.
As described in Appendix A.4, the rs274ngc_errors.cc and the rs274ngc_return.hh files are prepared automatically.
The source code is heavily documented. In general, for each function, four fields are given:
1. Returned Value - a description of possible returned values and the circumstances in which particular values may be returned.
2. Side Effects - a description of the important side effects (things other than the returned value) of executing a function. Since the returned value of most functions is used to indicate error status, the side effects of most functions are important.
3. Called By - a list of functions which call the function being documented.
4. Arguments - a one-line description of the meaning of each argument to a function, placed immediately after the declaration of the argument. This field is omitted if there are no arguments.
In addition to these four fields, most functions have a paragraph or two (up to several pages) of discussion. These discussions include many references to the RS274 manuals [NCMS], [EIA], [Monarch], and [Fanuc]. Where a function implements an algorithm for geometric or numerical calculation (as do many of the functions having to do with cutter radius compensation, for example), the algorithm is described.
In the EMC Controller, Interpreter input may be taken from a file or via manual data input (MDI) from the controller console. In the SAI, input may be taken from a file or from the keyboard of the computer running the Interpreter. Two major phases of interpretation take place. In the first phase, a call to rs274ngc_read causes the Interpreter to read a line of code, to check it somewhat, and to store the information from the line in a structure called a "block". In the second phase, a call to rs274ngc_execute causes the Interpreter to examine the block, to check it further, and (usually) to make calls to canonical machining functions.
The Interpreter reads lines of RS274/NGC code one at a time. First the line is read into a buffer. Next, any spaces not in comments are removed, and any upper case letters not in comments are changed to lower case letters.
Then the buffer and a counter holding the index of the next character to be read are handed around among a lot of functions named read_XXXX. All such functions read characters from the buffer using the counter. They all reset the counter to point at the character in the buffer following the last one used by the function. The first character read by most of these functions is expected to be a member of some set of characters (often a specific single character), and each function checks the first character.
Each line of code is stored until it has been executed in a reusable "block" structure, which has a slot for every potential piece of information on the line. Each time a useful piece of information has been extracted from the line, the information is put into the block.
The read_XXXX functions do a lot of error detection, but they only look for errors which would cause reading or storing to fail. After reading and storing is complete, more checking functions (check_g_codes, check_m_codes, and check_other_codes) are run. These functions look for logical errors, such as all axis words missing with a G code for motion in effect.
Once a block is built and checked, the block is executed by the execute_block function, which calls one or more functions named convert_XXXX. In RS274/NGC, as in all dialects of RS274, a line of code may specify several different things to do, such as moving from one place to another along a straight line or arc, changing the feed rate, starting the spindle turning, etc. The order of execution is shown in Table 8.
This section describes the Interpreter-do-it functions. They are arranged alphabetically. All function names start with "rs274ngc_".
If mdi is not null, read the string mdi points to. If mdi is null, read the next line of the currently open NC code file.
These are interface functions to call to get information from the Interpreter. If a function has a return value, the return value contains the information. If a function returns nothing, information is copied into one of the arguments to the function. These functions do not change the state of the Interpreter.
Copy the text of the error message whose number is error_code into the error_text array, but stop at max_size if the text is longer.
Copy the name of the currently open file into the file_name array, but stop at max_size if the name is longer.
Copy the text of the most recently read line into the line_text array, but stop at max_size if the text is longer.
Copy the function name from the stack_index'th position of the function call stack at the time of the most recent error into the function_name string, but stop at max_size if the name is longer.
This section describes the world-give-information functions. These functions get information for the Interpreter. They are arranged alphabetically. All function names start with "GET_EXTERNAL_".
Return the system angular unit factor, in units / degree. The Interpreter is not currently using this function.
Return the system length unit factor, in units / mm. The Interpreter is not currently using this function.
The Interpreter is not using these six GET_EXTERNAL_ORIGIN functions, each of which returns the current value of the origin offset for the axis it names.
Return nothing but copy the name of the parameter file into the filename array, stopping at max_size if the name is longer. An empty string may be placed in filename.
Return the system value for the spindle speed setting in revolutions per minute (rpm). The actual spindle speed may differ from this.
Returns the system value for the carousel slot in which the tool currently in the spindle belongs. Return value zero means there is no tool in the spindle.
Returns the CANON_TOOL_TABLE structure associated with the tool in the given pocket. A CANON_TOOL_TABLE structure has three data elements: id (an int), length (a double), and diameter (a double).
Function call hierarchies are shown in the following six figures. Except in Figure 13, which is highly recursive, if a function is called by more than one other function, its name may appear more than once in a figure. The functions called by a function are those listed underneath the calling function, one level further indented than the calling function. In Figure 13, function calls are shown with arrows from the caller to the called.
Figure 11 shows the hierarchies of all Interpreter-do-it functions other than rs274ngc_read and rs274ngc_execute.
Figure 12 and Figure 13 show the hierarchy starting with the Interpreter-do-it function rs274ngc_read. Figure 12 stops at read_real_value and Figure 13 begins there.
Figure 14 and Figure 15 show the hierarchy starting with the Interpreter-do-it function rs274_ngc_execute. Figure 14 stops at convert_motion and Figure 15 begins there.
Figure 16 shows the hierarchy of function calls from the driver.
Calls to canonical machining functions are not included in the figures.
This figure shows the hierarchy of function calls from Interpreter-do-it functions to other Interpreter functions and to world-give-information functions. This figure does not show the sub-hierarchies starting at rs274ngc_read. (see Figure 12 and Figure 13) and rs274ngc_execute (see Figure 14 and Figure 15).
Interpreter-do-it interface functions are shown in boldface, other Interpreter functions are shown in ordinary typeface, and world-give-information functions are shown in ITALIC.
This figure shows the hierarchy of function calls from the Interpreter function rs274ngc_read to other Interpreter functions. This figure does not show the sub-hierarchy starting at read_real_value. That is shown in Figure 13. To save space, calls to read_real_value are shown in parentheses next to the caller, rather than indented below the caller.
Interpreter-do-it interface functions are shown in boldface, other Interpreter functions are shown in ordinary typeface, and world-give-information functions are shown in ITALIC.
This figure shows function calls from convert_motion to other Interpreter functions. Convert_motion is shown called by convert_g in Figure 14. To save space, calls to cycle_feed are shown in parentheses next to the caller, rather than indented below the caller.
Interpreter-do-it interface functions are shown in boldface, other Interpreter functions are shown in ordinary typeface, and world-give-information functions are shown in ITALIC.
Interpreter-do-it interface functions are shown in boldface, other Interpreter functions are shown in ordinary typeface, and world-give-information functions are shown in ITALIC.
This section focus on parts of the software that may be of particular interest to developers.
The Interpreter maintains a model of its world when it runs. The data type of the model is a struct named "setup_struct" defined in rs274ngc.hh The working model, a global variable declared in rs274ngc.cc, is named _setup and is the only instance of a setup_struct. The model includes around 100 attributes. Most of these are doubles or ints for things like "traverse_rate", but one, "parameters" is an array of 5600 doubles, another is the entire tool table, a third is a block (see Appendix D.8.2), and a few others are substantial arrays.
The model is initialized when rs274ngc_init is called. Some of the initial values are hard-coded, while others are obtained by calls (in rs274ngc_synch) to various world-give-information functions.
While the Interpreter runs, the model is updated constantly. Most of the updating is done assuming that canonical machining function calls have had their intended effects. Updating after probing is done by calls to world-give-information functions.
One item in the _setup model is a block struct. The block struct is defined in rs274ngc.hh and has the attributes listed in Table 14. The rotary axis attributes are conditional; for example, b_number and b_flag are not part of the struct unless the -DBB flag is used in compiling. Some letters (the ones for which negative values are OK) have two attributes: a flag and a number. Other letters (the ones for which negative values are not OK) have only a number.
Information from a line of code is put into the block when the line is read. When an rs274ngc_execute function call is made, it is the block that is executed. The block is re-initialized each time a line of code is read. The letters that have flags are initialized by setting the flag to OFF. The letters that do not have flags are initialized by setting the number to -1.
The g_modes array in the block keeps track of which G modal groups are used on a line of code. The values in the g_modes array are initialized to -1 before each line of NC code is read. When a G-code is first read, the G number is multiplied by ten (to make an integer). That number is used as an index into the _gees array (defined in rs274ngc.cc). The value at that index is the modal group number for the G code (call it n). The G number is then inserted as the value at the nth index of the g_modes array. When reading a line is complete, the g_modes array contains a record of which G codes are to be executed.
The g_modes array also make it easy to check that at most one member of each G modal group is used on a line of code; when a G code is read, just check that the g_modes value for the modal group of the G code is -1; if not, another G code from the same group was previously read from the same line of NC code.
The m_modes array in the block is handled similarly, the main difference being that M codes are all integers, so they do not need to be multiplied by ten to get an integer. Thus, the _ems array, which serves the same function with respect to M codes that _gees serves for G codes, is a tenth the size of the _gees array.
The expression evaluation software is a recursive descent parser that evaluates as it parses. The function call hierarchy is shown in Figure 13. This software is a coherent package that could be copied out of the rs274ngc.cc file and used for other purposes. The read_real_expression function can handle any number of levels of precedence.
As discussed in Section 3.3.3, parameter values on a line of RS274/NGC code are all evaluated before any parameters are reset. This is often called "parallel" setting. It is implemented by having a parameter buffer (in the _setup model). When a line of code is read, any parameter values on the line are taken from the parameters array, and any parameter settings are recorded in the parameter buffer, not by changing the parameters array. If the line is executed, the parameters in the parameters array are reset according to the settings in the parameter buffer. This has no other effect on execution because parameters are not used during execution.
A side effect of having the parameter buffer is that it ensures that the parameters in the _setup model will not change while a line of code is being read. Nothing else in the model changes during reading, so with the buffer, if there is an error during reading, nothing needs to be done to recover state and continue interpretation. In previous interpreter versions, there was no parameter buffer, parameters changed during reading, and it was not safe to continue interpretation after an error during reading.