Here’s a bit of code to read SVG paths – it’s from my code to convert vector graphics to OpenVG commands and 6809 assembler for the Vectrex (among other things). However, as that’s progressing at around the speed of continental drift I may as well put it up here in the hope that someone else may get some use out of it. It uses Boost.Spirit, which is an excellent method of turning EBNF grammars into something that looks like Martian hieroglyphics, should you be so minded :
// Literals.</pre>
<pre>
nsParser::rule<sIter> flag;
nsParser::rule<sIter> comma;
nsParser::rule<sIter> sign;
nsParser::rule<sIter> wsp;
nsParser::rule<sIter> digit;
nsParser::rule<sIter> dot;
nsParser::rule<sIter> comma_wsp;
nsParser::rule<sIter> exponent;
nsParser::rule<sIter> digit_sequence;
nsParser::rule<sIter> integer_constant;
nsParser::rule<sIter> floating_point_constant;
nsParser::rule<sIter> fractional_constant;
nsParser::rule<sIter> number;
nsParser::rule<sIter> nonnegative_number;
nsParser::rule<sIter> coordinate;
nsParser::rule<sIter> coordinate_pair;
// Path commands.
nsParser::rule<sIter> closepath;
nsParser::rule<sIter> lineto_argument_sequence;
nsParser::rule<sIter> lineto;
nsParser::rule<sIter> moveto_argument_sequence;
nsParser::rule<sIter> moveto;
nsParser::rule<sIter> horizontal_lineto_argument_sequence;
nsParser::rule<sIter> horizontal_lineto;
nsParser::rule<sIter> vertical_lineto_argument_sequence;
nsParser::rule<sIter> vertical_lineto;
nsParser::rule<sIter> curveto;
nsParser::rule<sIter> curveto_argument;
nsParser::rule<sIter> curveto_argument_sequence;
nsParser::rule<sIter> smooth_curveto;
nsParser::rule<sIter> smooth_curveto_argument;
nsParser::rule<sIter> smooth_curveto_argument_sequence;
nsParser::rule<sIter> quadratic_bezier_curveto;
nsParser::rule<sIter> quadratic_bezier_curveto_argument;
nsParser::rule<sIter> quadratic_bezier_curveto_argument_sequence;
nsParser::rule<sIter> smooth_quadratic_bezier_curveto;
nsParser::rule<sIter> smooth_quadratic_bezier_curveto_argument;
nsParser::rule<sIter> smooth_quadratic_bezier_curveto_argument_sequence;
nsParser::rule<sIter> elliptical_arc;
nsParser::rule<sIter> elliptical_arc_argument;
nsParser::rule<sIter> elliptical_arc_argument_sequence;
nsParser::rule<sIter> drawto_command;
nsParser::rule<sIter> drawto_commands;
nsParser::rule<sIter> moveto_drawto_command_group;
nsParser::rule<sIter> moveto_drawto_command_groups;
nsParser::rule<sIter> svg_path;
CParsePath::CParsePath ()
{
InputString = "";
itStart = InputString.begin ();
itEnd = InputString.end ();
// Define parser elements.
flag = (nsParser::lit ('0') | nsParser::lit ('1'));
comma = (nsParser::lit (','));
sign = (nsParser::lit ('+') | nsParser::lit ('-'));
wsp = (
nsParser::lit (' ') |
nsParser::lit ('\t') |
nsParser::lit ('\r') |
nsParser::lit ('\n')
);
digit = (
nsParser::lit ('0') |
nsParser::lit ('1') |
nsParser::lit ('2') |
nsParser::lit ('3') |
nsParser::lit ('4') |
nsParser::lit ('5') |
nsParser::lit ('6') |
nsParser::lit ('7') |
nsParser::lit ('8') |
nsParser::lit ('9')
);
dot = nsParser::lit ('.');
// 0 or 1 : EBNF ? Qi -
// 0 or more : EBNF * Qi *
// 1 or more : EBNF + Qi +
comma_wsp = (+wsp >> -comma >> *wsp) | (comma >> *wsp);
/*
digit-sequence:
digit
| digit digit-sequence
NOTE : Don't understand - isn't this just "one or more"?
*/
digit_sequence = (+digit);
exponent = ((nsParser::lit ('E') | nsParser::lit ('e')) >> -sign >> digit_sequence);
integer_constant = digit_sequence;
fractional_constant = ((-digit_sequence >> dot >> digit_sequence) | (digit_sequence >> dot));
floating_point_constant = ((fractional_constant >> -digit_sequence) | (digit_sequence >> exponent));
number = ((-sign >> integer_constant) | (-sign >> floating_point_constant));
nonnegative_number = (integer_constant | floating_point_constant);
coordinate = number;
coordinate_pair = (coordinate >> -comma-wsp >> coordinate);
closepath = (nsParser::lit (ABSOLUTE_CLOSEPATH) | nsParser::lit (RELATIVE_CLOSEPATH));
lineto_argument_sequence = ((coordinate_pair) | (coordinate_pair >> -comma_wsp >> lineto_argument_sequence));
lineto = (nsParser::lit (ABSOLUTE_LINETO) | nsParser::lit (RELATIVE_LINETO)) >> *wsp >> lineto_argument_sequence;
moveto_argument_sequence = ((coordinate_pair) | (coordinate_pair >> -comma_wsp >> lineto_argument_sequence));
moveto = (nsParser::lit (ABSOLUTE_MOVETO) | nsParser::lit (RELATIVE_MOVETO)) >> *wsp >> moveto_argument_sequence;
horizontal_lineto_argument_sequence = ((coordinate) | (coordinate >> -comma_wsp >> horizontal_lineto_argument_sequence));
horizontal_lineto = (nsParser::lit (ABSOLUTE_HLINETO) | nsParser::lit (RELATIVE_HLINETO)) >> *wsp >> horizontal_lineto_argument_sequence;
vertical_lineto_argument_sequence = ((coordinate) | (coordinate >> -comma_wsp >> vertical_lineto_argument_sequence));
vertical_lineto = (nsParser::lit (ABSOLUTE_VLINETO) | nsParser::lit (RELATIVE_VLINETO)) >> *wsp >> vertical_lineto_argument_sequence;
curveto_argument = (coordinate_pair >> -comma_wsp >> coordinate_pair >> -comma_wsp >> coordinate_pair);
curveto_argument_sequence = ((curveto_argument) | (curveto_argument >> -comma-wsp >> curveto_argument_sequence));
curveto = ((nsParser::lit (ABSOLUTE_CURVETO) | nsParser::lit (RELATIVE_CURVETO)) >> *wsp >> curveto_argument_sequence);
smooth_curveto_argument = (coordinate_pair >> -comma_wsp >> coordinate_pair >> -comma_wsp >> coordinate_pair);
smooth_curveto_argument_sequence = ((smooth_curveto_argument) | (smooth_curveto_argument >> -comma-wsp >> smooth_curveto_argument_sequence));
smooth_curveto = ((nsParser::lit (ABSOLUTE_SCURVETO) | nsParser::lit (RELATIVE_CURVETO)) >> *wsp >> smooth_curveto_argument_sequence);
quadratic_bezier_curveto_argument = (coordinate_pair >> -comma_wsp >> coordinate_pair);
quadratic_bezier_curveto_argument_sequence = ((quadratic_bezier_curveto_argument) | (quadratic_bezier_curveto_argument >> -comma-wsp >> quadratic_bezier_curveto_argument_sequence));
quadratic_bezier_curveto = ((nsParser::lit (ABSOLUTE_QCURVETO) | nsParser::lit (RELATIVE_QCURVETO)) >> *wsp >> quadratic_bezier_curveto_argument_sequence);
smooth_quadratic_bezier_curveto_argument_sequence = ((smooth_quadratic_bezier_curveto_argument) | (smooth_quadratic_bezier_curveto_argument >> -comma-wsp >> smooth_quadratic_bezier_curveto_argument_sequence));
smooth_quadratic_bezier_curveto_argument = (coordinate_pair >> -comma_wsp >> smooth_quadratic_bezier_curveto_argument_sequence);
smooth_quadratic_bezier_curveto = ((nsParser::lit (ABSOLUTE_SQCURVETO) | nsParser::lit (RELATIVE_SQCURVETO)) >> *wsp >> smooth_quadratic_bezier_curveto_argument_sequence);
elliptical_arc_argument = nonnegative_number >> -comma_wsp >> nonnegative_number -comma_wsp >> number >> comma_wsp >> flag >> comma_wsp >> coordinate_pair;
elliptical_arc_argument_sequence = (elliptical_arc_argument | (elliptical_arc_argument >> -comma_wsp >> elliptical_arc_argument_sequence));
elliptical_arc = ((nsParser::lit (ABSOLUTE_ARCTO) | nsParser::lit (RELATIVE_ARCTO)) >> *wsp >> elliptical_arc_argument_sequence);
drawto_command =
closepath |
lineto |
horizontal_lineto |
vertical_lineto |
curveto |
smooth_curveto |
quadratic_bezier_curveto |
smooth_quadratic_bezier_curveto |
elliptical_arc;
drawto_commands = (drawto_command | (drawto_command >> *wsp >> drawto_commands));
moveto_drawto_command_group = (moveto >> *wsp >> -drawto_commands);
moveto_drawto_command_groups = moveto_drawto_command_group | (moveto_drawto_command_group >> *wsp >> moveto_drawto_command_groups);
svg_path = *wsp >> -moveto_drawto_command_groups >> *wsp;
}
</pre>
<pre>
NOTE : Obviously this is C++ rather than C, however I can’t seem to get WordPress to accept “C++” as a category name at present …
