/// <summary> /// Gets the precedence of operator codes. /// </summary> /// <param name="opcode">operater code</param> /// <returns>value indicating precedence</returns> private static int OperatorPrecedence(GerberOpcodes opcode) { switch (opcode) { case GerberOpcodes.Add: case GerberOpcodes.Subtract: return(1); case GerberOpcodes.Multiple: case GerberOpcodes.Divide: return(2); } return(0); }
public static ApertureMacro ProcessApertureMacro(GerberLineReader reader) { const int MathOperationStackSize = 2; ApertureMacro apertureMacro = new ApertureMacro(); GerberInstruction instruction; GerberOpcodes[] mathOperations = new GerberOpcodes[MathOperationStackSize]; char characterRead; int primitive = 0; int mathOperationIndex = 0; int equate = 0; bool continueLoop = true; bool comma = false; // Just read an operator (one of '*+X/) bool isNegative = false; // Negative numbers succeeding ',' bool foundPrimitive = false; int length = 0; // Get macro name apertureMacro.Name = reader.GetStringValue('*'); characterRead = reader.Read(); // skip '*' // The first instruction in all programs will be NOP. instruction = new GerberInstruction(); instruction.Opcode = GerberOpcodes.NOP; apertureMacro.InstructionList.Add(instruction); while (continueLoop && !reader.EndOfFile) { length = 0; characterRead = reader.Read(); switch (characterRead) { case '$': if (foundPrimitive) { instruction = new GerberInstruction(); instruction.Opcode = GerberOpcodes.PushParameter; apertureMacro.InstructionList.Add(instruction); apertureMacro.NufPushes++; instruction.Data.IntValue = reader.GetIntegerValue(ref length); comma = false; } else { equate = reader.GetIntegerValue(ref length); } break; case '*': while (mathOperationIndex != 0) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } // Check is due to some gerber files has spurious empty lines (eg EagleCad) if (foundPrimitive) { instruction = new GerberInstruction(); if (equate > 0) { instruction.Opcode = GerberOpcodes.PopParameter; instruction.Data.IntValue = equate; } else { instruction.Opcode = GerberOpcodes.Primative; instruction.Data.IntValue = primitive; } apertureMacro.InstructionList.Add(instruction); equate = 0; primitive = 0; foundPrimitive = false; } break; case '=': if (equate > 0) { foundPrimitive = true; } break; case ',': if (!foundPrimitive) { foundPrimitive = true; break; } while (mathOperationIndex != 0) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } comma = true; break; case '+': while ((mathOperationIndex != 0) && OperatorPrecedence((mathOperationIndex > 0) ? mathOperations[mathOperationIndex - 1] : GerberOpcodes.NOP) >= (OperatorPrecedence(GerberOpcodes.Add))) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } mathOperations[mathOperationIndex++] = GerberOpcodes.Add; comma = true; break; case '-': if (comma) { isNegative = true; comma = false; break; } while ((mathOperationIndex != 0) && OperatorPrecedence((mathOperationIndex > 0) ? mathOperations[mathOperationIndex - 1] : GerberOpcodes.NOP) >= (OperatorPrecedence(GerberOpcodes.Subtract))) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } mathOperations[mathOperationIndex++] = GerberOpcodes.Subtract; break; case '/': while ((mathOperationIndex != 0) && OperatorPrecedence((mathOperationIndex > 0) ? mathOperations[mathOperationIndex - 1] : GerberOpcodes.NOP) >= (OperatorPrecedence(GerberOpcodes.Divide))) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } mathOperations[mathOperationIndex++] = GerberOpcodes.Divide; comma = true; break; case 'X': case 'x': while ((mathOperationIndex != 0) && OperatorPrecedence((mathOperationIndex > 0) ? mathOperations[mathOperationIndex - 1] : GerberOpcodes.NOP) >= (OperatorPrecedence(GerberOpcodes.Multiple))) { instruction = new GerberInstruction(); instruction.Opcode = mathOperations[--mathOperationIndex]; apertureMacro.InstructionList.Add(instruction); } mathOperations[mathOperationIndex++] = GerberOpcodes.Multiple; comma = true; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': // Comments in aperture macros are a definition starting with zero and ends with a '*' if ((characterRead == '0') && (!foundPrimitive) && (primitive == 0)) { // Comment continues until next '*', just throw it away. reader.GetStringValue('*'); characterRead = reader.Read(); // Read the '*'. break; } // First number in an aperture macro describes the primitive as a numerical value if (!foundPrimitive) { primitive = (primitive * 10) + (characterRead - '0'); break; } reader.Position--; instruction = new GerberInstruction(); instruction.Opcode = GerberOpcodes.Push; apertureMacro.InstructionList.Add(instruction); apertureMacro.NufPushes++; instruction.Data.DoubleValue = reader.GetDoubleValue(); if (isNegative) { instruction.Data.DoubleValue = -(instruction.Data.DoubleValue); } isNegative = false; comma = false; break; case '%': reader.Position--; // Must return with % first in string since the main parser needs it. continueLoop = false; // Reached the end of the macro. break; default: // Whitespace. break; } } if (reader.EndOfFile) { return(null); } return(apertureMacro); }