You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							264 lines
						
					
					
						
							8.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							264 lines
						
					
					
						
							8.5 KiB
						
					
					
				
								/**
							 | 
						|
								 * @file am_param.cpp
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								 * This program source code file is part of KiCad, a free EDA CAD application.
							 | 
						|
								 *
							 | 
						|
								 * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
							 | 
						|
								 * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
							 | 
						|
								 * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
							 | 
						|
								 *
							 | 
						|
								 * This program is free software; you can redistribute it and/or
							 | 
						|
								 * modify it under the terms of the GNU General Public License
							 | 
						|
								 * as published by the Free Software Foundation; either version 2
							 | 
						|
								 * of the License, or (at your option) any later version.
							 | 
						|
								 *
							 | 
						|
								 * This program is distributed in the hope that it will be useful,
							 | 
						|
								 * but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						|
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								 * GNU General Public License for more details.
							 | 
						|
								 *
							 | 
						|
								 * You should have received a copy of the GNU General Public License
							 | 
						|
								 * along with this program; if not, you may find one here:
							 | 
						|
								 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
							 | 
						|
								 * or you may search the http://www.gnu.org website for the version 2 license,
							 | 
						|
								 * or you may write to the Free Software Foundation, Inc.,
							 | 
						|
								 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								#include <am_param.h>
							 | 
						|
								#include <am_primitive.h>
							 | 
						|
								
							 | 
						|
								extern int    ReadInt( char*& text, bool aSkipSeparator = true );
							 | 
						|
								extern double ReadDouble( char*& text, bool aSkipSeparator = true );
							 | 
						|
								extern double Evaluate( AM_PARAM_EVAL_STACK& aExp );
							 | 
						|
								
							 | 
						|
								/* Class AM_PARAM
							 | 
						|
								 * holds a parameter value for an "aperture macro" as defined within
							 | 
						|
								 * standard RS274X.  The parameter can be a constant, i.e. "immediate" parameter,
							 | 
						|
								 * or depend on some defered values, defined in a D_CODE, by the ADD command.
							 | 
						|
								 * Note the actual value could need an evaluation from an arithmetical expression
							 | 
						|
								 * items in the expression are stored in .
							 | 
						|
								 * A simple definition is just a value stored in one item in m_paramStack
							 | 
						|
								 */
							 | 
						|
								AM_PARAM::AM_PARAM( )
							 | 
						|
								{
							 | 
						|
								    m_index = -1;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Function IsImmediate
							 | 
						|
								 * tests if this AM_PARAM holds an immediate parameter or has parameter
							 | 
						|
								 * held by an owning D_CODE.
							 | 
						|
								 */
							 | 
						|
								bool AM_PARAM::IsImmediate() const
							 | 
						|
								{
							 | 
						|
								    bool is_immediate = true;
							 | 
						|
								    for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
							 | 
						|
								    {
							 | 
						|
								        if( m_paramStack[ii].IsDefered() )
							 | 
						|
								        {   // a defered value is found in operand list,
							 | 
						|
								            // so the parameter is not immediate
							 | 
						|
								            is_immediate = false;
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    return is_immediate;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								double AM_PARAM::GetValue( const D_CODE* aDcode ) const
							 | 
						|
								{
							 | 
						|
								    // In macros, actual values are sometimes given by an expression like:
							 | 
						|
								    // 0-$2/2-$4
							 | 
						|
								    // Because arithmetic predence is used, the parameters (values (double) and operators)
							 | 
						|
								    // are stored in a stack, with all numeric values converted to the actual values
							 | 
						|
								    // when they are defered parameters
							 | 
						|
								    // Each item is stored in a AM_PARAM_EVAL (a value or an operator)
							 | 
						|
								    //
							 | 
						|
								    // Then the stack with all values resolved is parsed and numeric values
							 | 
						|
								    // calculated according to the precedence of operators
							 | 
						|
								    double curr_value = 0.0;
							 | 
						|
								    parm_item_type op_code;
							 | 
						|
								
							 | 
						|
								    AM_PARAM_EVAL_STACK ops;
							 | 
						|
								
							 | 
						|
								    for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
							 | 
						|
								    {
							 | 
						|
								        AM_PARAM_ITEM item = m_paramStack[ii];
							 | 
						|
								
							 | 
						|
								        switch( item.GetType() )
							 | 
						|
								        {
							 | 
						|
								            case ADD:
							 | 
						|
								            case SUB:
							 | 
						|
								            case MUL:
							 | 
						|
								            case DIV:       // just an operator for next parameter value
							 | 
						|
								            case OPEN_PAR:
							 | 
						|
								            case CLOSE_PAR: // Priority modifiers: store in stack
							 | 
						|
								                op_code = item.GetType();
							 | 
						|
								                ops.push_back( AM_PARAM_EVAL( op_code ) );
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case PUSHPARM:
							 | 
						|
								                // a defered value: get the actual parameter from the aDcode
							 | 
						|
								                if( aDcode )    // should be always true here
							 | 
						|
								                {
							 | 
						|
								                    if( item.GetIndex() <= aDcode->GetParamCount() )
							 | 
						|
								                    {
							 | 
						|
								                        curr_value = aDcode->GetParam( item.GetIndex() );
							 | 
						|
								                    }
							 | 
						|
								                    else    // Get parameter from local param definition
							 | 
						|
								                    {
							 | 
						|
								                        const APERTURE_MACRO * am_parent = aDcode->GetMacro();
							 | 
						|
								                        curr_value = am_parent->GetLocalParam( aDcode, item.GetIndex() );
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    wxLogDebug( wxT( "AM_PARAM::GetValue(): NULL param aDcode\n" ) );
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                ops.push_back( AM_PARAM_EVAL( curr_value ) );
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case PUSHVALUE: // a value is on the stack:
							 | 
						|
								                curr_value = item.GetValue();
							 | 
						|
								                ops.push_back( AM_PARAM_EVAL( curr_value ) );
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            default:
							 | 
						|
								                wxLogDebug( "AM_PARAM::GetValue(): dcode %d prm %d/%d: unexpected type %d",
							 | 
						|
								                            aDcode ? aDcode->m_Num_Dcode : -1, ii, m_paramStack.size(), item.GetType() );
							 | 
						|
								                break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    double result = Evaluate( ops );
							 | 
						|
								
							 | 
						|
								    return result;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * add an operator/operand to the current stack
							 | 
						|
								 * aType = NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE
							 | 
						|
								 * aValue required only for PUSHVALUE (double) or PUSHPARM (int) aType.
							 | 
						|
								 */
							 | 
						|
								void AM_PARAM::PushOperator( parm_item_type aType, double aValue )
							 | 
						|
								{
							 | 
						|
								    AM_PARAM_ITEM item( aType, aValue);
							 | 
						|
								    m_paramStack.push_back( item );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								void AM_PARAM::PushOperator( parm_item_type aType, int aValue )
							 | 
						|
								{
							 | 
						|
								    AM_PARAM_ITEM item( aType, aValue);
							 | 
						|
								    m_paramStack.push_back( item );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Function ReadParam
							 | 
						|
								 * Read one aperture macro parameter
							 | 
						|
								 * a parameter can be:
							 | 
						|
								 *      a number
							 | 
						|
								 *      a reference to an aperture definition parameter value: $1 ot $3 ...
							 | 
						|
								 * a parameter definition can be complex and have operators between numbers and/or other parameter
							 | 
						|
								 * like $1+3 or $2x2..
							 | 
						|
								 * Note minus sign is not always an operator. It can be the sign of a value.
							 | 
						|
								 * Parameters are separated by a comma ( of finish by *)
							 | 
						|
								 * @param aText = pointer to the parameter to read. Will be modified to point to the next field
							 | 
						|
								 * @return true if a param is read, or false
							 | 
						|
								 */
							 | 
						|
								bool AM_PARAM::ReadParam( char*& aText  )
							 | 
						|
								{
							 | 
						|
								    bool found = false;
							 | 
						|
								    int ivalue;
							 | 
						|
								    double dvalue;
							 | 
						|
								    bool end = false;
							 | 
						|
								
							 | 
						|
								    while( !end )
							 | 
						|
								    {
							 | 
						|
								        switch( *aText )
							 | 
						|
								        {
							 | 
						|
								        case ',':
							 | 
						|
								            aText++;
							 | 
						|
								
							 | 
						|
								            if( !found )    // happens when a string starts by ',' before any param
							 | 
						|
								                break;      // just skip this separator
							 | 
						|
								            // fall through
							 | 
						|
								        case '\n':
							 | 
						|
								        case '\r':
							 | 
						|
								        case 0:     // EOL
							 | 
						|
								        case '*':   // Terminator in a gerber command
							 | 
						|
								            end = true;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case ' ':
							 | 
						|
								            aText++;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case '$':
							 | 
						|
								            // defered value defined later, in ADD command which define defered parameters
							 | 
						|
								            ++aText;
							 | 
						|
								            ivalue = ReadInt( aText, false );
							 | 
						|
								            if( m_index < 1 )
							 | 
						|
								                SetIndex( ivalue );
							 | 
						|
								            PushOperator( PUSHPARM, ivalue );
							 | 
						|
								            found = true;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case '/':
							 | 
						|
								            PushOperator( DIV );
							 | 
						|
								            aText++;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case '(':   // Open a block to evaluate an expression between '(' and ')'
							 | 
						|
								            PushOperator( OPEN_PAR );
							 | 
						|
								            aText++;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case ')':   // close a block between '(' and ')'
							 | 
						|
								            PushOperator( CLOSE_PAR );
							 | 
						|
								            aText++;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case 'x':
							 | 
						|
								        case 'X':
							 | 
						|
								            PushOperator( MUL );
							 | 
						|
								            aText++;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case '-':
							 | 
						|
								        case '+':
							 | 
						|
								            // Test if this is an operator between 2 params, or the sign of a value
							 | 
						|
								            if( m_paramStack.size() > 0 && !m_paramStack.back().IsOperator() )
							 | 
						|
								            {   // Seems an operator
							 | 
						|
								                PushOperator( *aText == '+' ? ADD : SUB );
							 | 
						|
								                aText++;
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {   // seems the sign of a value
							 | 
						|
								                dvalue = ReadDouble( aText, false );
							 | 
						|
								                PushOperator( PUSHVALUE, dvalue );
							 | 
						|
								                found = true;
							 | 
						|
								            }
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        case '=':   // A local definition found like $4=$3/2
							 | 
						|
								            // At this point, one defered parameter is expected to be read.
							 | 
						|
								            // this parameter value (the index) is stored in m_index.
							 | 
						|
								            // The list of items is cleared
							 | 
						|
								            aText++;
							 | 
						|
								            m_paramStack.clear();
							 | 
						|
								            found = false;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        default:
							 | 
						|
								           dvalue = ReadDouble( aText, false );
							 | 
						|
								            PushOperator( PUSHVALUE, dvalue );
							 | 
						|
								            found = true;
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return found;
							 | 
						|
								}
							 |