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