Getting to like Backus–Naur form
Thrashing out a simple class to tokenise a G-code, and feed the tokens in to a Bison type parser has turned out to be a simple task. Adding extra functionality just entails adding tokens to a list within the tokenising code, and then adding a line or two of BNF notation. Want to allow a mathematical function to be called from G-code, not a problem. define the token (it could be a single character or a whole word), and then specify the syntax within the bison.y file. Need to enforce a specific structure, not a problem. e.g.:
atan(0.5, 0.5)
Is described as:
expr = ATAN LPAREN NUM COMMA NUM RPAREN
// or
expr = ATAN LPAREN expr COMMA expr RPAREN
Simples. Adding conditional expressions is equally as trivial:
term = IF RPAREN expr EQUAL expr LPAREN THEN epr
(where the final expr could be a goto, return, or assignment)
The lexer just needs to interpret the tokens, and the parser will handle the rest, including checking that the syntax is correct - What is missing is the C/C++ code to do the low level work. But for the most part, this would just be a line or two along the lines of { $$ = atan2($1, $3); }
It is also possible to have:
expr = ATAN LPAREN expr RPAREN : { $$ = atan($1); }
And now you can have two different atan functions that can be used within a G-code file. Certainly beats having to make multiple changes across countless funtions (error prone and likely to lead to bugs being introduced). The downside to this simplicity and ease of extending the “language” is a larger binary along with a slight increase in execution time. But parsing of an input file doesn’t need high speed as there are other bottlenecks that limit how fast the data can be consumed.