diff options
Diffstat (limited to 'new/sch_sweet_parser.cpp')
-rw-r--r-- | new/sch_sweet_parser.cpp | 1561 |
1 files changed, 1561 insertions, 0 deletions
diff --git a/new/sch_sweet_parser.cpp b/new/sch_sweet_parser.cpp new file mode 100644 index 0000000..f0be7bd --- /dev/null +++ b/new/sch_sweet_parser.cpp @@ -0,0 +1,1561 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <sch_sweet_parser.h> +#include <sch_part.h> +#include <sch_lib_table.h> +#include <sch_lpid.h> + +#include <macros.h> + +using namespace SCH; +using namespace PR; + + +#define MAX_INHERITANCE_NESTING 6 ///< max depth of inheritance, no problem going larger + + +static inline int internal( const STRING& aCoord ) +{ + return LogicalToInternal( strtod( aCoord.c_str(), NULL ) ); +} + +static inline int fromWidth( const STRING& aWidth ) +{ + return WidthToInternal( strtod( aWidth.c_str(), NULL ) ); +} + +static inline int fromFontz( const STRING& aFontSize ) +{ + return FontzToInternal( strtod( aFontSize.c_str(), NULL ) ); +} + + +/** + * Enum PartBit + * is a set of bit positions that can be used to create flag bits within + * PART::contains to indicate what state the PART is in and what it contains, i.e. + * whether the PART has been parsed, and what the PART contains, categorically. + */ +enum PartBit +{ + parsed, ///< have parsed this part already, otherwise 'body' text must be parsed + extends, ///< saw "extends" keyword, inheriting from another PART + value, + anchor, + reference, + footprint, + datasheet, + model, + keywords, +}; + + +/// Function PB +/// is a PartBit shifter for PART::contains field. +static inline const int PB( PartBit oneBitOnly ) +{ + return ( 1 << oneBitOnly ); +} + + +void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ) +{ + T tok; + + libs = aTable; + + // empty everything out, could be re-parsing this object and it may not be empty. + me->clear(); + +#if 0 + // Be flexible regarding the starting point of the stream. + // Caller may not have read the first two tokens out of the + // stream: T_LEFT and T_part, so ignore them if seen here. + // The 1st two tokens T_LEFT and T_part are then optional in the grammar. + if( ( tok = NextTok() ) == T_LEFT ) + { + if( ( tok = NextTok() ) != T_part ) + Expecting( T_part ); + } + +#else + // "( part" are not optional + NeedLEFT(); + + if( ( tok = NextTok() ) != T_part ) + Expecting( T_part ); +#endif + + NeedSYMBOLorNUMBER(); // toss NAME_HINT + tok = NextTok(); + + // extends must be _first_ thing, if it is present at all, after NAME_HINT + if( tok == T_extends ) + { + parseExtends( me ); + tok = NextTok(); + } + + for( ; tok!=T_RIGHT; tok = NextTok() ) + { + if( tok == T_LEFT ) + { + PROPERTY* prop; + + tok = NextTok(); + + // because exceptions are thrown, any 'new' allocation has to be stored + // somewhere other than on the stack, ASAP. + + switch( tok ) + { + default: + // describe what we expect at this level + Expecting( + "anchor|value|footprint|model|keywords|alternates\n" + "|property\n" + " |property_del\n" + "|pin\n" + " |pin_merge|pin_swap|pin_renum|pin_rename|route_pin_swap\n" + "|polyline|line|rectangle|circle|arc|bezier|text" + ); + break; + + case T_anchor: + if( contains & PB(anchor) ) + Duplicate( tok ); + NeedNUMBER( "anchor x" ); + me->anchor.x = internal( CurText() ); + NeedNUMBER( "anchor y" ); + me->anchor.y = internal( CurText() ); + contains |= PB(anchor); + break; + + case T_line: + case T_polyline: + POLY_LINE* pl; + pl = new POLY_LINE( me ); + me->graphics.push_back( pl ); + parsePolyLine( pl ); + break; + + case T_rectangle: + RECTANGLE* rect; + rect = new RECTANGLE( me ); + me->graphics.push_back( rect ); + parseRectangle( rect ); + break; + + case T_circle: + CIRCLE* circ; + circ = new CIRCLE( me ); + me->graphics.push_back( circ ); + parseCircle( circ ); + break; + + case T_arc: + ARC* arc; + arc = new ARC( me ); + me->graphics.push_back( arc ); + parseArc( arc ); + break; + + case T_bezier: + BEZIER* bezier; + bezier = new BEZIER( me ); + me->graphics.push_back( bezier ); + parseBezier( bezier ); + break; + + case T_text: + GR_TEXT* text; + text = new GR_TEXT( me ); + me->graphics.push_back( text ); + parseText( text ); + break; + + case T_property: + prop = new PROPERTY( me ); + // @todo check for uniqueness + me->properties.push_back( prop ); + NeedSYMBOLorNUMBER(); + prop->name = FromUTF8(); + + L_prop: + NeedSYMBOLorNUMBER(); + prop->text = FromUTF8(); + tok = NextTok(); + if( tok == T_LEFT ) + { + tok = NextTok(); + if( tok != T_effects ) + Expecting( T_effects ); + parseTextEffects( prop->EffectsLookup() ); + NeedRIGHT(); + } + else if( tok != T_RIGHT ) + Expecting( ") | effects" ); + break; + + case T_property_del: + parsePropertyDel( me ); + break; + + // reference in a PART is incomplete, it is just the prefix of an + // unannotated reference. Only components have full reference designators. + case T_reference: + if( contains & PB(reference) ) + Duplicate( tok ); + contains |= PB(reference); + prop = me->FieldLookup( PART::REFERENCE ); + goto L_prop; + + case T_value: + if( contains & PB(value) ) + Duplicate( tok ); + contains |= PB(value); + prop = me->FieldLookup( PART::VALUE ); + goto L_prop; + + case T_footprint: + if( contains & PB(footprint) ) + Duplicate( tok ); + contains |= PB(footprint); + prop = me->FieldLookup( PART::FOOTPRINT ); + goto L_prop; + + case T_datasheet: + if( contains & PB(datasheet) ) + Duplicate( tok ); + contains |= PB(datasheet); + prop = me->FieldLookup( PART::DATASHEET ); + goto L_prop; + + case T_model: + if( contains & PB(model) ) + Duplicate( tok ); + contains |= PB(model); + prop = me->FieldLookup( PART::MODEL ); + goto L_prop; + + case T_keywords: + parseKeywords( me ); + break; + + case T_alternates: + // @todo: do we want to inherit alternates? + parseAlternates( me ); + break; + + case T_pin: + // @todo PADNAMEs must be unique + PIN* pin; + pin = new PIN( me ); + me->pins.push_back( pin ); + parsePin( pin ); + break; + + case T_pin_del: + parsePinDel( me ); + break; + + case T_pin_swap: + parsePinSwap( me ); + break; + + case T_pin_renum: + parsePinRenum( me ); + break; + + case T_pin_rename: + parsePinRename( me ); + break; + + case T_pin_merge: + parsePinMerge( me ); + break; + + /* + @todo + + case T_route_pin_swap: + break; + */ + } + } + + else + { + switch( tok ) + { + default: + Unexpected( tok ); + } + } + } + + contains |= PB(parsed); + + me->contains |= contains; +} + + +void SWEET_PARSER::parseExtends( PART* me ) +{ + PART* base; + int offset; + + if( contains & PB(extends) ) + Duplicate( T_extends ); + + NeedSYMBOLorNUMBER(); + me->setExtends( new LPID() ); + + offset = me->extends->Parse( CurText() ); + if( offset > -1 ) // -1 is success + THROW_PARSE_ERROR( _("invalid extends LPID"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() + offset ); + + base = libs->LookupPart( *me->extends, me->Owner() ); + + // we could be going in circles here, recursively, or too deep, set limits + // and disallow extending from self (even indirectly) + int extendsDepth = 0; + for( const PART* ancestor = base; ancestor && extendsDepth<MAX_INHERITANCE_NESTING; + ++extendsDepth, ancestor = ancestor->base ) + { + if( ancestor == me ) + { + THROW_PARSE_ERROR( _("'extends' may not have self as any ancestor"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + } + + if( extendsDepth == MAX_INHERITANCE_NESTING ) + { + THROW_PARSE_ERROR( _("max allowed extends depth exceeded"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + me->inherit( *base ); + me->base = base; + contains |= PB(extends); +} + + +void SWEET_PARSER::parseAlternates( PART* me ) +{ + T tok; + PART_REF lpid; + int offset; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( "lpid" ); + + // lpid.clear(); Parse does this + + offset = lpid.Parse( CurText() ); + if( offset > -1 ) + THROW_PARSE_ERROR( _("invalid alternates LPID"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() + offset ); + + // PART_REF assignment should be OK, it contains no ownership + me->alternates.push_back( lpid ); + } +} + + +void SWEET_PARSER::parseKeywords( PART* me ) +{ + T tok; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( !IsSymbol( tok ) && tok!=T_NUMBER ) + Expecting( "symbol|number" ); + + // just insert them, duplicates are silently removed and tossed. + me->keywords.insert( FromUTF8() ); + } +} + + +void SWEET_PARSER::parseFont( FONT* me ) +{ + /* + # The FONT value needs to be defined. Currently, EESchema does not support + # different fonts. In the future this feature may be implemented and at + # that time FONT will have to be defined. Initially, only the font size and + # style are required. Italic and bold styles are optional. The font size + # height and width are in units yet to be determined. + (font [FONT] (size HEIGHT WIDTH) [italic] [bold]) + */ + + // handle the [FONT] 'position dependently', i.e. first + T tok = NextTok(); + bool sawBold = false; + bool sawItalic = false; + bool sawSize = false; + + if( IsSymbol( tok ) ) + { + me->name = FromUTF8(); + tok = NextTok(); + } + + for( ; tok != T_RIGHT; tok = NextTok() ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + + switch( tok ) + { + case T_size: + if( sawSize ) + Duplicate( T_size ); + sawSize = true; + + NeedNUMBER( "size height" ); + me->size.height = fromFontz( CurText() ); + + NeedNUMBER( "size width" ); + me->size.width = fromFontz( CurText() ); + NeedRIGHT(); + break; + + default: + Expecting( "size" ); + } + } + else + { + switch( tok ) + { + case T_bold: + if( sawBold ) + Duplicate( T_bold ); + sawBold = true; + me->bold = true; + break; + + case T_italic: + if( sawItalic ) + Duplicate( T_italic ); + sawItalic = true; + me->italic = true; + break; + + default: + Unexpected( "bold|italic" ); + } + } + } +} + + +void SWEET_PARSER::parseBool( bool* aBool ) +{ + T tok = NeedSYMBOL(); + + switch( tok ) + { + case T_yes: + case T_no: + *aBool = (tok == T_yes); + break; + default: + Expecting( "yes|no" ); + } +} + + +void SWEET_PARSER::parseStroke( STROKE* me ) +{ + /* + (stroke [WIDTH] [(style [(dashed...)]...)]) + + future place holder for arrow heads, dashed lines, all line glamour + */ + + NeedNUMBER( "stroke" ); + *me = fromWidth( CurText() ); + NeedRIGHT(); +} + + +void SWEET_PARSER::parsePinText( PINTEXT* me ) +{ + /* either: + (signal SIGNAL (font [FONT] (size HEIGHT WIDTH) [italic] [bold])(visible YES)) + or + (pad PADNAME (font [FONT] (size HEIGHT WIDTH) [italic] [bold])(visible YES)) + */ + T tok; + bool sawFont = false; + bool sawVis = false; + + // pad or signal text + NeedSYMBOLorNUMBER(); + me->text = FromUTF8(); + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + + switch( tok ) + { + case T_font: + if( sawFont ) + Duplicate( tok ); + sawFont = true; + parseFont( &me->font ); + break; + + case T_visible: + if( sawVis ) + Duplicate( tok ); + sawVis = true; + parseBool( &me->isVisible ); + NeedRIGHT(); + break; + + default: + Expecting( "font" ); + } + } + + else + { + switch( tok ) + { + default: + Expecting( T_LEFT ); + } + } + } +} + + +void SWEET_PARSER::parsePin( PIN* me ) +{ + /* + (pin TYPE SHAPE + (at X Y [ANGLE]) + (length LENGTH) + (signal NAME (font [FONT] (size HEIGHT WIDTH) [italic] [bold])(visible YES)) + (pad NUMBER (font [FONT] (size HEIGHT WIDTH) [italic] [bold] (visible YES)) + (visible YES) + ) + */ + + T tok; + bool sawShape = false; + bool sawType = false; + bool sawAt = false; + bool sawLen = false; + bool sawSignal = false; + bool sawPad = false; + bool sawVis = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + + switch( tok ) + { + case T_at: + if( sawAt ) + Duplicate( tok ); + sawAt = true; + parseAt( &me->pos, &me->angle ); + break; + + case T_length: + if( sawLen ) + Duplicate( tok ); + sawLen = true; + NeedNUMBER( "length" ); + me->length = internal( CurText() ); + NeedRIGHT(); + break; + + case T_signal: + if( sawSignal ) + Duplicate( tok ); + sawSignal = true; + parsePinText( &me->signal ); + break; + + case T_pad: + if( sawPad ) + Duplicate( tok ); + sawPad = true; + parsePinText( &me->pad ); + break; + + case T_visible: + if( sawVis ) + Duplicate( tok ); + sawVis = true; + parseBool( &me->isVisible ); + NeedRIGHT(); + break; + + default: + Unexpected( tok ); + } + } + + else // not wrapped in parentheses + { + switch( tok ) + { + case T_in: + case T_out: + case T_inout: + case T_tristate: + case T_passive: + case T_unspecified: + case T_power_in: + case T_power_out: + case T_open_collector: + case T_open_emitter: + case T_unconnected: + if( sawType ) + Duplicate( tok ); + sawType = true; + me->connectionType = tok; + break; + + case T_none: + case T_line: + case T_inverted: + case T_clock: + case T_inverted_clk: + case T_input_low: + case T_clock_low: + case T_falling_edge: + case T_non_logic: + if( sawShape ) + Duplicate( tok ); + sawShape = true; + me->shape = tok; + break; + + default: + Unexpected( tok ); + } + } + } +} + + +void SWEET_PARSER::parsePinDel( PART* me ) +{ + wxString pad; + + // we do this somewhat unorthodoxically because we want to avoid doing two lookups, + // which would need to be done to 1) find pin, and 2) delete pin. Only one + // lookup is needed with this scheme. + + NeedSYMBOLorNUMBER(); + pad = FromUTF8(); + + // lookup now while CurOffset() is still meaningful. + PINS::iterator it = me->pinFindByPad( pad ); + if( it == me->pins.end() ) + { + THROW_PARSE_ERROR( _("undefined pin"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + +/* enable in future, but not now while testing + if( (*it)->birthplace == me ) + { + THROW_PARSE_ERROR( _("pin_del allowed for inherited pins only"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } +*/ + + NeedRIGHT(); + + delete *it; // good thing I'm a friend. + me->pins.erase( it ); +} + + +void SWEET_PARSER::parsePinSwap( PART* me ) +{ + PIN* pin1; + PIN* pin2; + + wxString pad; + + NeedSYMBOLorNUMBER(); + pad = FromUTF8(); + + // lookup now while CurOffset() is still meaningful. + pin1 = me->PinFindByPad( pad ); + if( !pin1 ) + { + THROW_PARSE_ERROR( _("undefined pin"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + NeedSYMBOLorNUMBER(); + pad = FromUTF8(); + + pin2 = me->PinFindByPad( pad ); + if( !pin2 ) + { + THROW_PARSE_ERROR( _("undefined pin"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + NeedRIGHT(); + + // swap only the text, but might want to swap entire PIN_TEXTs + pin2->pad.text = pin1->pad.text; + pin1->pad.text = pad; +} + + +void SWEET_PARSER::parsePinRenum( PART* me ) +{ + PIN* pin; + + wxString oldPad; + wxString newPad; + + NeedSYMBOLorNUMBER(); + oldPad = FromUTF8(); + + // lookup now while CurOffset() is still meaningful. + pin = me->PinFindByPad( oldPad ); + if( !pin ) + { + THROW_PARSE_ERROR( _("undefined pin"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + NeedSYMBOLorNUMBER(); + newPad = FromUTF8(); + + NeedRIGHT(); + + // @todo: check for pad legalities + pin->pad.text = newPad; +} + + +void SWEET_PARSER::parsePinRename( PART* me ) +{ + PIN* pin; + + wxString pad; + wxString newSignal; + + NeedSYMBOLorNUMBER(); + pad = FromUTF8(); + + // lookup now while CurOffset() is still meaningful. + pin = me->PinFindByPad( pad ); + if( !pin ) + { + THROW_PARSE_ERROR( _("undefined pin"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + NeedSYMBOLorNUMBER(); + newSignal = FromUTF8(); + + NeedRIGHT(); + + pin->signal.text = newSignal; +} + + +void SWEET_PARSER::parsePinMerge( PART* me ) +{ + T tok; + wxString pad; + wxString signal; + wxString msg; + + NeedSYMBOLorNUMBER(); + + wxString anchorPad = FromUTF8(); + + // lookup now while CurOffset() is still good. + PINS::iterator pit = me->pinFindByPad( anchorPad ); + if( pit == me->pins.end() ) + { + msg.Printf( _( "undefined pin %s" ), anchorPad.GetData() ); + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + if( !(*pit)->pin_merge.IsEmpty() && anchorPad != (*pit)->pin_merge ) + { + msg.Printf( _( "pin %s already in pin_merge group %s" ), + anchorPad.GetData(), (*pit)->pin_merge.GetData() ); + + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + (*pit)->isVisible = true; + (*pit)->pin_merge = anchorPad; + + // allocate or find a MERGE_SET; + MERGE_SET& ms = me->pin_merges[anchorPad]; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + + switch( tok ) + { + case T_signals: + { + PINS sigPins; // no ownership + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( "signal" ); + + signal = FromUTF8(); + + sigPins.clear(); + + me->PinsFindBySignal( &sigPins, signal ); + + if( !sigPins.size() ) + { + msg.Printf( _( "no pins with signal %s" ), signal.GetData() ); + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + for( pit = sigPins.begin(); pit != sigPins.end(); ++pit ) + { + if( !(*pit)->pin_merge.IsEmpty() && anchorPad != (*pit)->pin_merge ) + { + msg.Printf( _( "signal pin %s already in pin_merge group %s" ), + pad.GetData(), (*pit)->pin_merge.GetData() ); + + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + (*pit)->isVisible = true; + (*pit)->pin_merge = anchorPad; + ms.insert( pad ); + } + } + } + break; + + case T_pads: + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( "pad" ); + + pad = FromUTF8(); + + D(printf("pad=%s\n", TO_UTF8( pad ) );) + + // find the PIN and mark it as being in this MERGE_SET or throw + // error if already in another MERGET_SET. + + pit = me->pinFindByPad( pad ); + if( pit == me->pins.end() ) + { + msg.Printf( _( "undefined pin %s" ), pad.GetData() ); + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + if( !(*pit)->pin_merge.IsEmpty() /* && anchorPad != (*pit)->pin_merge */ ) + { + msg.Printf( _( "pin %s already in pin_merge group %s" ), + pad.GetData(), (*pit)->pin_merge.GetData() ); + + THROW_PARSE_ERROR( msg, + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + (*pit)->isVisible = false; + (*pit)->pin_merge = anchorPad; + + ms.insert( pad ); + } + break; + + default: + Expecting( "pads|signals" ); + break; + } + } + else + { + Expecting( T_LEFT ); + } + } +} + + +void SWEET_PARSER::parsePropertyDel( PART* me ) +{ + NeedSYMBOLorNUMBER(); + + wxString propertyName = FromUTF8(); + + if( !me->PropDelete( propertyName ) ) + { + wxString msg; + msg.Printf( _( "Unable to find property: %s" ), propertyName.GetData() ); + THROW_IO_ERROR( msg ); + } + NeedRIGHT(); +} + + +void SWEET_PARSER::parseTextEffects( TEXT_EFFECTS* me ) +{ + /* + (effects [PROPERTY] + + # Position requires X and Y coordinates. Position coordinates can be + # non-intergr. Angle is in degrees and defaults to 0 if not defined. + (at X Y [ANGLE]) + + # The FONT value needs to be defined. Currently, EESchema does not support + # different fonts. In the future this feature may be implemented and at + # that time FONT will have to be defined. Initially, only the font size and + # style are required. Italic and bold styles are optional. The font size + # height and width are in units yet to be determined. + (font [FONT] (size HEIGHT WIDTH) [italic] [bold]) + + # Valid visibility values are yes and no. + (visible YES) + ) + */ + + bool sawFont = false; + bool sawAt = false; + bool sawVis = false; + + T tok = NextTok(); + + if( IsSymbol( tok ) ) + { + me->propName = FromUTF8(); + tok = NextTok(); + } + + for( ; tok != T_RIGHT; tok = NextTok() ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_at: + if( sawAt ) + Duplicate( tok ); + sawAt = true; + parseAt( &me->pos, &me->angle ); + break; + + case T_font: + if( sawFont ) + Duplicate( tok ); + sawFont = true; + parseFont( &me->font ); + break; + + case T_visible: + if( sawVis ) + Duplicate( sawVis ); + sawVis = true; + parseBool( &me->isVisible ); + NeedRIGHT(); + break; + + default: + Expecting( "at|font|visible" ); + } + } +} + + +void SWEET_PARSER::parsePolyLine( POLY_LINE* me ) +{ + /* + (polyline|line + (pts (xy X Y) (xy X Y) (xy X Y) (xy X Y) (xy X Y)) + + # Line widths are in percent of a pin delta + [(stroke [WIDTH] [(style [(dashed...)]...)])] + + + # Valid fill types are none, filled, and transparent. + (fill FILL_TYPE) + ) + */ + + T tok; + int count = 0; + bool sawStroke = false; + bool sawFill = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_stroke: + if( sawStroke ) + Duplicate( tok ); + sawStroke = true; + parseStroke( &me->stroke ); + break; + + case T_pts: + if( count ) + Duplicate( tok ); + for( ; ( tok = NextTok() ) != T_RIGHT; ++count ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NeedSYMBOL(); + if( tok != T_xy ) + Expecting( T_xy ); + + me->pts.push_back( POINT() ); + + NeedNUMBER( "x" ); + me->pts.back().x = internal( CurText() ); + + NeedNUMBER( "y" ); + me->pts.back().y = internal( CurText() ); + + NeedRIGHT(); + } + if( count < 2 ) + Expecting( ">= 2 pts" ); + break; + + case T_fill: + if( sawFill ) + Duplicate( tok ); + tok = NeedSYMBOL(); + switch( tok ) + { + case T_none: + case T_filled: + case T_transparent: + me->fillType = tok; + break; + default: + Expecting( "none|filled|transparent" ); + } + NeedRIGHT(); + sawFill = true; + break; + + default: + Expecting( "pts|stroke|fill" ); + } + } +} + + +void SWEET_PARSER::parseBezier( BEZIER* me ) +{ + parsePolyLine( me ); +} + + +void SWEET_PARSER::parseRectangle( RECTANGLE* me ) +{ + /* + (rectangle (start X Y) (end X Y) (stroke WIDTH) (fill FILL_TYPE)) + */ + + T tok; + bool sawStart = false; + bool sawEnd = false; + bool sawStroke = false; + bool sawFill = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_stroke: + if( sawStroke ) + Duplicate( tok ); + sawStroke = true; + parseStroke( &me->stroke ); + break; + + case T_fill: + if( sawFill ) + Duplicate( tok ); + sawFill = true; + tok = NeedSYMBOL(); + switch( tok ) + { + case T_none: + case T_filled: + case T_transparent: + me->fillType = tok; + break; + default: + Expecting( "none|filled|transparent" ); + } + NeedRIGHT(); + break; + + case T_start: + if( sawStart ) + Duplicate( tok ); + sawStart = true; + NeedNUMBER( "x" ); + me->start.x = internal( CurText() ); + NeedNUMBER( "y" ); + me->start.y = internal( CurText() ); + NeedRIGHT(); + break; + + case T_end: + if( sawEnd ) + Duplicate( tok ); + sawEnd = true; + NeedNUMBER( "x" ); + me->end.x = internal( CurText() ); + NeedNUMBER( "y" ); + me->end.y = internal( CurText() ); + NeedRIGHT(); + break; + + default: + Expecting( "start|end|stroke|fill" ); + } + } +} + + +void SWEET_PARSER::parseCircle( CIRCLE* me ) +{ + /* + (circle (center X Y) + # Radius length is in units if defined or mils. + (radius LENGTH) + (stroke WIDTH) + (fill FILL_TYPE) + ) + */ + + T tok; + bool sawCenter = false; + bool sawRadius = false; + bool sawStroke = false; + bool sawFill = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_stroke: + if( sawStroke ) + Duplicate( tok ); + sawStroke = true; + parseStroke( &me->stroke ); + break; + + case T_fill: + if( sawFill ) + Duplicate( tok ); + sawFill = true; + tok = NeedSYMBOL(); + switch( tok ) + { + case T_none: + case T_filled: + case T_transparent: + me->fillType = tok; + break; + default: + Expecting( "none|filled|transparent" ); + } + NeedRIGHT(); + break; + + case T_center: + if( sawCenter ) + Duplicate( tok ); + sawCenter = true; + NeedNUMBER( "center x" ); + me->center.x = internal( CurText() ); + NeedNUMBER( "center y" ); + me->center.y = internal( CurText() ); + NeedRIGHT(); + break; + + case T_radius: + if( sawRadius ) + Duplicate( tok ); + sawRadius = true; + NeedNUMBER( "radius" ); + me->radius = internal( CurText() ); + NeedRIGHT(); + break; + + default: + Expecting( "center|radius|stroke|fill" ); + } + } +} + + +void SWEET_PARSER::parseArc( ARC* me ) +{ + /* + (arc (pos X Y) (radius RADIUS) (start X Y) (end X Y) + (stroke WIDTH) + (fill FILL_TYPE) + ) + */ + + T tok; + bool sawPos = false; + bool sawStart = false; + bool sawEnd = false; + bool sawRadius = false; + bool sawStroke = false; + bool sawFill = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_stroke: + if( sawStroke ) + Duplicate( tok ); + sawStroke = true; + parseStroke( &me->stroke ); + break; + + case T_fill: + if( sawFill ) + Duplicate( tok ); + sawFill = true; + tok = NeedSYMBOL(); + switch( tok ) + { + case T_none: + case T_filled: + case T_transparent: + me->fillType = tok; + break; + default: + Expecting( "none|filled|transparent" ); + } + NeedRIGHT(); + break; + + case T_pos: + if( sawPos ) + Duplicate( tok ); + sawPos = true; + NeedNUMBER( "pos x" ); + me->pos.x = internal( CurText() ); + NeedNUMBER( "pos y" ); + me->pos.y = internal( CurText() ); + NeedRIGHT(); + break; + + case T_radius: + if( sawRadius ) + Duplicate( tok ); + sawRadius = true; + NeedNUMBER( "radius" ); + me->radius = internal( CurText() ); + NeedRIGHT(); + break; + + case T_start: + if( sawStart ) + Duplicate( tok ); + sawStart = true; + NeedNUMBER( "start x" ); + me->start.x = internal( CurText() ); + NeedNUMBER( "start y" ); + me->start.y = internal( CurText() ); + NeedRIGHT(); + break; + + case T_end: + if( sawEnd ) + Duplicate( tok ); + sawEnd = true; + NeedNUMBER( "end x" ); + me->end.x = internal( CurText() ); + NeedNUMBER( "end y" ); + me->end.y = internal( CurText() ); + NeedRIGHT(); + break; + + default: + Expecting( "center|radius|stroke|fill" ); + } + } +} + + +void SWEET_PARSER::parseAt( POINT* pos, float* angle ) +{ + T tok; + + NeedNUMBER( "at x" ); + pos->x = internal( CurText() ); + + NeedNUMBER( "at y" ); + pos->y = internal( CurText() ); + + tok = NextTok(); + if( angle && tok == T_NUMBER ) + { + *angle = strtod( CurText(), NULL ); + tok = NextTok(); + } + if( tok != T_RIGHT ) + Expecting( T_RIGHT ); +} + + +void SWEET_PARSER::parseText( GR_TEXT* me ) +{ + /* + (text "This is the text that gets drawn." + (at X Y [ANGLE]) + + # Valid horizontal justification values are center, right, and left. Valid + # vertical justification values are center, top, bottom. + (justify HORIZONTAL_JUSTIFY VERTICAL_JUSTIFY) + (font [FONT] (size HEIGHT WIDTH) [italic] [bold]) + (visible YES) + (fill FILL_TYPE) + ) + */ + + T tok; + bool sawAt = false; + bool sawFill = false; + bool sawFont = false; + bool sawVis = false; + bool sawJust = false; + bool sawText = false; + + while( ( tok = NextTok() ) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + + switch( tok ) + { + case T_at: + if( sawAt ) + Duplicate( tok ); + parseAt( &me->pos, &me->angle ); + sawAt = true; + break; + + case T_fill: + if( sawFill ) + Duplicate( tok ); + tok = NeedSYMBOL(); + switch( tok ) + { + case T_none: + case T_filled: + case T_transparent: + me->fillType = tok; + break; + default: + Expecting( "none|filled|transparent" ); + } + NeedRIGHT(); + sawFill = true; + break; + + case T_justify: + if( sawJust ) + Duplicate( tok ); + tok = NeedSYMBOL(); + switch( tok ) + { + case T_center: + case T_right: + case T_left: + me->hjustify = tok; + break; + default: + Expecting( "center|right|left" ); + } + + tok = NeedSYMBOL(); + switch( tok ) + { + case T_center: + case T_top: + case T_bottom: + me->vjustify = tok; + break; + default: + Expecting( "center|top|bottom" ); + } + NeedRIGHT(); + sawJust = true; + break; + + case T_visible: + if( sawVis ) + Duplicate( tok ); + parseBool( &me->isVisible ); + NeedRIGHT(); + sawVis = true; + break; + + case T_font: + if( sawFont ) + Duplicate( tok ); + sawFont = true; + parseFont( &me->font ); + break; + + default: + Expecting( "at|justify|font|visible|fill" ); + } + } + else + { + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( T_STRING ); + + if( sawText ) + Duplicate( tok ); + sawText = true; + + me->text = wxString::FromUTF8( CurText() ); + } + } +} + |