bumping version to 3.5-rc1
[supercollider.git] / lang / LangSource / PyrLexer.cpp
blob1ba9faaf6c9900d24ad76ff4dba3a98e9dda6dae
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <stdlib.h>
22 #include <string.h>
23 #include <float.h>
24 #include <math.h>
25 #include <new>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <cerrno>
29 #include <limits>
30 #include <set>
32 #ifdef SC_WIN32
33 # include <direct.h>
34 #else
35 # include <sys/param.h>
36 #endif
38 #include <boost/filesystem/path.hpp>
41 #include "PyrParseNode.h"
42 #include "Bison/lang11d_tab.h"
43 #include "SCBase.h"
44 #include "PyrObject.h"
45 #include "PyrObjectProto.h"
46 #include "PyrLexer.h"
47 #include "PyrSched.h"
48 #include "SC_InlineUnaryOp.h"
49 #include "SC_InlineBinaryOp.h"
50 #include "GC.h"
51 #include "SimpleStack.h"
53 #include "PyrSymbolTable.h"
54 #include "PyrInterpreter.h"
55 #include "PyrPrimitive.h"
56 #include "PyrObjectProto.h"
57 #include "PyrPrimitiveProto.h"
58 #include "PyrKernelProto.h"
59 #include "InitAlloc.h"
60 #include "bullet.h"
61 #include "PredefinedSymbols.h"
62 #ifdef SC_WIN32
63 #else
64 # include "dirent.h"
65 #endif
66 #include <string.h>
68 #include "SC_LibraryConfig.h"
70 #include "SC_DirUtils.h"
73 int yyparse();
74 int processaccidental1(char *s);
75 int processaccidental2(char *s);
78 extern bool gFullyFunctional;
79 double compileStartTime;
80 int gNumCompiledFiles;
82 thisProcess.interpreter.executeFile("Macintosh HD:score").size.postln;
85 PyrSymbol *gCompilingFileSym = 0;
86 VMGlobals *gCompilingVMGlobals = 0;
87 static char gCompileDir[MAXPATHLEN];
89 //#define DEBUGLEX 1
90 bool gDebugLexer = false;
92 bool gShowWarnings = false;
93 LongStack brackets;
94 LongStack closedFuncCharNo;
95 LongStack generatorStack;
96 int lastClosedFuncCharNo = 0;
98 const char *binopchars = "!@%&*-+=|<>?/";
99 char yytext[MAXYYLEN];
100 char curfilename[PATH_MAX];
102 int yylen;
103 int lexCmdLine = 0;
104 bool compilingCmdLine = false;
105 bool compilingCmdLineErrorWindow = false;
106 long zzval;
108 int lineno, charno, linepos;
109 int *linestarts;
110 int maxlinestarts;
112 char *text;
113 int textlen;
114 int textpos;
115 int errLineOffset, errCharPosOffset;
116 int parseFailed = 0;
117 bool compiledOK = false;
118 std::set<std::string> compiledDirectories;
120 /* so the text editor's dumb paren matching will work */
121 #define OPENPAREN '('
122 #define OPENCURLY '{'
123 #define OPENSQUAR '['
124 #define CLOSSQUAR ']'
125 #define CLOSCURLY '}'
126 #define CLOSPAREN ')'
128 //int rtf2txt(char* txt);
130 int sc_strtoi(const char *str, int n, int base)
132 int z = 0;
133 for (int i=0; i<n; ++i)
135 int c = *str++;
136 if (!c) break;
137 if (c >= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0';
138 else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10;
139 else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10;
141 return z;
144 double sc_strtof(const char *str, int n, int base)
146 double z = 0.;
147 int decptpos = 0;
148 for (int i=0; i<n; ++i)
150 int c = *str++;
151 if (!c) break;
152 if (c >= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0';
153 else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10;
154 else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10;
155 else if (c == '.') decptpos = i;
157 //calculation previously included decimal point in count of columns (was n-decptpos); there are 1 less than n characters which are columns in the number contribution
158 z = z / pow((double)base, n -1- decptpos);
159 return z;
162 static void sc_InitCompileDirectory(void)
164 // main class library folder: only used for relative path resolution
165 sc_GetResourceDirectory(gCompileDir, MAXPATHLEN-32);
166 sc_AppendToPath(gCompileDir, MAXPATHLEN, "SCClassLibrary");
169 extern void asRelativePath(char *inPath, char *outPath)
171 uint32 len = strlen(gCompileDir);
172 if (strlen(inPath) < len || memcmp(inPath, gCompileDir, len) != 0) {
173 // gCompileDir is not the prefix.
174 strcpy(outPath, inPath);
175 return;
177 strcpy(outPath, inPath + len);
181 static bool getFileText(char* filename, char **text, int *length)
183 FILE *file;
184 char *ltext;
185 int llength;
187 #ifdef SC_WIN32
188 file = fopen(filename, "rb");
189 #else
190 file = fopen(filename, "r");
191 #endif
192 if (!file) return false;
194 fseek(file, 0L, SEEK_END);
195 llength = ftell(file);
196 fseek(file, 0L, SEEK_SET);
197 ltext = (char*)pyr_pool_compile->Alloc((llength+1) * sizeof(char));
198 #ifdef SC_WIN32
199 // win32 isprint( ) doesn't like the 0xcd after the end of file when
200 // there is a mismatch in lengths due to line endings....
201 memset(ltext,0,(llength+1) * sizeof(char));
202 #endif //SC_WIN32
203 MEMFAIL(ltext);
205 size_t size = fread(ltext, 1, llength, file);
206 if (size != llength) {
207 error("error when reading file");
208 fclose(file);
209 return false;
211 ltext[llength] = 0;
212 //ltext[llength] = 0;
213 *length = llength;
214 fclose(file);
215 *text = ltext;
216 return true;
220 int bugctr = 0;
222 // strips out all the RichTextFile crap
223 int rtf2txt(char* txt)
225 int rdpos=0, wrpos=0;
226 char c;
227 if (strncmp(txt,"{\\rtf",5)!=0) return 0; // OK, not an RTF file
228 text:
229 switch (txt[wrpos]=txt[rdpos++])
231 case 0:
233 char fname[32];
234 sprintf(fname, "rtf2txt_out%d.txt", bugctr++);
235 FILE *fp = fopen(fname, "w");
236 fwrite(txt,wrpos,1,fp);
237 fclose(fp);
239 return wrpos;
240 case OPENCURLY:
241 case CLOSCURLY:
242 case '\n': goto text;
243 case '\\':
244 if (strncmp(txt+rdpos,"fonttbl",7)==0
245 || strncmp(txt+rdpos,"filetbl",7)==0
246 || strncmp(txt+rdpos,"colortbl",8)==0
247 || strncmp(txt+rdpos,"stylesheet",10)==0
250 int level = 1;
251 while(level && (c=txt[rdpos++]) != 0) {
252 if (c == OPENCURLY) level++;
253 else if (c == CLOSCURLY) level--;
255 } else if (strncmp(txt+rdpos,"\'a0",3)==0 || (strncmp(txt+rdpos,"\'A0",3)==0))
257 txt[wrpos++] = ' '; rdpos = rdpos + 3;
258 } else {
259 if (txt[rdpos]==CLOSCURLY || txt[rdpos]==OPENCURLY
260 || txt[rdpos]=='\\' || txt[rdpos]=='\t'|| txt[rdpos]=='\n')
261 { txt[wrpos++] = txt[rdpos++]; goto text; }
262 if (strncmp(txt+rdpos,"tab",3)==0) { txt[wrpos++] = '\t'; }
263 if (strncmp(txt+rdpos,"par",3)==0) { txt[wrpos++] = '\n'; }
265 while((c=txt[rdpos++]) && c!=' ' && c!='\\');
266 if (c=='\\') rdpos--;
268 goto text;
269 default :
270 wrpos++;
271 goto text;
275 // strips HTML down to plaintext tags in a fairly simple-minded way
276 int html2txt(char* txt)
278 int rdpos=-1, wrpos=0, bodypos=-1;
279 bool intag = false;
281 // First check if we can find a BODY tag to start at
282 while(bodypos == -1 && txt[++rdpos] != 0){
283 if(strncmp(txt+rdpos, "<body", 5) == 0) // FIXME: should be case-insensitive, ideally
284 bodypos = rdpos;
286 if(bodypos != -1)
287 rdpos = bodypos;
288 else
289 rdpos = 0;
291 // Now we start from our start, and add the non-tag text to the result
292 while(txt[rdpos] != 0){
293 if(intag){
294 if(txt[rdpos++] == '>')
295 intag = false;
296 }else{
297 if(txt[rdpos] == '<'){
298 intag = true;
299 ++rdpos;
300 }else{
302 if(strncmp(txt+rdpos, "&amp;", 5)==0){
303 txt[wrpos++] = '&';
304 rdpos += 5;
305 }else if(strncmp(txt+rdpos, "&nbsp;", 6)==0){
306 txt[wrpos++] = ' ';
307 rdpos += 6;
308 }else if(strncmp(txt+rdpos, "&lt;", 4)==0){
309 txt[wrpos++] = '<';
310 rdpos += 4;
311 }else if(strncmp(txt+rdpos, "&gt;", 4)==0){
312 txt[wrpos++] = '>';
313 rdpos += 4;
314 }else{
316 txt[wrpos++] = txt[rdpos++];
321 txt[wrpos] = 0;
322 return wrpos;
326 bool startLexer(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
328 char *filename = fileSym->name;
330 textlen = -1;
332 if(!fileSym->u.source) {
333 if (!getFileText(filename, &text, &textlen)) return false;
334 fileSym->u.source = text;
335 rtf2txt(text);
337 else
338 text = fileSym->u.source;
340 if((startPos >= 0) && (endPos > 0)) {
341 textlen = endPos - startPos;
342 text += startPos;
344 else if(textlen == -1)
345 textlen = strlen(text);
347 if(lineOffset > 0) errLineOffset = lineOffset;
348 else errLineOffset = 0;
350 if(startPos > 0) errCharPosOffset = startPos;
351 else errCharPosOffset = 0;
353 initLongStack(&brackets);
354 initLongStack(&closedFuncCharNo);
355 initLongStack(&generatorStack);
356 lastClosedFuncCharNo = 0;
357 textpos = 0;
358 linepos = 0;
359 lineno = 1;
360 charno = 0;
362 yylen = 0;
363 zzval = 0;
364 parseFailed = 0;
365 lexCmdLine = 0;
366 strcpy(curfilename, filename);
367 maxlinestarts = 1000;
368 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
369 linestarts[0] = 0;
370 linestarts[1] = 0;
372 return true;
375 void startLexerCmdLine(char *textbuf, int textbuflen)
377 // pyrmalloc:
378 // lifetime: kill after compile. (this one gets killed anyway)
379 text = (char*)pyr_pool_compile->Alloc((textbuflen+2) * sizeof(char));
380 MEMFAIL(text);
381 memcpy(text, textbuf, textbuflen);
382 text[textbuflen] = ' ';
383 text[textbuflen+1] = 0;
384 textlen = textbuflen + 1;
386 rtf2txt(text);
388 initLongStack(&brackets);
389 initLongStack(&closedFuncCharNo);
390 initLongStack(&generatorStack);
391 lastClosedFuncCharNo = 0;
392 textpos = 0;
393 linepos = 0;
394 lineno = 1;
395 charno = 0;
397 yylen = 0;
398 zzval = 0;
399 parseFailed = 0;
400 lexCmdLine = 1;
401 strcpy(curfilename, "selected text");
402 maxlinestarts = 1000;
403 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
404 linestarts[0] = 0;
405 linestarts[1] = 0;
407 errLineOffset = 0;
408 errCharPosOffset = 0;
411 void finiLexer()
413 pyr_pool_compile->Free(linestarts);
414 freeLongStack(&brackets);
415 freeLongStack(&closedFuncCharNo);
416 freeLongStack(&generatorStack);
419 void initLexer()
421 //strcpy(binopchars, "!@%&*-+=|:<>?/");
424 int input()
426 int c;
427 if (textpos >= textlen) {
428 c = 0;
429 } else {
430 c = text[textpos++];
431 charno++;
433 if (c == '\n' || c == '\r') {
434 lineno++;
435 linepos = textpos;
436 if (linestarts) {
437 if (lineno >= maxlinestarts) {
438 maxlinestarts += maxlinestarts;
439 linestarts = (int*)pyr_pool_compile->Realloc(
440 linestarts, maxlinestarts * sizeof(int*));
442 linestarts[lineno] = linepos;
444 charno = 0;
446 if (c != 0 && yylen < MAXYYLEN-2) yytext[yylen++] = c;
447 //if (gDebugLexer) postfl("input '%c' %d\n",c,c);
448 return c;
451 int input0()
453 int c;
454 if (textpos >= textlen) {
455 c = 0;
456 textpos++; // so unput will work properly
457 } else {
458 c = text[textpos++];
459 charno++;
461 if (c == '\n' || c == '\r') {
462 lineno++;
463 linepos = textpos;
464 if (linestarts) {
465 if (lineno >= maxlinestarts) {
466 maxlinestarts += maxlinestarts;
467 linestarts = (int*)pyr_pool_compile->Realloc(
468 linestarts, maxlinestarts * sizeof(int*));
470 linestarts[lineno] = linepos;
472 charno = 0;
474 //if (gDebugLexer) postfl("input0 '%c' %d\n",c,c);
475 return c;
478 void unput(int c)
480 if (textpos>0) textpos--;
481 if (c) {
482 if (yylen) --yylen;
483 if (charno) --charno;
484 if (c == '\n' || c == '\r') {
485 --lineno;
490 void unput0(int c)
492 if (textpos>0) textpos--;
493 if (charno) --charno;
494 if (c == '\n' || c == '\r') {
495 --lineno;
499 int yylex()
501 int r, c, c2, d;
502 int radix;
503 char extPath[MAXPATHLEN]; // for error reporting
505 yylen = 0;
506 // finite state machine to parse input stream into tokens
508 if (lexCmdLine == 1) {
509 lexCmdLine = 2;
510 r = INTERPRET;
511 goto leave;
513 start:
514 c = input();
516 if (c == 0) { r = 0; goto leave; }
517 else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') {
518 yylen = 0;
519 goto start;
521 else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto ident;
522 else if (c == '/') {
523 c = input();
524 if (c == '/') goto comment1;
525 else if (c == '*') goto comment2;
526 else { unput(c); goto binop; }
528 else if (c >= '0' && c <= '9') goto digits_1;
529 else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
530 pushls(&brackets, (int)c);
531 if (c == OPENCURLY) {
532 pushls(&closedFuncCharNo, linestarts[lineno] + charno - 1);
534 r = c;
535 goto leave;
537 else if (c == CLOSSQUAR) {
538 if (!emptyls(&brackets)) {
539 if ((d = popls(&brackets)) != OPENSQUAR) {
540 fatal();
541 post("opening bracket was a '%c', but found a '%c'\n",d,c);
542 goto error2;
544 } else {
545 fatal();
546 post("unmatched '%c'\n",c);
547 goto error2;
549 r = c;
550 goto leave;
552 else if (c == CLOSPAREN) {
553 if (!emptyls(&brackets)) {
554 if ((d = popls(&brackets)) != OPENPAREN) {
555 fatal();
556 post("opening bracket was a '%c', but found a '%c'\n",d,c);
557 goto error2;
559 } else {
560 fatal();
561 post("unmatched '%c'\n",c);
562 goto error2;
564 r = c;
565 goto leave;
567 else if (c == CLOSCURLY) {
568 if (!emptyls(&brackets)) {
569 if ((d = popls(&brackets)) != OPENCURLY) {
570 fatal();
571 post("opening bracket was a '%c', but found a '%c'\n",d,c);
572 goto error2;
574 lastClosedFuncCharNo = popls(&closedFuncCharNo);
575 } else {
576 fatal();
577 post("unmatched '%c'\n",c);
578 goto error2;
580 r = c;
581 goto leave;
583 else if (c == '^') { r = c; goto leave; }
584 else if (c == '~') { r = c; goto leave; }
585 else if (c == ';') { r = c; goto leave; }
586 else if (c == ':') { r = c; goto leave; }
587 else if (c == '`') { r = c; goto leave; }
588 else if (c == '\\') goto symbol1;
589 else if (c == '\'') goto symbol3;
590 else if (c == '"') goto string1;
591 else if (c == '.') {
592 if ((c = input()) == '.') {
593 if ((c = input()) == '.') {
594 r = ELLIPSIS;
595 goto leave;
596 } else {
597 r = DOTDOT;
598 unput(c);
599 goto leave;
601 } else {
602 unput(c);
603 r = '.';
604 goto leave;
608 else if (c == '#') {
609 if ((c = input()) == OPENCURLY) {
610 pushls(&brackets, OPENCURLY);
611 pushls(&closedFuncCharNo, linestarts[lineno] + charno - 2);
612 r = BEGINCLOSEDFUNC;
613 } else {
614 unput(c);
615 r = '#';
617 goto leave;
619 else if (c == '$') {
620 c = input();
621 if (c == '\\') {
622 c = input();
623 switch (c) {
624 case 'n' : c = '\n'; break;
625 case 'r' : c = '\r'; break;
626 case 't' : c = '\t'; break;
627 case 'f' : c = '\f'; break;
628 case 'v' : c = '\v'; break;
631 r = processchar(c);
632 goto leave;
634 else if (c == ',') { r = c; goto leave; }
635 else if (c == '=') {
636 c = input();
637 if (strchr(binopchars, c)) goto binop;
638 else {
639 unput(c);
640 r = '=';
641 goto leave;
644 else if (strchr(binopchars, c)) goto binop;
645 else if(!(isprint(c) || isspace(c) || c == 0)) {
646 yylen = 0;
647 goto start;
649 else goto error1;
651 ident:
652 c = input();
654 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
655 || c == '_' || (c >= '0' && c <= '9')) goto ident;
656 else if (c == ':') {
657 yytext[yylen] = 0;
658 r = processkeywordbinop(yytext) ;
659 goto leave;
660 } else {
661 unput(c);
662 yytext[yylen] = 0;
663 r = processident(yytext) ;
664 goto leave;
667 symbol1:
668 c = input();
670 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto symbol2;
671 else if (c >= '0' && c <= '9') goto symbol4;
672 else {
673 unput(c);
674 yytext[yylen] = 0;
675 r = processsymbol(yytext) ;
676 goto leave;
679 symbol2:
680 c = input();
682 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
683 || c == '_' || (c >= '0' && c <= '9')) goto symbol2;
684 else {
685 unput(c);
686 yytext[yylen] = 0;
687 r = processsymbol(yytext) ;
688 goto leave;
691 symbol4:
692 c = input();
693 if (c >= '0' && c <= '9') goto symbol4;
694 else {
695 unput(c);
696 yytext[yylen] = 0;
697 r = processsymbol(yytext) ;
698 goto leave;
703 binop:
705 c = input();
707 if (c == 0) goto binop2;
708 if (strchr(binopchars, c)) goto binop;
709 else {
710 binop2:
711 unput(c);
712 yytext[yylen] = 0;
713 r = processbinop(yytext) ;
714 goto leave;
717 radix_digits_1:
719 c = input();
720 if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_1;
721 if (c >= 'a' && c <= 'a' + sc_min(36,radix) - 11) goto radix_digits_1;
722 if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_1;
723 if (c == '.') {
724 goto radix_digits_2;
726 unput(c);
727 yytext[yylen] = 0;
728 r = processintradix(yytext, yylen, radix);
729 goto leave;
731 radix_digits_2:
733 c = input();
734 if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_2;
735 if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_2;
736 // do not allow lower case after decimal point.
737 unput(c);
738 yytext[yylen] = 0;
739 r = processfloatradix(yytext, yylen, radix);
740 goto leave;
742 hexdigits:
744 c = input();
745 if (c >= '0' && c <= '9') goto hexdigits;
746 if (c >= 'a' && c <= 'f') goto hexdigits;
747 if (c >= 'A' && c <= 'F') goto hexdigits;
748 unput(c);
749 yytext[yylen] = 0;
750 r = processhex(yytext);
751 goto leave;
753 digits_1: /* number started with digits */
755 c = input();
757 if (c >= '0' && c <= '9') goto digits_1;
758 else if (c == 'r') {
759 radix = sc_strtoi(yytext, yylen-1, 10);
760 yylen = 0;
761 goto radix_digits_1;
763 else if (c == 'e' || c == 'E') goto expon_1;
764 else if (c == '.') {
765 c2 = input();
766 if (c2 >= '0' && c2 <= '9') goto digits_2;
767 else {
768 unput(c2);
769 unput(c);
770 yytext[yylen] = 0;
771 r = processint(yytext);
772 goto leave;
775 else if (c == 'b' || c == 's') {
776 d = input();
777 if (d >= '0' && d <= '9') goto accidental1;
778 if (d == c) goto accidental2;
779 goto accidental3;
780 accidental1:
781 d = input();
782 if (d >= '0' && d <= '9') goto accidental1;
783 unput(d);
784 yytext[yylen] = 0;
785 r = processaccidental1(yytext);
786 goto leave;
787 accidental2:
788 d = input();
789 if (d == c) goto accidental2;
790 accidental3:
791 unput(d);
792 yytext[yylen] = 0;
793 r = processaccidental2(yytext);
794 goto leave;
796 else if (c == 'x') {
797 yylen = 0;
798 goto hexdigits;
799 } else {
800 unput(c);
801 yytext[yylen] = 0;
802 r = processint(yytext);
803 goto leave;
806 digits_2:
808 c = input();
810 if (c >= '0' && c <= '9') goto digits_2;
811 else if (c == 'e' || c == 'E') goto expon_1;
812 // else if (c == 'π' || c == '∏') {
813 // --yylen;
814 // yytext[yylen] = 0;
815 // r = processfloat(yytext, 1);
816 // goto leave;
817 // }
818 else {
819 unput(c);
820 yytext[yylen] = 0;
821 r = processfloat(yytext, 0);
822 goto leave;
825 expon_1: /* e has been seen, need digits */
826 c = input();
828 if (c >= '0' && c <= '9') goto expon_3;
829 else if (c == '+' || c == '-') goto expon_2;
830 else goto error1;
832 expon_2: /* + or - seen but still need digits */
833 c = input();
835 if (c >= '0' && c <= '9') goto expon_3;
836 else goto error1;
838 expon_3:
839 c = input();
841 if (c >= '0' && c <= '9') goto expon_3;
842 // else if (c == 'π' || c == '∏') {
843 // --yylen;
844 // yytext[yylen] = 0;
845 // r = processfloat(yytext, 1);
846 // goto leave;
847 // }
848 else {
849 unput(c);
850 yytext[yylen] = 0;
851 r = processfloat(yytext, 0);
852 goto leave;
855 symbol3 : {
856 int startline, endchar;
857 startline = lineno;
858 endchar = '\'';
860 /*do {
861 c = input();
862 } while (c != endchar && c != 0);*/
863 for (;yylen<MAXYYLEN;) {
864 c = input();
865 if (c == '\n' || c == '\r') {
866 asRelativePath(curfilename,extPath);
867 post("Symbol open at end of line on line %d in file '%s'\n",
868 startline+errLineOffset, extPath);
869 yylen = 0;
870 r = 0;
871 goto leave;
873 if (c == '\\') {
874 yylen--;
875 c = input();
876 } else if (c == endchar) break;
877 if (c == 0) break;
879 if (c == 0) {
880 asRelativePath(curfilename,extPath);
881 post("Open ended symbol ... started on line %d in file '%s'\n",
882 startline+errLineOffset, extPath);
883 yylen = 0;
884 r = 0;
885 goto leave;
887 yytext[yylen] = 0;
888 yytext[yylen-1] = 0;
889 r = processsymbol(yytext);
890 goto leave;
893 string1 : {
894 int startline, endchar;
895 startline = lineno;
896 endchar = '"';
898 for (;yylen<MAXYYLEN;) {
899 c = input();
900 if (c == '\\') {
901 yylen--;
902 c = input();
903 switch (c) {
904 case 'n' : yytext[yylen-1] = '\n'; break;
905 case 'r' : yytext[yylen-1] = '\r'; break;
906 case 't' : yytext[yylen-1] = '\t'; break;
907 case 'f' : yytext[yylen-1] = '\f'; break;
908 case 'v' : yytext[yylen-1] = '\v'; break;
910 } else if (c == '\r') c = '\n';
911 else if (c == endchar) break;
912 if (c == 0) break;
914 if (c == 0) {
915 asRelativePath(curfilename,extPath);
916 post("Open ended string ... started on line %d in file '%s'\n",
917 startline+errLineOffset, extPath);
918 yylen = 0;
919 r = 0;
920 goto leave;
922 yylen--;
924 do {
925 c = input0();
926 } while (c && isspace(c));
928 if (c == '"') goto string1;
929 else if (c) unput0(c);
931 yytext[yylen] = 0;
932 r = processstring(yytext);
933 goto leave;
936 comment1: /* comment -- to end of line */
937 do {
938 c = input0();
939 } while (c != '\n' && c != '\r' && c != 0);
940 yylen = 0;
941 if (c == 0) { r = 0; goto leave; }
942 else goto start;
944 comment2 : {
945 int startline, clevel, prevc;
946 startline = lineno;
947 prevc = 0;
948 clevel = 1;
949 do {
950 c = input0();
951 if (c == '/' && prevc == '*') {
952 if (--clevel <= 0) break;
953 } else if (c == '*' && prevc == '/') clevel++;
954 prevc = c;
955 } while (c != 0);
956 yylen = 0;
957 if (c == 0) {
958 asRelativePath(curfilename,extPath);
959 post("Open ended comment ... started on line %d in file '%s'\n",
960 startline+errLineOffset, extPath);
961 r = 0;
962 goto leave;
964 goto start;
968 error1:
970 yytext[yylen] = 0;
972 asRelativePath(curfilename, extPath);
973 post("illegal input string '%s' \n at '%s' line %d char %d\n",
974 yytext, extPath, lineno+errLineOffset, charno);
975 post("code %d\n", c);
976 //postfl(" '%c' '%s'\n", c, binopchars);
977 //postfl("%d\n", strchr(binopchars, c));
979 error2:
980 asRelativePath(curfilename, extPath);
981 post(" in file '%s' line %d char %d\n", extPath, lineno+errLineOffset, charno);
982 r = BADTOKEN;
983 goto leave;
985 leave:
986 yytext[yylen] = 0;
988 #if DEBUGLEX
989 if (gDebugLexer) postfl("yylex: %d '%s'\n",r,yytext);
990 #endif
991 //if (lexCmdLine>0) postfl("yylex: %d '%s'\n",r,yytext);
992 return r;
995 int processbinop(char *token)
997 PyrSymbol *sym;
998 PyrSlot slot;
999 PyrSlotNode *node;
1001 #if DEBUGLEX
1002 if (gDebugLexer) postfl("processbinop: '%s'\n",token);
1003 #endif
1004 sym = getsym(token);
1005 SetSymbol(&slot, sym);
1006 node = newPyrSlotNode(&slot);
1007 zzval = (long)node;
1008 if (strcmp(token, "<-")==0) return LEFTARROW;
1009 if (strcmp(token, "<>")==0) return READWRITEVAR;
1010 if (strcmp(token, "|")==0) return '|';
1011 if (strcmp(token, "<")==0) return '<';
1012 if (strcmp(token, ">")==0) return '>';
1013 if (strcmp(token, "-")==0) return '-';
1014 if (strcmp(token, "*")==0) return '*';
1015 if (strcmp(token, "+")==0) return '+';
1016 return BINOP;
1019 int processkeywordbinop(char *token)
1021 PyrSymbol *sym;
1022 PyrSlot slot;
1023 PyrSlotNode *node;
1025 //post("'%s' file '%s'\n", token, curfilename);
1027 #if DEBUGLEX
1028 if (gDebugLexer) postfl("processkeywordbinop: '%s'\n",token);
1029 #endif
1030 token[strlen(token)-1] = 0; // strip off colon
1031 sym = getsym(token);
1032 SetSymbol(&slot, sym);
1033 node = newPyrSlotNode(&slot);
1034 zzval = (long)node;
1035 return KEYBINOP;
1038 int processident(char *token)
1040 char c;
1041 PyrSymbol *sym;
1043 PyrSlot slot;
1044 PyrParseNode *node;
1046 c = token[0];
1047 zzval = -1;
1049 #if DEBUGLEX
1050 if (gDebugLexer) postfl("word: '%s'\n",token);
1051 #endif
1053 strcpy(uptoken, token);
1054 for (str = uptoken; *str; ++str) {
1055 if (*str >= 'a' && *str <= 'z') *str += 'A' - 'a';
1058 if (token[0] == '_') {
1059 if (token[1] == 0) {
1060 node = newPyrCurryArgNode();
1061 zzval = (long)node;
1062 return CURRYARG;
1063 } else {
1064 sym = getsym(token);
1065 SetSymbol(&slot, sym);
1066 node = newPyrSlotNode(&slot);
1067 zzval = (long)node;
1068 return PRIMITIVENAME;
1071 if (token[0] >= 'A' && token[0] <= 'Z') {
1072 sym = getsym(token);
1073 SetSymbol(&slot, sym);
1074 node = newPyrSlotNode(&slot);
1075 zzval = (long)node;
1076 #if DEBUGLEX
1077 if (gDebugLexer) postfl("CLASSNAME: '%s'\n",token);
1078 #endif
1079 return CLASSNAME;
1081 if (strcmp("var",token) ==0) return VAR;
1082 if (strcmp("arg",token) ==0) return ARG;
1083 if (strcmp("classvar",token) ==0) return CLASSVAR;
1084 if (strcmp("const",token) ==0) return SC_CONST;
1086 if (strcmp("while",token) ==0) {
1088 sym = getsym(token);
1089 SetSymbol(&slot, sym);
1090 node = newPyrSlotNode(&slot);
1091 zzval = (long)node;
1092 return WHILE;
1094 if (strcmp("pi",token) ==0) {
1095 SetFloat(&slot, pi);
1096 node = newPyrSlotNode(&slot);
1097 zzval = (long)node;
1098 return PIE;
1100 if (strcmp("true",token) ==0) {
1101 SetTrue(&slot);
1102 node = newPyrSlotNode(&slot);
1103 zzval = (long)node;
1104 return TRUEOBJ;
1106 if (strcmp("false",token) ==0) {
1107 SetFalse(&slot);
1108 node = newPyrSlotNode(&slot);
1109 zzval = (long)node;
1110 return FALSEOBJ;
1112 if (strcmp("nil",token) ==0) {
1113 SetNil(&slot);
1114 node = newPyrSlotNode(&slot);
1115 zzval = (long)node;
1116 return NILOBJ;
1118 if (strcmp("inf",token) ==0) {
1119 SetFloat(&slot, std::numeric_limits<double>::infinity());
1120 node = newPyrSlotNode(&slot);
1121 zzval = (long)node;
1122 return SC_FLOAT;
1125 sym = getsym(token);
1127 SetSymbol(&slot, sym);
1128 node = newPyrSlotNode(&slot);
1129 zzval = (long)node;
1130 return NAME;
1133 int processhex(char *s)
1135 PyrSlot slot;
1136 PyrSlotNode *node;
1137 char *c;
1138 int val;
1139 #if DEBUGLEX
1140 if (gDebugLexer) postfl("processhex: '%s'\n",s);
1141 #endif
1143 c = s;
1144 val = 0;
1145 while (*c) {
1146 if (*c >= '0' && *c <= '9') val = val*16 + *c - '0';
1147 else if (*c >= 'a' && *c <= 'z') val = val*16 + *c - 'a' + 10;
1148 else if (*c >= 'A' && *c <= 'Z') val = val*16 + *c - 'A' + 10;
1149 c++;
1152 SetInt(&slot, val);
1153 node = newPyrSlotNode(&slot);
1154 zzval = (long)node;
1155 return INTEGER;
1159 int processintradix(char *s, int n, int radix)
1161 PyrSlot slot;
1162 PyrSlotNode *node;
1163 #if DEBUGLEX
1164 if (gDebugLexer) postfl("processintradix: '%s'\n",s);
1165 #endif
1167 SetInt(&slot, sc_strtoi(s, n, radix));
1168 node = newPyrSlotNode(&slot);
1169 zzval = (long)node;
1170 return INTEGER;
1173 int processfloatradix(char *s, int n, int radix)
1175 PyrSlot slot;
1176 PyrSlotNode *node;
1177 #if DEBUGLEX
1178 if (gDebugLexer) postfl("processfloatradix: '%s'\n",s);
1179 #endif
1181 SetFloat(&slot, sc_strtof(s, n, radix));
1182 node = newPyrSlotNode(&slot);
1183 zzval = (long)node;
1184 return INTEGER;
1187 int processint(char *s)
1189 PyrSlot slot;
1190 PyrSlotNode *node;
1191 #if DEBUGLEX
1192 if (gDebugLexer) postfl("processint: '%s'\n",s);
1193 #endif
1195 SetInt(&slot, atoi(s));
1196 node = newPyrSlotNode(&slot);
1197 zzval = (long)node;
1198 return INTEGER;
1201 int processchar(int c)
1203 PyrSlot slot;
1204 PyrSlotNode *node;
1205 #if DEBUGLEX
1206 if (gDebugLexer) postfl("processhex: '%c'\n",c);
1207 #endif
1209 SetChar(&slot, c);
1210 node = newPyrSlotNode(&slot);
1211 zzval = (long)node;
1212 return ASCII;
1215 int processfloat(char *s, int sawpi)
1217 PyrSlot slot;
1218 PyrSlotNode *node;
1219 double z;
1220 #if DEBUGLEX
1221 if (gDebugLexer) postfl("processfloat: '%s'\n",s);
1222 #endif
1224 if (sawpi) { z = atof(s)*pi; SetFloat(&slot, z); }
1225 else { SetFloat(&slot, atof(s)); }
1226 node = newPyrSlotNode(&slot);
1227 zzval = (long)node;
1228 return SC_FLOAT;
1232 int processaccidental1(char *s)
1234 PyrSlot slot;
1235 PyrSlotNode *node;
1236 char *c;
1237 double degree=0.;
1238 double cents=0.;
1239 double centsdiv=1000.;
1240 #if 0
1241 printf("processaccidental1: '%s'\n",s);
1242 #endif
1244 c = s;
1245 while (*c) {
1246 if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0';
1247 else break;
1248 c++;
1251 if (*c == 'b') centsdiv = -1000.;
1252 else if (*c == 's') centsdiv = 1000.;
1253 c++;
1255 while (*c) {
1256 if (*c >= '0' && *c <= '9') {
1257 cents = cents*10. + *c - '0';
1259 else break;
1260 c++;
1263 if (cents > 499.) cents = 499.;
1265 SetFloat(&slot, degree + cents/centsdiv);
1266 node = newPyrSlotNode(&slot);
1267 zzval = (long)node;
1268 return ACCIDENTAL;
1271 int processaccidental2(char *s)
1273 PyrSlot slot;
1274 PyrSlotNode *node;
1275 char *c;
1276 double degree=0.;
1277 double semitones=0.;
1278 #if 0
1279 printf("processaccidental2: '%s'\n",s);
1280 #endif
1282 c = s;
1283 while (*c) {
1284 if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0';
1285 else break;
1286 c++;
1289 while (*c) {
1290 if (*c == 'b') semitones -= 1.;
1291 else if (*c == 's') semitones += 1.;
1292 c++;
1295 if (semitones > 4.) semitones = 4.;
1297 SetFloat(&slot, degree + semitones/10.);
1298 node = newPyrSlotNode(&slot);
1299 zzval = (long)node;
1300 return ACCIDENTAL;
1303 int processsymbol(char *s)
1305 PyrSlot slot;
1306 PyrSlotNode *node;
1307 PyrSymbol *sym;
1308 #if DEBUGLEX
1309 if (gDebugLexer) postfl("processsymbol: '%s'\n",s);
1310 #endif
1311 sym = getsym(s+1);
1313 SetSymbol(&slot, sym);
1314 node = newPyrSlotNode(&slot);
1315 zzval = (long)node;
1316 return SYMBOL;
1319 int processstring(char *s)
1321 PyrSlot slot;
1322 PyrSlotNode *node;
1323 PyrString *string;
1324 #if DEBUGLEX
1325 if (gDebugLexer) postfl("processstring: '%s'\n",s);
1326 #endif
1327 int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
1328 string = newPyrString(gMainVMGlobals->gc, s+1, flags, false);
1329 SetObject(&slot, string);
1330 node = newPyrSlotNode(&slot);
1331 zzval = (long)node;
1332 return STRING;
1335 void yyerror(const char *s)
1337 parseFailed = 1;
1338 yytext[yylen] = 0;
1339 error("Parse error\n");
1340 postErrorLine(lineno, linepos, charno);
1341 //Debugger();
1344 void fatal()
1346 parseFailed = 1;
1347 yytext[yylen] = 0;
1348 error("Parse error\n");
1349 postErrorLine(lineno, linepos, charno);
1350 //Debugger();
1353 #if 0
1354 void postErrorLine()
1356 int i, j, start, end;
1357 char str[256];
1359 parseFailed = true;
1360 for (i=textpos-1; i>=0; --i) {
1361 if (text[i] == '\r' || text[i] == '\n') break;
1363 start = i+1;
1364 for (i=textpos; i < textlen; ++i) {
1365 if (text[i] == '\r' || text[i] == '\n') break;
1367 end=i;
1368 for (i=start, j=0; i<end; ++i) {
1369 if (i == textpos) str[j++] = '¶';
1370 str[j++] = text[i];
1372 if (textpos == end) str[j++] = '¶';
1373 str[j] = 0;
1375 postfl("%s\n", str);
1377 #endif
1379 void postErrorLine(int linenum, int start, int charpos)
1381 int i, j, end, pos;
1382 char str[256];
1384 //post("start %d\n", start);
1385 //parseFailed = true;
1386 char extPath[MAXPATHLEN];
1387 asRelativePath(curfilename, extPath);
1388 post(" in file '%s'\n", extPath);
1389 post(" line %d char %d:\n", linenum+errLineOffset, charpos);
1390 // nice: postfl previous line for context
1392 //postfl("text '%s' %d\n", text, text);
1394 // postfl error line for context
1395 pos = start + charpos;
1396 for (i=pos; i < textlen; ++i) {
1397 if (text[i] == 0 || text[i] == '\r' || text[i] == '\n') break;
1399 end=i;
1400 for (i=start, j=0; i<end && j<255; ++i) {
1401 if (i == pos) str[j++] = BULLET_CHAR;
1402 str[j++] = text[i];
1404 if (pos == end) str[j++] = BULLET_CHAR;
1405 str[j] = 0;
1406 post(" %s\n", str);
1408 i=end+1;
1409 if (i<textlen) {
1410 // postfl following line for context
1411 for (j=0; j<255 && i<textlen; ++i) {
1412 if (text[i] == 0 ||text[i] == '\r' || text[i] == '\n') break;
1413 str[j++] = text[i];
1415 str[j] = 0;
1416 post(" %s\n", str);
1418 post("-----------------------------------\n", str);
1422 void c2pstrcpy(unsigned char* dst, const char *src);
1423 void c2pstrcpy(unsigned char* dst, const char *src)
1425 int c;
1426 unsigned char *dstp = &dst[1];
1427 while ((c = *src++) != 0) *dstp++ = c;
1428 dst[0] = dstp - dst - 1;
1431 void p2cstrcpy(char *dst, const unsigned char* src);
1432 void p2cstrcpy(char *dst, const unsigned char* src)
1434 int n = *src++;
1435 for (int i=0; i<n; ++i) *dst++ = *src++;
1436 *dst++ = 0;
1440 void pstrncpy(unsigned char *s1, unsigned char *s2, int n);
1441 void pstrncpy(unsigned char *s1, unsigned char *s2, int n)
1443 int i, m;
1444 m = *s2++;
1445 n = (n < m) ? n : m;
1446 *s1 = n; s1++;
1447 for (i=0; i<n; ++i) { *s1 = *s2; s1++; s2++; }
1450 int pstrcmp(unsigned char *s1, unsigned char *s2);
1451 int pstrcmp(unsigned char *s1, unsigned char *s2)
1453 int i, len1, len2, len;
1454 len1 = *s1++;
1455 len2 = *s2++;
1456 len = sc_min(len1, len2);
1457 for (i=0; i<len; ++i) {
1458 if (s1[i] < s2[i]) return -1;
1459 if (s1[i] > s2[i]) return 1;
1461 if (len1 < len2) return -1;
1462 if (len1 > len2) return 1;
1463 return 0;
1466 bool scanForClosingBracket()
1468 int r, c, d, startLevel;
1469 bool res = true;
1470 // finite state machine to parse input stream into tokens
1472 #if DEBUGLEX
1473 if (gDebugLexer) postfl("->scanForClosingBracket\n");
1474 #endif
1475 startLevel = brackets.num;
1476 start:
1477 c = input0();
1479 if (c == 0) goto leave;
1480 else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') {
1481 goto start;
1483 else if (c == '\'') goto symbol3;
1484 else if (c == '"') goto string1;
1485 else if (c == '/') {
1486 c = input0();
1487 if (c == '/') goto comment1;
1488 else if (c == '*') goto comment2;
1489 else { unput(c); goto start; }
1491 else if (c == '$') {
1492 c = input0();
1493 if (c == '\\') {
1494 c = input0();
1495 switch (c) {
1496 case 'n' : c = '\n'; break;
1497 case 'r' : c = '\r'; break;
1498 case 't' : c = '\t'; break;
1499 case 'f' : c = '\f'; break;
1500 case 'v' : c = '\v'; break;
1503 goto start;
1505 else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
1506 pushls(&brackets, (int)c);
1507 r = c;
1508 goto start;
1510 else if (c == CLOSSQUAR) {
1511 if (!emptyls(&brackets)) {
1512 if ((d = popls(&brackets)) != OPENSQUAR) {
1513 fatal();
1514 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1515 goto error1;
1517 } else {
1518 fatal();
1519 post("unmatched '%c'\n",c);
1520 goto error1;
1522 r = c;
1523 if (brackets.num < startLevel) goto leave;
1524 else goto start;
1526 else if (c == CLOSPAREN) {
1527 if (!emptyls(&brackets)) {
1528 if ((d = popls(&brackets)) != OPENPAREN) {
1529 fatal();
1530 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1531 goto error1;
1533 } else {
1534 fatal();
1535 post("unmatched '%c'\n",c);
1536 goto error1;
1538 if (brackets.num < startLevel) goto leave;
1539 else goto start;
1541 else if (c == CLOSCURLY) {
1542 if (!emptyls(&brackets)) {
1543 if ((d = popls(&brackets)) != OPENCURLY) {
1544 fatal();
1545 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1546 goto error1;
1548 } else {
1549 fatal();
1550 post("unmatched '%c'\n",c);
1551 goto error1;
1553 if (brackets.num < startLevel) goto leave;
1554 else goto start;
1555 } else {
1556 goto start;
1558 symbol3 : {
1559 int startline, endchar;
1560 startline = lineno;
1561 endchar = '\'';
1563 do {
1564 c = input0();
1565 if (c == '\\') {
1566 c = input0();
1568 } while (c != endchar && c != 0);
1569 if (c == 0) {
1570 char extPath[MAXPATHLEN];
1571 asRelativePath(curfilename, extPath);
1572 post("Open ended symbol ... started on line %d in file '%s'\n",
1573 startline, extPath);
1574 goto error2;
1576 goto start;
1579 string1 : {
1580 int startline, endchar;
1581 startline = lineno;
1582 endchar = '\"';
1584 do {
1585 c = input0();
1586 if (c == '\\') {
1587 c = input0();
1589 } while (c != endchar && c != 0);
1590 if (c == 0) {
1591 char extPath[MAXPATHLEN];
1592 asRelativePath(curfilename, extPath);
1593 post("Open ended string ... started on line %d in file '%s'\n",
1594 startline, extPath);
1595 goto error2;
1597 goto start;
1599 comment1: /* comment -- to end of line */
1600 do {
1601 c = input0();
1602 } while (c != '\n' && c != '\r' && c != 0);
1603 if (c == 0) { goto leave; }
1604 else goto start;
1606 comment2 : {
1607 int startline, clevel, prevc;
1608 startline = lineno;
1609 prevc = 0;
1610 clevel = 1;
1611 do {
1612 c = input0();
1613 if (c == '/' && prevc == '*') {
1614 if (--clevel <= 0) break;
1615 } else if (c == '*' && prevc == '/') clevel++;
1616 prevc = c;
1617 } while (c != 0);
1618 if (c == 0) {
1619 char extPath[MAXPATHLEN];
1620 asRelativePath(curfilename, extPath);
1621 post("Open ended comment ... started on line %d in file '%s'\n",
1622 startline, extPath);
1623 goto error2;
1625 goto start;
1628 error1:
1629 char extPath[MAXPATHLEN];
1630 asRelativePath(curfilename, extPath);
1631 post(" in file '%s' line %d char %d\n", extPath, lineno, charno);
1632 res = false;
1633 goto leave;
1635 error2:
1636 res = false;
1637 goto leave;
1639 leave:
1640 #if DEBUGLEX
1641 if (gDebugLexer) postfl("<-scanForClosingBracket\n");
1642 #endif
1643 return res;
1647 int numClassDeps;
1648 static ClassExtFile* sClassExtFiles;
1649 static ClassExtFile* eClassExtFiles;
1651 ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos);
1652 ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos)
1654 ClassExtFile* classext;
1655 classext = (ClassExtFile*)pyr_pool_compile->Alloc(sizeof(ClassExtFile));
1656 classext->fileSym = fileSym;
1657 classext->next = 0;
1658 classext->startPos = startPos;
1659 classext->endPos = endPos;
1660 if (!sClassExtFiles) sClassExtFiles = classext;
1661 else eClassExtFiles->next = classext;
1662 eClassExtFiles = classext;
1663 return classext;
1667 ClassDependancy* newClassDependancy(PyrSymbol *className, PyrSymbol *superClassName,
1668 PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
1670 ClassDependancy* classdep;
1672 //post("classdep '%s' '%s' '%s' %d %d\n", className->name, superClassName->name,
1673 // fileSym->name, className, superClassName);
1674 // pyrmalloc:
1675 // lifetime: kill after compile.
1676 numClassDeps++;
1677 if (className->classdep) {
1678 error("duplicate Class found: '%s' \n", className->name);
1679 post("%s\n",className->classdep->fileSym->name);
1680 postfl("%s\n\n",fileSym->name);
1681 return className->classdep;
1683 classdep = (ClassDependancy*)pyr_pool_compile->Alloc(sizeof(ClassDependancy));
1684 MEMFAIL(text);
1685 classdep->className = className;
1686 classdep->superClassName = superClassName;
1687 classdep->fileSym = fileSym;
1688 classdep->superClassDep = NULL;
1689 classdep->next = NULL;
1690 classdep->subclasses = NULL;
1692 classdep->startPos = startPos;
1693 classdep->endPos = endPos;
1694 classdep->lineOffset = lineOffset;
1696 className->classdep = classdep;
1697 return classdep;
1700 void buildDepTree()
1702 ClassDependancy *next;
1703 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1705 //postfl("->buildDepTree\n"); fflush(stdout);
1706 for (int i=0; i<symbolTable->TableSize(); ++i) {
1707 PyrSymbol *sym = symbolTable->Get(i);
1708 if (sym && (sym->flags & sym_Class)) {
1709 if (sym->classdep) {
1710 if (sym->classdep->superClassName->classdep) {
1711 next = sym->classdep->superClassName->classdep->subclasses;
1712 sym->classdep->superClassName->classdep->subclasses = sym->classdep;
1713 sym->classdep->next = next;
1714 } else if (sym->classdep->superClassName != s_none) {
1715 error("Superclass '%s' of class '%s' is not defined in any file.\n%s\n",
1716 sym->classdep->superClassName->name, sym->classdep->className->name,sym->classdep->fileSym->name);
1721 //postfl("<-buildDepTree\n"); fflush(stdout);
1724 extern PyrClass *gClassList;
1726 ClassDependancy **gClassCompileOrder;
1727 int gClassCompileOrderNum = 0;
1728 int gClassCompileOrderSize = 1000;
1730 void compileDepTree();
1732 void traverseFullDepTree()
1734 //postfl("->traverseFullDepTree\n"); fflush(stdout);
1735 gClassCompileOrderNum = 0;
1736 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Alloc(
1737 gClassCompileOrderSize * sizeof(ClassDependancy));
1738 MEMFAIL(gClassCompileOrder);
1740 // parse and compile all files
1741 initParser(); // sets compiler errors to 0
1742 gParserResult = -1;
1744 traverseDepTree(s_object->classdep, 0);
1745 compileDepTree(); // compiles backwards using the order defined in gClassCompileOrder
1746 compileClassExtensions();
1748 pyr_pool_compile->Free(gClassCompileOrder);
1750 finiParser();
1751 //postfl("<-traverseFullDepTree\n"); fflush(stdout);
1755 void traverseDepTree(ClassDependancy *classdep, int level)
1757 ClassDependancy *subclassdep;
1759 if (!classdep) return;
1761 subclassdep = classdep->subclasses;
1762 for (; subclassdep; subclassdep = subclassdep->next) {
1763 traverseDepTree(subclassdep, level+1);
1765 if (gClassCompileOrderNum > gClassCompileOrderSize) {
1766 gClassCompileOrderSize *= 2;
1767 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Realloc(gClassCompileOrder,
1768 gClassCompileOrderSize * sizeof(ClassDependancy));
1769 MEMFAIL(gClassCompileOrder);
1772 /* postfl("traverse level:%d, gClassCompileOrderNum:%d, '%s' '%s' '%s'\n", level, gClassCompileOrderNum, classdep->className->name, classdep->superClassName->name,
1773 classdep->fileSym->name); fflush(stdout);
1776 gClassCompileOrder[gClassCompileOrderNum++] = classdep;
1780 void compileClass(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
1782 //fprintf(stderr, "compileClass: %d\n", fileSym->u.index);
1784 gCompilingFileSym = fileSym;
1785 gCompilingVMGlobals = 0;
1786 gRootParseNode = NULL;
1787 initParserPool();
1788 if (startLexer(fileSym, startPos, endPos, lineOffset)) {
1789 //postfl("->Parsing %s\n", fileSym->name); fflush(stdout);
1790 parseFailed = yyparse();
1791 //postfl("<-Parsing %s %d\n", fileSym->name, parseFailed); fflush(stdout);
1792 //post("parseFailed %d\n", parseFailed); fflush(stdout);
1793 if (!parseFailed && gRootParseNode) {
1794 //postfl("Compiling nodes %p\n", gRootParseNode);fflush(stdout);
1795 compilingCmdLine = false;
1796 compileNodeList(gRootParseNode, true);
1797 //postfl("done compiling\n");fflush(stdout);
1798 } else {
1799 compileErrors++;
1800 char extPath[MAXPATHLEN];
1801 asRelativePath(fileSym->name, extPath);
1802 error("file '%s' parse failed\n", extPath);
1803 postfl("error parsing\n");
1805 finiLexer();
1806 } else {
1807 error("file '%s' open failed\n", fileSym->name);
1809 freeParserPool();
1812 void compileDepTree()
1814 ClassDependancy *classdep;
1815 int i;
1817 for (i=gClassCompileOrderNum-1; i>=0; --i) {
1818 classdep = gClassCompileOrder[i];
1819 /*postfl("compile %d '%s' '%s' '%s'...%d/%d/%d\n", i, classdep->className->name, classdep->superClassName->name,
1820 classdep->fileSym->name, classdep->startLine, classdep->endLine, classDep->lineOffset);*/
1821 compileClass(classdep->fileSym, classdep->startPos, classdep->endPos, classdep->lineOffset);
1823 //postfl("<compile\n");
1826 void compileClassExtensions()
1828 if (sClassExtFiles) {
1829 ClassExtFile *classext = sClassExtFiles;
1830 do {
1831 //postfl("compile class ext: %d/%d\n", classext->startPos, classext->endPos);
1832 compileClass(classext->fileSym, classext->startPos, classext->endPos, -1);
1833 classext = classext->next;
1834 } while (classext);
1838 void findDiscrepancy();
1840 void traverseFullDepTree2()
1843 // assign a class index to all classes
1844 if (!parseFailed && !compileErrors) {
1845 buildClassTree();
1846 gNumClasses = 0;
1848 // now I index them during pass one
1849 indexClassTree(class_object, 0);
1850 setSelectorFlags();
1851 if (2*numClassDeps != gNumClasses) {
1852 error("There is a discrepancy.\n");
1853 /* not always correct
1854 if(2*numClassDeps < gNumClasses) {
1855 post("Duplicate files may exist in the directory structure.\n");
1856 } else {
1857 post("Some class files may be missing.\n");
1860 post("numClassDeps %d gNumClasses %d\n", numClassDeps, gNumClasses);
1861 findDiscrepancy();
1862 compileErrors++;
1863 } else {
1864 double elapsed;
1865 buildBigMethodMatrix();
1866 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1867 post("\tNumber of Symbols %d\n", symbolTable->NumItems());
1868 post("\tByte Code Size %d\n", totalByteCodes);
1869 //elapsed = TickCount() - compileStartTime;
1870 //elapsed = 0;
1871 elapsed = elapsedTime() - compileStartTime;
1872 post("\tcompiled %d files in %.2f seconds\n",
1873 gNumCompiledFiles, elapsed );
1874 if(numOverwrites == 1){
1875 post("\nInfo: One method is currently overwritten by an extension. To see which, execute:\nMethodOverride.printAll\n\n");
1877 else if(numOverwrites > 1){
1878 post("\nInfo: %i methods are currently overwritten by extensions. To see which, execute:\nMethodOverride.printAll\n\n", numOverwrites);
1880 post("compile done\n");
1885 bool parseOneClass(PyrSymbol *fileSym)
1887 int token;
1888 PyrSymbol *className, *superClassName;
1889 ClassDependancy *classdep;
1890 bool res;
1892 int startPos, startLine, startLineOffset;
1894 res = true;
1896 startPos = textpos;
1897 startLineOffset = lineno - 1;
1899 token = yylex();
1900 if (token == CLASSNAME) {
1901 className = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1902 // I think this is wrong: zzval is space pool alloced
1903 //pyrfree((PyrSlot*)zzval);
1905 token = yylex();
1906 if (token == 0) return false;
1907 if (token == OPENSQUAR) {
1908 scanForClosingBracket(); // eat indexing spec
1909 token = yylex();
1910 if (token == 0) return false;
1912 if (token == ':') {
1913 token = yylex(); // get super class
1914 if (token == 0) return false;
1915 if (token == CLASSNAME) {
1916 superClassName = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1917 // I think this is wrong: zzval is space pool alloced
1918 //pyrfree((PyrSlot*)zzval);
1919 token = yylex();
1920 if (token == 0) return false;
1921 if (token == OPENCURLY) {
1922 scanForClosingBracket(); // eat class body
1923 classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1924 } else {
1925 compileErrors++;
1926 postfl("Expected %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1927 postErrorLine(lineno, linepos, charno);
1928 return false;
1930 } else {
1931 compileErrors++;
1932 post("Expected superclass name. got token: '%s' %d\n", yytext, token);
1933 postErrorLine(lineno, linepos, charno);
1934 return false;
1936 } else if (token == OPENCURLY) {
1937 if (className == s_object) superClassName = s_none;
1938 else superClassName = s_object;
1939 scanForClosingBracket(); // eat class body
1940 classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1941 } else {
1942 compileErrors++;
1943 post("Expected ':' or %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1944 postErrorLine(lineno, linepos, charno);
1945 return false;
1947 } else if (token == '+') {
1948 token = yylex();
1949 if (token == 0) return false;
1950 scanForClosingBracket();
1952 newClassExtFile(fileSym, startPos, textpos);
1953 return false;
1954 } else {
1955 if (token != 0) {
1956 compileErrors++;
1957 post("Expected class name. got token: '%s' %d\n", yytext, token);
1958 postErrorLine(lineno, linepos, charno);
1959 return false;
1960 } else {
1961 res = false;
1964 return res;
1967 //void ClearLibMenu();
1969 void aboutToFreeRuntime();
1970 void aboutToFreeRuntime()
1972 //ClearLibMenu();
1975 //void init_graph_compile();
1976 //void tellPlugInsAboutToCompile();
1977 void pyrmath_init_globs();
1979 void initPassOne()
1981 aboutToFreeRuntime();
1983 //dump_pool_histo(pyr_pool_runtime);
1984 pyr_pool_runtime->FreeAllInternal();
1985 //dump_pool_histo(pyr_pool_runtime);
1986 //gPermanentObjPool.Init(pyr_pool_runtime, PERMOBJCHUNK);
1987 sClassExtFiles = 0;
1989 void *ptr = pyr_pool_runtime->Alloc(sizeof(SymbolTable));
1990 gMainVMGlobals->symbolTable = new (ptr) SymbolTable(pyr_pool_runtime, 8192);
1992 //gFileSymbolTable = newSymbolTable(512);
1994 pyrmath_init_globs();
1996 initSymbols(); // initialize symbol globals
1997 //init_graph_compile();
1998 initSpecialSelectors();
1999 initSpecialClasses();
2000 initClasses();
2001 initParserPool();
2002 initParseNodes();
2003 initPrimitives();
2004 //tellPlugInsAboutToCompile();
2005 initLexer();
2006 compileErrors = 0;
2007 numClassDeps = 0;
2008 compiledOK = false;
2009 compiledDirectories.clear();
2010 sc_InitCompileDirectory();
2013 void finiPassOne()
2015 //postfl("->finiPassOne\n");
2016 freeParserPool();
2017 //postfl("<-finiPassOne\n");
2020 static bool passOne_ProcessDir(const char *dirname, int level)
2022 if (!sc_DirectoryExists(dirname))
2023 return true;
2025 if (compiledDirectories.find(std::string(dirname)) != compiledDirectories.end())
2026 // already compiled
2027 return true;
2029 bool success = true;
2031 if (gLibraryConfig && gLibraryConfig->pathIsExcluded(dirname)) {
2032 post("\texcluding dir: '%s'\n", dirname);
2033 return success;
2036 if (level == 0) post("\tcompiling dir: '%s'\n", dirname);
2038 SC_DirHandle *dir = sc_OpenDir(dirname);
2039 if (!dir) {
2040 error("open directory failed '%s'\n", dirname); fflush(stdout);
2041 return false;
2044 for (;;) {
2045 char diritem[MAXPATHLEN];
2046 bool skipItem = true;
2047 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
2048 if (!validItem) break;
2049 if (skipItem) continue;
2051 if (sc_DirectoryExists(diritem)) {
2052 success = passOne_ProcessDir(diritem, level + 1);
2053 } else {
2054 success = passOne_ProcessOneFile(diritem, level + 1);
2057 if (!success) break;
2060 compiledDirectories.insert(std::string(dirname));
2061 sc_CloseDir(dir);
2062 return success;
2065 bool passOne()
2067 initPassOne();
2069 if (sc_IsStandAlone()) {
2070 /// FIXME: this should be moved to the LibraryConfig file
2071 if (!passOne_ProcessDir(gCompileDir, 0))
2072 return false;
2073 } else
2074 if (!gLibraryConfig->forEachIncludedDirectory(passOne_ProcessDir))
2075 return false;
2077 finiPassOne();
2078 return true;
2081 // true if filename ends in ".sc"
2082 bool isValidSourceFileName(char *filename)
2084 int len = strlen(filename);
2085 bool validExtension = (len>3 && strncmp(filename+len-3, ".sc", 3) == 0)
2086 || (len>7 && strncmp(filename+len-7, ".sc.rtf", 7) == 0);
2087 if (!validExtension)
2088 return false;
2090 boost::filesystem::path pathname(filename);
2092 if (pathname.filename().c_str()[0] == '.') // hidden filename
2093 return false;
2095 return true;
2098 // sekhar's replacement
2099 bool passOne_ProcessOneFile(const char * filenamearg, int level)
2101 bool success = true;
2103 bool isAlias = false;
2105 char filename[MAXPATHLEN];
2106 int status = sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN);
2108 if (status<0) {
2109 printf("WARNING: skipping invalid symbolic link: %s\n", filenamearg);
2110 return success;
2113 if (gLibraryConfig && gLibraryConfig->pathIsExcluded(filename)) {
2114 post("\texcluding file: '%s'\n", filename);
2115 return success;
2118 if (isValidSourceFileName(filename)) {
2119 gNumCompiledFiles++;
2120 PyrSymbol * fileSym = getsym(filename);
2121 fileSym->u.source = NULL;
2122 if (startLexer(fileSym, -1, -1, -1)) {
2123 while (parseOneClass(fileSym)) { };
2124 finiLexer();
2125 } else {
2126 error("file '%s' open failed\n", filename);
2127 success = false;
2129 } else {
2130 if (sc_DirectoryExists(filename))
2131 success = passOne_ProcessDir(filename, level);
2133 return success;
2136 void schedRun();
2138 void compileSucceeded();
2139 void compileSucceeded()
2141 compiledOK = !(parseFailed || compileErrors);
2142 if (compiledOK) {
2143 compiledOK = true;
2145 compiledOK = initRuntime(gMainVMGlobals, 128*1024, pyr_pool_runtime);
2147 if (compiledOK) {
2148 VMGlobals *g = gMainVMGlobals;
2150 g->canCallOS = true;
2151 //++g->sp; SetObject(g->sp, g->process);
2152 //runInterpreter(g, s_hardwaresetup, 1);
2154 ++g->sp; SetObject(g->sp, g->process);
2155 runInterpreter(g, s_startup, 1);
2156 g->canCallOS = false;
2158 schedRun();
2160 flushPostBuf();
2164 void aboutToCompileLibrary();
2165 void aboutToCompileLibrary()
2167 //printf("->aboutToCompileLibrary\n");
2168 pthread_mutex_lock (&gLangMutex);
2169 if (compiledOK) {
2170 ++gMainVMGlobals->sp;
2171 SetObject(gMainVMGlobals->sp, gMainVMGlobals->process);
2172 runInterpreter(gMainVMGlobals, s_shutdown, 1);
2173 gVMGlobals.gc->ScanFinalizers(); // run finalizers
2175 pthread_mutex_unlock (&gLangMutex);
2176 //printf("<-aboutToCompileLibrary\n");
2179 void closeAllGUIScreens();
2180 void TempoClock_stopAll(void);
2181 void closeAllCustomPorts();
2183 void shutdownLibrary()
2185 closeAllGUIScreens();
2186 schedStop();
2187 aboutToCompileLibrary();
2189 TempoClock_stopAll();
2191 pthread_mutex_lock (&gLangMutex);
2192 closeAllCustomPorts();
2194 pyr_pool_runtime->FreeAll();
2195 compiledOK = false;
2196 pthread_mutex_unlock (&gLangMutex);
2199 SC_DLLEXPORT_C bool compileLibrary()
2201 //printf("->compileLibrary\n");
2202 shutdownLibrary();
2204 pthread_mutex_lock (&gLangMutex);
2205 gNumCompiledFiles = 0;
2206 compiledOK = false;
2208 // FIXME: the library config should have been initialized earlier!
2209 if (!gLibraryConfig)
2210 SC_LanguageConfig::readDefaultLibraryConfig();
2212 compileStartTime = elapsedTime();
2214 totalByteCodes = 0;
2216 #ifdef NDEBUG
2217 postfl("compiling class library...\n");
2218 #else
2219 postfl("compiling class library (debug build)...\n");
2220 #endif
2222 bool res = passOne();
2223 if (res) {
2225 postfl("\tpass 1 done\n");
2227 if (!compileErrors) {
2228 buildDepTree();
2229 traverseFullDepTree();
2230 traverseFullDepTree2();
2231 flushPostBuf();
2233 if (!compileErrors && gShowWarnings) {
2234 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
2235 symbolTable->CheckSymbols();
2238 pyr_pool_compile->FreeAll();
2239 flushPostBuf();
2240 compileSucceeded();
2241 } else {
2242 compiledOK = false;
2245 pthread_mutex_unlock (&gLangMutex);
2246 //printf("<-compileLibrary\n");
2247 return compiledOK;
2250 void signal_init_globs();
2252 void dumpByteCodes(PyrBlock *theBlock);
2254 SC_DLLEXPORT_C void runLibrary(PyrSymbol* selector)
2256 VMGlobals *g = gMainVMGlobals;
2257 g->canCallOS = true;
2258 try {
2259 if (compiledOK) {
2260 ++g->sp; SetObject(g->sp, g->process);
2261 runInterpreter(g, selector, 1);
2262 } else {
2263 postfl("Library has not been compiled successfully.\n");
2265 } catch (std::exception &ex) {
2266 PyrMethod *meth = g->method;
2267 if (meth) {
2268 int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1;
2269 post("caught exception in runLibrary %s:%s %3d\n",
2270 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip
2272 dumpByteCodes(meth);
2273 } else {
2274 post("caught exception in runLibrary\n");
2276 error(ex.what());
2277 } catch (...) {
2278 postfl(BULLET"DANGER: OUT of MEMORY. Operation failed.\n");
2280 g->canCallOS = false;
2283 void interpretCmdLine(const char *textbuf, int textlen, char *methodname)
2285 PyrString *string;
2287 if (compiledOK) {
2288 PyrSlot slot;
2290 string = newPyrStringN(gMainVMGlobals->gc, textlen, 0, false);
2291 memcpy(string->s, textbuf, textlen);
2292 SetObject(&slotRawInterpreter(&gMainVMGlobals->process->interpreter)->cmdLine, string);
2293 gMainVMGlobals->gc->GCWrite(slotRawObject(&gMainVMGlobals->process->interpreter), string);
2294 SetObject(&slot, gMainVMGlobals->process);
2295 //#if __profile__
2296 // ProfilerInit(collectSummary, microsecondsTimeBase, 500, 100);
2297 //#endif
2298 slotCopy((++gMainVMGlobals->sp), &slot);
2299 runInterpreter(gMainVMGlobals, getsym(methodname), 1);
2300 //#if __profile__
2301 // ProfilerDump("\pErase2.prof");
2302 // ProfilerTerm();
2303 //#endif
2304 } else {
2305 postfl("Library has not been compiled successfully.\n");
2309 void init_SuperCollider()