KiCad PCB EDA Suite
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-2020 KiCad Developers, see AUTHORS.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 <am_param.h>
31 #include <am_primitive.h>
32 #include <macros.h>
33 
34 #include <wx/debug.h>
35 
36 
37 extern int ReadInt( char*& text, bool aSkipSeparator = true );
38 extern double ReadDouble( char*& text, bool aSkipSeparator = true );
39 extern double Evaluate( AM_PARAM_EVAL_STACK& aExp );
40 
41 /* Class AM_PARAM
42  * holds a parameter value for an "aperture macro" as defined within
43  * standard RS274X. The parameter can be a constant, i.e. "immediate" parameter,
44  * or depend on some defered values, defined in a D_CODE, by the ADD command.
45  * Note the actual value could need an evaluation from an arithmetical expression
46  * items in the expression are stored in .
47  * A simple definition is just a value stored in one item in m_paramStack
48  */
50 {
51  m_index = -1;
52 }
53 
60 {
61  bool is_immediate = true;
62  for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
63  {
64  if( m_paramStack[ii].IsDefered() )
65  { // a defered value is found in operand list,
66  // so the parameter is not immediate
67  is_immediate = false;
68  break;
69  }
70  }
71  return is_immediate;
72 }
73 
74 double AM_PARAM::GetValue( const D_CODE* aDcode ) const
75 {
76  // In macros, actual values are sometimes given by an expression like:
77  // 0-$2/2-$4
78  // Because arithmetic predence is used, the parameters (values (double) and operators)
79  // are stored in a stack, with all numeric values converted to the actual values
80  // when they are defered parameters
81  // Each item is stored in a AM_PARAM_EVAL (a value or an operator)
82  //
83  // Then the stack with all values resolved is parsed and numeric values
84  // calculated according to the precedence of operators
85  double curr_value = 0.0;
86  parm_item_type op_code;
87 
89 
90  for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
91  {
92  AM_PARAM_ITEM item = m_paramStack[ii];
93 
94  switch( item.GetType() )
95  {
96  case ADD:
97  case SUB:
98  case MUL:
99  case DIV: // just an operator for next parameter value
100  case OPEN_PAR:
101  case CLOSE_PAR: // Priority modifiers: store in stack
102  op_code = item.GetType();
103  ops.push_back( AM_PARAM_EVAL( op_code ) );
104  break;
105 
106  case PUSHPARM:
107  // a defered value: get the actual parameter from the aDcode
108  if( aDcode ) // should be always true here
109  {
110  if( item.GetIndex() <= aDcode->GetParamCount() )
111  {
112  curr_value = aDcode->GetParam( item.GetIndex() );
113  }
114  else // Get parameter from local param definition
115  {
116  const APERTURE_MACRO * am_parent = aDcode->GetMacro();
117  curr_value = am_parent->GetLocalParam( aDcode, item.GetIndex() );
118  }
119  }
120  else
121  {
122  wxFAIL_MSG( "AM_PARAM::GetValue(): NULL param aDcode" );
123  }
124 
125  ops.push_back( AM_PARAM_EVAL( curr_value ) );
126  break;
127 
128  case PUSHVALUE: // a value is on the stack:
129  curr_value = item.GetValue();
130  ops.push_back( AM_PARAM_EVAL( curr_value ) );
131  break;
132 
133  default:
134  wxFAIL_MSG( wxString::Format( "AM_PARAM::GetValue(): dcode %d prm %d/%d: "
135  "unexpected type %d",
136  aDcode ? aDcode->m_Num_Dcode : -1, ii,
137  m_paramStack.size(), item.GetType() ) );
138  break;
139  }
140  }
141 
142  double result = Evaluate( ops );
143 
144  return result;
145 }
146 
152 void AM_PARAM::PushOperator( parm_item_type aType, double aValue )
153 {
154  AM_PARAM_ITEM item( aType, aValue);
155  m_paramStack.push_back( item );
156 }
157 
158 void AM_PARAM::PushOperator( parm_item_type aType, int aValue )
159 {
160  AM_PARAM_ITEM item( aType, aValue);
161  m_paramStack.push_back( item );
162 }
163 
177 bool AM_PARAM::ReadParam( char*& aText )
178 {
179  bool found = false;
180  int ivalue;
181  double dvalue;
182  bool end = false;
183 
184  while( !end )
185  {
186  switch( *aText )
187  {
188  case ',':
189  aText++;
190 
191  if( !found ) // happens when a string starts by ',' before any param
192  break; // just skip this separator
193 
195 
196  case '\n':
197  case '\r':
198  case 0: // EOL
199  case '*': // Terminator in a gerber command
200  end = true;
201  break;
202 
203  case ' ':
204  aText++;
205  break;
206 
207  case '$':
208  // defered value defined later, in ADD command which define defered parameters
209  ++aText;
210  ivalue = ReadInt( aText, false );
211  if( m_index < 1 )
212  SetIndex( ivalue );
213  PushOperator( PUSHPARM, ivalue );
214  found = true;
215  break;
216 
217  case '/':
218  PushOperator( DIV );
219  aText++;
220  break;
221 
222  case '(': // Open a block to evaluate an expression between '(' and ')'
224  aText++;
225  break;
226 
227  case ')': // close a block between '(' and ')'
229  aText++;
230  break;
231 
232  case 'x':
233  case 'X':
234  PushOperator( MUL );
235  aText++;
236  break;
237 
238  case '-':
239  case '+':
240  // Test if this is an operator between 2 params, or the sign of a value
241  if( m_paramStack.size() > 0 && !m_paramStack.back().IsOperator() )
242  { // Seems an operator
243  PushOperator( *aText == '+' ? ADD : SUB );
244  aText++;
245  }
246  else
247  { // seems the sign of a value
248  dvalue = ReadDouble( aText, false );
249  PushOperator( PUSHVALUE, dvalue );
250  found = true;
251  }
252  break;
253 
254  case '=': // A local definition found like $4=$3/2
255  // At this point, one defered parameter is expected to be read.
256  // this parameter value (the index) is stored in m_index.
257  // The list of items is cleared
258  aText++;
259  m_paramStack.clear();
260  found = false;
261  break;
262 
263  default:
264  dvalue = ReadDouble( aText, false );
265  PushOperator( PUSHVALUE, dvalue );
266  found = true;
267  break;
268  }
269  }
270 
271  return found;
272 }
std::vector< AM_PARAM_ITEM > m_paramStack
List of operands/operators to evaluate the actual value if a par def is $3/2, there are 3 items in st...
Definition: am_param.h:336
unsigned GetParamCount() const
Return the number of parameters stored in parameter list.
Definition: dcode.h:100
double GetValue(const D_CODE *aDcode) const
Definition: am_param.cpp:74
unsigned GetIndex() const
Definition: am_param.h:251
bool IsImmediate() const
Test if this AM_PARAM holds an immediate parameter or is a pointer into a parameter held by an owning...
Definition: am_param.cpp:59
parm_item_type GetType() const
Definition: am_param.h:246
double ReadDouble(char *&text, bool aSkipSeparator=true)
Read a double precision floating point number from an ASCII character buffer.
Hold an operand for an AM_PARAM as defined within standard RS274X.
Definition: am_param.h:219
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
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
double GetLocalParam(const D_CODE *aDcode, unsigned aParamId) const
Usually, parameters are defined inside the aperture primitive using immediate mode or deferred mode.
bool ReadParam(char *&aText)
Read one aperture macro parameter.
Definition: am_param.cpp:177
This file contains miscellaneous commonly used macros and functions.
void PushOperator(parm_item_type aType, double aValue)
Add an operator/operand to the current stack.
Definition: am_param.cpp:152
parm_item_type
Definition: am_param.h:148
int m_Num_Dcode
D code value ( >= 10 )
Definition: dcode.h:190
double GetParam(unsigned aIdx) const
Return a parameter stored in parameter list.
Definition: dcode.h:110
std::vector< AM_PARAM_EVAL > AM_PARAM_EVAL_STACK
Definition: am_param.h:210
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
This helper class hold a value or an arithmetic operator to calculate the final value of a aperture m...
Definition: am_param.h:160
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
int ReadInt(char *&text, bool aSkipSeparator=true)
Read an integer from an ASCII character buffer.
double GetValue() const
Definition: am_param.h:241
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:125
void SetIndex(int aIndex)
Definition: am_param.h:314
Support the "aperture macro" defined within standard RS274X.
Definition: am_primitive.h:167
int m_index
has meaning to define parameter local to an aperture macro
Definition: am_param.h:335
AM_PARAM()
Definition: am_param.cpp:49