KiCad PCB EDA Suite
class_am_param.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
9  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
10  * Copyright (C) 1992-2017 KiCad Developers, see change_log.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include <class_am_param.h>
31 #include <class_aperture_macro.h>
32 
33 extern int ReadInt( char*& text, bool aSkipSeparator = true );
34 extern double ReadDouble( char*& text, bool aSkipSeparator = true );
35 extern double Evaluate( AM_PARAM_EVAL_STACK& aExp );
36 
37 /* Class AM_PARAM
38  * holds a parameter value for an "aperture macro" as defined within
39  * standard RS274X. The parameter can be a constant, i.e. "immediate" parameter,
40  * or depend on some defered values, defined in a D_CODE, by the ADD command.
41  * Note the actual value could need an evaluation from an arithmetical expression
42  * items in the expression are stored in .
43  * A simple definition is just a value stored in one item in m_paramStack
44  */
46 {
47  m_index = -1;
48 }
49 
56 {
57  bool is_immediate = true;
58  for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
59  {
60  if( m_paramStack[ii].IsDefered() )
61  { // a defered value is found in operand list,
62  // so the parameter is not immediate
63  is_immediate = false;
64  break;
65  }
66  }
67  return is_immediate;
68 }
69 
70 double AM_PARAM::GetValue( const D_CODE* aDcode ) const
71 {
72  // In macros, actual values are sometimes given by an expression like:
73  // 0-$2/2-$4
74  // Because arithmetic predence is used, the parameters (values (double) and operators)
75  // are stored in a stack, with all numeric values converted to the actual values
76  // when they are defered parameters
77  // Each item is stored in a AM_PARAM_EVAL (a value or an operator)
78  //
79  // Then the stack with all values resolved is parsed and numeric values
80  // calculated according to the precedence of operators
81  double curr_value = 0.0;
82  parm_item_type op_code;
83 
85 
86  for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
87  {
88  AM_PARAM_ITEM item = m_paramStack[ii];
89 
90  switch( item.GetType() )
91  {
92  case ADD:
93  case SUB:
94  case MUL:
95  case DIV: // just an operator for next parameter value
96  case OPEN_PAR:
97  case CLOSE_PAR: // Priority modifiers: store in stack
98  op_code = item.GetType();
99  ops.push_back( AM_PARAM_EVAL( op_code ) );
100  break;
101 
102  case PUSHPARM:
103  // a defered value: get the actual parameter from the aDcode
104  if( aDcode ) // should be always true here
105  {
106  if( item.GetIndex() <= aDcode->GetParamCount() )
107  {
108  curr_value = aDcode->GetParam( item.GetIndex() );
109  }
110  else // Get parameter from local param definition
111  {
112  const APERTURE_MACRO * am_parent = aDcode->GetMacro();
113  curr_value = am_parent->GetLocalParam( aDcode, item.GetIndex() );
114  }
115  }
116  else
117  {
118  wxLogDebug( wxT( "AM_PARAM::GetValue(): NULL param aDcode\n" ) );
119  }
120 
121  ops.push_back( AM_PARAM_EVAL( curr_value ) );
122  break;
123 
124  case PUSHVALUE: // a value is on the stack:
125  curr_value = item.GetValue();
126  ops.push_back( AM_PARAM_EVAL( curr_value ) );
127  break;
128 
129  default:
130  wxLogDebug( "AM_PARAM::GetValue(): unexpected type\n" );
131  break;
132  }
133  }
134 
135  double result = Evaluate( ops );
136 
137  return result;
138 }
139 
145 void AM_PARAM::PushOperator( parm_item_type aType, double aValue )
146 {
147  AM_PARAM_ITEM item( aType, aValue);
148  m_paramStack.push_back( item );
149 }
150 
151 void AM_PARAM::PushOperator( parm_item_type aType, int aValue )
152 {
153  AM_PARAM_ITEM item( aType, aValue);
154  m_paramStack.push_back( item );
155 }
156 
170 bool AM_PARAM::ReadParam( char*& aText )
171 {
172  bool found = false;
173  int ivalue;
174  double dvalue;
175  bool end = false;
176 
177  while( !end )
178  {
179  switch( *aText )
180  {
181  case ',':
182  aText++;
183  // fall through
184  case 0: // EOL
185  case '*': // Terminator in a gerber command
186  end = true;
187  break;
188 
189  case ' ':
190  aText++;
191  break;
192 
193  case '$':
194  // defered value defined later, in ADD command which define defered parameters
195  ++aText;
196  ivalue = ReadInt( aText, false );
197  if( m_index < 1 )
198  SetIndex( ivalue );
199  PushOperator( PUSHPARM, ivalue );
200  found = true;
201  break;
202 
203  case '/':
204  PushOperator( DIV );
205  aText++;
206  break;
207 
208  case '(': // Open a block to evaluate an expression between '(' and ')'
210  aText++;
211  break;
212 
213  case ')': // close a block between '(' and ')'
215  aText++;
216  break;
217 
218  case 'x':
219  case 'X':
220  PushOperator( MUL );
221  aText++;
222  break;
223 
224  case '-':
225  case '+':
226  // Test if this is an operator between 2 params, or the sign of a value
227  if( m_paramStack.size() > 0 && !m_paramStack.back().IsOperator() )
228  { // Seems an operator
229  PushOperator( *aText == '+' ? ADD : SUB );
230  aText++;
231  }
232  else
233  { // seems the sign of a value
234  dvalue = ReadDouble( aText, false );
235  PushOperator( PUSHVALUE, dvalue );
236  found = true;
237  }
238  break;
239 
240  case '=': // A local definition found like $4=$3/2
241  // At this point, one defered parameter is expected to be read.
242  // this parameter value (the index) is stored in m_index.
243  // The list of items is cleared
244  aText++;
245  m_paramStack.clear();
246  found = false;
247  break;
248 
249  default:
250  dvalue = ReadDouble( aText, false );
251  PushOperator( PUSHVALUE, dvalue );
252  found = true;
253  break;
254  }
255  }
256 
257  return found;
258 }
std::vector< AM_PARAM_ITEM > m_paramStack
std::vector< AM_PARAM_EVAL > AM_PARAM_EVAL_STACK
double ReadDouble(char *&text, bool aSkipSeparator=true)
Function ReadDouble reads a double from an ASCII character buffer.
double GetParam(unsigned aIdx) const
GetParam() Returns a parameter stored in parameter list.
Definition: dcode.h:141
unsigned GetIndex() const
Class AM_PARAM holds an operand for an AM_PARAM as defined within standard RS274X.
bool ReadParam(char *&aText)
Function ReadParam Read one aperture macro parameter a parameter can be: a number a reference to an a...
void PushOperator(parm_item_type aType, double aValue)
function PushOperator add an operator/operand to the current stack
double Evaluate(AM_PARAM_EVAL_STACK &aExp)
Evaluate an basic arithmetic expression (infix notation) with precedence The expression is a sequence...
Definition: evaluate.cpp:102
parm_item_type GetType() const
double GetValue(const D_CODE *aDcode) const
unsigned GetParamCount() const
GetParamCount() Returns the number of parameters stored in parameter list.
Definition: dcode.h:131
bool IsImmediate() const
Function IsImmediate tests if this AM_PARAM holds an immediate parameter or is a pointer into a param...
This helper class hold a value or an arithmetic operator to calculate the final value of a aperture m...
double GetLocalParam(const D_CODE *aDcode, unsigned aParamId) const
function GetLocalParam Usually, parameters are defined inside the aperture primitive using immediate ...
int ReadInt(char *&text, bool aSkipSeparator=true)
Function ReadInt reads an int from an ASCII character buffer.
Class D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:82
parm_item_type
double GetValue() const
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:157
void SetIndex(int aIndex)
Struct APERTURE_MACRO helps support the "aperture macro" defined within standard RS274X.