KiCad PCB EDA Suite
pcb_parser.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 CERN
5  * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <errno.h>
31 #include <common.h>
32 #include <confirm.h>
33 #include <macros.h>
34 #include <trigo.h>
35 #include <class_title_block.h>
36 
37 #include <class_board.h>
38 #include <class_dimension.h>
39 #include <class_drawsegment.h>
40 #include <class_edge_mod.h>
41 #include <class_mire.h>
42 #include <class_module.h>
43 #include <class_netclass.h>
44 #include <class_pad.h>
45 #include <class_track.h>
46 #include <class_zone.h>
47 #include <kicad_plugin.h>
48 #include <pcb_plot_params_parser.h>
49 #include <pcb_plot_params.h>
50 #include <zones.h>
51 #include <pcb_parser.h>
52 
53 using namespace PCB_KEYS_T;
54 
55 
57 {
58  m_tooRecent = false;
59  m_requiredVersion = 0;
60  m_layerIndices.clear();
61  m_layerMasks.clear();
62 
63  // Add untranslated default (i.e. english) layernames.
64  // Some may be overridden later if parsing a board rather than a footprint.
65  // The english name will survive if parsing only a footprint.
66  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
67  {
68  std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
69 
70  m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
71  m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
72  }
73 
74  m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
75  m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
76  m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
77  m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
78  m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
79  m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
80  m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
81  m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
82 
83  // This is for the first pretty & *.kicad_pcb formats, which had
84  // Inner1_Cu - Inner14_Cu with the numbering sequence
85  // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
86  // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
87  // kept the gap between one of the outside layers and the last cu internal.
88 
89  for( int i=1; i<=14; ++i )
90  {
91  std::string key = StrPrintf( "Inner%d.Cu", i );
92 
93  m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
94  }
95 
96 #if defined(DEBUG) && 0
97  printf( "m_layerMasks:\n" );
98  for( LSET_MAP::const_iterator it = m_layerMasks.begin(); it != m_layerMasks.end(); ++it )
99  {
100  printf( " [%s] == 0x%s\n", it->first.c_str(), it->second.FmtHex().c_str() );
101  }
102 
103  printf( "m_layerIndices:\n" );
104  for( LAYER_ID_MAP::const_iterator it = m_layerIndices.begin(); it != m_layerIndices.end(); ++it )
105  {
106  printf( " [%s] == %d\n", it->first.c_str(), it->second );
107  }
108 #endif
109 
110 }
111 
112 
113 void PCB_PARSER::pushValueIntoMap( int aIndex, int aValue )
114 {
115  // Add aValue in netcode mapping (m_netCodes) at index aNetCode
116  // ensure there is room in m_netCodes for that, and add room if needed.
117 
118  if( (int)m_netCodes.size() <= aIndex )
119  m_netCodes.resize( aIndex+1 );
120 
121  m_netCodes[aIndex] = aValue;
122 }
123 
125 {
126  char* tmp;
127 
128  errno = 0;
129 
130  double fval = strtod( CurText(), &tmp );
131 
132  if( errno )
133  {
134  wxString error;
135  error.Printf( _( "invalid floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
136  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
137 
138  THROW_IO_ERROR( error );
139  }
140 
141  if( CurText() == tmp )
142  {
143  wxString error;
144  error.Printf( _( "missing floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
145  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
146 
147  THROW_IO_ERROR( error );
148  }
149 
150  return fval;
151 }
152 
153 
155 {
156  T token = NextTok();
157 
158  if( token == T_yes )
159  return true;
160  else if( token == T_no )
161  return false;
162  else
163  Expecting( "yes or no" );
164 
165  return false;
166 }
167 
168 
170 {
171  if( NextTok() != T_version )
172  Expecting( GetTokenText( T_version ) );
173 
174  int pcb_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
175 
176  NeedRIGHT();
177 
178  return pcb_version;
179 }
180 
181 
183 {
184  int year, month, day;
185 
186  year = m_requiredVersion / 10000;
187  month = ( m_requiredVersion / 100 ) - ( year * 100 );
188  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
189 
190  // wx throws an assertion, not a catchable exception, when the date is invalid.
191  // User input shouldn't give wx asserts, so check manually and throw a proper
192  // error instead
193  if( day <= 0 || month <= 0 || month > 12 ||
194  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
195  {
196  wxString err;
197  err.Printf( _( "cannot interpret date code %d" ), m_requiredVersion );
198  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
199  }
200 
201  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
202  return date.FormatDate();
203 }
204 
205 
207 {
208  if( CurTok() != T_LEFT )
209  NeedLEFT();
210 
211  wxPoint pt;
212  T token = NextTok();
213 
214  if( token != T_xy )
215  Expecting( T_xy );
216 
217  pt.x = parseBoardUnits( "X coordinate" );
218  pt.y = parseBoardUnits( "Y coordinate" );
219 
220  NeedRIGHT();
221 
222  return pt;
223 }
224 
225 
226 void PCB_PARSER::parseXY( int* aX, int* aY )
227 {
228  wxPoint pt = parseXY();
229 
230  if( aX )
231  *aX = pt.x;
232 
233  if( aY )
234  *aY = pt.y;
235 }
236 
237 
239 {
240  wxCHECK_RET( CurTok() == T_effects,
241  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
242 
243  T token;
244 
245  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
246  {
247  if( token == T_LEFT )
248  token = NextTok();
249 
250  switch( token )
251  {
252  case T_font:
253  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
254  {
255  if( token == T_LEFT )
256  continue;
257 
258  switch( token )
259  {
260  case T_size:
261  {
262  wxSize sz;
263  sz.SetHeight( parseBoardUnits( "text height" ) );
264  sz.SetWidth( parseBoardUnits( "text width" ) );
265  aText->SetTextSize( sz );
266  NeedRIGHT();
267  }
268  break;
269 
270  case T_thickness:
271  aText->SetThickness( parseBoardUnits( "text thickness" ) );
272  NeedRIGHT();
273  break;
274 
275  case T_bold:
276  aText->SetBold( true );
277  break;
278 
279  case T_italic:
280  aText->SetItalic( true );
281  break;
282 
283  default:
284  Expecting( "size, bold, or italic" );
285  }
286  }
287  break;
288 
289  case T_justify:
290  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
291  {
292  if( token == T_LEFT )
293  continue;
294 
295  switch( token )
296  {
297  case T_left:
299  break;
300 
301  case T_right:
303  break;
304 
305  case T_top:
307  break;
308 
309  case T_bottom:
311  break;
312 
313  case T_mirror:
314  aText->SetMirrored( true );
315  break;
316 
317  default:
318  Expecting( "left, right, top, bottom, or mirror" );
319  }
320 
321  }
322  break;
323 
324  case T_hide:
325  aText->SetVisible( false );
326  break;
327 
328  default:
329  Expecting( "font, justify, or hide" );
330  }
331  }
332 }
333 
334 
336 {
337  wxCHECK_MSG( CurTok() == T_model, NULL,
338  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as S3D_INFO." ) );
339 
340  T token;
341 
342  S3D_INFO* n3D = new S3D_INFO;
343  NeedSYMBOLorNUMBER();
344  n3D->m_Filename = FromUTF8();
345 
346  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
347  {
348  if( token != T_LEFT )
349  Expecting( T_LEFT );
350 
351  token = NextTok();
352 
353  switch( token )
354  {
355  case T_at:
356  NeedLEFT();
357  token = NextTok();
358 
359  if( token != T_xyz )
360  Expecting( T_xyz );
361 
362  n3D->m_Offset.x = parseDouble( "x value" );
363  n3D->m_Offset.y = parseDouble( "y value" );
364  n3D->m_Offset.z = parseDouble( "z value" );
365  NeedRIGHT();
366  break;
367 
368  case T_scale:
369  NeedLEFT();
370  token = NextTok();
371 
372  if( token != T_xyz )
373  Expecting( T_xyz );
374 
375  n3D->m_Scale.x = parseDouble( "x value" );
376  n3D->m_Scale.y = parseDouble( "y value" );
377  n3D->m_Scale.z = parseDouble( "z value" );
378  NeedRIGHT();
379  break;
380 
381  case T_rotate:
382  NeedLEFT();
383  token = NextTok();
384 
385  if( token != T_xyz )
386  Expecting( T_xyz );
387 
388  n3D->m_Rotation.x = parseDouble( "x value" );
389  n3D->m_Rotation.y = parseDouble( "y value" );
390  n3D->m_Rotation.z = parseDouble( "z value" );
391  NeedRIGHT();
392  break;
393 
394  default:
395  Expecting( "at, scale, or rotate" );
396  }
397 
398  NeedRIGHT();
399  }
400 
401  return n3D;
402 }
403 
404 
406 {
407  T token;
408  BOARD_ITEM* item;
409  LOCALE_IO toggle;
410 
411  // MODULEs can be prefixed with an initial block of single line comments and these
412  // are kept for Format() so they round trip in s-expression form. BOARDs might
413  // eventually do the same, but currently do not.
414  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
415 
416  token = CurTok();
417 
418  if( token != T_LEFT )
419  Expecting( T_LEFT );
420 
421  switch( NextTok() )
422  {
423  case T_kicad_pcb:
424  if( m_board == NULL )
425  m_board = new BOARD();
426 
427  item = (BOARD_ITEM*) parseBOARD();
428  break;
429 
430  case T_module:
431  item = (BOARD_ITEM*) parseMODULE( initial_comments.release() );
432  break;
433 
434  default:
435  wxString err;
436  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
437  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
438  }
439 
440  return item;
441 }
442 
443 
445 {
446  try
447  {
448  return parseBOARD_unchecked();
449  }
450  catch( const PARSE_ERROR& parse_error )
451  {
452  if( m_tooRecent )
453  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
454  else
455  throw;
456  }
457 }
458 
459 
461 {
462  T token;
463 
464  parseHeader();
465 
466  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
467  {
468  if( token != T_LEFT )
469  Expecting( T_LEFT );
470 
471  token = NextTok();
472 
473  switch( token )
474  {
475  case T_general:
476  parseGeneralSection();
477  break;
478 
479  case T_page:
480  parsePAGE_INFO();
481  break;
482 
483  case T_title_block:
484  parseTITLE_BLOCK();
485  break;
486 
487  case T_layers:
488  parseLayers();
489  break;
490 
491  case T_setup:
492  parseSetup();
493  break;
494 
495  case T_net:
496  parseNETINFO_ITEM();
497  break;
498 
499  case T_net_class:
500  parseNETCLASS();
501  break;
502 
503  case T_gr_arc:
504  case T_gr_circle:
505  case T_gr_curve:
506  case T_gr_line:
507  case T_gr_poly:
508  m_board->Add( parseDRAWSEGMENT(), ADD_APPEND );
509  break;
510 
511  case T_gr_text:
512  m_board->Add( parseTEXTE_PCB(), ADD_APPEND );
513  break;
514 
515  case T_dimension:
516  m_board->Add( parseDIMENSION(), ADD_APPEND );
517  break;
518 
519  case T_module:
520  m_board->Add( parseMODULE(), ADD_APPEND );
521  break;
522 
523  case T_segment:
524  m_board->Add( parseTRACK(), ADD_APPEND );
525  break;
526 
527  case T_via:
528  m_board->Add( parseVIA(), ADD_APPEND );
529  break;
530 
531  case T_zone:
532  m_board->Add( parseZONE_CONTAINER(), ADD_APPEND );
533  break;
534 
535  case T_target:
536  m_board->Add( parsePCB_TARGET(), ADD_APPEND );
537  break;
538 
539  default:
540  wxString err;
541  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
542  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
543  }
544  }
545 
546  return m_board;
547 }
548 
549 
551 {
552  wxCHECK_RET( CurTok() == T_kicad_pcb,
553  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
554 
555  NeedLEFT();
556 
557  T tok = NextTok();
558  if( tok == T_version )
559  {
560  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
561  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
562  NeedRIGHT();
563 
564  // Skip the host name and host build version information.
565  NeedLEFT();
566  NeedSYMBOL();
567  NeedSYMBOL();
568  NeedSYMBOL();
569  NeedRIGHT();
570  }
571  else
572  {
573  m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
574  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
575 
576  // Skip the host name and host build version information.
577  NeedSYMBOL();
578  NeedSYMBOL();
579  NeedRIGHT();
580  }
581 
582  m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
583 }
584 
585 
587 {
588  wxCHECK_RET( CurTok() == T_general,
589  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
590  wxT( " as a general section." ) );
591 
592  T token;
593 
594  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
595  {
596  if( token != T_LEFT )
597  Expecting( T_LEFT );
598 
599  token = NextTok();
600 
601  switch( token )
602  {
603  case T_thickness:
604  m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) );
605  NeedRIGHT();
606  break;
607 
608  case T_nets:
609  m_netCodes.resize( parseInt( "nets number" ) );
610  NeedRIGHT();
611  break;
612 
613  case T_no_connects:
614  // ignore
615  parseInt( "no connect count" );
616  NeedRIGHT();
617  break;
618 
619  default: // Skip everything but the board thickness.
620  //wxLogDebug( wxT( "Skipping general section token %s " ), GetChars( GetTokenString( token ) ) );
621 
622  while( ( token = NextTok() ) != T_RIGHT )
623  {
624  if( !IsSymbol( token ) && token != T_NUMBER )
625  Expecting( "symbol or number" );
626  }
627  }
628  }
629 }
630 
631 
633 {
634  wxCHECK_RET( CurTok() == T_page,
635  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
636 
637  T token;
638  PAGE_INFO pageInfo;
639 
640  NeedSYMBOL();
641 
642  wxString pageType = FromUTF8();
643 
644  if( !pageInfo.SetType( pageType ) )
645  {
646  wxString err;
647  err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
648  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
649  }
650 
651  if( pageType == PAGE_INFO::Custom )
652  {
653  double width = parseDouble( "width" ); // width in mm
654 
655  // Perform some controls to avoid crashes if the size is edited by hands
656  if( width < 100.0 )
657  width = 100.0;
658  else if( width > 1200.0 )
659  width = 1200.0;
660 
661  double height = parseDouble( "height" ); // height in mm
662 
663  if( height < 100.0 )
664  height = 100.0;
665  else if( height > 1200.0 )
666  height = 1200.0;
667 
668  pageInfo.SetWidthMils( Mm2mils( width ) );
669  pageInfo.SetHeightMils( Mm2mils( height ) );
670  }
671 
672  token = NextTok();
673 
674  if( token == T_portrait )
675  {
676  pageInfo.SetPortrait( true );
677  NeedRIGHT();
678  }
679  else if( token != T_RIGHT )
680  {
681  Expecting( "portrait|)" );
682  }
683 
684  m_board->SetPageSettings( pageInfo );
685 }
686 
687 
689 {
690  wxCHECK_RET( CurTok() == T_title_block,
691  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
692  wxT( " as TITLE_BLOCK." ) );
693 
694  T token;
695  TITLE_BLOCK titleBlock;
696 
697  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
698  {
699  if( token != T_LEFT )
700  Expecting( T_LEFT );
701 
702  token = NextTok();
703 
704  switch( token )
705  {
706  case T_title:
707  NextTok();
708  titleBlock.SetTitle( FromUTF8() );
709  break;
710 
711  case T_date:
712  NextTok();
713  titleBlock.SetDate( FromUTF8() );
714  break;
715 
716  case T_rev:
717  NextTok();
718  titleBlock.SetRevision( FromUTF8() );
719  break;
720 
721  case T_company:
722  NextTok();
723  titleBlock.SetCompany( FromUTF8() );
724  break;
725 
726  case T_comment:
727  {
728  int commentNumber = parseInt( "comment" );
729 
730  switch( commentNumber )
731  {
732  case 1:
733  NextTok();
734  titleBlock.SetComment1( FromUTF8() );
735  break;
736 
737  case 2:
738  NextTok();
739  titleBlock.SetComment2( FromUTF8() );
740  break;
741 
742  case 3:
743  NextTok();
744  titleBlock.SetComment3( FromUTF8() );
745  break;
746 
747  case 4:
748  NextTok();
749  titleBlock.SetComment4( FromUTF8() );
750  break;
751 
752  default:
753  wxString err;
754  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
755  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
756  }
757  }
758  break;
759 
760  default:
761  Expecting( "title, date, rev, company, or comment" );
762  }
763 
764  NeedRIGHT();
765  }
766 
767  m_board->SetTitleBlock( titleBlock );
768 }
769 
770 
772 {
773  T token;
774 
775  std::string name;
776  std::string type;
777  bool isVisible = true;
778 
779  aLayer->clear();
780 
781  if( CurTok() != T_LEFT )
782  Expecting( T_LEFT );
783 
784  // this layer_num is not used, we DO depend on LAYER_T however.
785  LAYER_NUM layer_num = parseInt( "layer index" );
786 
787  NeedSYMBOLorNUMBER();
788  name = CurText();
789 
790  NeedSYMBOL();
791  type = CurText();
792 
793  token = NextTok();
794 
795  if( token == T_hide )
796  {
797  isVisible = false;
798  NeedRIGHT();
799  }
800  else if( token != T_RIGHT )
801  {
802  Expecting( "hide or )" );
803  }
804 
805  aLayer->m_name = FROM_UTF8( name.c_str() );
806  aLayer->m_type = LAYER::ParseType( type.c_str() );
807  aLayer->m_number = layer_num;
808  aLayer->m_visible = isVisible;
809 }
810 
811 
812 
814 {
815  wxCHECK_RET( CurTok() == T_layers,
816  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
817 
818  T token;
819  LSET visibleLayers;
820  LSET enabledLayers;
821  int copperLayerCount = 0;
822  LAYER layer;
823 
824  std::vector<LAYER> cu;
825 
826  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
827  {
828  parseLayer( &layer );
829 
830  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
831  break;
832 
833  cu.push_back( layer ); // it's copper
834  }
835 
836  // All Cu layers are parsed, but not the non-cu layers here.
837 
838  // The original *.kicad_pcb file format and the inverted
839  // Cu stack format both have all the Cu layers first, so use this
840  // trick to handle either. The layer number in the (layers ..)
841  // s-expression element are ignored.
842  if( cu.size() )
843  {
844  // Rework the layer numbers, which changed when the Cu stack
845  // was flipped. So we instead use position in the list.
846  cu[cu.size()-1].m_number = B_Cu;
847 
848  for( unsigned i=0; i < cu.size()-1; ++i )
849  {
850  cu[i].m_number = i;
851  }
852 
853  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
854  {
855  enabledLayers.set( it->m_number );
856 
857  if( it->m_visible )
858  visibleLayers.set( it->m_number );
859 
860  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
861 
862  UTF8 name = it->m_name;
863 
864  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
865  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
866  }
867 
868  copperLayerCount = cu.size();
869  }
870 
871  // process non-copper layers
872  while( token != T_RIGHT )
873  {
874  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
875 
876  if( it == m_layerIndices.end() )
877  {
878  wxString error = wxString::Format(
879  _( "Layer '%s' in file '%s' at line %d, is not in fixed layer hash" ),
880  GetChars( layer.m_name ),
881  GetChars( CurSource() ),
882  CurLineNumber(),
883  CurOffset()
884  );
885 
886  THROW_IO_ERROR( error );
887  }
888 
889  layer.m_number = it->second;
890 
891  enabledLayers.set( layer.m_number );
892 
893  if( layer.m_visible )
894  visibleLayers.set( layer.m_number );
895 
896  // DBG( printf( "aux m_visible:%s\n", layer.m_visible ? "true" : "false" );)
897 
898  m_board->SetLayerDescr( it->second, layer );
899 
900  token = NextTok();
901 
902  if( token != T_LEFT )
903  break;
904 
905  parseLayer( &layer );
906  }
907 
908  // We need at least 2 copper layers and there must be an even number of them.
909  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
910  {
911  wxString err = wxString::Format(
912  _( "%d is not a valid layer count" ), copperLayerCount );
913 
914  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
915  }
916 
917  m_board->SetCopperLayerCount( copperLayerCount );
918  m_board->SetEnabledLayers( enabledLayers );
919 
920  // call SetEnabledLayers before SetVisibleLayers()
921  m_board->SetVisibleLayers( visibleLayers );
922 }
923 
924 
925 template<class T, class M>
926 T PCB_PARSER::lookUpLayer( const M& aMap )
927 {
928  // avoid constructing another std::string, use lexer's directly
929  typename M::const_iterator it = aMap.find( curText );
930 
931  if( it == aMap.end() )
932  {
933 #if 0 && defined(DEBUG)
934  // dump the whole darn table, there's something wrong with it.
935  for( it = aMap.begin(); it != aMap.end(); ++it )
936  {
937  wxLogDebug( &aMap == (void*)&m_layerIndices ? wxT( "lm[%s] = %d" ) :
938  wxT( "lm[%s] = %08X" ), it->first.c_str(), it->second );
939  }
940 #endif
941 
942  wxString error = wxString::Format( _(
943  "Layer '%s' in file\n"
944  "'%s'\n"
945  "at line %d, position %d\n"
946  "was not defined in the layers section"
947  ),
948  GetChars( FROM_UTF8( CurText() ) ),
949  GetChars( CurSource() ),
950  CurLineNumber(), CurOffset() );
951 
952  THROW_IO_ERROR( error );
953  }
954 
955  return it->second;
956 }
957 
958 
960 {
961  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
962  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
963 
964  NextTok();
965 
966  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
967 
968  // Handle closing ) in object parser.
969 
970  return layerIndex;
971 }
972 
973 
975 {
976  wxCHECK_MSG( CurTok() == T_layers, LSET(),
977  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
978  wxT( " as item layer mask." ) );
979 
980  LSET layerMask;
981 
982  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
983  {
984  LSET mask = lookUpLayer<LSET>( m_layerMasks );
985  layerMask |= mask;
986  }
987 
988  return layerMask;
989 }
990 
991 
993 {
994  wxCHECK_RET( CurTok() == T_setup,
995  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
996 
997  T token;
998  NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault();
999  // TODO Orson: is it really necessary to first operate on a copy and then apply it?
1000  // would not it be better to use reference here and apply all the changes instantly?
1001  BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings();
1002  ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();
1003 
1004  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1005  {
1006  if( token != T_LEFT )
1007  Expecting( T_LEFT );
1008 
1009  token = NextTok();
1010 
1011  switch( token )
1012  {
1013  case T_last_trace_width: // not used now
1014  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1015  NeedRIGHT();
1016  break;
1017 
1018  case T_user_trace_width:
1019  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1020  NeedRIGHT();
1021  break;
1022 
1023  case T_trace_clearance:
1024  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1025  NeedRIGHT();
1026  break;
1027 
1028  case T_zone_clearance:
1029  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1030  NeedRIGHT();
1031  break;
1032 
1033  case T_zone_45_only:
1034  zoneSettings.m_Zone_45_Only = parseBool();
1035  NeedRIGHT();
1036  break;
1037 
1038  case T_trace_min:
1039  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1040  NeedRIGHT();
1041  break;
1042 
1043  case T_segment_width:
1044  designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width );
1045  NeedRIGHT();
1046  break;
1047 
1048  case T_edge_width:
1049  designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width );
1050  NeedRIGHT();
1051  break;
1052 
1053  case T_via_size:
1054  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1055  NeedRIGHT();
1056  break;
1057 
1058  case T_via_drill:
1059  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1060  NeedRIGHT();
1061  break;
1062 
1063  case T_via_min_size:
1064  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1065  NeedRIGHT();
1066  break;
1067 
1068  case T_via_min_drill:
1069  designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill );
1070  NeedRIGHT();
1071  break;
1072 
1073  case T_user_via:
1074  {
1075  int viaSize = parseBoardUnits( "user via size" );
1076  int viaDrill = parseBoardUnits( "user via drill" );
1077  designSettings.m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) );
1078  NeedRIGHT();
1079  }
1080  break;
1081 
1082  case T_uvia_size:
1083  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1084  NeedRIGHT();
1085  break;
1086 
1087  case T_uvia_drill:
1088  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1089  NeedRIGHT();
1090  break;
1091 
1092  case T_uvias_allowed:
1093  designSettings.m_MicroViasAllowed = parseBool();
1094  NeedRIGHT();
1095  break;
1096 
1098  designSettings.m_BlindBuriedViaAllowed = parseBool();
1099  NeedRIGHT();
1100  break;
1101 
1102  case T_uvia_min_size:
1103  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1104  NeedRIGHT();
1105  break;
1106 
1107  case T_uvia_min_drill:
1108  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1109  NeedRIGHT();
1110  break;
1111 
1112  case T_pcb_text_width:
1113  designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width );
1114  NeedRIGHT();
1115  break;
1116 
1117  case T_pcb_text_size:
1118  designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" );
1119  designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" );
1120  NeedRIGHT();
1121  break;
1122 
1123  case T_mod_edge_width:
1124  designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width );
1125  NeedRIGHT();
1126  break;
1127 
1128  case T_mod_text_size:
1129  designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" );
1130  designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" );
1131  NeedRIGHT();
1132  break;
1133 
1134  case T_mod_text_width:
1135  designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width );
1136  NeedRIGHT();
1137  break;
1138 
1139  case T_pad_size:
1140  {
1141  wxSize sz;
1142  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1143  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1144  designSettings.m_Pad_Master.SetSize( sz );
1145  NeedRIGHT();
1146  }
1147  break;
1148 
1149  case T_pad_drill:
1150  {
1151  int drillSize = parseBoardUnits( T_pad_drill );
1152  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1153  NeedRIGHT();
1154  }
1155  break;
1156 
1158  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1159  NeedRIGHT();
1160  break;
1161 
1163  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1164  NeedRIGHT();
1165  break;
1166 
1168  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1169  NeedRIGHT();
1170  break;
1171 
1174  NeedRIGHT();
1175  break;
1176 
1177  case T_aux_axis_origin:
1178  {
1179  int x = parseBoardUnits( "auxiliary origin X" );
1180  int y = parseBoardUnits( "auxiliary origin Y" );
1181  // m_board->SetAuxOrigin( wxPoint( x, y ) ); gets overwritten via SetDesignSettings below
1182  designSettings.m_AuxOrigin = wxPoint( x, y );
1183  NeedRIGHT();
1184  }
1185  break;
1186 
1187  case T_grid_origin:
1188  {
1189  int x = parseBoardUnits( "grid origin X" );
1190  int y = parseBoardUnits( "grid origin Y" );
1191  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten SetDesignSettings below
1192  designSettings.m_GridOrigin = wxPoint( x, y );
1193  NeedRIGHT();
1194  }
1195  break;
1196 
1197  case T_visible_elements:
1198  designSettings.SetVisibleElements( parseHex() | MIN_VISIBILITY_MASK );
1199  NeedRIGHT();
1200  break;
1201 
1202  case T_pcbplotparams:
1203  {
1204  PCB_PLOT_PARAMS plotParams;
1205  PCB_PLOT_PARAMS_PARSER parser( reader );
1206  // parser must share the same current line as our current PCB parser
1207  // synchronize it.
1208  parser.SyncLineReaderWith( *this );
1209 
1210  plotParams.Parse( &parser );
1211  SyncLineReaderWith( parser );
1212 
1213  m_board->SetPlotOptions( plotParams );
1214  }
1215  break;
1216 
1217  default:
1218  Unexpected( CurText() );
1219  }
1220  }
1221 
1222  m_board->SetDesignSettings( designSettings );
1223  m_board->SetZoneSettings( zoneSettings );
1224 }
1225 
1226 
1228 {
1229  wxCHECK_RET( CurTok() == T_net,
1230  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
1231 
1232  int netCode = parseInt( "net number" );
1233 
1234  NeedSYMBOLorNUMBER();
1235  wxString name = FromUTF8();
1236 
1237  NeedRIGHT();
1238 
1239  // net 0 should be already in list, so store this net
1240  // if it is not the net 0, or if the net 0 does not exists.
1241  // (TODO: a better test.)
1242  if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) )
1243  {
1244  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
1245  m_board->Add( net );
1246 
1247  // Store the new code mapping
1248  pushValueIntoMap( netCode, net->GetNet() );
1249  }
1250 }
1251 
1252 
1254 {
1255  wxCHECK_RET( CurTok() == T_net_class,
1256  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
1257 
1258  T token;
1259 
1260  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
1261 
1262  // Read netclass name (can be a name or just a number like track width)
1263  NeedSYMBOLorNUMBER();
1264  nc->SetName( FromUTF8() );
1265  NeedSYMBOL();
1266  nc->SetDescription( FromUTF8() );
1267 
1268  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1269  {
1270  if( token != T_LEFT )
1271  Expecting( T_LEFT );
1272 
1273  token = NextTok();
1274 
1275  switch( token )
1276  {
1277  case T_clearance:
1278  nc->SetClearance( parseBoardUnits( T_clearance ) );
1279  break;
1280 
1281  case T_trace_width:
1282  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
1283  break;
1284 
1285  case T_via_dia:
1286  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
1287  break;
1288 
1289  case T_via_drill:
1290  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
1291  break;
1292 
1293  case T_uvia_dia:
1294  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
1295  break;
1296 
1297  case T_uvia_drill:
1298  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1299  break;
1300 
1301  case T_diff_pair_width:
1302  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
1303  break;
1304 
1305  case T_diff_pair_gap:
1306  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
1307  break;
1308 
1309  case T_add_net:
1310  NeedSYMBOLorNUMBER();
1311  nc->Add( FromUTF8() );
1312  break;
1313 
1314  default:
1315  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, diff_pair_width, diff_pair_gap or add_net" );
1316  }
1317 
1318  NeedRIGHT();
1319  }
1320 
1321  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
1322  {
1323  // Must have been a name conflict, this is a bad board file.
1324  // User may have done a hand edit to the file.
1325 
1326  // unique_ptr will delete nc on this code path
1327 
1328  wxString error;
1329  error.Printf( _( "duplicate NETCLASS name '%s' in file <%s> at line %d, offset %d" ),
1330  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
1331  THROW_IO_ERROR( error );
1332  }
1333 }
1334 
1335 
1337 {
1338  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
1339  CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
1340  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
1341 
1342  T token;
1343  wxPoint pt;
1344  std::unique_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) );
1345 
1346  switch( CurTok() )
1347  {
1348  case T_gr_arc:
1349  segment->SetShape( S_ARC );
1350  NeedLEFT();
1351  token = NextTok();
1352 
1353  // the start keyword actually gives the arc center
1354  // Allows also T_center for future change
1355  if( token != T_start && token != T_center )
1356  Expecting( T_start );
1357 
1358  pt.x = parseBoardUnits( "X coordinate" );
1359  pt.y = parseBoardUnits( "Y coordinate" );
1360  segment->SetCenter( pt );
1361  NeedRIGHT();
1362  NeedLEFT();
1363  token = NextTok();
1364 
1365  if( token != T_end ) // the end keyword actually gives the starting point of the arc
1366  Expecting( T_end );
1367 
1368  pt.x = parseBoardUnits( "X coordinate" );
1369  pt.y = parseBoardUnits( "Y coordinate" );
1370  segment->SetArcStart( pt );
1371  NeedRIGHT();
1372  break;
1373 
1374  case T_gr_circle:
1375  segment->SetShape( S_CIRCLE );
1376  NeedLEFT();
1377  token = NextTok();
1378 
1379  if( token != T_center )
1380  Expecting( T_center );
1381 
1382  pt.x = parseBoardUnits( "X coordinate" );
1383  pt.y = parseBoardUnits( "Y coordinate" );
1384  segment->SetCenter( pt );
1385  NeedRIGHT();
1386  NeedLEFT();
1387 
1388  token = NextTok();
1389 
1390  if( token != T_end )
1391  Expecting( T_end );
1392 
1393  pt.x = parseBoardUnits( "X coordinate" );
1394  pt.y = parseBoardUnits( "Y coordinate" );
1395  segment->SetEnd( pt );
1396  NeedRIGHT();
1397  break;
1398 
1399  case T_gr_curve:
1400  segment->SetShape( S_CURVE );
1401  NeedLEFT();
1402  token = NextTok();
1403 
1404  if( token != T_pts )
1405  Expecting( T_pts );
1406 
1407  segment->SetStart( parseXY() );
1408  segment->SetBezControl1( parseXY() );
1409  segment->SetBezControl2( parseXY() );
1410  segment->SetEnd( parseXY() );
1411  NeedRIGHT();
1412  break;
1413 
1414  case T_gr_line:
1415  // Default DRAWSEGMENT type is S_SEGMENT.
1416  NeedLEFT();
1417  token = NextTok();
1418 
1419  if( token != T_start )
1420  Expecting( T_start );
1421 
1422  pt.x = parseBoardUnits( "X coordinate" );
1423  pt.y = parseBoardUnits( "Y coordinate" );
1424  segment->SetStart( pt );
1425  NeedRIGHT();
1426  NeedLEFT();
1427  token = NextTok();
1428 
1429  if( token != T_end )
1430  Expecting( T_end );
1431 
1432  pt.x = parseBoardUnits( "X coordinate" );
1433  pt.y = parseBoardUnits( "Y coordinate" );
1434  segment->SetEnd( pt );
1435  NeedRIGHT();
1436  break;
1437 
1438  case T_gr_poly:
1439  {
1440  segment->SetShape( S_POLYGON );
1441  NeedLEFT();
1442  token = NextTok();
1443 
1444  if( token != T_pts )
1445  Expecting( T_pts );
1446 
1447  std::vector< wxPoint > pts;
1448 
1449  while( (token = NextTok()) != T_RIGHT )
1450  pts.push_back( parseXY() );
1451 
1452  segment->SetPolyPoints( pts );
1453  }
1454  break;
1455 
1456  default:
1457  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
1458  }
1459 
1460  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1461  {
1462  if( token != T_LEFT )
1463  Expecting( T_LEFT );
1464 
1465  token = NextTok();
1466 
1467  switch( token )
1468  {
1469  case T_angle:
1470  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
1471  break;
1472 
1473  case T_layer:
1474  segment->SetLayer( parseBoardItemLayer() );
1475  break;
1476 
1477  case T_width:
1478  segment->SetWidth( parseBoardUnits( T_width ) );
1479  break;
1480 
1481  case T_tstamp:
1482  segment->SetTimeStamp( parseHex() );
1483  break;
1484 
1485  case T_status:
1486  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
1487  break;
1488 
1489  default:
1490  Expecting( "layer, width, tstamp, or status" );
1491  }
1492 
1493  NeedRIGHT();
1494  }
1495 
1496  return segment.release();
1497 }
1498 
1499 
1501 {
1502  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
1503  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) );
1504 
1505  T token;
1506 
1507  std::unique_ptr<TEXTE_PCB> text( new TEXTE_PCB( m_board ) );
1508  NeedSYMBOLorNUMBER();
1509 
1510  text->SetText( FromUTF8() );
1511  NeedLEFT();
1512  token = NextTok();
1513 
1514  if( token != T_at )
1515  Expecting( T_at );
1516 
1517  wxPoint pt;
1518 
1519  pt.x = parseBoardUnits( "X coordinate" );
1520  pt.y = parseBoardUnits( "Y coordinate" );
1521  text->SetTextPos( pt );
1522 
1523  // If there is no orientation defined, then it is the default value of 0 degrees.
1524  token = NextTok();
1525 
1526  if( token == T_NUMBER )
1527  {
1528  text->SetTextAngle( parseDouble() * 10.0 );
1529  NeedRIGHT();
1530  }
1531  else if( token != T_RIGHT )
1532  {
1533  Unexpected( CurText() );
1534  }
1535 
1536  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1537  {
1538  if( token != T_LEFT )
1539  Expecting( T_LEFT );
1540 
1541  token = NextTok();
1542 
1543  switch( token )
1544  {
1545  case T_layer:
1546  text->SetLayer( parseBoardItemLayer() );
1547  NeedRIGHT();
1548  break;
1549 
1550  case T_tstamp:
1551  text->SetTimeStamp( parseHex() );
1552  NeedRIGHT();
1553  break;
1554 
1555  case T_effects:
1556  parseEDA_TEXT( (EDA_TEXT*) text.get() );
1557  break;
1558 
1559  default:
1560  Expecting( "layer, tstamp or effects" );
1561  }
1562  }
1563 
1564  return text.release();
1565 }
1566 
1567 
1569 {
1570  wxCHECK_MSG( CurTok() == T_dimension, NULL,
1571  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
1572 
1573  T token;
1574 
1575  std::unique_ptr<DIMENSION> dimension( new DIMENSION( NULL ) );
1576 
1577  dimension->SetValue( parseBoardUnits( "dimension value" ) );
1578  NeedLEFT();
1579  token = NextTok();
1580 
1581  if( token != T_width )
1582  Expecting( T_width );
1583 
1584  dimension->SetWidth( parseBoardUnits( "dimension width value" ) );
1585  NeedRIGHT();
1586 
1587  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1588  {
1589  if( token != T_LEFT )
1590  Expecting( T_LEFT );
1591 
1592  token = NextTok();
1593 
1594  switch( token )
1595  {
1596  case T_layer:
1597  dimension->SetLayer( parseBoardItemLayer() );
1598  NeedRIGHT();
1599  break;
1600 
1601  case T_tstamp:
1602  dimension->SetTimeStamp( parseHex() );
1603  NeedRIGHT();
1604  break;
1605 
1606  case T_gr_text:
1607  {
1608  TEXTE_PCB* text = parseTEXTE_PCB();
1609  dimension->Text() = *text;
1610  dimension->SetPosition( text->GetTextPos() );
1611  delete text;
1612  break;
1613  }
1614 
1615  case T_feature1:
1616  NeedLEFT();
1617  token = NextTok();
1618 
1619  if( token != T_pts )
1620  Expecting( T_pts );
1621 
1622  parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y );
1623  parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y );
1624  dimension->UpdateHeight();
1625  NeedRIGHT();
1626  NeedRIGHT();
1627  break;
1628 
1629  case T_feature2:
1630  NeedLEFT();
1631  token = NextTok();
1632 
1633  if( token != T_pts )
1634  Expecting( T_pts );
1635 
1636  parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y );
1637  parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y );
1638  dimension->UpdateHeight();
1639  NeedRIGHT();
1640  NeedRIGHT();
1641  break;
1642 
1643 
1644  case T_crossbar:
1645  NeedLEFT();
1646  token = NextTok();
1647 
1648  if( token != T_pts )
1649  Expecting( T_pts );
1650 
1651  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1652  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1653  dimension->UpdateHeight();
1654  NeedRIGHT();
1655  NeedRIGHT();
1656  break;
1657 
1658  case T_arrow1a:
1659  NeedLEFT();
1660  token = NextTok();
1661 
1662  if( token != T_pts )
1663  Expecting( T_pts );
1664 
1665  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1666  parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y );
1667  NeedRIGHT();
1668  NeedRIGHT();
1669  break;
1670 
1671  case T_arrow1b:
1672  NeedLEFT();
1673  token = NextTok();
1674 
1675  if( token != T_pts )
1676  Expecting( T_pts );
1677 
1678  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1679  parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y );
1680  NeedRIGHT();
1681  NeedRIGHT();
1682  break;
1683 
1684  case T_arrow2a:
1685  NeedLEFT();
1686  token = NextTok();
1687 
1688  if( token != T_pts )
1689  Expecting( T_pts );
1690 
1691  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1692  parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y );
1693  NeedRIGHT();
1694  NeedRIGHT();
1695  break;
1696 
1697  case T_arrow2b:
1698  NeedLEFT();
1699  token = NextTok();
1700 
1701  if( token != T_pts )
1702  Expecting( T_pts );
1703 
1704  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1705  parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y );
1706  NeedRIGHT();
1707  NeedRIGHT();
1708  break;
1709 
1710  default:
1711  Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, "
1712  "arrow1b, arrow2a, or arrow2b" );
1713  }
1714  }
1715 
1716  return dimension.release();
1717 }
1718 
1719 
1720 MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
1721 {
1722  try
1723  {
1724  return parseMODULE_unchecked( aInitialComments );
1725  }
1726  catch( const PARSE_ERROR& parse_error )
1727  {
1728  if( m_tooRecent )
1729  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
1730  else
1731  throw;
1732  }
1733 }
1734 
1735 
1736 MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
1737 {
1738  wxCHECK_MSG( CurTok() == T_module, NULL,
1739  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
1740 
1741  wxString name;
1742  wxPoint pt;
1743  T token;
1744  LIB_ID fpid;
1745 
1746  std::unique_ptr<MODULE> module( new MODULE( m_board ) );
1747 
1748  module->SetInitialComments( aInitialComments );
1749 
1750  token = NextTok();
1751 
1752  if( !IsSymbol( token ) && token != T_NUMBER )
1753  Expecting( "symbol|number" );
1754 
1755  name = FromUTF8();
1756 
1757  if( !name.IsEmpty() && fpid.Parse( FromUTF8() ) >= 0 )
1758  {
1759  wxString error;
1760  error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
1761  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
1762  THROW_IO_ERROR( error );
1763  }
1764 
1765  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1766  {
1767  if( token == T_LEFT )
1768  token = NextTok();
1769 
1770  switch( token )
1771  {
1772  case T_version:
1773  {
1774  // Theoretically a module nested in a PCB could declare its own version, though
1775  // as of writing this comment we don't do that. Just in case, take the greater
1776  // version.
1777  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1778  NeedRIGHT();
1779  m_requiredVersion = std::max( m_requiredVersion, this_version );
1780  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
1781  break;
1782  }
1783 
1784  case T_locked:
1785  module->SetLocked( true );
1786  break;
1787 
1788  case T_placed:
1789  module->SetIsPlaced( true );
1790  break;
1791 
1792  case T_layer:
1793  {
1794  // Footprints can be only on the front side or the back side.
1795  // but because we can find some stupid layer in file, ensure a
1796  // acceptable layer is set for the footprint
1797  PCB_LAYER_ID layer = parseBoardItemLayer();
1798  module->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
1799  }
1800  NeedRIGHT();
1801  break;
1802 
1803  case T_tedit:
1804  module->SetLastEditTime( parseHex() );
1805  NeedRIGHT();
1806  break;
1807 
1808  case T_tstamp:
1809  module->SetTimeStamp( parseHex() );
1810  NeedRIGHT();
1811  break;
1812 
1813  case T_at:
1814  pt.x = parseBoardUnits( "X coordinate" );
1815  pt.y = parseBoardUnits( "Y coordinate" );
1816  module->SetPosition( pt );
1817  token = NextTok();
1818 
1819  if( token == T_NUMBER )
1820  {
1821  module->SetOrientation( parseDouble() * 10.0 );
1822  NeedRIGHT();
1823  }
1824  else if( token != T_RIGHT )
1825  {
1826  Expecting( T_RIGHT );
1827  }
1828 
1829  break;
1830 
1831  case T_descr:
1832  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1833  module->SetDescription( FromUTF8() );
1834  NeedRIGHT();
1835  break;
1836 
1837  case T_tags:
1838  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1839  module->SetKeywords( FromUTF8() );
1840  NeedRIGHT();
1841  break;
1842 
1843  case T_path:
1844  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
1845  module->SetPath( FromUTF8() );
1846  NeedRIGHT();
1847  break;
1848 
1849  case T_autoplace_cost90:
1850  module->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
1851  NeedRIGHT();
1852  break;
1853 
1854  case T_autoplace_cost180:
1855  module->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
1856  NeedRIGHT();
1857  break;
1858 
1859  case T_solder_mask_margin:
1860  module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
1861  NeedRIGHT();
1862  break;
1863 
1864  case T_solder_paste_margin:
1865  module->SetLocalSolderPasteMargin(
1866  parseBoardUnits( "local solder paste margin value" ) );
1867  NeedRIGHT();
1868  break;
1869 
1870  case T_solder_paste_ratio:
1871  module->SetLocalSolderPasteMarginRatio(
1872  parseDouble( "local solder paste margin ratio value" ) );
1873  NeedRIGHT();
1874  break;
1875 
1876  case T_clearance:
1877  module->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
1878  NeedRIGHT();
1879  break;
1880 
1881  case T_zone_connect:
1882  module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
1883  NeedRIGHT();
1884  break;
1885 
1886  case T_thermal_width:
1887  module->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
1888  NeedRIGHT();
1889  break;
1890 
1891  case T_thermal_gap:
1892  module->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
1893  NeedRIGHT();
1894  break;
1895 
1896  case T_attr:
1897  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1898  {
1899  switch( token )
1900  {
1901  case T_smd:
1902  module->SetAttributes( module->GetAttributes() | MOD_CMS );
1903  break;
1904 
1905  case T_virtual:
1906  module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL );
1907  break;
1908 
1909  default:
1910  Expecting( "smd and/or virtual" );
1911  }
1912  }
1913  break;
1914 
1915  case T_fp_text:
1916  {
1917  TEXTE_MODULE* text = parseTEXTE_MODULE();
1918  text->SetParent( module.get() );
1919  double orientation = text->GetTextAngle();
1920  orientation -= module->GetOrientation();
1921  text->SetTextAngle( orientation );
1922  text->SetDrawCoord();
1923 
1924  switch( text->GetType() )
1925  {
1927  module->Reference() = *text;
1928  delete text;
1929  break;
1930 
1932  module->Value() = *text;
1933  delete text;
1934  break;
1935 
1936  default:
1937  module->GraphicalItemsList().PushBack( text );
1938  }
1939  }
1940  break;
1941 
1942  case T_fp_arc:
1943  case T_fp_circle:
1944  case T_fp_curve:
1945  case T_fp_line:
1946  case T_fp_poly:
1947  {
1948  EDGE_MODULE* em = parseEDGE_MODULE();
1949  em->SetParent( module.get() );
1950  em->SetDrawCoord();
1951  module->GraphicalItemsList().PushBack( em );
1952  }
1953  break;
1954 
1955  case T_pad:
1956  {
1957  D_PAD* pad = parseD_PAD( module.get() );
1958  pt = pad->GetPos0();
1959 
1960  RotatePoint( &pt, module->GetOrientation() );
1961  pad->SetPosition( pt + module->GetPosition() );
1962  module->Add( pad, ADD_APPEND );
1963  }
1964  break;
1965 
1966  case T_model:
1967  module->Add3DModel( parse3DModel() );
1968  break;
1969 
1970  default:
1971  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
1972  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
1973  "solder_paste_margin, solder_paste_ratio, clearance, "
1974  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
1975  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" );
1976  }
1977  }
1978 
1979  module->SetFPID( fpid );
1980  module->CalculateBoundingBox();
1981 
1982  return module.release();
1983 }
1984 
1985 
1987 {
1988  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
1989  wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ),
1990  GetChars( GetTokenString( CurTok() ) ),
1991  CurLineNumber(), CurOffset() ) );
1992 
1993  T token = NextTok();
1994 
1995  std::unique_ptr<TEXTE_MODULE> text( new TEXTE_MODULE( NULL ) );
1996 
1997  switch( token )
1998  {
1999  case T_reference:
2000  text->SetType( TEXTE_MODULE::TEXT_is_REFERENCE );
2001  break;
2002 
2003  case T_value:
2004  text->SetType( TEXTE_MODULE::TEXT_is_VALUE );
2005  break;
2006 
2007  case T_user:
2008  break; // Default type is user text.
2009 
2010  default:
2011  THROW_IO_ERROR( wxString::Format( _( "cannot handle footprint text type %s" ),
2012  GetChars( FromUTF8() ) ) );
2013  }
2014 
2015  NeedSYMBOLorNUMBER();
2016 
2017  text->SetText( FromUTF8() );
2018  NeedLEFT();
2019  token = NextTok();
2020 
2021  if( token != T_at )
2022  Expecting( T_at );
2023 
2024  wxPoint pt;
2025 
2026  pt.x = parseBoardUnits( "X coordinate" );
2027  pt.y = parseBoardUnits( "Y coordinate" );
2028  text->SetPos0( pt );
2029  token = NextTok();
2030 
2031  // If there is no orientation defined, then it is the default value of 0 degrees.
2032  if( token == T_NUMBER )
2033  {
2034  text->SetTextAngle( parseDouble() * 10.0 );
2035  NeedRIGHT();
2036  }
2037  else if( token != T_RIGHT )
2038  {
2039  Unexpected( CurText() );
2040  }
2041 
2042  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2043  {
2044  if( token == T_LEFT )
2045  token = NextTok();
2046 
2047  switch( token )
2048  {
2049  case T_layer:
2050  text->SetLayer( parseBoardItemLayer() );
2051  NeedRIGHT();
2052  break;
2053 
2054  case T_hide:
2055  text->SetVisible( false );
2056  break;
2057 
2058  case T_effects:
2059  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2060  break;
2061 
2062  default:
2063  Expecting( "hide or effects" );
2064  }
2065  }
2066 
2067  return text.release();
2068 }
2069 
2070 
2072 {
2073  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2074  CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
2075  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
2076 
2077  wxPoint pt;
2078  T token;
2079 
2080  std::unique_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) );
2081 
2082  switch( CurTok() )
2083  {
2084  case T_fp_arc:
2085  segment->SetShape( S_ARC );
2086  NeedLEFT();
2087  token = NextTok();
2088 
2089  // the start keyword actually gives the arc center
2090  // Allows also T_center for future change
2091  if( token != T_start && token != T_center )
2092  Expecting( T_start );
2093 
2094  pt.x = parseBoardUnits( "X coordinate" );
2095  pt.y = parseBoardUnits( "Y coordinate" );
2096  segment->SetStart0( pt );
2097  NeedRIGHT();
2098  NeedLEFT();
2099  token = NextTok();
2100 
2101  if( token != T_end ) // end keyword actually gives the starting point of the arc
2102  Expecting( T_end );
2103 
2104  pt.x = parseBoardUnits( "X coordinate" );
2105  pt.y = parseBoardUnits( "Y coordinate" );
2106  segment->SetEnd0( pt );
2107  NeedRIGHT();
2108  NeedLEFT();
2109  token = NextTok();
2110 
2111  if( token != T_angle )
2112  Expecting( T_angle );
2113 
2114  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2115  NeedRIGHT();
2116  break;
2117 
2118  case T_fp_circle:
2119  segment->SetShape( S_CIRCLE );
2120  NeedLEFT();
2121  token = NextTok();
2122 
2123  if( token != T_center )
2124  Expecting( T_center );
2125 
2126  pt.x = parseBoardUnits( "X coordinate" );
2127  pt.y = parseBoardUnits( "Y coordinate" );
2128  segment->SetStart0( pt );
2129  NeedRIGHT();
2130  NeedLEFT();
2131  token = NextTok();
2132 
2133  if( token != T_end )
2134  Expecting( T_end );
2135 
2136  pt.x = parseBoardUnits( "X coordinate" );
2137  pt.y = parseBoardUnits( "Y coordinate" );
2138  segment->SetEnd0( pt );
2139  NeedRIGHT();
2140  break;
2141 
2142  case T_fp_curve:
2143  segment->SetShape( S_CURVE );
2144  NeedLEFT();
2145  token = NextTok();
2146 
2147  if( token != T_pts )
2148  Expecting( T_pts );
2149 
2150  segment->SetStart0( parseXY() );
2151  segment->SetBezControl1( parseXY() );
2152  segment->SetBezControl2( parseXY() );
2153  segment->SetEnd0( parseXY() );
2154  NeedRIGHT();
2155  break;
2156 
2157  case T_fp_line:
2158  // Default DRAWSEGMENT type is S_SEGMENT.
2159  NeedLEFT();
2160  token = NextTok();
2161 
2162  if( token != T_start )
2163  Expecting( T_start );
2164 
2165  pt.x = parseBoardUnits( "X coordinate" );
2166  pt.y = parseBoardUnits( "Y coordinate" );
2167  segment->SetStart0( pt );
2168 
2169  NeedRIGHT();
2170  NeedLEFT();
2171  token = NextTok();
2172 
2173  if( token != T_end )
2174  Expecting( T_end );
2175 
2176  pt.x = parseBoardUnits( "X coordinate" );
2177  pt.y = parseBoardUnits( "Y coordinate" );
2178  segment->SetEnd0( pt );
2179  NeedRIGHT();
2180  break;
2181 
2182  case T_fp_poly:
2183  {
2184  segment->SetShape( S_POLYGON );
2185  NeedLEFT();
2186  token = NextTok();
2187 
2188  if( token != T_pts )
2189  Expecting( T_pts );
2190 
2191  std::vector< wxPoint > pts;
2192 
2193  while( (token = NextTok()) != T_RIGHT )
2194  pts.push_back( parseXY() );
2195 
2196  segment->SetPolyPoints( pts );
2197  }
2198  break;
2199 
2200  default:
2201  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
2202  }
2203 
2204  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2205  {
2206  if( token != T_LEFT )
2207  Expecting( T_LEFT );
2208 
2209  token = NextTok();
2210 
2211  switch( token )
2212  {
2213  case T_layer:
2214  segment->SetLayer( parseBoardItemLayer() );
2215  break;
2216 
2217  case T_width:
2218  segment->SetWidth( parseBoardUnits( T_width ) );
2219  break;
2220 
2221  case T_tstamp:
2222  segment->SetTimeStamp( parseHex() );
2223  break;
2224 
2225  case T_status:
2226  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2227  break;
2228 
2229  default:
2230  Expecting( "layer or width" );
2231  }
2232 
2233  NeedRIGHT();
2234  }
2235 
2236  return segment.release();
2237 }
2238 
2239 
2241 {
2242  wxCHECK_MSG( CurTok() == T_pad, NULL,
2243  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) );
2244 
2245  wxSize sz;
2246  wxPoint pt;
2247 
2248  std::unique_ptr< D_PAD > pad( new D_PAD( aParent ) );
2249 
2250  NeedSYMBOLorNUMBER();
2251  pad->SetName( FromUTF8() );
2252 
2253  T token = NextTok();
2254 
2255  switch( token )
2256  {
2257  case T_thru_hole:
2258  pad->SetAttribute( PAD_ATTRIB_STANDARD );
2259  break;
2260 
2261  case T_smd:
2262  pad->SetAttribute( PAD_ATTRIB_SMD );
2263 
2264  // Default D_PAD object is thru hole with drill.
2265  // SMD pads have no hole
2266  pad->SetDrillSize( wxSize( 0, 0 ) );
2267  break;
2268 
2269  case T_connect:
2270  pad->SetAttribute( PAD_ATTRIB_CONN );
2271 
2272  // Default D_PAD object is thru hole with drill.
2273  // CONN pads have no hole
2274  pad->SetDrillSize( wxSize( 0, 0 ) );
2275  break;
2276 
2277  case T_np_thru_hole:
2278  pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
2279  break;
2280 
2281  default:
2282  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
2283  }
2284 
2285  token = NextTok();
2286 
2287  switch( token )
2288  {
2289  case T_circle:
2290  pad->SetShape( PAD_SHAPE_CIRCLE );
2291  break;
2292 
2293  case T_rect:
2294  pad->SetShape( PAD_SHAPE_RECT );
2295  break;
2296 
2297  case T_oval:
2298  pad->SetShape( PAD_SHAPE_OVAL );
2299  break;
2300 
2301  case T_trapezoid:
2302  pad->SetShape( PAD_SHAPE_TRAPEZOID );
2303  break;
2304 
2305  case T_roundrect:
2306  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2307  break;
2308 
2309  case T_custom:
2310  pad->SetShape( PAD_SHAPE_CUSTOM );
2311  break;
2312 
2313  default:
2314  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
2315  }
2316 
2317  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2318  {
2319  if( token != T_LEFT )
2320  Expecting( T_LEFT );
2321 
2322  token = NextTok();
2323 
2324  switch( token )
2325  {
2326  case T_size:
2327  sz.SetWidth( parseBoardUnits( "width value" ) );
2328  sz.SetHeight( parseBoardUnits( "height value" ) );
2329  pad->SetSize( sz );
2330  NeedRIGHT();
2331  break;
2332 
2333  case T_at:
2334  pt.x = parseBoardUnits( "X coordinate" );
2335  pt.y = parseBoardUnits( "Y coordinate" );
2336  pad->SetPos0( pt );
2337  token = NextTok();
2338 
2339  if( token == T_NUMBER )
2340  {
2341  pad->SetOrientation( parseDouble() * 10.0 );
2342  NeedRIGHT();
2343  }
2344  else if( token != T_RIGHT )
2345  {
2346  Expecting( ") or angle value" );
2347  }
2348 
2349  break;
2350 
2351  case T_rect_delta:
2352  {
2353  wxSize delta;
2354  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
2355  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
2356  pad->SetDelta( delta );
2357  NeedRIGHT();
2358  }
2359  break;
2360 
2361  case T_drill:
2362  {
2363  bool haveWidth = false;
2364  wxSize drillSize = pad->GetDrillSize();
2365 
2366  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2367  {
2368  if( token == T_LEFT )
2369  token = NextTok();
2370 
2371  switch( token )
2372  {
2373  case T_oval:
2374  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
2375  break;
2376 
2377  case T_NUMBER:
2378  {
2379  if( !haveWidth )
2380  {
2381  drillSize.SetWidth( parseBoardUnits() );
2382 
2383  // If height is not defined the width and height are the same.
2384  drillSize.SetHeight( drillSize.GetWidth() );
2385  haveWidth = true;
2386  }
2387  else
2388  {
2389  drillSize.SetHeight( parseBoardUnits() );
2390  }
2391 
2392  }
2393  break;
2394 
2395  case T_offset:
2396  pt.x = parseBoardUnits( "drill offset x" );
2397  pt.y = parseBoardUnits( "drill offset y" );
2398  pad->SetOffset( pt );
2399  NeedRIGHT();
2400  break;
2401 
2402  default:
2403  Expecting( "oval, size, or offset" );
2404  }
2405  }
2406 
2407  // This fixes a bug caused by setting the default D_PAD drill size to a value
2408  // other than 0 used to fix a bunch of debug assertions even though it is defined
2409  // as a through hole pad. Wouldn't a though hole pad with no drill be a surface
2410  // mount pad (or a conn pad which is a smd pad with no solder paste)?
2411  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
2412  pad->SetDrillSize( drillSize );
2413  else
2414  pad->SetDrillSize( wxSize( 0, 0 ) );
2415 
2416  }
2417  break;
2418 
2419  case T_layers:
2420  {
2421  LSET layerMask = parseBoardItemLayersAsMask();
2422  pad->SetLayerSet( layerMask );
2423  }
2424  break;
2425 
2426  case T_net:
2427  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2429  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2430  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2431  );
2432  NeedSYMBOLorNUMBER();
2433  if( m_board && FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
2435  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2436  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2437  );
2438  NeedRIGHT();
2439  break;
2440 
2441  case T_die_length:
2442  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
2443  NeedRIGHT();
2444  break;
2445 
2446  case T_solder_mask_margin:
2447  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
2448  NeedRIGHT();
2449  break;
2450 
2451  case T_solder_paste_margin:
2452  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
2453  NeedRIGHT();
2454  break;
2455 
2457  pad->SetLocalSolderPasteMarginRatio(
2458  parseDouble( "pad local solder paste margin ratio value" ) );
2459  NeedRIGHT();
2460  break;
2461 
2462  case T_clearance:
2463  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
2464  NeedRIGHT();
2465  break;
2466 
2467  case T_zone_connect:
2468  pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
2469  NeedRIGHT();
2470  break;
2471 
2472  case T_thermal_width:
2473  pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) );
2474  NeedRIGHT();
2475  break;
2476 
2477  case T_thermal_gap:
2478  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
2479  NeedRIGHT();
2480  break;
2481 
2482  case T_roundrect_rratio:
2483  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
2484  NeedRIGHT();
2485  break;
2486 
2487  case T_options:
2488  parseD_PAD_option( pad.get() );
2489  break;
2490 
2491  case T_primitives:
2492  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2493  {
2494  if( token == T_LEFT )
2495  token = NextTok();
2496 
2497  // Currently, I am using parseDRAWSEGMENT() to read basic shapes parameters,
2498  // because they are the same as a DRAWSEGMENT.
2499  // However it could be better to write a specific parser, to avoid possible issues
2500  // if the DRAWSEGMENT parser is modified.
2501  DRAWSEGMENT* dummysegm = NULL;
2502 
2503  switch( token )
2504  {
2505  case T_gr_arc:
2506  dummysegm = parseDRAWSEGMENT();
2507  pad->AddPrimitive( dummysegm->GetCenter(), dummysegm->GetArcStart(),
2508  dummysegm->GetAngle(), dummysegm->GetWidth() );
2509  break;
2510 
2511  case T_gr_line:
2512  dummysegm = parseDRAWSEGMENT();
2513  pad->AddPrimitive( dummysegm->GetStart(), dummysegm->GetEnd(),
2514  dummysegm->GetWidth() );
2515  break;
2516 
2517  case T_gr_circle:
2518  dummysegm = parseDRAWSEGMENT();
2519  pad->AddPrimitive( dummysegm->GetCenter(), dummysegm->GetRadius(),
2520  dummysegm->GetWidth() );
2521  break;
2522 
2523  case T_gr_poly:
2524  dummysegm = parseDRAWSEGMENT();
2525  pad->AddPrimitive( dummysegm->GetPolyPoints(), dummysegm->GetWidth() );
2526  break;
2527 
2528  default:
2529  Expecting( "gr_line, gr_arc, gr_circle or gr_poly" );
2530  break;
2531  }
2532 
2533  delete dummysegm;
2534  }
2535  break;
2536 
2537  default:
2538  Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,\n"
2539  "solder_paste_margin, solder_paste_margin_ratio, clearance,\n"
2540  "zone_connect, fp_poly, primitives, thermal_width, or thermal_gap" );
2541  }
2542  }
2543 
2544  // Be sure the custom shape polygon is built:
2545  if( pad->GetShape() == PAD_SHAPE_CUSTOM )
2546  pad->MergePrimitivesAsPolygon();
2547 
2548  return pad.release();
2549 }
2550 
2551 
2553 {
2554  // Parse only the (option ...) inside a pad description
2555  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
2556  {
2557  if( token != T_LEFT )
2558  Expecting( T_LEFT );
2559 
2560  token = NextTok();
2561 
2562  switch( token )
2563  {
2564  case T_anchor:
2565  token = NextTok();
2566  // Custom shaped pads have a "anchor pad", which is the reference
2567  // for connection calculations.
2568  // Because this is an anchor, only the 2 very basic shapes are managed:
2569  // circle and rect. The default is circle
2570  switch( token )
2571  {
2572  case T_circle: // default
2573  break;
2574 
2575  case T_rect:
2577  break;
2578 
2579  default:
2580  // Currently, because pad options is a moving target
2581  // just skip unknown keywords
2582  break;
2583  }
2584  NeedRIGHT();
2585  break;
2586 
2587  case T_clearance:
2588  token = NextTok();
2589  // Custom shaped pads have a clearance area that is the pad shape
2590  // (like usual pads) or the convew hull of the pad shape.
2591  switch( token )
2592  {
2593  case T_outline:
2595  break;
2596 
2597  case T_convexhull:
2599  break;
2600 
2601  default:
2602  // Currently, because pad options is a moving target
2603  // just skip unknown keywords
2604  break;
2605  }
2606  NeedRIGHT();
2607  break;
2608 
2609  default:
2610  // Currently, because pad options is a moving target
2611  // just skip unknown keywords
2612  while( (token = NextTok() ) != T_RIGHT )
2613  {}
2614  break;
2615  }
2616  }
2617 
2618  return true;
2619 }
2620 
2621 
2623 {
2624  wxCHECK_MSG( CurTok() == T_segment, NULL,
2625  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
2626 
2627  wxPoint pt;
2628  T token;
2629 
2630  std::unique_ptr< TRACK > track( new TRACK( m_board ) );
2631 
2632  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2633  {
2634  if( token != T_LEFT )
2635  Expecting( T_LEFT );
2636 
2637  token = NextTok();
2638 
2639  switch( token )
2640  {
2641  case T_start:
2642  pt.x = parseBoardUnits( "start x" );
2643  pt.y = parseBoardUnits( "start y" );
2644  track->SetStart( pt );
2645  break;
2646 
2647  case T_end:
2648  pt.x = parseBoardUnits( "end x" );
2649  pt.y = parseBoardUnits( "end y" );
2650  track->SetEnd( pt );
2651  break;
2652 
2653  case T_width:
2654  track->SetWidth( parseBoardUnits( "width" ) );
2655  break;
2656 
2657  case T_layer:
2658  track->SetLayer( parseBoardItemLayer() );
2659  break;
2660 
2661  case T_net:
2662  if( ! track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2664  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2665  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2666  );
2667  break;
2668 
2669  case T_tstamp:
2670  track->SetTimeStamp( parseHex() );
2671  break;
2672 
2673  case T_status:
2674  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2675  break;
2676 
2677  default:
2678  Expecting( "start, end, width, layer, net, tstamp, or status" );
2679  }
2680 
2681  NeedRIGHT();
2682  }
2683 
2684  return track.release();
2685 }
2686 
2687 
2689 {
2690  wxCHECK_MSG( CurTok() == T_via, NULL,
2691  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
2692 
2693  wxPoint pt;
2694  T token;
2695 
2696  std::unique_ptr< VIA > via( new VIA( m_board ) );
2697 
2698  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2699  {
2700  if( token == T_LEFT )
2701  token = NextTok();
2702 
2703  switch( token )
2704  {
2705  case T_blind:
2706  via->SetViaType( VIA_BLIND_BURIED );
2707  break;
2708 
2709  case T_micro:
2710  via->SetViaType( VIA_MICROVIA );
2711  break;
2712 
2713  case T_at:
2714  pt.x = parseBoardUnits( "start x" );
2715  pt.y = parseBoardUnits( "start y" );
2716  via->SetStart( pt );
2717  via->SetEnd( pt );
2718  NeedRIGHT();
2719  break;
2720 
2721  case T_size:
2722  via->SetWidth( parseBoardUnits( "via width" ) );
2723  NeedRIGHT();
2724  break;
2725 
2726  case T_drill:
2727  via->SetDrill( parseBoardUnits( "drill diameter" ) );
2728  NeedRIGHT();
2729  break;
2730 
2731  case T_layers:
2732  {
2733  PCB_LAYER_ID layer1, layer2;
2734  NextTok();
2735  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2736  NextTok();
2737  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2738  via->SetLayerPair( layer1, layer2 );
2739  NeedRIGHT();
2740  }
2741  break;
2742 
2743  case T_net:
2744  if(! via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true))
2746  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2747  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2748  );
2749  NeedRIGHT();
2750  break;
2751 
2752  case T_tstamp:
2753  via->SetTimeStamp( parseHex() );
2754  NeedRIGHT();
2755  break;
2756 
2757  case T_status:
2758  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2759  NeedRIGHT();
2760  break;
2761 
2762  default:
2763  Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
2764  }
2765  }
2766 
2767  return via.release();
2768 }
2769 
2770 
2772 {
2773  wxCHECK_MSG( CurTok() == T_zone, NULL,
2774  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
2775  wxT( " as ZONE_CONTAINER." ) );
2776 
2778 
2779  int hatchPitch = ZONE_CONTAINER::GetDefaultHatchPitch();
2780  wxPoint pt;
2781  T token;
2782  int tmp;
2783  wxString netnameFromfile; // the zone net name find in file
2784 
2785  // bigger scope since each filled_polygon is concatenated in here
2786  SHAPE_POLY_SET pts;
2787 
2788  std::unique_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
2789 
2790  zone->SetPriority( 0 );
2791 
2792  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2793  {
2794  if( token == T_LEFT )
2795  token = NextTok();
2796 
2797  switch( token )
2798  {
2799  case T_net:
2800  // Init the net code only, not the netname, to be sure
2801  // the zone net name is the name read in file.
2802  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2803  tmp = getNetCode( parseInt( "net number" ) );
2804 
2805  if( tmp < 0 )
2806  tmp = 0;
2807 
2808  if( ! zone->SetNetCode( tmp, /* aNoAssert */ true ) )
2810  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2811  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2812  );
2813 
2814  NeedRIGHT();
2815  break;
2816 
2817  case T_net_name:
2818  NeedSYMBOLorNUMBER();
2819  netnameFromfile = FromUTF8();
2820  NeedRIGHT();
2821  break;
2822 
2823  case T_layer:
2824  zone->SetLayer( parseBoardItemLayer() );
2825  NeedRIGHT();
2826  break;
2827 
2828  case T_tstamp:
2829  zone->SetTimeStamp( parseHex() );
2830  NeedRIGHT();
2831  break;
2832 
2833  case T_hatch:
2834  token = NextTok();
2835 
2836  if( token != T_none && token != T_edge && token != T_full )
2837  Expecting( "none, edge, or full" );
2838 
2839  switch( token )
2840  {
2841  default:
2842  case T_none: hatchStyle = ZONE_CONTAINER::NO_HATCH; break;
2843  case T_edge: hatchStyle = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2844  case T_full: hatchStyle = ZONE_CONTAINER::DIAGONAL_FULL;
2845  }
2846 
2847  hatchPitch = parseBoardUnits( "hatch pitch" );
2848  NeedRIGHT();
2849  break;
2850 
2851  case T_priority:
2852  zone->SetPriority( parseInt( "zone priority" ) );
2853  NeedRIGHT();
2854  break;
2855 
2856  case T_connect_pads:
2857  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2858  {
2859  if( token == T_LEFT )
2860  token = NextTok();
2861 
2862  switch( token )
2863  {
2864  case T_yes:
2865  zone->SetPadConnection( PAD_ZONE_CONN_FULL );
2866  break;
2867 
2868  case T_no:
2869  zone->SetPadConnection( PAD_ZONE_CONN_NONE );
2870  break;
2871 
2872  case T_thru_hole_only:
2873  zone->SetPadConnection( PAD_ZONE_CONN_THT_THERMAL );
2874  break;
2875 
2876  case T_clearance:
2877  zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) );
2878  NeedRIGHT();
2879  break;
2880 
2881  default:
2882  Expecting( "yes, no, or clearance" );
2883  }
2884  }
2885 
2886  break;
2887 
2888  case T_min_thickness:
2889  zone->SetMinThickness( parseBoardUnits( T_min_thickness ) );
2890  NeedRIGHT();
2891  break;
2892 
2893  case T_fill:
2894  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2895  {
2896  if( token == T_LEFT )
2897  token = NextTok();
2898 
2899  switch( token )
2900  {
2901  case T_yes:
2902  zone->SetIsFilled( true );
2903  break;
2904 
2905  case T_mode:
2906  token = NextTok();
2907 
2908  if( token != T_segment && token != T_polygon )
2909  Expecting( "segment or polygon" );
2910 
2911  // @todo Create an enum for fill modes.
2912  zone->SetFillMode( token == T_polygon ? 0 : 1 );
2913  NeedRIGHT();
2914  break;
2915 
2916  case T_arc_segments:
2917  zone->SetArcSegmentCount( parseInt( "arc segment count" ) );
2918  NeedRIGHT();
2919  break;
2920 
2921  case T_thermal_gap:
2922  zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) );
2923  NeedRIGHT();
2924  break;
2925 
2927  zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
2928  NeedRIGHT();
2929  break;
2930 
2931  case T_smoothing:
2932  switch( NextTok() )
2933  {
2934  case T_none:
2935  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
2936  break;
2937 
2938  case T_chamfer:
2939  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2940  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER );
2941  break;
2942 
2943  case T_fillet:
2944  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2945  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET );
2946  break;
2947 
2948  default:
2949  Expecting( "none, chamfer, or fillet" );
2950  }
2951  NeedRIGHT();
2952  break;
2953 
2954  case T_radius:
2955  tmp = parseBoardUnits( "corner radius" );
2956  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2957  zone->SetCornerRadius( tmp );
2958  NeedRIGHT();
2959  break;
2960 
2961  default:
2962  Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, "
2963  "smoothing, or radius" );
2964  }
2965  }
2966  break;
2967 
2968  case T_keepout:
2969  zone->SetIsKeepout( true );
2970 
2971  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2972  {
2973  if( token == T_LEFT )
2974  token = NextTok();
2975 
2976  switch( token )
2977  {
2978  case T_tracks:
2979  token = NextTok();
2980 
2981  if( token != T_allowed && token != T_not_allowed )
2982  Expecting( "allowed or not_allowed" );
2983  zone->SetDoNotAllowTracks( token == T_not_allowed );
2984  break;
2985 
2986  case T_vias:
2987  token = NextTok();
2988 
2989  if( token != T_allowed && token != T_not_allowed )
2990  Expecting( "allowed or not_allowed" );
2991  zone->SetDoNotAllowVias( token == T_not_allowed );
2992  break;
2993 
2994  case T_copperpour:
2995  token = NextTok();
2996 
2997  if( token != T_allowed && token != T_not_allowed )
2998  Expecting( "allowed or not_allowed" );
2999  zone->SetDoNotAllowCopperPour( token == T_not_allowed );
3000  break;
3001 
3002  default:
3003  Expecting( "tracks, vias or copperpour" );
3004  }
3005 
3006  NeedRIGHT();
3007  }
3008 
3009  break;
3010 
3011  case T_polygon:
3012  {
3013  std::vector< wxPoint > corners;
3014 
3015  NeedLEFT();
3016  token = NextTok();
3017 
3018  if( token != T_pts )
3019  Expecting( T_pts );
3020 
3021  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3022  {
3023  corners.push_back( parseXY() );
3024  }
3025 
3026  NeedRIGHT();
3027 
3028  // Remark: The first polygon is the main outline.
3029  // Others are holes inside the main outline.
3030  zone->AddPolygon( corners );
3031  }
3032  break;
3033 
3034  case T_filled_polygon:
3035  {
3036  // "(filled_polygon (pts"
3037  NeedLEFT();
3038  token = NextTok();
3039 
3040  if( token != T_pts )
3041  Expecting( T_pts );
3042 
3043  pts.NewOutline();
3044 
3045  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3046  {
3047  pts.Append( parseXY() );
3048  }
3049 
3050  NeedRIGHT();
3051  }
3052  break;
3053 
3054  case T_fill_segments:
3055  {
3056  std::vector< SEGMENT > segs;
3057 
3058  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3059  {
3060  if( token != T_LEFT )
3061  Expecting( T_LEFT );
3062 
3063  token = NextTok();
3064 
3065  if( token != T_pts )
3066  Expecting( T_pts );
3067 
3068  SEGMENT segment( parseXY(), parseXY() );
3069  NeedRIGHT();
3070  segs.push_back( segment );
3071  }
3072 
3073  zone->AddFillSegments( segs );
3074  }
3075  break;
3076 
3077  default:
3078  Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, "
3079  "fill, polygon, filled_polygon, or fill_segments" );
3080  }
3081  }
3082 
3083  if( zone->GetNumCorners() > 2 )
3084  {
3085  if( !zone->IsOnCopperLayer() )
3086  {
3087  zone->SetFillMode( 0 );
3088  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3089  }
3090 
3091  // Set hatch here, after outlines corners are read
3092  zone->SetHatch( hatchStyle, hatchPitch, true );
3093  }
3094 
3095  if( !pts.IsEmpty() )
3096  zone->AddFilledPolysList( pts );
3097 
3098  // Ensure keepout and non copper zones do not have a net
3099  // (which have no sense for these zones)
3100  // the netcode 0 is used for these zones
3101  bool zone_has_net = zone->IsOnCopperLayer() && !zone->GetIsKeepout();
3102 
3103  if( !zone_has_net )
3104  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3105 
3106  // Ensure the zone net name is valid, and matches the net code, for copper zones
3107  if( zone_has_net && ( zone->GetNet()->GetNetname() != netnameFromfile ) )
3108  {
3109  // Can happens which old boards, with nonexistent nets ...
3110  // or after being edited by hand
3111  // We try to fix the mismatch.
3112  NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
3113 
3114  if( net ) // An existing net has the same net name. use it for the zone
3115  zone->SetNetCode( net->GetNet() );
3116  else // Not existing net: add a new net to keep trace of the zone netname
3117  {
3118  int newnetcode = m_board->GetNetCount();
3119  net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
3120  m_board->Add( net );
3121 
3122  // Store the new code mapping
3123  pushValueIntoMap( newnetcode, net->GetNet() );
3124  // and update the zone netcode
3125  zone->SetNetCode( net->GetNet() );
3126 
3127  // Prompt the user
3128  wxString msg;
3129  msg.Printf( _( "There is a zone that belongs to a not existing net\n"
3130  "\"%s\"\n"
3131  "you should verify and edit it (run DRC test)." ),
3132  GetChars( netnameFromfile ) );
3133  DisplayError( NULL, msg );
3134  }
3135  }
3136 
3137  return zone.release();
3138 }
3139 
3140 
3142 {
3143  wxCHECK_MSG( CurTok() == T_target, NULL,
3144  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
3145 
3146  wxPoint pt;
3147  T token;
3148 
3149  std::unique_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) );
3150 
3151  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3152  {
3153  if( token == T_LEFT )
3154  token = NextTok();
3155 
3156  switch( token )
3157  {
3158  case T_x:
3159  target->SetShape( 1 );
3160  break;
3161 
3162  case T_plus:
3163  target->SetShape( 0 );
3164  break;
3165 
3166  case T_at:
3167  pt.x = parseBoardUnits( "target x position" );
3168  pt.y = parseBoardUnits( "target y position" );
3169  target->SetPosition( pt );
3170  NeedRIGHT();
3171  break;
3172 
3173  case T_size:
3174  target->SetSize( parseBoardUnits( "target size" ) );
3175  NeedRIGHT();
3176  break;
3177 
3178  case T_width:
3179  target->SetWidth( parseBoardUnits( "target thickness" ) );
3180  NeedRIGHT();
3181  break;
3182 
3183  case T_layer:
3184  target->SetLayer( parseBoardItemLayer() );
3185  NeedRIGHT();
3186  break;
3187 
3188  case T_tstamp:
3189  target->SetTimeStamp( parseHex() );
3190  NeedRIGHT();
3191  break;
3192 
3193  default:
3194  Expecting( "x, plus, at, size, width, layer or tstamp" );
3195  }
3196  }
3197 
3198  return target.release();
3199 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:178
void SetComment1(const wxString &aComment)
void parseHeader()
Definition: pcb_parser.cpp:550
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
int parseVersion()
Parse a format version tag like (version 20160417) return the version.
Definition: pcb_parser.cpp:169
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.h:41
int m_SolderMaskMargin
Solder mask margin.
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
LSET parseBoardItemLayersAsMask()
Function parseBoardItemLayersAsMask parses the layers definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:974
PCB_TARGET class definition.
double x
Definition: sg_base.h:70
wxPoint m_GridOrigin
origin for grid offsets
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
const wxPoint & GetTextPos() const
Definition: eda_text.h:224
wxString m_name
The name of the layer, there should be no spaces in this name.
Definition: class_board.h:111
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
int m_SolderPasteMargin
Solder paste margin absolute value.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
This file is part of the common library.
Class PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
int m_ModuleTextWidth
Default footprint texts thickness.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
std::vector< int > m_TrackWidthList
Track width list.
S3D_INFO * parse3DModel()
Definition: pcb_parser.cpp:335
void SetRevision(const wxString &aRevision)
const wxPoint GetCenter() const override
Function GetCenter()
int m_ModuleSegmentWidth
Default width for all graphic lines.
TEXT_TYPE GetType() const
TRACK * parseTRACK()
VIA * parseVIA()
int m_PcbTextWidth
current Pcb (not module) Text width
Class BOARD to handle a board.
LAYER_T m_type
The type of the layer.
Definition: class_board.h:113
void SetItalic(bool isItalic)
Definition: eda_text.h:169
ZoneConnection
How pads are covered by copper in zone.
Definition: zones.h:55
polygon (not yet used for tracks, but could be in microwave apps)
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:61
wxPoint parseXY()
Function parseXY parses a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:206
void SetVisible(bool aVisible)
Definition: eda_text.h:175
void parseNETINFO_ITEM()
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:77
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
BOARD * parseBOARD()
Definition: pcb_parser.cpp:444
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:204
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Classes to handle copper zones.
const wxPoint & GetPos0() const
Definition: class_pad.h:248
bool parseD_PAD_option(D_PAD *aPad)
int Parse(const UTF8 &aId)
Function Parse.
Definition: lib_id.cpp:122
void parseEDA_TEXT(EDA_TEXT *aText)
Function parseEDA_TEXT parses the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:238
static const wxChar Custom[]
"User" defined page type
const std::vector< wxPoint > & GetPolyPoints() const
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:259
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:214
DIMENSION * parseDIMENSION()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:688
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
double y
Definition: sg_base.h:71
SGPOINT m_Offset
an offset (unit = inch) for the 3D shape
Definition: 3d_info.h:44
Class LIB_ID.
Definition: lib_id.h:56
wxSize m_ModuleTextSize
Default footprint texts size.
#define cu(a)
Definition: auxiliary.h:88
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
static const int delta[8][2]
Definition: solve.cpp:112
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
void parseLayers()
Definition: pcb_parser.cpp:813
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
void SetComment4(const wxString &aComment)
This file contains miscellaneous commonly used macros and functions.
const wxPoint & GetArcStart() const
Pads are not covered.
Definition: zones.h:57
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:114
void parsePAGE_INFO()
Definition: pcb_parser.cpp:632
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseDouble.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
bool parseBool()
Definition: pcb_parser.cpp:154
DIMENSION class definition.
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:238
PCB_LAYER_ID
A quick note on layer IDs:
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:182
Class LSET is a set of PCB_LAYER_IDs.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Function Name returns the fixed name association with aLayerId.
Definition: lset.cpp:73
#define MIN_VISIBILITY_MASK
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:227
Class SHAPE_POLY_SET.
wxSize m_PcbTextSize
current Pcb (not module) Text size
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Definition: pcb_lexer.h:23
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
int m_TrackMinWidth
track min value for width ((min copper size value
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
Arcs (with rounded ends)
int m_ViasMinSize
vias (not micro vias) min diameter
void SetNetCode(int aNetCode)
MODULE * parseMODULE_unchecked(wxArrayString *aInitialComments=0)
Function parseMODULE_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERRO...
DRAWSEGMENT * parseDRAWSEGMENT()
int m_DrawSegmentWidth
current graphic line width (not EDGE layer)
PCB_TARGET * parsePCB_TARGET()
int m_ViasMinDrill
vias (not micro vias) min drill diameter
PCB_LAYER_ID parseBoardItemLayer()
Function parseBoardItemLayer parses the layer definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:959
void SetCompany(const wxString &aCompany)
bool m_visible
Definition: class_board.h:115
void SetSize(const wxSize &aSize)
Definition: class_pad.h:253
static unsigned long parseHex(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseHex.
int m_ZoneClearance
Clearance value.
TEXTE_PCB * parseTEXTE_PCB()
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
bool SetType(const wxString &aStandardPageDescriptionName, bool IsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
Bezier Curve.
int GetNet() const
Function GetNet.
static LAYER_T ParseType(const char *aType)
Function ParseType converts a string to a LAYER_T.
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:405
void SetTitle(const wxString &aTitle)
int m_MicroViasMinSize
micro vias (not vias) min diameter
Class PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board...
void parseNETCLASS()
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:62
int NewOutline()
Creates a new empty polygon in the set and returns its index
void SetPortrait(bool isPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
void SetHeightMils(int aHeightInMils)
Thermal relief only for THT pads.
Definition: zones.h:60
Pad object description.
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
Class ZONE_SETTINGS handles zones parameters.
BOARD * parseBOARD_unchecked()
Function parseBOARD_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR...
Definition: pcb_parser.cpp:460
ZONE_CONTAINER * parseZONE_CONTAINER()
void clear()
Definition: class_board.h:92
void parseLayer(LAYER *aLayer)
Definition: pcb_parser.cpp:771
virtual void SetPosition(const wxPoint &aPos) override
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
void SetComment2(const wxString &aComment)
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
T
enum T contains all this lexer's tokens.
Definition: pcb_lexer.h:26
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double GetAngle() const
bool SyncLineReaderWith(DSNLEXER &aLexer)
Useable only for DSN lexers which share the same LINE_READER Synchronizes the pointers handling the d...
Definition: dsnlexer.cpp:169
EDGE_MODULE * parseEDGE_MODULE()
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define max(a, b)
Definition: auxiliary.h:86
Class LAYER holds information pertinent to a layer of a BOARD.
Definition: class_board.h:85
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
void parseGeneralSection()
Definition: pcb_parser.cpp:586
SGPOINT m_Rotation
an X,Y,Z rotation (unit = degrees) for the 3D shape
Definition: 3d_info.h:43
void init()
Function init clears and re-establishes m_layerMap with the default layer names.
Definition: pcb_parser.cpp:56
void SetWidthMils(int aWidthInMils)
void SetDrawCoord()
Set absolute coordinates.
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
double z
Definition: sg_base.h:72
Usual pad.
Definition: pad_shapes.h:60
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
void pushValueIntoMap(int aIndex, int aValue)
function pushValueIntoMap Add aValue value in netcode mapping (m_netCodes) at index aIndex ensure the...
Definition: pcb_parser.cpp:113
The common library.
int GetWidth() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
Vias size and drill list.
double parseDouble()
Function parseDouble parses the current token as an ASCII numeric string with possible leading whites...
Definition: pcb_parser.cpp:124
const char * name
const char * GetTokenText(T aTok)
Function GetTokenText is in the DSN namespace and returns the C string representing a SPECCTRA_DB::ke...
Definition: specctra.cpp:69
Struct SEGMENT is a simple container used when filling areas with segments.
Definition: class_zone.h:57
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones. ...
Definition: class_pad.h:227
Pcbnew s-expression file format parser definition.
void SetTextAngle(double aAngle)
SGPOINT m_Scale
scaling factors for the 3D footprint shape
Definition: 3d_info.h:42
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:143
Module description (excepted pads)
void SetComment3(const wxString &aComment)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
bool m_MicroViasAllowed
true to allow micro vias
TEXTE_MODULE * parseTEXTE_MODULE()
int m_number
Definition: class_board.h:117
D_PAD * parseD_PAD(MODULE *aParent=NULL)
MODULE * parseMODULE(wxArrayString *aInitialComments=0)
Function parseMODULE.
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
int m_EdgeSegmentWidth
current graphic line width (EDGE layer only)
double m_SolderPasteMarginRatio
Solder pask margin ratio value of pad size The final margin is the sum of these 2 values...
EDGE_MODULE class definition.
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
void SetBold(bool aBold)
Definition: eda_text.h:172
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:71
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
wxPoint m_AuxOrigin
origin for plot exports
Class DIMENSION.
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:74
void parseSetup()
Definition: pcb_parser.cpp:992
T lookUpLayer(const M &aMap)
Function lookUpLayer parses the current token for the layer definition of a BOARD_ITEM object...
Definition: pcb_parser.cpp:926
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
int m_SolderMaskMinWidth
Solder mask min width.
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
wxString m_Filename
The 3D shape filename in 3D library.
Definition: 3d_info.h:45
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...