KiCad PCB EDA Suite
Loading...
Searching...
No Matches
am_param.cpp
Go to the documentation of this file.
1
4
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 <[email protected]>
10 * Copyright The 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, see <https://www.gnu.org/licenses/>.
24 */
25
26#include <am_param.h>
27#include <am_primitive.h>
28#include <aperture_macro.h>
29#include <macros.h>
30
31extern int ReadInt( char*& text, bool aSkipSeparator = true );
32extern double ReadDouble( char*& text, bool aSkipSeparator = true );
33extern double Evaluate( AM_PARAM_EVAL_STACK& aExp );
34
35
37{
38 m_index = -1;
39}
40
41
43{
44 bool is_immediate = true;
45 for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
46 {
47 if( m_paramStack[ii].IsDefered() )
48 { // a defered value is found in operand list,
49 // so the parameter is not immediate
50 is_immediate = false;
51 break;
52 }
53 }
54 return is_immediate;
55}
56
57
58double AM_PARAM::GetValueFromMacro( APERTURE_MACRO* aApertureMacro ) const
59{
60 // In macros, actual values are sometimes given by an expression like:
61 // 0-$2/2-$4
62 // Because arithmetic predence is used, the parameters (values (double) and operators)
63 // are stored in a stack, with all numeric values converted to the actual values
64 // when they are defered parameters
65 // Each item is stored in a AM_PARAM_EVAL (a value or an operator)
66 //
67 // Then the stack with all values resolved is parsed and numeric values
68 // calculated according to the precedence of operators
69 double curr_value = 0.0;
70 parm_item_type op_code;
71
73
74 for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
75 {
76 AM_PARAM_ITEM item = m_paramStack[ii];
77
78 switch( item.GetType() )
79 {
80 case ADD:
81 case SUB:
82 case MUL:
83 case DIV: // just an operator for next parameter value
84 case OPEN_PAR:
85 case CLOSE_PAR: // Priority modifiers: store in stack
86 op_code = item.GetType();
87 ops.emplace_back( op_code );
88 break;
89
90 case PUSHPARM:
91 // a defered value: get the actual parameter from the aperture macro
92 if( aApertureMacro ) // should be always true here
93 {
94 // Get the actual value
95 curr_value = aApertureMacro->GetLocalParamValue( item.GetIndex() );
96 }
97 else
98 {
99 wxFAIL_MSG( wxT( "AM_PARAM::GetValue(): NULL param aApertureMacro" ) );
100 }
101
102 ops.emplace_back( curr_value );
103 break;
104
105 case PUSHVALUE: // a value is on the stack:
106 curr_value = item.GetValue();
107 ops.emplace_back( curr_value );
108 break;
109
110 default:
111 wxFAIL_MSG( wxString::Format( wxT( "AM_PARAM::GetValue(): unexpected prm type %d" ),
112 item.GetType() ) );
113 break;
114 }
115 }
116
117 double result = Evaluate( ops );
118
119 return result;
120}
121
122
123void AM_PARAM::PushOperator( parm_item_type aType, double aValue )
124{
125 AM_PARAM_ITEM item( aType, aValue);
126 m_paramStack.push_back( item );
127}
128
129
130void AM_PARAM::PushOperator( parm_item_type aType, int aValue )
131{
132 AM_PARAM_ITEM item( aType, aValue);
133 m_paramStack.push_back( item );
134}
135
136
138{
139 bool found = false;
140 int ivalue;
141 double dvalue;
142 bool end = false;
143
144 while( !end )
145 {
146 switch( *aText )
147 {
148 case ',':
149 aText++;
150
151 if( !found ) // happens when a string starts by ',' before any param
152 break; // just skip this separator
153
155
156 case '\n':
157 case '\r':
158 case 0: // EOL
159 case '*': // Terminator in a gerber command
160 end = true;
161 break;
162
163 case ' ':
164 aText++;
165 break;
166
167 case '$':
168 // defered value defined later, in ADD command which define defered parameters
169 ++aText;
170 ivalue = ReadInt( aText, false );
171
172 if( m_index < 1 )
173 SetIndex( ivalue );
174
175 PushOperator( PUSHPARM, ivalue );
176 found = true;
177 break;
178
179 case '/':
180 PushOperator( DIV );
181 aText++;
182 break;
183
184 case '(': // Open a block to evaluate an expression between '(' and ')'
186 aText++;
187 break;
188
189 case ')': // close a block between '(' and ')'
191 aText++;
192 break;
193
194 case 'x':
195 case 'X':
196 PushOperator( MUL );
197 aText++;
198 break;
199
200 case '-':
201 case '+':
202 // Test if this is an operator between 2 params, or the sign of a value
203 if( m_paramStack.size() > 0 && !m_paramStack.back().IsOperator() )
204 { // Seems an operator
205 PushOperator( *aText == '+' ? ADD : SUB );
206 aText++;
207 }
208 else
209 { // seems the sign of a value
210 dvalue = ReadDouble( aText, false );
211 PushOperator( PUSHVALUE, dvalue );
212 found = true;
213 }
214 break;
215
216 case '=': // A local definition found like $4=$3/2
217 // At this point, one defered parameter is expected to be read.
218 // this parameter value (the index) is stored in m_index.
219 // The list of items is cleared
220 aText++;
221 m_paramStack.clear();
222 found = false;
223 break;
224
225 default:
226 dvalue = ReadDouble( aText, false );
227 PushOperator( PUSHVALUE, dvalue );
228 found = true;
229 break;
230 }
231 }
232
233 return found;
234}
double Evaluate(AM_PARAM_EVAL_STACK &aExp)
Evaluate an basic arithmetic expression (infix notation) with precedence The expression is a sequence...
Definition evaluate.cpp:98
int ReadInt(char *&text, bool aSkipSeparator=true)
Read an integer from an ASCII character buffer.
double ReadDouble(char *&text, bool aSkipSeparator=true)
Read a double precision floating point number from an ASCII character buffer.
parm_item_type
Definition am_param.h:145
@ OPEN_PAR
Definition am_param.h:146
@ MUL
Definition am_param.h:146
@ SUB
Definition am_param.h:146
@ CLOSE_PAR
Definition am_param.h:146
@ DIV
Definition am_param.h:146
@ PUSHVALUE
Definition am_param.h:146
@ ADD
Definition am_param.h:146
@ PUSHPARM
Definition am_param.h:146
std::vector< AM_PARAM_EVAL > AM_PARAM_EVAL_STACK
Definition am_param.h:206
Hold an operand for an AM_PARAM as defined within standard RS274X.
Definition am_param.h:216
double GetValue() const
Definition am_param.h:237
unsigned GetIndex() const
Definition am_param.h:247
parm_item_type GetType() const
Definition am_param.h:242
bool ReadParamFromAmDef(char *&aText)
Read one aperture macro parameter.
Definition am_param.cpp:137
void SetIndex(int aIndex)
Definition am_param.h:310
void PushOperator(parm_item_type aType, double aValue)
Add an operator/operand to the current stack.
Definition am_param.cpp:123
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:42
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:343
int m_index
has meaning to define parameter local to an aperture macro this is the id of a parameter defined like...
Definition am_param.h:337
double GetValueFromMacro(APERTURE_MACRO *aApertureMacro) const
Definition am_param.cpp:58
Support the "aperture macro" defined within standard RS274X.
double GetLocalParamValue(int aIndex)
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.