Source code for gcode_reader.syntax

import re

# Matches +1.4e+05
floating_point_regex = r"[-+]?\d*\.?\d+(?:[eE](?:[-+]?\d*\.?\d+))?"


ABS_POSITION = ["x", "y", "z"]


[docs] def resolve_flavor(flavor: str) -> dict: """Helper function to resolve gcode flavor from string or dict Args: flavor (str | dict): G-code flavor as a string key or a dictionary Raises: ValueError: If the flavor string is not recognized TypeError: If the flavor is not a string or a dictionary Returns: dict: G-code flavor dictionary """ if isinstance(flavor, str): flavor_dict = flavors.get(flavor) if flavor_dict is None: raise ValueError( f"Unknown flavor string: {flavor}. Must be one of {list(flavors.keys())}" ) return flavor_dict elif not isinstance(flavor, dict): raise TypeError("flavor must be a string or a dictionary") return flavor
[docs] def available_flavors() -> list[str]: """Returns a list of available G-code flavor keys Returns: list[str]: List of available G-code flavor keys """ return list(flavors.keys())
flavors = { # Reprap and Marlin # Marlin: https://marlinfw.org/meta/gcode/ # RepRap: https://reprap.org/wiki/G-code "default": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile(rf"([A-Za-z])({floating_point_regex})"), "comment_re": re.compile(r";(.*)$"), "generic_expression_re": r"\[\s*[^\[\]]*\s*\]", "function_expression_re": [ rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)\[({floating_point_regex})\])", rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)({floating_point_regex}))", ], "parameter": "#<PARAM>", "parameter_re": r"#\<(.*?)\>", "parameter_declare_re": rf"#\<(.*?)\>\s?=\s?({floating_point_regex})", # Format: #<key> = value "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "location": ["X", "Y", "Z"], "arc_center": ["I", "J"], "feed_rate": "F", "extrusion_rate": "E", "time_s": "S", "time_ms": "P", "other": None, "line_number": None, }, "code_map": { # NOTE: code_map reserved for 'G' codes "linear_move": (0, 1), "rapid": 0, "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": {}, # NOTE: Special codes reserved for 'M' codes "units": { "feed_rate": 60, # Conversion to seconds "commands": {"G20": "inches", "G21": "mm"}, }, }, "cead": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile( rf"([NXYZABCEFGMgmnxyzabcef]|ELX|elx)=?({floating_point_regex})" ), # Only specific words allowed "comment_re": re.compile(r";(.*)$"), "generic_expression_re": r"\(\s*[^\(\)]*\s*\)", "function_expression_re": r"((DEVICE|PRESETON|IC|COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)(\(.+\)))", "parameter": "PARAM", "parameter_line_indicator": r"DEF ", "parameter_re": r"([A-Za-z_]+)(?!=)", # Format: PARAM (without an '=' after it) "parameter_declare_re": rf"([A-Za-z_]+)=({floating_point_regex})", # Format: key=value "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "location": ["X", "Y", "Z"], "rotation": ["A", "B", "C"], # x,y,z axis "arc_center": ["I", "J"], "feed_rate": "F", "extrusion_rate": "E", "time_s": "S", "time_ms": "P", "other": None, "line_number": "N", }, "code_map": { "linear_move": (0, 1), "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": {}, "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, "juggerbot": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile(rf"([A-Za-z])({floating_point_regex})"), "comment_re": re.compile(r";(.*)$"), "generic_expression_re": r"\[\s*[^\[\]]*\s*\]", "function_expression_re": [ rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)\[({floating_point_regex})\])", rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)({floating_point_regex}))", ], "parameter": "#<PARAM>", "parameter_re": r"#\<(.*?)\>", "parameter_declare_re": rf"#\<(.*?)\>\s?=\s?({floating_point_regex})", # Format: #<key> = value "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "tool": "T", "location": ["X", "Y", "Z", "B"], "arc_center": ["I", "J"], "feed_rate": "F", "extrusion_rate": "S", "time_s": "s", "time_ms": "P", "other": None, "line_number": None, }, "code_map": { "linear_move": (0, 1), "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": { "extruder_on": 3, "extruder_off": 5, }, "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, "cincinnati": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile(rf"([A-Za-z])({floating_point_regex})"), "comment_re": re.compile(r"\((.*)\)$"), "generic_expression_re": r"\[\s*[^\[\]]*\s*\]", "function_expression_re": [ rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)\[({floating_point_regex})\])", rf"((COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)({floating_point_regex}))", ], "parameter": "#<PARAM>", "parameter_re": r"#\<(.*?)\>", "parameter_declare_re": rf"#\<(.*?)\>\s?=\s?({floating_point_regex})", # Format: #<key> = value "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "location": ["X", "Y", "Z", "W"], "arc_center": ["I", "J"], "feed_rate": "F", "extrusion_rate": "S", # "time_s": "s", # Cincinnati might not have this "time_ms": "P", "other": "L", "line_number": None, }, "code_map": { "linear_move": (0, 1), "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": { "purge": 69, "extruder_on": 3, "extruder_off": 5, "set_acceleration": 66, "park": 68, }, "location_correction_pairs": { "Z": ("W", "-"), }, # "Z" is location, "W" is correction, "-" is subtraction --> z=Z-W "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, "ingersoll": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile(rf"([A-Za-z]|CA|ca)({floating_point_regex})"), "comment_re": re.compile(r";(.*)$"), "generic_expression_re": [r"\(\s*[^\(\)]*\s*\)"], "function_expression_re": [ r"((EXTRUDER|COS|TAN|SIN|ACOS|ATAN|ASIN|ABS|ROUND|SQRT)(\(\d+.?\d*\)|\d+.?\d*))", r"((EXTRUDERB)\((True|False)\))", r"((CA\s*)=(\s*\S+))", ], "parameter": None, "parameter_re": None, "parameter_declare_re": rf"(\w+)\s*=\s*({floating_point_regex})", # Format: #<key> = value "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "location": ["X", "Y", "Z"], "arc_center": ["I", "J"], "feed_rate": "F", "extrusion_rate": "E", "time_s": "F", "line_number": "N", "other": [], }, "code_map": { "linear_move": (0, 1), "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": {}, "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, "hendrick": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile(rf"([A-Za-z])({floating_point_regex})"), "comment_re": re.compile(r";(.*)$|\((.*)\)"), "generic_expression_re": None, "function_expression_re": None, "parameter": None, "parameter_re": None, "parameter_declare_re": None, "data_type_map": { "default": float, "g": int, "m": int, "n": int, "t": int, "comment": str, "raw": str, }, "word_map": { # https://www.machinistguides.com/cnc-code-guide/ "config": "M", "tool": "T", "location": ["X", "Y", "Z"], "rotation": ["A", "B", "C"], # x,y,z axis "arc_center": ["I", "J", "K"], "feed_rate": "F", "spindle": "S", "height": "h", "other": "L", "line_number": None, }, "code_map": { "linear_move": (0, 1), "arc_move": (2, 3), "dwell": 4, "absolute_position": 90, "incremental_position": 91, "work_coordinate": 54, "machine_coordinate": 53, }, "special_codes": {}, "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, "electroimpact": { "command_re": re.compile(r"([GMgm])(\d+)"), "word_re": re.compile( rf"([NXYZABJFSTKGMnxyzabjfstkgm]|CP|cp)=?({floating_point_regex})" ), "comment_re": re.compile(r"\((.*)\)$"), "generic_expression_re": None, "function_expression_re": None, "parameter": None, "parameter_re": None, "parameter_declare_re": None, "data_type_map": { "default": float, "g": int, "m": int, "n": int, "comment": str, "raw": str, }, "word_map": { "config": "M", "location": ["X", "Y", "Z"], "rotation": ["A", "B"], # x,y axis "feed_rate": "F", "extrusion_rate": "J", # J = bead area "extrusion_length": "K", # K = cumulative extrusion length "line_number": "N", }, "code_map": { "linear_move": (0, 1), }, "special_codes": { "head_on": 9, "lane_on": 301, # Enables extruder lanes "part_offset": 38, "head_offset": 22, }, "units": { "feed_rate": 1, # TODO: Conversion to seconds "commands": {}, }, }, }