What Macro B Actually Is
Fanuc custom macro B lets you write parametric programs where variables replace hard-coded numbers. It is not a separate language. It runs inside G-code, uses local variables (assigned #1 through #33), global variables (#100 and up), and supports arithmetic, loops, and conditional jumps. That is it. Most shops I see that get stuck on this are not stuck on the syntax. They are stuck on the fact that it changes how you think about part programs entirely. When you start writing macros, you stop thinking in terms of "what toolpath do I need?" and start thinking in terms of "what inputs change between parts?" The second mindset is harder but pays off once it clicks. Local variables are scoped to the macro call. If you call a macro and pass #1 as 50, #1 is 50 only inside that macro. Once it returns, the calling program's #1 goes back to whatever it was before. That is reliable. Global variables, though, stick around. That means #100 in your main program is the same #100 inside any macro that reads it. This is useful until it is not. I have watched two different operators fight for hours because one loaded values into #100 and the other expected them to be cleared from the previous job.
The workaround is simple: at the start of every macro, assign your globals explicitly instead of relying on them being set by whoever ran the program last. Write #100=#1, #101=#2 at the top and treat any undefined global as a liability.
The Core Syntax You Need
There are only a handful of constructs that matter in practice. Anything else is noise. Variable assignment uses equals signs. #1=10 sets variable one to ten. You can do math. #2=#1*3.14159 works. String operations exist too, mostly for copying characters between variables with functions like STR, MID, LEN, and ASC. Those come up constantly when you are parsing input strings from operators. Conditionals use IF. IF [#1 GT 5] GOTO 100 jumps to block 100 if variable one is greater than five. The brackets are mandatory. Without them, the compiler complains and then refuses to run because you forgot a space or used LT instead of LT. I have wasted more time on missing spaces in conditions than anything else in this language.
Get the Full Details

Loops use WHILE. WHILE [#1 LE 10] DO 1 starts a loop, and #1=#1+1 increments it, and END1 closes it. If you forget to increment the variable inside the loop, the machine runs that loop forever and alarms out. Usually at three in the morning. Usually after you already paid for setup.
A Real Problem I Ran Into
Last year I was programming a family of bracket plates using a single macro. The operator would enter the plate width into #100, the height into #101, and the hole count into #102. The macro calculated hole spacing, tool offsets, and feed rates automatically. Everything worked fine for six months until someone started running a job where the hole pattern was centered but the plate had an odd width like 127.3 millimeters. The macro calculated the first hole position using #200=[#100-#102*#201]/2, where #201 was the spacing. The math was correct, but Fanuc's built-in truncation on certain intermediate calculations caused the final hole positions to drift by about 0.02 millimeters per iteration. On a 20-hole pattern, that added up to nearly half a millimeter of cumulative error on the far side. That is enough to scrap a part if the hole needs to line up with a mating fixture. The fix was to force floating point behavior throughout by adding a zero-length offset to every intermediate result. #200=[#100-#102*#201]/2.0 instead of dividing by an integer. That single change eliminated the truncation issue and the error went away completely. Fanuc's documentation mentions this behavior in a footnote somewhere, but most programmers never read it.
Macros vs. Subprograms
A common mistake is treating every macro like a subprogram. They are not the same thing. A subprogram with M98 is just a block of code you call repeatedly. A macro with variables lets you change the geometry between calls. If your part family has only one size, use a subprogram. It is simpler, faster to debug, and easier for the next person to read. Macros are worth the overhead when the geometry changes in a predictable way. That said, macros inside subprograms are legal and sometimes necessary. You can call a macro from a main program, and that macro can call another macro. Nesting depth on Fanuc is typically seven levels, sometimes eight depending on the controller revision. Going past seven will either alarm out or silently drop variables, which is worse because the machine keeps running and you get garbage results instead of a clear error.

Reading Operator Input
One of the most practical uses of macro B is letting the operator set part parameters at the control without editing the program. You do this with the prompt. #100= with nothing after the equals sign tells the controller to pause and wait for the operator to type a value. This is genuinely useful, but it is also a source of failure if you do not validate the input. An operator can type anything. Letters, symbols, negative numbers where only positive ones make sense. I have seen a macro crash into a part because the operator accidentally typed 1000 instead of 100 for a stock dimension, and the macro then tried to cut through the vise. The defense is a validation block right after every input prompt. Check that the value is in range, check that it is not zero if division is coming, and if it fails, jump to an alarm block or re-prompt the operator. It adds lines, but it prevents scrap and broken tools.
What Macro B Cannot Do Well
Macro B is not a replacement for CAD-based CAM. You cannot easily model complex 3D geometry in it. You cannot generate toolpaths for freeform surfaces. You cannot preview the toolpath visually inside the control. It is a calculation engine dressed up as G-code, and it excels at repetitive families of parts with parametric dimensions, not at shaping turbine blades. It is also brittle. If someone changes the order of variables in a shared macro, or renames a global variable, or forgets to clear it after use, the macro does not warn you. It just runs wrong. And because it runs inside the CNC control, you often do not catch the bug until the spindle is moving toward the part. Static analysis tools exist for G-code, but none of them understand macro variable scoping well enough to catch these issues before execution. If your shop is doing highly variable geometries with tight tolerances, I would recommend looking at parameterized CAM templates instead. They offer the same parametric flexibility with simulation, collision checking, and better error handling. Macro B is still the right tool for simpler families where you need the operator to change dimensions on the fly and you want everything running on the control without external software. It is just not the right tool for everything.