I can't speak about the other CNC systems out there since I only use MACH3 in it's simplest form on my CNC router.
However on the mill it's LinuxCNC and that has been an interesting adventure mostly because LCNC is open source and therefore lots of different 'programmers' have input and many of them couldn't write a user manual (or internal) documentation if their life depended on it.
Even the add on documents often are written more like a glossary/dictionary rather than a description of how it works so it's been a bit of a tough slog.
For example. I'm working on the tool change. Not for the lathe but for the mill and not for one that has a tool changer with numbered pockets and numbered tools.
The G-Code command for changing a tool is Tx M06 and by default LCNC stops the machine, throws up a dialog asking you to install Tool x and press OK when it's done. MACH3 isn't much different. Same command. It's also programmed to move to a tool change position. You can write BASIC language gode to add automatic tool changing in MACH3.
LCNC has a document:
which sort of explains how to remap the M codes, M6 particularly with either more G-Code or a combination of G-Code and the Python Language.
The G-Code you see in the large files generated by the CAM software are a small subset of what can actually be done. On the subject of tool changes for example all you might see in this code which I've written off the top of my head)
M5 (stop the spindle)
G53 G0 Z0 (furthest point from spindle in machine co-ordinates at full speed)
G53 G0 X1 Y1 (tool changer position)
T3 M6 G43 (throw up change tool dialog and set the current workspace offset for Z tip of tool matches same Z position as the last tool)
M3 S250 (turn on the spindle again at new speed for this tool)
G0 Xn Ym (go to the xy position for the next milling operation)
G0 Zp (go to the first Z position just above the work)
( Start milling with G1 Fs and X,Y,Z) variables for slower speed motion )
But even MACH3 has some simple features for repetitive milling.
For example I put in a number of holes into a plastic front panel using my CNC router. This is a fragment of the G-Code I wrote by hand. I've added comments that aren't in the actual program to make this more readable:
G90 (Absolute motion rather than G91 relative motion)
G0 Z0 F5 ( Go up to the previously Z0 point (0.1 above the part) at full speed and set the G1 speed to 5 IPM)
M3 ( Turn on the relay for the Bosch Colt router power which has a dial for speed)
G0 X0 Y0 F90 (Go to the corner of the jig that holds the plastic part. The F90 is redundant and not needed)
G1 X0.709 Y-0.205 F60 (Move to the first hole location at 60 IPM)
M98 P4000 ( and this is what would be known in programming language as a subroutine call)
X0.909
M98 P4000
The subroutine is located like this:
O4000 ( The O makes this a label. The 4000 is just the subroutine #)
z-0.25 F20 ( Move at 20 IPM down to the -0.25" position which with the 0.125" diameter router bit is just through the plastic.
Z0 F30 ( Move out of the hole back 0.1" above the plastic and ... )
m99 ( return )
I usually make 25 at a time.
Now back to LinuxCNC. The G-Code is interpreted by a standard called RS274NGC so the interpreter reads those G0 M6 G43 statements and creates output for the CNC hardware to do the motion. What you usually don't see in the CAM generated code is this sort of G-Code.
The name of the subroutine for M6 Tool Remapping and automatic probing to a touch sensor. The Python interpreter reads in the G-Code file "m6remap.ngc" which is identified on the first line with:
o<m6remap> sub
Let's initialize some local variables used inside this subroutine. Note this even takes into account if the measurement system is G20 or G21 for Imperial or Metric.
o300 if[#<_imperial>]
#2001=.1 (Z up distance between probes)
#2002=25 (Fast probe feed rate)
#2003=1 (Slow probe feed rate)
#2004=40 (Z up feed rate.)
o300 endif
o310 if[#<_metric>]
#2001=2.5 (Z up distance between probes)
#2002=635 (Fast probe feed rate)
#2003=25 (Slow probe feed rate)
#2004=1000 (Z up feed rate.)
o310 endif
Here's an example line
G53 G0 Z[#<_ini[AXIS_Z]MAX_LIMIT>+#<_ini[PROBE_SCREEN]Z_SAFE_TRAVEL_OFFSET>]
Yikes eh? What the heck does that mean and is it portable to other systems. The answer is yes if they are running LinuxCNC and have the .ini file set correctly.
Let's take it apart.
G53 says don't use the current workspace co-ordinates but use the physical machine co-ordinates relative to the home switches.
G0 says move at full speed which in my machine for Z is 180 IPM which is scary fast.
As usual in G-Code the Z has a numeric argument for where to go and in this case it's a numerical expression defined inside the [ ] and the parameters are from the LCNC ".ini" file which on my machine is G3616-MESA-7i92.ini.
Inside the ini file are sections that in Pascal or C would be called Records or Structures and comments start with '#'.
For example the X axis:
[AXIS_X]
MIN_LIMIT = -0.04
MAX_LIMIT = 13.5
MAX_VELOCITY = 3.0
MAX_ACCELERATION = 15
and for the Probe Screen
# begin Touch Probe
[PROBE_SCREEN]
# Offset from [AXIS_Z]MAX_LIMIT for performing moves during various probe
# screen movements. This must be a negative number.
Z_SAFE_TRAVEL_OFFSET = -0.1
# Absolute distance from table to bottom of spindle
WORK_HEIGHT = 12.718
From within the RS274NGC interpreter the
[#< ini[AXIS_X]MAX_LIMIT>+
says use the machine ini file record structure [AXIS_X] with MAX_LIMIT field which is 13.5 in this case and add it to the number #<_ini[PROBE_SCREEN]Z_SAFE_TRAVEL_OFFSET>]
in the ini file record [PROBE_SCREEN Z] with SAFE_TRAVEL_OFFSET field which in this case is -0.1
The end result of that statement in interpreted G-Code is:
G53 G0 Z13.4
So G-Code does have a programming language feel to it. And this could all have been done in the Python Language too. Just simpler here with G-Code.
Confusing? Yes. But most programming languages are.