Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 991 lines (923 sloc) 16.366 kb
a9461cd initializing repo from version 0.10.2 minus the example files
Julian authored
1 // codeline.cpp
2 // Revision 10-feb-2005
3
4 #include "codeline.h"
5
6 #include "keyword.h"
7 #include "token.h"
8 #include "error.h"
9 #include "util.h"
10
11 #include "trace.h"
12
13 #include <iostream>
14 #include <sstream>
15 #include <algorithm>
16 #include <cctype>
17 #include <iostream>
18
19 #include <math.h>
20
21 using std::cerr;
22 using std::endl;
23 using std::flush;
24 using std::istringstream;
25 using std::fill_n;
26 using std::transform;
27 using std::isxdigit;
28
29
30 namespace {
31
32 inline bool is_space (char c)
33 {
34 return isspace (static_cast <unsigned char> (c) );
35 }
36
37 inline bool is_bindigit (char c)
38 {
39 return c == '0' || c == '1';
40 }
41
42 inline bool is_octdigit (char c)
43 {
44 return c >= '0' && c <= '7';
45 }
46
47 inline bool is_decdigit (char c)
48 {
49 return isdigit (static_cast <unsigned char> (c) );
50 }
51
52
53 inline bool is_hexdigit (char c)
54 {
55 return isxdigit (static_cast <unsigned char> (c) );
56 }
57
58 inline bool is_base (char c, int base)
59 {
60 switch (base)
61 {
62 case 2:
63 return is_bindigit (c);
64 case 8:
65 return is_octdigit (c);
66 case 16:
67 return is_hexdigit (c);
68 default:
69 return false;
70 }
71 }
72
73 inline int valdigit (unsigned char c)
74 {
75 if (islower (c) )
76 c= static_cast <unsigned char> (c + '9' - 'a' + 1);
77 else if (isupper (c) )
78 c= static_cast <unsigned char> (c + '9' - 'A' + 1);
79 return c - '0';
80 }
81
82 inline bool is_beginidentifier (char c)
83 {
84 return isalpha (static_cast <unsigned char> (c) ) /* || c == '_' */;
85 }
86
87 inline bool is_identifier (char c)
88 {
89 return isalnum (static_cast <unsigned char> (c) ) || c == '_';
90 }
91
92 } // namespace
93
94 BlNumber CodeLine::Token::number (const std::string & str)
95 {
96 const size_t l= str.size ();
97 if (l == 0)
98 return 0;
99 size_t i= 0;
100 BlNumber n= 0;
101 unsigned char c;
102 if (str [0] == '&')
103 {
104 if (l > 1)
105 {
106 long num= 0;
107 c= str [1];
108 if (c == 'X' || c == 'x')
109 {
110 // Binary
111 i= 1;
112 while (++i < l && is_bindigit (c= str [i]) )
113 {
114 num*= 2;
115 num+= c- '0';
116 }
117 }
118 else if (c == 'O' || c == 'o')
119 {
120 // Octal
121 i= 1;
122 while (++i < l && is_octdigit (c= str [i]) )
123 {
124 num*= 8;
125 num+= c- '0';
126 }
127 }
128 else
129 {
130 // Hexadecimal
131 if (c == 'H' || c == 'h')
132 i= 1;
133 while (++i < l && is_hexdigit (c= str [i] ) )
134 {
135 num*= 16;
136 if (c >= 'a' && c <= 'f')
137 c= (unsigned char)
138 (c + '9' - 'a' + 1);
139 else if (c >= 'A' && c <= 'F')
140 c= (unsigned char)
141 (c + '9' - 'A' + 1);
142 num+= c - '0';
143 }
144 }
145 n= num;
146 }
147 }
148 else {
149 // Decimal
150 #if 0
151 while (i < l && is_digit (c= str [i]) )
152 {
153 n*= 10;
154 n+= c - '0';
155 ++i;
156 }
157 if (i < l && str [i] == '.')
158 {
159 ++i;
160 BlNumber mult= 0.1;
161 while (i < l && is_digit (c= str [i] ) )
162 {
163 n+= (c - '0') * mult;
164 mult/= 10;
165 ++i;
166 }
167 }
168 if (i < l && (str [i] == 'E' || str [i] == 'e') )
169 {
170 ++i;
171 BlNumber e= 0;
172 bool neg= false;
173 if (str [i] == '-')
174 {
175 neg= true;
176 ++i;
177 }
178 while (i < l && (is_digit (c= str [i] ) ) )
179 {
180 e*= 10;
181 e+= c - '0';
182 ++i;
183 }
184 if (neg) e= -e;
185 n*= pow (10, e);
186 }
187 #else
188 istringstream iss (str);
189 iss >> n;
190 #endif
191 }
192 return n;
193 }
194
195 BlNumber CodeLine::Token::number () const
196 {
197 switch (code)
198 {
199 case keyNUMBER:
200 case keySTRING:
201 return number (str);
202 case keyINTEGER:
203 return valueint;
204 case keyENDLINE:
205 return 0.0;
206 default:
207 if (showdebuginfo () )
208 cerr << "Codeline::Token::number called but code= " <<
209 code << " is not valid." << endl;
210 throw ErrBlassicInternal;
211 }
212 }
213
214 CodeLine::CodeLine () :
215 strcontent (0),
216 linenumber (LineEndProgram),
217 len (0),
218 owner (false),
219 pos (0),
220 chk (0),
221 lastcode (0)
222 {
223 }
224
225 CodeLine::CodeLine (const BlChar * str, BlLineNumber number,
226 BlLineLength length) :
227 strcontent (str),
228 linenumber (number),
229 len (length),
230 owner (false),
231 pos (0),
232 chk (0),
233 lastcode (0)
234 {
235 }
236
237 CodeLine::CodeLine (const CodeLine & old) :
238 strcontent (old.strcontent),
239 linenumber (old.linenumber),
240 len (old.len),
241 owner (false),
242 pos (0),
243 chk (0),
244 lastcode (0)
245 {
246 }
247
248 CodeLine::~CodeLine ()
249 {
250 TRACEFUNC (tr, "CodeLine::~CodeLine");
251
252 if (owner && strcontent)
253 delete [] strcontent;
254 }
255
256 void CodeLine::assign (const BlChar * str, BlLineNumber number,
257 BlLineLength length)
258 {
259 if (owner)
260 delete strcontent;
261 strcontent= str;
262 linenumber= number;
263 len= length;
264 owner= false;
265 pos= 0;
266 chk= 0;
267 lastcode= 0;
268 }
269
270 CodeLine & CodeLine::operator= (const CodeLine & old)
271 {
272 if (& old != this)
273 {
274 if (owner && strcontent)
275 delete [] strcontent;
276 strcontent= old.strcontent;
277 linenumber= old.linenumber;
278 len= old.len;
279 owner= false;
280 pos= 0;
281 chk= 0;
282 lastcode= 0;
283 }
284 return * this;
285 }
286
287 CodeLine::Token CodeLine::getdata ()
288 {
289 using std::string;
290
291 while (pos < len && is_space (strcontent [pos] ) )
292 ++pos;
293 Token r;
294 if (pos >= len)
295 {
296 r.code= lastcode= keyENDLINE;
297 return r;
298 }
299 char c= strcontent [pos];
300 if (c == '"')
301 {
302 ++pos;
303 while ( (c= strcontent [pos++]) != '\0')
304 r.str+= c;
305 }
306 else if (c == INTEGER_PREFIX)
307 {
308 //BlInteger n;
309 //n= * (BlInteger *) (strcontent + pos + 1);
310 //r.valueint= n;
311 r.valueint= peek32 (strcontent + pos + 1);
312 r.code= keyINTEGER;
313 pos+= 5;
314 return r;
315 }
316 else
317 {
318 while (pos < len &&
319 (c= strcontent [pos]) != ',' && c != ':' && c != '\'')
320 {
321 if (c == INTEGER_PREFIX)
322 {
323 r.str+= util::to_string
324 (peek32 (strcontent + pos + 1) );
325 pos+= 5;
326 }
327 else
328 {
329 if (iskey (c) )
330 {
331 BlCode s= c;
332 s<<= 8;
333 s|= strcontent [pos + 1];
334 r.str+= decodekeyword (s);
335 pos+= 2;
336 }
337 else
338 {
339 r.str+= c;
340 ++pos;
341 }
342 }
343 }
344 string::size_type last= r.str.find_last_not_of (" ");
345 if (last != string::npos)
346 r.str.erase (last + 1);
347 }
348 r.code= keySTRING;
349 return r;
350 }
351
352 namespace {
353
354 BlChar validinitident [256];
355 BlChar validident [256];
356
357 bool inittables ()
358 {
359 fill_n (& validident [0], 256, 0);
360 fill_n (& validinitident [0], 256, 0);
361
362 // cast to avoid a warning.
363 validident [static_cast <unsigned char> ('_')]= '_';
364
365 for (BlChar i= '0'; i <= '9'; ++i)
366 {
367 validident [i]= i;
368 }
369
370 for (BlChar i= 'A'; i <= 'Z'; ++i)
371 {
372 validident [i]= i;
373 validinitident [i]= i;
374 }
375 for (BlChar i= 'a'; i <= 'z'; ++i)
376 {
377 validident [i]= BlChar (i - 'a' + 'A');
378 validinitident [i]= BlChar (i - 'a' + 'A');
379 }
380 return true;
381 }
382
383 bool initiated= inittables ();
384
385 } // namespace
386
387 void CodeLine::gettoken (Token & r)
388 {
389 using std::string;
390
391 while (pos < len && is_space (strcontent [pos] ) )
392 ++pos;
393 if (pos >= len)
394 {
395 r.code= lastcode= keyENDLINE;
396 ++chk;
397 return;
398 }
399 BlChar c= strcontent [pos];
400 BlChar c2;
401 if (c == '\0')
402 {
403 r.code= lastcode= keyENDLINE;
404 ++chk;
405 return;
406 }
407 else if (iskey (c) )
408 {
409 BlCode code= c;
410 ++pos;
411 code<<= 8;
412 code|= strcontent [pos++];
413 switch (code)
414 {
415 case keyTHEN:
416 case keyELSE:
417 ++chk;
418 break;
419 case keyEQUALMINOR:
420 code= keyMINOREQUAL;
421 break;
422 case keyEQUALGREATER:
423 code= keyGREATEREQUAL;
424 break;
425 case keyGREATERMINOR:
426 code= keyDISTINCT;
427 break;
428 default:
429 ; // Nothing in particular.
430 }
431 r.code= lastcode= code;
432 return;
433 }
434 else if ( (c2= validinitident [c]) != 0)
435 {
436 r.code= lastcode= keyIDENTIFIER;
437 r.str= c2;
438 while ( ++pos < len &&
439 (c2= validident [ (c= strcontent [pos] ) ] ) != 0)
440 {
441 r.str+= c2;
442 }
443 if (pos < len &&
444 (c == '$' || c == '%' || c == '!' || c == '#') )
445 {
446 ++pos;
447 r.str+= c;
448 }
449 return;
450 }
451 else if (is_decdigit (c) || c == '.')
452 {
453 r.code= lastcode= keyNUMBER;
454 {
455 string strnum;
456 while (pos < len &&
457 (is_decdigit (c= strcontent [pos]) ) )
458 {
459 strnum+= c;
460 ++pos;
461 }
462 if (pos < len && (c= strcontent [pos] ) == '.')
463 {
464 strnum+= '.';
465 ++pos;
466 while (pos < len &&
467 (is_decdigit (c= strcontent [pos]) ) )
468 {
469 strnum+= c;
470 ++pos;
471 }
472 }
473 if (pos < len && (c == 'E' || c == 'e') )
474 {
475 strnum+= c;
476 ++pos;
477 if ( (c= strcontent [pos]) == '-' || c == '+')
478 {
479 strnum+= c;
480 ++pos;
481 }
482 while (pos < len &&
483 (is_decdigit (c= strcontent [pos] ) ) )
484 {
485 strnum+= c;
486 ++pos;
487 }
488 }
489 r.str= strnum;
490 }
491 return;
492 }
493 else if (c == '&')
494 {
495 #if 0
496 // Hexadecimal, octal or binary number.
497 r.code= keyNUMBER;
498 r.str= '&';
499 ++pos;
500 if (pos < len)
501 {
502 c= strcontent [pos];
503 if (c == 'X' || c == 'x')
504 {
505 // Binary
506 ++pos;
507 r.str+= c;
508 while (pos < len &&
509 is_bindigit (strcontent [pos] ) )
510 {
511 r.str+= strcontent [pos];
512 ++pos;
513 }
514 }
515 else if (c == 'O' || c == 'o')
516 {
517 // Octal
518 ++pos;
519 r.str+= c;
520 while (pos < len &&
521 is_octdigit (strcontent [pos] ) )
522 {
523 r.str+= strcontent [pos];
524 ++pos;
525 }
526 }
527 else
528 {
529 // Hexadecimal
530 if (c == 'H' || c == 'h')
531 {
532 ++pos;
533 r.str+= c;
534 }
535 while (pos < len &&
536 is_xdigit (strcontent [pos] ) )
537 {
538 r.str+= strcontent [pos];
539 ++pos;
540 }
541 }
542 }
543 #else
544
545 // Doing it another way, to return the values
546 // as integers.
547 ++pos;
548 if (pos >= len)
549 r.code= '&';
550 else
551 {
552 int base= 0;
553 BlLineLength oldpos= pos;
554 c= strcontent [pos];
555 switch (c)
556 {
557 case 'X': case 'x':
558 // Binary
559 base= 2; ++pos; break;
560 case 'O': case 'o':
561 // Octal
562 base= 8; ++pos; break;
563 case 'H': case 'h':
564 // Hexadecimal
565 base= 16; ++pos; break;
566 default:
567 if (is_hexdigit (c) )
568 base= 16;
569 }
570 switch (base)
571 {
572 case 2:
573 case 8:
574 case 16:
575 if (pos >= len || ! is_base
576 ( (c= strcontent [pos] ), base) )
577 {
578 pos= oldpos;
579 r.code= '&';
580 }
581 else
582 {
583 r.code= lastcode= keyINTEGER;
584 r.valueint= 0;
585 do
586 {
587 r.valueint*= base;
588 r.valueint+= valdigit (c);
589 ++pos;
590 } while (pos < len && is_base
591 ( (c= strcontent [pos] ),
592 base) );
593 }
594 return;
595 //break;
596 default:
597 pos= oldpos;
598 r.code= lastcode= '&';
599 return;
600 }
601 }
602
603 #endif
604 }
605 else
606 {
607 ++pos;
608 switch (c)
609 {
610 case INTEGER_PREFIX:
611 r.code= lastcode= keyINTEGER;
612 {
613 r.valueint= peek32 (strcontent + pos);
614 pos+= 4;
615 }
616 return;
617 //break;
618 case '"':
619 r.code= lastcode= keySTRING;
620 r.str.erase ();
621 while ( (c= strcontent [pos++]) != '\0')
622 r.str+= c;
623 return;
624 //break;
625 case '<':
626 if (pos < len)
627 {
628 switch (strcontent [pos] )
629 {
630 case '>':
631 r.code= keyDISTINCT;
632 ++pos;
633 break;
634 case '=':
635 r.code= keyMINOREQUAL;
636 ++pos;
637 break;
638 default:
639 r.code= '<';
640 }
641 }
642 else r.code= '<';
643 lastcode= r.code;
644 return;
645 //break;
646 case '>':
647 if (pos < len)
648 {
649 switch (strcontent [pos] )
650 {
651 case '<':
652 r.code= keyDISTINCT;
653 ++pos;
654 break;
655 case '=':
656 r.code= keyGREATEREQUAL;
657 ++pos;
658 break;
659 default:
660 r.code= '>';
661 }
662 }
663 else r.code= '>';
664 lastcode= r.code;
665 return;
666 //break;
667 case '=':
668 if (pos < len)
669 {
670 switch (strcontent [pos] )
671 {
672 case '<':
673 r.code= keyMINOREQUAL;
674 ++pos;
675 break;
676 case '>':
677 r.code= keyGREATEREQUAL;
678 ++pos;
679 break;
680 default:
681 r.code= '=';
682 }
683 }
684 else r.code= '=';
685 lastcode= r.code;
686 return;
687 //break;
688 case '\'':
689 r.code= lastcode= keyENDLINE;
690 ++chk;
691 pos= len;
692 return;
693 //break;
694 case ':':
695 r.code= lastcode= ':';
696 ++chk;
697 return;
698 //break;
699 default:
700 r.code= lastcode= c;
701 return;
702 }
703 }
704 }
705
706 void CodeLine::gotochunk (BlChunk chknew)
707 {
708 pos= 0; chk= 0;
709 if (chknew == 0)
710 {
711 lastcode= 0;
712 return;
713 }
714 while (chk < chknew)
715 {
716 if (pos >= len)
717 {
718 lastcode= keyENDLINE;
719 return;
720 }
721 char c= strcontent [pos];
722 if (c == INTEGER_PREFIX)
723 {
724 pos+= 5;
725 }
726 else if (iskey (c) )
727 {
728 BlCode code;
729 code= strcontent [pos++];
730 code<<= 8;
731 code|= strcontent [pos++];
732 if (code == keyTHEN || code == keyELSE)
733 {
734 lastcode= code;
735 ++chk;
736 }
737 else if (code == keyREM)
738 {
739 lastcode= code;
740 pos= len;
741 }
742 }
743 else
744 {
745 if (c == '\'')
746 {
747 lastcode= '\'';
748 pos= len;
749 }
750 if (c == '"')
751 {
752 ++pos;
753 while (strcontent [pos] != '\0')
754 ++pos;
755 ++pos;
756 }
757 else
758 {
759 if (c == ':')
760 {
761 lastcode= ':';
762 ++chk;
763 }
764 ++pos;
765 }
766 }
767 }
768 }
769
770 namespace {
771
772 using std::string;
773
774 inline string stringupper (const string & str)
775 {
776 string u (str.size (), 0);
777 transform (str.begin (), str.end (), u.begin (), toupper);
778 return u;
779 }
780
781 inline bool is_word (const Tokenizer::Token & token, const char * str)
782 {
783 if (token.type != Tokenizer::Plain)
784 return false;
785 return stringupper (token.str) == str;
786 }
787
788 inline bool isGO (const Tokenizer::Token & token)
789 {
790 return is_word (token, "GO");
791 }
792
793 inline bool isSUB (const Tokenizer::Token & token)
794 {
795 return is_word (token, "SUB");
796 }
797
798 const string strprefinteger (1, INTEGER_PREFIX);
799
800 inline string codeinteger (BlInteger n)
801 {
802 #ifdef BLASSIC_INTEL
803
804 return strprefinteger +
805 string (reinterpret_cast <const char *> (& n), 4);
806
807 #else
808
809 return strprefinteger +
810 char (n & 0xFF) +
811 char ( (n >> 8) & 0xFF) +
812 char ( (n >> 16) & 0xFF) +
813 char (n >> 24);
814
815 #endif
816 }
817
818 } // namespace
819
820 void CodeLine::scan (const std::string & line)
821 {
822 using std::string;
823
824 //linenumber= 0;
825 //len= 0;
826 //pos= 0;
827 //BlLineNumber newlinenumber= 0;
828 BlLineNumber newlinenumber= LineDirectCommand;
829 string newcontent;
830 static const char INVALID []= "Line number invalid";
831
832 if (! line.empty () )
833 {
834 int i= 0, l= line.size ();
835 while (i < l && is_space (line [i] ) )
836 ++i;
837 if (i < l && is_decdigit (line [i] ) )
838 {
839 newlinenumber= 0;
840 while (i < l && is_decdigit (line [i] ) )
841 {
842 if (newlinenumber > BlMaxLineNumber / 10)
843 {
844 if (showdebuginfo () )
845 cerr << INVALID << endl;
846 throw ErrSyntax;
847 }
848 newlinenumber*= 10;
849 BlLineNumber n= static_cast <BlLineNumber>
850 (line [i] - '0');
851 if (newlinenumber > BlMaxLineNumber - n)
852 {
853 if (showdebuginfo () )
854 cerr << INVALID << endl;
855 throw ErrSyntax;
856 }
857 newlinenumber+= n;
858 ++i;
859 }
860 if (i < l && line [i] == ' ') ++i;
861 }
862 else i= 0;
863
864 Tokenizer t (line.substr (i) );
865 //string str;
866 Tokenizer::Token token;
867 Tokenizer::Token prevtoken;
868 BlCode code;
869 bool incomment= false;
870 bool addspace;
871 string::size_type prevsize= string::npos;
872 string::size_type lastsize= 0;
873
874 while (! incomment &&
875 (token= t.get () ).type != Tokenizer::EndLine)
876 {
877 //cerr << '(' << str << ')' << flush;
878 switch (token.type)
879 {
880 case Tokenizer::Blank:
881 newcontent+= token.str;
882 break;
883 case Tokenizer::Literal:
884 newcontent+= '"';
885 newcontent+= token.str;
886 newcontent+= '\0';
887 break;
888 case Tokenizer::Integer:
889 newcontent+= codeinteger (token.n);
890 break;
891 case Tokenizer::Plain:
892 //code= 0;
893 addspace= false;
894 if (token.str == "?")
895 {
896 code= keyPRINT;
897 char c= t.peek ();
898 if (c != '\0' && !
899 is_space (c) )
900 addspace= true;
901 }
902 else
903 code= keyword (token.str);
904
905 // GO TO
906 if (code == keyTO)
907 {
908 if (isGO (prevtoken) )
909 {
910 code= keyGOTO;
911 newcontent.erase
912 (prevsize);
913 }
914 }
915 // GO SUB
916 if (code == 0 && isSUB (token) )
917 {
918 if (isGO (prevtoken) )
919 {
920 code= keyGOSUB;
921 newcontent.erase
922 (prevsize);
923 }
924 }
925 if (code == 0)
926 {
927 newcontent+= token.str;
928 if (token.str == "'")
929 incomment= true;
930 }
931 else
932 {
933 newcontent+= char (code >> 8);
934 newcontent+= char (code & 0xFF);
935 if (code == keyREM)
936 incomment= true;
937 }
938 if (addspace)
939 newcontent+= ' ';
940 break;
941 default:
942 throw ErrBlassicInternal;
943 }
944 if (token.type != Tokenizer::Blank)
945 {
946 prevtoken= token;
947 prevsize= lastsize;
948 }
949 lastsize= newcontent.size ();
950 }
951 if (incomment)
952 {
953 newcontent+= t.getrest ();
954 }
955
956 //if (owner && strcontent)
957 // delete [] strcontent;
958
959 }
960
961 BlLineLength newlen= newcontent.size ();
962 if (newlen > 0)
963 {
964 //strcontent= new unsigned char [newlen];
965 //newcontent.copy ( (char *) strcontent, newlen);
966 unsigned char * auxcontent= new unsigned char [newlen];
967 // No need to protect auxcontent, copy and delete
968 // must not throw.
969 newcontent.copy ( (char *) auxcontent, newlen);
970 if (owner && strcontent)
971 delete [] strcontent;
972 strcontent= auxcontent;
973 owner= true;
974 }
975 else
976 {
977 if (owner && strcontent)
978 delete [] strcontent;
979 owner= false;
980 strcontent= NULL;
981 }
982
983 len= newlen;
984 linenumber= newlinenumber;
985 pos= 0;
986 chk= 0;
987 lastcode= 0;
988 }
989
990 // Fin de codeline.cpp
Something went wrong with that request. Please try again.