|
|
/*
* 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() ); } } }
|