Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / shapesyylex.ll
blobd7dde0f3cfb7aab120dc4f54026ac91637c37f10
1 /* This file is part of Shapes.
2  *
3  * Shapes is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * any later version.
7  *
8  * Shapes is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with Shapes.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Copyright 2008 Henrik Tidefelt
17  */
21 #include <cmath>
23 #include "shapesscanner.h"
24 #include "shapesvalue.h"
25 #include "shapestypes.h"
26 #include "astflow.h"
27 #include "astvar.h"
28 #include "astclass.h"
29 #include "shapesexceptions.h"
30 #include "texlabelmanager.h"
31 #include "globals.h"
32 #include "exitcodes.h"
34 using namespace Shapes;
35 #include "yyltype.h"
36 #include "shapesparser.h"
38 #include <string>
39 #include <cstdlib>
40 #include <iostream>
41 #include <fstream>
42 #include <iomanip>
44 #define YY_USER_ACTION doBeforeEachAction( );
45 #define YY_EXIT_FAILURE Shapes::Interaction::EXIT_INTERNAL_ERROR
47 double shapes_strtod( char * str, char ** end );
48 char shapes_hexToChar( char c1, char c2 );
52 WhiteSpace [ ]
54 Float [~]?[0-9]+([.][0-9]*)?("*^"[~]?[0-9]+)?
55 Greek "α"|"β"|"γ"|"Γ"|"δ"|"Δ"|"ε"|"ζ"|"η"|"Θ"|"ι"|"κ"|"λ"|"Λ"|"μ"|"ν"|"χ"|"Ξ"|"π"|"Π"|"ρ"|"σ"|"Σ"|"τ"|"ϕ"|"ω"|"Ω"
56 LowerCaseLetter [a-z_?]
57 UpperCaseLetter [A-Z]
58 Letter {LowerCaseLetter}|{UpperCaseLetter}|{Greek}
59 Identifier {Letter}({Letter}|[0-9])*
60 DynamicMark "@"
61 StateMark "#"|"•"
62 TypeMark "//"|"§"
65 %option c++
66 %option noyywrap
67 %option yylineno
69 %option prefix="shapes"
70 %option yyclass="ShapesScanner"
72 %x DiscardRestOfLineAndBEGIN_INITIAL
73 %x Incl
74 %x Needs
75 %x InclFrom
76 %x InclPath
77 %x String
78 %x PoorMansString
79 %x DataStringPlain
80 %x DataStringHex
81 %x Comment
82 %x LaTeXOption
83 %x LaTeXClass
84 %x LaTeXPreamble
85 %x LaTeXDocumentTop
86 %x RandSeed
87 %x NewUnitName
88 %x NewUnitEqual
89 %x NewUnitValue
90 %x Echo
91 %x Author
96 ^"##classoption"[ \t]+ { BEGIN( LaTeXOption ); }
97 ^"##documentclass"[ \t]+ { BEGIN( LaTeXClass ); }
98 ^"##preamble"[ \t] { BEGIN( LaTeXPreamble ); }
99 ^"##documenttop"[ \t] { BEGIN( LaTeXDocumentTop ); }
100 ^"##no-lmodernT1"[\n] { Kernel::theTeXLabelManager.setlmodernT1( shapeslloc, false ); }
101 ^"##no-utf8"[\n] { Kernel::theTeXLabelManager.setutf8( shapeslloc, false ); }
102 ^"##seed"[ \t]+ { BEGIN( RandSeed ); }
103 ^"##unit"[ \t]+ { BEGIN( NewUnitName ); }
104 ^"##include"[ \t]+ { BEGIN( Incl ); return T_srcLoc; }
105 ^"##needs"[ \t]+ { BEGIN( Needs ); return T_srcLoc; }
106 ^"##echo"[ \t] { BEGIN( Echo ); }
107 ^"##author"[ \t] { BEGIN( Author ); }
108 ^"##"[^\"] {
109         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "All lines beginning with ## must be scanner specials.       Please use a leading horizontal whitespace if this is not what is intended." ) ) );
112 <DiscardRestOfLineAndBEGIN_INITIAL>.* {
113         BEGIN( INITIAL );
116 <LaTeXOption>[^,\n]+ { Kernel::theTeXLabelManager.addDocumentOption( shapeslloc, yytext ); }
117 <LaTeXOption>[\n] {
118         shapeslloc.firstLine = shapeslloc.lastLine + 1;
119         shapeslloc.lastLine = shapeslloc.firstLine;
120         shapeslloc.lastColumn = 0;
121         BEGIN( INITIAL );
124 <LaTeXClass>.+ { Kernel::theTeXLabelManager.setDocumentClass( shapeslloc, yytext ); }
125 <LaTeXClass>[\n] {
126         shapeslloc.firstLine = shapeslloc.lastLine + 1;
127         shapeslloc.lastLine = shapeslloc.firstLine;
128         shapeslloc.lastColumn = 0;
129         BEGIN( INITIAL );
132 <LaTeXPreamble>.* { Kernel::theTeXLabelManager.addPreambleLine( shapeslloc, yytext ); }
133 <LaTeXPreamble>[\n] {
134         shapeslloc.firstLine = shapeslloc.lastLine + 1;
135         shapeslloc.lastLine = shapeslloc.firstLine;
136         shapeslloc.lastColumn = 0;
137         BEGIN( INITIAL );
140 <LaTeXDocumentTop>.* { Kernel::theTeXLabelManager.addDocumentTopLine( shapeslloc, yytext );     }
141 <LaTeXDocumentTop>[\n] {
142         shapeslloc.firstLine = shapeslloc.lastLine + 1;
143         shapeslloc.lastLine = shapeslloc.firstLine;
144         shapeslloc.lastColumn = 0;
145         BEGIN( INITIAL );
148 <RandSeed>.* {
149         char * end;
150         long int s = strtol( yytext, & end, 10 );
151         if( *end != '\0' )
152                 {
153                         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Failed to scan integer." ) ) );
154                 }
155         else
156                 {
157                         if( s < 0 )
158                                 {
159                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Random nuber generator seed must not be negative." ) ) );
160                                 }
161                         else
162                                 {
163                                         srand( s );
164                                 }
165                 }
167 <RandSeed>[\n] {
168         shapeslloc.firstLine = shapeslloc.lastLine + 1;
169         shapeslloc.lastLine = shapeslloc.firstLine;
170         shapeslloc.lastColumn = 0;
171         BEGIN( INITIAL );
174 <NewUnitName>{Identifier} {
175         newUnitName = strdup( yytext );
176         BEGIN( NewUnitEqual );
178 <NewUnitName>. {
179         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Expected identifier." ) ) );
180         BEGIN( DiscardRestOfLineAndBEGIN_INITIAL );
182 <NewUnitEqual>[ \t]*"="[ \t]* { BEGIN( NewUnitValue ); }
183 <NewUnitEqual>. {
184         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Expected '='." ) ) );
185         BEGIN( DiscardRestOfLineAndBEGIN_INITIAL );
187 <NewUnitValue>{Float}"bp" {
188         char * end;
189         double newUnitValue = shapes_strtod( yytext, & end );
190         typedef typeof unitTable MapType;
191         MapType::const_iterator i = unitTable.find( newUnitName );
192         if( i != unitTable.end( ) )
193                 {
194                         if( i->second != newUnitValue )
195                                 {
196                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
197                                 }
198                 }
199         else
200                 {
201                         unitTable[ newUnitName ] = newUnitValue;
202                 }
203         BEGIN( INITIAL );
205 <NewUnitValue>{Float}"mm" {
206         char * end;
207         double newUnitValue = shapes_strtod( yytext, & end ) * ( 0.1 * 72 / 2.54 );
208         typedef typeof unitTable MapType;
209         MapType::const_iterator i = unitTable.find( newUnitName );
210         if( i != unitTable.end( ) )
211                 {
212                         if( i->second != newUnitValue )
213                                 {
214                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
215                                 }
216                 }
217         else
218                 {
219                         unitTable[ newUnitName ] = newUnitValue;
220                 }
221         BEGIN( INITIAL );
223 <NewUnitValue>{Float}"cm" {
224         char * end;
225         double newUnitValue = shapes_strtod( yytext, & end ) * ( 72 / 2.54 );
226         typedef typeof unitTable MapType;
227         MapType::const_iterator i = unitTable.find( newUnitName );
228         if( i != unitTable.end( ) )
229                 {
230                         if( i->second != newUnitValue )
231                                 {
232                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
233                                 }
234                 }
235         else
236                 {
237                         unitTable[ newUnitName ] = newUnitValue;
238                 }
239         BEGIN( INITIAL );
241 <NewUnitValue>{Float}"m" {
242         char * end;
243         double newUnitValue = shapes_strtod( yytext, & end ) * ( 100 * 72 / 2.54 );
244         typedef typeof unitTable MapType;
245         MapType::const_iterator i = unitTable.find( newUnitName );
246         if( i != unitTable.end( ) )
247                 {
248                         if( i->second != newUnitValue )
249                                 {
250                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
251                                 }
252                 }
253         else
254                 {
255                         unitTable[ newUnitName ] = newUnitValue;
256                 }
257         BEGIN( INITIAL );
259 <NewUnitValue>{Float}"in" {
260         char * end;
261         double newUnitValue = shapes_strtod( yytext, & end ) * 72;
262         typedef typeof unitTable MapType;
263         MapType::const_iterator i = unitTable.find( newUnitName );
264         if( i != unitTable.end( ) )
265                 {
266                         if( i->second != newUnitValue )
267                                 {
268                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
269                                 }
270                 }
271         else
272                 {
273                         unitTable[ newUnitName ] = newUnitValue;
274                 }
275         BEGIN( INITIAL );
277 <NewUnitValue>{Float}{Identifier} {
278         char * end;
279         double val = shapes_strtod( yytext, & end );
281         typedef typeof unitTable MapType;
282         MapType::const_iterator i = unitTable.find( end );
283         if( i == unitTable.end( ) )
284                 {
285                         Ast::theAnalysisErrorsList.push_back( new Exceptions::LookupUnknownUnit( shapeslloc, strrefdup( end ) ) );
286                 }
287         else
288                 {
289                         double newUnitValue = val * i->second;
291                         i = unitTable.find( newUnitName );
292                         if( i != unitTable.end( ) )
293                                 {
294                                         if( i->second != newUnitValue )
295                                                 {
296                                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExistingUnit( shapeslloc, strrefdup( newUnitName ) ) );
297                                                 }
298                                 }
299                         else
300                                 {
301                                         unitTable[ newUnitName ] = newUnitValue;
302                                 }
303                 }
304         BEGIN( INITIAL );
306 <NewUnitValue>. {
307         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Expected a length." ) ) );
308         BEGIN( DiscardRestOfLineAndBEGIN_INITIAL );
313 {Float}"°" |
314 {Float}"^^" {
315         char * end;
316         shapeslval.floatVal = M_PI / 180 * shapes_strtod( yytext, & end );
317         return T_float;
320 {Float}"bp" {
321         char * end;
322         shapeslval.floatVal = shapes_strtod( yytext, & end );
323         return T_length;
326 {Float}"mm" {
327         char * end;
328         shapeslval.floatVal = shapes_strtod( yytext, & end ) * ( 0.1 * 72 / 2.54 );
329         return T_length;
332 {Float}"cm" {
333         char * end;
334         shapeslval.floatVal = shapes_strtod( yytext, & end ) * ( 72 / 2.54 );
335         return T_length;
338 {Float}"m" {
339         char * end;
340         shapeslval.floatVal = shapes_strtod( yytext, & end ) * ( 100 * 72 / 2.54 );
341         return T_length;
344 {Float}"in" {
345         char * end;
346         shapeslval.floatVal = shapes_strtod( yytext, & end ) * 72;
347         return T_length;
350 {Float}{Identifier} {
351         char * end;
352         double val = shapes_strtod( yytext, & end );
354         typedef typeof unitTable MapType;
355         MapType::const_iterator i = unitTable.find( end );
356         if( i == unitTable.end( ) )
357                 {
358                         Ast::theAnalysisErrorsList.push_back( new Exceptions::LookupUnknownUnit( shapeslloc, strrefdup( end ) ) );
359                 }
360         else
361                 {
362                         shapeslval.floatVal = val * i->second;
363                 }
364         return T_length;
367 {Float}[\%][D0] {
368         char * end;
369         double val = shapes_strtod( yytext, & end );
370         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST );
371         return T_speciallength;
374 {Float}[\%][C1] {
375         char * end;
376         double val = shapes_strtod( yytext, & end );
377         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CIRC );
378         return T_speciallength;
381 {Float}[\%][M2] {
382         char * end;
383         double val = shapes_strtod( yytext, & end );
384         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CORR );
385         return T_speciallength;
388 {Float}[\%][F3] {
389         char * end;
390         double val = shapes_strtod( yytext, & end );
391         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CIRC | Computation::SPECIALU_CORR );
392         return T_speciallength;
395 {Float}[\%][d4] {
396         char * end;
397         double val = shapes_strtod( yytext, & end );
398         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_NOINFLEX );
399         return T_speciallength;
402 {Float}[\%][c5] {
403         char * end;
404         double val = shapes_strtod( yytext, & end );
405         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CIRC | Computation::SPECIALU_NOINFLEX     );
406         return T_speciallength;
409 {Float}[\%][m6] {
410         char * end;
411         double val = shapes_strtod( yytext, & end );
412         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CORR | Computation::SPECIALU_NOINFLEX     );
413         return T_speciallength;
416 {Float}[\%][f7] {
417         char * end;
418         double val = shapes_strtod( yytext, & end );
419         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_DIST | Computation::SPECIALU_CIRC | Computation::SPECIALU_CORR | Computation::SPECIALU_NOINFLEX        );
420         return T_speciallength;
423 {Float}[\%][i9] {
424         char * end;
425         double val = shapes_strtod( yytext, & end );
426         shapeslval.expr = new Ast::SpecialLength( shapeslloc, val, Computation::SPECIALU_NOINFLEX );
427         return T_speciallength;
431 {Float} {
432         char * end;
433         shapeslval.floatVal = shapes_strtod( yytext, & end );
434         return T_float;
437 "\'"[~]?[0-9]+ {
438         const char * src = yytext + 1;
439         bool negative = false;
440         if( *src == '~' )
441                 {
442                         negative = true;
443                         ++src;
444                 }
445         char * end;
446         int absval = strtol( src, & end, 10 );
447         if( negative )
448                 {
449                         shapeslval.intVal = - absval;
450                 }
451         else
452                 {
453                         shapeslval.intVal = absval;
454                 }
455         return T_int;
458 "\'0x"[0-9A-F]+ {
459         char * end;
460         shapeslval.intVal = strtol( yytext + 3, & end, 16 );
461         return T_int;
464 "\'0b"[0-1]+ {
465         char * end;
466         shapeslval.intVal = strtol( yytext + 3, & end, 2 );
467         return T_int;
470 "∞" {
471         shapeslval.floatVal = HUGE_VAL;
472         return T_float;
475 "true" {
476         shapeslval.boolVal = true;
477         return T_bool;
480 "false" {
481         shapeslval.boolVal = false;
482         return T_bool;
485 "--" { return T_minusminus; }
486 "++" { return T_plusplus; }
487 ".." { return T_ddot; }
488 "..." { return T_dddot; }
490 "::" { return T_declaretype; }
491 ":=" { return T_assign; }
492 "=" { return T_eqeq; }
493 "/="|"≠" { return T_eqneq; }
495 "->"|"→" { return T_mapsto; }
496 "../" { return T_surrounding; }
497 "[]" { return T_emptybrackets; }
498 "[...]" { return T_dddotbrackets; }
499 "()"|"⊙" { return T_compose; }
501 "(>" { return T_unionLeft; }
502 "<)" { return T_unionRight; }
503 "<>" { return T_split; }
504 "(<" { return T_splitLeft; }
505 ">)" { return T_splitRight; }
506 "(|" { return T_absLeft; }
507 "|)" { return T_absRight; }
509 [\{\}\(\)\[\]\<\>] { return yytext[0]; }
510 [\.\,\;\:\_\@\!\#\%\&\|\^\-\+\'\"\\] { return yytext[0]; }
511 [*/~=] { return yytext[0]; }
513 "*/"|"∥" { return T_projection; }
514 "/_"|"∠" { return T_angle; }
515 "&|" { return T_ampersandMore; }
517 "<="|"≤" { return T_lesseq; }
518 ">="|"≥" { return T_greatereq; }
520 "<<"|"≪" { return T_llthan; }
521 ">>"|"≫" { return T_ggthan; }
523 "@@" { return T_atat; }
525 "and"|"⋀" { return T_and; }
526 "or"|"⋁" { return T_or; }
527 "xor"|"⊻" { return T_xor; }
528 "not"|"¬" { return T_not; }
530 "dynamic" { return T_dynamic; }
532 "cycle" { return T_cycle; }
534 "TeX" { return T_tex; }
536 "indexof" { return T_indexof; }
537 "depthof" { return T_depthof; }
538 "VARNAME" { return T_variableName; }
540 "continuation" { return T_continuation; /* Reserved for future use */ }
541 "continue" { return T_continue; /* Reserved for future use */ }
542 "escape_continuation" { return T_esc_continuation; }
543 "escape_continue" { return T_esc_continue; }
544 "escape_backtrace" { return T_esc_backtrace; }
546 "class" { return T_class; }
547 "__members__" { return T_members; }
548 "__prepare__" { return T_prepare; }
549 "__abstract__" { return T_abstract; }
550 "__overrides<" { return T_overrides; }
551 ">__" { return T_gr__; }
553 {WhiteSpace}+ ;
554 [\t]+ {
555         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Illegal use of reserved tab character." ) ) );
558 [\n] {
559         shapeslloc.firstLine = shapeslloc.lastLine + 1;
560         shapeslloc.lastLine = shapeslloc.firstLine;
561         shapeslloc.lastColumn = 0;
564 <INITIAL>"|**".*[\n] { ++shapeslloc.lastLine; shapeslloc.lastColumn = 0; }
565 <INITIAL>"/**" { quoteDepth = 1; BEGIN( Comment ); }
566 <INITIAL>"**/" { throw Exceptions::ScannerError( shapeslloc, strrefdup( "Found closing comment delimiter outside comment." ) ); }
567 <Comment>"/**" { ++quoteDepth; more( ); }
568 <Comment>"**/" {
569         --quoteDepth;
570         if( quoteDepth == 0 )
571                 {
572                         BEGIN( INITIAL );
573                 }
574         else
575                 {
576                         more( );
577                 }
579 <Comment>. { }
580 <Comment>[\n] { ++shapeslloc.lastLine; shapeslloc.lastColumn = 0; }
581 <Comment><<EOF>> {
582         /* It seems like YY_USER_ACTION is not invoked at EOF, so we do this manually,
583          * however ignornig yyleng (which has the value 1).
584          */
585         shapeslloc.firstColumn = shapeslloc.lastColumn;
586         throw Exceptions::ScannerError( shapeslloc, strrefdup( "Found EOF while scanning comment." ) );
589 <INITIAL>[`][\n]? {
590         if( yyleng > 1 )
591                 {
592                         ++shapeslloc.lastLine;
593                         shapeslloc.lastColumn = 0;
594                 }
595         quoteDepth = 1;
596         BEGIN( String );
598 <INITIAL>"´" { throw Exceptions::ScannerError( shapeslloc, strrefdup( "Found closing quote outside string." ) ); }
599 <String>"`" { ++quoteDepth; more( ); }
600 <String>"´" {
601         --quoteDepth;
602         if( quoteDepth == 0 )
603                 {
604                         yytext[ yyleng - 2 ] = '\0';
605                         rinseString( );
606                         --shapeslloc.firstColumn;
607                         BEGIN( INITIAL );
608                         return T_string;
609                 }
610         else
611                 {
612                         more( );
613                         yymore( ); // The purpose of this line is only to let flex know that we use yy_more_flag
614                 }
617 <String,PoorMansString>[\n] { ++shapeslloc.lastLine; shapeslloc.lastColumn = 0; more( ); }
618 <String,PoorMansString>. { more( ); }
619 <String,PoorMansString><<EOF>> {
620         /* It seems like YY_USER_ACTION is not invoked at EOF, so we do this manually,
621          * however ignornig yyleng (which has the value 1).
622          */
623         shapeslloc.firstColumn = shapeslloc.lastColumn;
624         throw Exceptions::ScannerError( shapeslloc, strrefdup( "Found EOF while scanning string." ) );
627 <INITIAL>"(\""[\n]? {
628         if( yyleng > 2 )
629                 {
630                         ++shapeslloc.lastLine;
631                         shapeslloc.lastColumn = 0;
632                 }
633         quoteDepth = 1;
634         BEGIN( PoorMansString );
636 <INITIAL>"\")" { throw Exceptions::ScannerError( shapeslloc, strrefdup( "Found closing poor man's quote outside string." ) ); }
637 <PoorMansString>"\")" {
638         yytext[ yyleng - 2 ] = '\0';
639         rinseString( );
640         --shapeslloc.firstColumn;
641         BEGIN( INITIAL );
642         return T_string;
645 <INITIAL>"\"{" {
646         while( ! dataStringChunks_.empty( ) )
647                 {
648                         delete dataStringChunks_.back( ).first;
649                         dataStringChunks_.pop_back( );
650                 }
651         dataStringTotalLength_ = 0;
652         BEGIN( DataStringHex );
654 <DataStringPlain,DataStringHex>[\n] { ++shapeslloc.lastLine; shapeslloc.lastColumn = 0; }
655 <DataStringPlain>[ -z]+ {
656         dataStringChunks_.push_back( std::pair< char *, size_t >( strdup( yytext ), yyleng ) );
657         dataStringTotalLength_ += yyleng;
659 <DataStringHex>[ \t]+ { }
660 <DataStringHex>(([A-F0-9]{2})|[a-z])+ {
661         char * res = new char[ yyleng + 1 ];
662         char * dst = res;
663         for( const char * src = yytext; *src != '\0'; ++dst )
664                 {
665                         if( 'a' <= *src && *src <= 'z' )
666                                 {
667                                         switch( *src )
668                                                 {
669                                                 case 'n':
670                                                         *dst = '\n';
671                                                         break;
672                                                 case 't':
673                                                         *dst = '\t';
674                                                         break;
675                                                 default:
676                                                         *dst = '\0';
677                                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( std::string( "Invalid character name in escape mode: " ) + *src ) ) );
678                                                 }
679                                         src += 1;
680                                 }
681                         else
682                                 {
683                                         *dst = shapes_hexToChar( src[0], src[1] );
684                                          src += 2;
685                                 }
686                 }
687         dataStringChunks_.push_back( std::pair< char *, size_t >( res, dst - res ) );
688         dataStringTotalLength_ += dst - res;
690 <DataStringHex>[{] { BEGIN( DataStringPlain ); }
691 <DataStringPlain>[}] { BEGIN( DataStringHex ); }
692 <DataStringHex>[}] {
693         concatenateDataString( );
694         BEGIN( INITIAL );
695         return T_string;
697 <DataStringPlain,DataStringHex>. {
698         throw Exceptions::ScannerError( shapeslloc, strrefdup( "Stray character in \"{...} string." ) );
701 <Incl>[^ \t\n]+ {
702         currentNeedFile = yytext;
703         currentNeedPushCount = 0;
704         currentNeedIsNeed = false;
705         BEGIN( InclFrom );
708 <Needs>[^ \t\n]+ {
709         currentNeedFile = yytext;
710         currentNeedPushCount = 0;
711         currentNeedIsNeed = true;
712         BEGIN( InclFrom );
715 <InclFrom>[ \t]+ { }
716 <InclFrom>[\n] { doInclusion( ); }
717 <InclFrom>":"[ \t]+ { BEGIN( InclPath ); }
718 <InclFrom>":". { throw Exceptions::ScannerError( shapeslloc, strrefdup( "The \":\" must be followed by whitespace." ) ); }
719 <InclFrom>. { throw Exceptions::ScannerError( shapeslloc, strrefdup( "Expected \":\"." ) ); }
721 <InclPath>[ \t]+ { }
722 <InclPath>[^ \t\n]+ {
723         push_frontNeedPath( yytext );
724         ++currentNeedPushCount;
726 <InclPath>[\n] {
727         if( currentNeedPushCount == 0 )
728                 {
729                         throw Exceptions::ScannerError( shapeslloc, strrefdup( "Missing paths after \"from\"." ) );
730                 }
731         doInclusion( );
734 <Echo>.* {
735         std::cerr << yytext << std::endl ;
736         BEGIN( INITIAL );
739 <Author>.* {
740         if( ! stateStack.empty( ) )
741                 {
742                         Kernel::theDocInfo.addExtensionAuthorString( shapeslloc.file_->name( ) + std::string( " by " ) + yytext );
743                 }
744         else
745                 {
746                         if( ! Kernel::theDocInfo.addInfo( "Author", SimplePDF::newString( yytext ) ) )
747                                 {
748                                         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( "Multiply specified #author." ) ) );
749                                 }
750                 }
751         BEGIN( INITIAL );
755 <<EOF>> {
756         /* It seems like YY_USER_ACTION is not invoked at EOF, so we do this manually,
757          * however ignornig yyleng (which has the value 1).
758          */
759         shapeslloc.firstColumn = shapeslloc.lastColumn;
761         if( stateStack.empty( ) )
762         {
763                 if( inPrelude_ )
764                         {
765                                 delete preludeFile_;
766                                 for( ; preludeIterator_ != needSearchPath.end( ); ++preludeIterator_ )
767                                         {
768                                                 std::string filename = needpathWithSuffix( *preludeIterator_, "Shapes-Prelude" );
769                                                 struct stat theStatDummy;
770                                                 if( stat( filename.c_str( ), & theStatDummy ) == 0 )
771                                                         {
772                                                                 preludeFile_ = new std::ifstream( filename.c_str( ) );
773                                                                 yy_switch_to_buffer( yy_create_buffer( preludeFile_, YY_BUF_SIZE ) );
774                                                                 shapeslloc = Ast::SourceLocation( Ast::FileID::build_stat( theStatDummy, filename ) );
775                                                                 break;
776                                                         }
777                                         }
779                                 if( preludeIterator_ == needSearchPath.end( ) )
780                                         {
781                                                 goto noMorePreludes;
782                                         }
784                                 goto done;
785                         }
787         noMorePreludes:
788                 if( ! yyinQueue_.empty( ) )
789                         {
790                                 yy_switch_to_buffer( yy_create_buffer( yyinQueue_.front( ).first, YY_BUF_SIZE ) );
791                                 shapeslloc = Ast::SourceLocation( yyinQueue_.front( ).second );
792                                 yyinQueue_.pop_front( );
793                                 if( inPrelude_ )
794                                         {
795                                                 inPrelude_ = false;
796                                                 if( interactive_ )
797                                                         {
798                                                                 return T_interactiveMark;
799                                                         }
800                                                 else
801                                                         {
802                                                                 return T_preludesep;
803                                                         }
804                                         }
805                         }
806                 else if( inPrelude_ )
807                         {
808                                 inPrelude_ = false;
809                                 return T_preludesep;
810                         }
811                 else
812                         {
813                                 return T_EOF;
814                         }
815         done:
816                 ++preludeIterator_; /* We do this here instead of before the "goto done;", so we get something to jump to.*/
817         }
818         else
819         {
820                 yy_delete_buffer( YY_CURRENT_BUFFER );
821                 yy_switch_to_buffer( stateStack.top( ) );
822                 stateStack.pop( );
823                 shapeslloc = locStack.top( );
824                 locStack.pop( );
825                 for( size_t tmp = pathCountStack.top( ); tmp > 0; --tmp )
826                         {
827                                 pop_frontNeedPath( );
828                         }
829                 pathCountStack.pop( );
830         }
833 {Identifier} {
834         shapeslval.char_p = strdup( yytext );
835         return T_identifier;
837 {TypeMark}{Identifier} {
838         const char * id = yytext + 2; // The type mark is allways 2 bytes.
839         shapeslval.char_p = strdup( id );
840         return T_typename;
843 {DynamicMark}{Identifier} {
844         shapeslval.char_p = strdup( yytext + 1 );
845         return T_dynamic_identifier;
847 {StateMark}{Identifier} {
848         const char * id = yytext;
849         // Depending on which state mark is used, we must skip different number of bytes.
850         if( *id == '#' )
851                 {
852                         id += 1;
853                 }
854         else // The state mark is '•'
855                 {
856                         id += 3;
857                 }
858         shapeslval.char_p = strdup( id );
859         return T_state_identifier;
861 {DynamicMark}{StateMark}{Identifier} {
862         const char * id = yytext + 1; // The dynamic mark is allways 1 byte.
863         // Depending on which state mark is used, we must skip different number of bytes.
864         if( *id == '#' )
865                 {
866                         id += 1;
867                 }
868         else // The state mark is '•'
869                 {
870                         id += 3;
871                 }
872         shapeslval.char_p = strdup( id );
873         return T_dynamic_state_identifier;
876 . {
877         Ast::theAnalysisErrorsList.push_back( new Exceptions::ScannerError( shapeslloc, strrefdup( ( std::string( "Scanner found unrecognized token: " ) + yytext ).c_str( ) ) ) );
878         BEGIN( DiscardRestOfLineAndBEGIN_INITIAL );
882 /* The closing %% above marks the end of the Rules section and the beginning
883  * of the User Subroutines section. All text from here to the end of the
884  * file is copied verbatim to the end of the generated lex.pdf.c file.
885  * This section is where you put definitions of helper functions.
886  */
888 double
889 shapes_strtod( char * str, char ** end )
891         char termTmp;
892         char * term = str;
893         for( ; *term != '\0'; ++term )
894                 {
895                         switch( *term )
896                                 {
897                                 case '0':
898                                 case '1':
899                                 case '2':
900                                 case '3':
901                                 case '4':
902                                 case '5':
903                                 case '6':
904                                 case '7':
905                                 case '8':
906                                 case '9':
907                                 case '.':
908                                         continue;
909                                 case '~':
910                                         *term = '-';
911                                         continue;
912                                 case '*':
913                                         // We replace the "*^" by something in the notation of strtod
914                                         *term = 'e';
915                                         if( *(term+2) == '~' )
916                                                 {
917                                                         *(term+1) = '-';
918                                                         *(term+2) = '0';
919                                                         term += 3;
920                                                 }
921                                         else
922                                                 {
923                                                         *(term+1) = '0';
924                                                         term += 2;
925                                                 }
926                                         continue;
927                                 }
928                         break;
929                 }
930         termTmp = *term;
931         *term = '\0';
932         double val = strtod( str, end );
933         *term = termTmp;
934         return val;
937 char
938 shapes_hexToChar( char c1, char c2 )
940         return
941                 static_cast< char >
942                 ( 16 * ( ( c1 < 'A' ) ? static_cast< unsigned char >( c1 - '0' ) : static_cast< unsigned char >( c1 - 'A' + 10 ) )
943                         +
944                         ( ( c2 < 'A' ) ? static_cast< unsigned char >( c2 - '0' ) : static_cast< unsigned char >( c2 - 'A' + 10 ) ) );
947 void
948 ShapesScanner::start( )
950         static const Ast::FileID * START_NULL_FILE = Ast::FileID::build_internal( "<start-null>" );
951         inPrelude_ = true;
952         if( interactive_ )
953                 {
954                         preludeIterator_ = needSearchPath.end( );
955                 }
956         else
957                 {
958                         preludeIterator_ = needSearchPath.begin( );
959                 }
960         preludeFile_ = new std::istringstream( "" ); /* This will result in EOF immediately, and then we turn to the first real file. */
961         yy_switch_to_buffer( yy_create_buffer( preludeFile_, YY_BUF_SIZE ) );
962         shapeslloc.file_ = START_NULL_FILE;
965 void
966 ShapesScanner::doInclusion( )
968         std::string path;
969         if( currentNeedIsNeed )
970                 {
971                         path = searchFile( currentNeedFile + ".shext" );
972                 }
973         else
974                 {
975                         path = searchFile( currentNeedFile + ".shape" );
976                 }
978         struct stat theStat;
979         if( stat( path.c_str( ), & theStat ) != 0 )
980                 {
981                         throw Exceptions::FileReadOpenError( shapeslloc, strrefdup( path.c_str( ) ), 0, 0, Exceptions::FileReadOpenError::STAT );
982                 }
983         const Ast::FileID * fileID = Ast::FileID::build_stat( theStat, path );
984         if( currentNeedIsNeed )
985                 {
986                         if( neededFiles.find( fileID ) != neededFiles.end( ) )
987                                 {
988                                         shapeslloc.firstLine = shapeslloc.lastLine + 1;
989                                         shapeslloc.lastLine = shapeslloc.firstLine;
990                                         shapeslloc.lastColumn = 0;
991                                         BEGIN( INITIAL );
992                                         return;
993                                 }
994                         neededFiles.insert( fileID );
995                 }
997         std::ifstream * iFile = new std::ifstream( path.c_str( ) );
998         if( ! iFile->good( ) )
999                 {
1000                         throw Exceptions::FileReadOpenError( shapeslloc, strrefdup( path.c_str( ) ), 0, 0 );
1001                 }
1003         shapeslloc.firstLine = shapeslloc.lastLine + 1;
1004         shapeslloc.lastLine = shapeslloc.firstLine;
1005         shapeslloc.lastColumn = 0;
1007         locStack.push( shapeslloc );
1008         shapeslloc = Ast::SourceLocation( fileID );
1009         stateStack.push( YY_CURRENT_BUFFER );
1010         yy_switch_to_buffer( yy_create_buffer( iFile, YY_BUF_SIZE ) );
1011         pathCountStack.push( currentNeedPushCount );
1013         BEGIN( INITIAL );
1016 void
1017 ShapesScanner::queueStream( std::istream * is, const Ast::FileID * yyinFile )
1019         yyinQueue_.push_back( std::pair< std::istream * , const Ast::FileID * >( is, yyinFile ) );