Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangSource / PyrLexer.cpp
blob09ca202b822418732c582365331149d11d2d7080
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 "PredefinedSymbols.h"
61 #ifdef SC_WIN32
62 #else
63 # include "dirent.h"
64 #endif
65 #include <string.h>
67 #include "SC_LibraryConfig.h"
69 #include "SC_DirUtils.h"
70 #include "SC_TextUtils.hpp"
72 int yyparse();
73 int processaccidental1(char *s);
74 int processaccidental2(char *s);
77 extern bool gFullyFunctional;
78 double compileStartTime;
79 int gNumCompiledFiles;
81 thisProcess.interpreter.executeFile("Macintosh HD:score").size.postln;
84 PyrSymbol *gCompilingFileSym = 0;
85 VMGlobals *gCompilingVMGlobals = 0;
86 static char gCompileDir[MAXPATHLEN];
88 //#define DEBUGLEX 1
89 bool gDebugLexer = false;
91 bool gShowWarnings = false;
92 LongStack brackets;
93 LongStack closedFuncCharNo;
94 LongStack generatorStack;
95 int lastClosedFuncCharNo = 0;
97 const char *binopchars = "!@%&*-+=|<>?/";
98 char yytext[MAXYYLEN];
99 char curfilename[PATH_MAX];
101 int yylen;
102 int lexCmdLine = 0;
103 bool compilingCmdLine = false;
104 bool compilingCmdLineErrorWindow = false;
105 long zzval;
107 int lineno, charno, linepos;
108 int *linestarts;
109 int maxlinestarts;
111 char *text;
112 int textlen;
113 int textpos;
114 int errLineOffset, errCharPosOffset;
115 int parseFailed = 0;
116 bool compiledOK = false;
117 std::set<std::string> compiledDirectories;
119 /* so the text editor's dumb paren matching will work */
120 #define OPENPAREN '('
121 #define OPENCURLY '{'
122 #define OPENSQUAR '['
123 #define CLOSSQUAR ']'
124 #define CLOSCURLY '}'
125 #define CLOSPAREN ')'
127 int sc_strtoi(const char *str, int n, int base)
129 int z = 0;
130 for (int i=0; i<n; ++i)
132 int c = *str++;
133 if (!c) break;
134 if (c >= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0';
135 else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10;
136 else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10;
138 return z;
141 double sc_strtof(const char *str, int n, int base)
143 double z = 0.;
144 int decptpos = 0;
145 for (int i=0; i<n; ++i)
147 int c = *str++;
148 if (!c) break;
149 if (c >= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0';
150 else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10;
151 else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10;
152 else if (c == '.') decptpos = i;
154 //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
155 z = z / pow((double)base, n -1- decptpos);
156 return z;
159 static void sc_InitCompileDirectory(void)
161 // main class library folder: only used for relative path resolution
162 sc_GetResourceDirectory(gCompileDir, MAXPATHLEN-32);
163 sc_AppendToPath(gCompileDir, MAXPATHLEN, "SCClassLibrary");
166 extern void asRelativePath(char *inPath, char *outPath)
168 uint32 len = strlen(gCompileDir);
169 if (strlen(inPath) < len || memcmp(inPath, gCompileDir, len) != 0) {
170 // gCompileDir is not the prefix.
171 strcpy(outPath, inPath);
172 return;
174 strcpy(outPath, inPath + len);
178 static bool getFileText(char* filename, char **text, int *length)
180 FILE *file;
181 char *ltext;
182 int llength;
184 #ifdef SC_WIN32
185 file = fopen(filename, "rb");
186 #else
187 file = fopen(filename, "r");
188 #endif
189 if (!file) return false;
191 fseek(file, 0L, SEEK_END);
192 llength = ftell(file);
193 fseek(file, 0L, SEEK_SET);
194 ltext = (char*)pyr_pool_compile->Alloc((llength+1) * sizeof(char));
195 #ifdef SC_WIN32
196 // win32 isprint( ) doesn't like the 0xcd after the end of file when
197 // there is a mismatch in lengths due to line endings....
198 memset(ltext,0,(llength+1) * sizeof(char));
199 #endif //SC_WIN32
200 MEMFAIL(ltext);
202 size_t size = fread(ltext, 1, llength, file);
203 if (size != llength) {
204 error("error when reading file");
205 fclose(file);
206 return false;
208 ltext[llength] = 0;
209 //ltext[llength] = 0;
210 *length = llength;
211 fclose(file);
212 *text = ltext;
213 return true;
217 int bugctr = 0;
220 bool startLexer(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
222 char *filename = fileSym->name;
224 textlen = -1;
226 if(!fileSym->u.source) {
227 if (!getFileText(filename, &text, &textlen)) return false;
228 fileSym->u.source = text;
229 rtf2txt(text);
231 else
232 text = fileSym->u.source;
234 if((startPos >= 0) && (endPos > 0)) {
235 textlen = endPos - startPos;
236 text += startPos;
238 else if(textlen == -1)
239 textlen = strlen(text);
241 if(lineOffset > 0) errLineOffset = lineOffset;
242 else errLineOffset = 0;
244 if(startPos > 0) errCharPosOffset = startPos;
245 else errCharPosOffset = 0;
247 initLongStack(&brackets);
248 initLongStack(&closedFuncCharNo);
249 initLongStack(&generatorStack);
250 lastClosedFuncCharNo = 0;
251 textpos = 0;
252 linepos = 0;
253 lineno = 1;
254 charno = 0;
256 yylen = 0;
257 zzval = 0;
258 parseFailed = 0;
259 lexCmdLine = 0;
260 strcpy(curfilename, filename);
261 maxlinestarts = 1000;
262 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
263 linestarts[0] = 0;
264 linestarts[1] = 0;
266 return true;
269 void startLexerCmdLine(char *textbuf, int textbuflen)
271 // pyrmalloc:
272 // lifetime: kill after compile. (this one gets killed anyway)
273 text = (char*)pyr_pool_compile->Alloc((textbuflen+2) * sizeof(char));
274 MEMFAIL(text);
275 memcpy(text, textbuf, textbuflen);
276 text[textbuflen] = ' ';
277 text[textbuflen+1] = 0;
278 textlen = textbuflen + 1;
280 rtf2txt(text);
282 initLongStack(&brackets);
283 initLongStack(&closedFuncCharNo);
284 initLongStack(&generatorStack);
285 lastClosedFuncCharNo = 0;
286 textpos = 0;
287 linepos = 0;
288 lineno = 1;
289 charno = 0;
291 yylen = 0;
292 zzval = 0;
293 parseFailed = 0;
294 lexCmdLine = 1;
295 strcpy(curfilename, "selected text");
296 maxlinestarts = 1000;
297 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
298 linestarts[0] = 0;
299 linestarts[1] = 0;
301 errLineOffset = 0;
302 errCharPosOffset = 0;
305 void finiLexer()
307 pyr_pool_compile->Free(linestarts);
308 freeLongStack(&brackets);
309 freeLongStack(&closedFuncCharNo);
310 freeLongStack(&generatorStack);
313 void initLexer()
315 //strcpy(binopchars, "!@%&*-+=|:<>?/");
318 int input()
320 int c;
321 if (textpos >= textlen) {
322 c = 0;
323 } else {
324 c = text[textpos++];
325 charno++;
327 if (c == '\n' || c == '\r') {
328 lineno++;
329 linepos = textpos;
330 if (linestarts) {
331 if (lineno >= maxlinestarts) {
332 maxlinestarts += maxlinestarts;
333 linestarts = (int*)pyr_pool_compile->Realloc(
334 linestarts, maxlinestarts * sizeof(int*));
336 linestarts[lineno] = linepos;
338 charno = 0;
340 if (c != 0 && yylen < MAXYYLEN-2) yytext[yylen++] = c;
341 //if (gDebugLexer) postfl("input '%c' %d\n",c,c);
342 return c;
345 int input0()
347 int c;
348 if (textpos >= textlen) {
349 c = 0;
350 textpos++; // so unput will work properly
351 } else {
352 c = text[textpos++];
353 charno++;
355 if (c == '\n' || c == '\r') {
356 lineno++;
357 linepos = textpos;
358 if (linestarts) {
359 if (lineno >= maxlinestarts) {
360 maxlinestarts += maxlinestarts;
361 linestarts = (int*)pyr_pool_compile->Realloc(
362 linestarts, maxlinestarts * sizeof(int*));
364 linestarts[lineno] = linepos;
366 charno = 0;
368 //if (gDebugLexer) postfl("input0 '%c' %d\n",c,c);
369 return c;
372 void unput(int c)
374 if (textpos>0) textpos--;
375 if (c) {
376 if (yylen) --yylen;
377 if (charno) --charno;
378 if (c == '\n' || c == '\r') {
379 --lineno;
384 void unput0(int c)
386 if (textpos>0) textpos--;
387 if (charno) --charno;
388 if (c == '\n' || c == '\r') {
389 --lineno;
393 int yylex()
395 int r, c, c2, d;
396 int radix;
397 char extPath[MAXPATHLEN]; // for error reporting
399 yylen = 0;
400 // finite state machine to parse input stream into tokens
402 if (lexCmdLine == 1) {
403 lexCmdLine = 2;
404 r = INTERPRET;
405 goto leave;
407 start:
408 c = input();
410 if (c == 0) { r = 0; goto leave; }
411 else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') {
412 yylen = 0;
413 goto start;
415 else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto ident;
416 else if (c == '/') {
417 c = input();
418 if (c == '/') goto comment1;
419 else if (c == '*') goto comment2;
420 else { unput(c); goto binop; }
422 else if (c >= '0' && c <= '9') goto digits_1;
423 else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
424 pushls(&brackets, (int)c);
425 if (c == OPENCURLY) {
426 pushls(&closedFuncCharNo, linestarts[lineno] + charno - 1);
428 r = c;
429 goto leave;
431 else if (c == CLOSSQUAR) {
432 if (!emptyls(&brackets)) {
433 if ((d = popls(&brackets)) != OPENSQUAR) {
434 fatal();
435 post("opening bracket was a '%c', but found a '%c'\n",d,c);
436 goto error2;
438 } else {
439 fatal();
440 post("unmatched '%c'\n",c);
441 goto error2;
443 r = c;
444 goto leave;
446 else if (c == CLOSPAREN) {
447 if (!emptyls(&brackets)) {
448 if ((d = popls(&brackets)) != OPENPAREN) {
449 fatal();
450 post("opening bracket was a '%c', but found a '%c'\n",d,c);
451 goto error2;
453 } else {
454 fatal();
455 post("unmatched '%c'\n",c);
456 goto error2;
458 r = c;
459 goto leave;
461 else if (c == CLOSCURLY) {
462 if (!emptyls(&brackets)) {
463 if ((d = popls(&brackets)) != OPENCURLY) {
464 fatal();
465 post("opening bracket was a '%c', but found a '%c'\n",d,c);
466 goto error2;
468 lastClosedFuncCharNo = popls(&closedFuncCharNo);
469 } else {
470 fatal();
471 post("unmatched '%c'\n",c);
472 goto error2;
474 r = c;
475 goto leave;
477 else if (c == '^') { r = c; goto leave; }
478 else if (c == '~') { r = c; goto leave; }
479 else if (c == ';') { r = c; goto leave; }
480 else if (c == ':') { r = c; goto leave; }
481 else if (c == '`') { r = c; goto leave; }
482 else if (c == '\\') goto symbol1;
483 else if (c == '\'') goto symbol3;
484 else if (c == '"') goto string1;
485 else if (c == '.') {
486 if ((c = input()) == '.') {
487 if ((c = input()) == '.') {
488 r = ELLIPSIS;
489 goto leave;
490 } else {
491 r = DOTDOT;
492 unput(c);
493 goto leave;
495 } else {
496 unput(c);
497 r = '.';
498 goto leave;
502 else if (c == '#') {
503 if ((c = input()) == OPENCURLY) {
504 pushls(&brackets, OPENCURLY);
505 pushls(&closedFuncCharNo, linestarts[lineno] + charno - 2);
506 r = BEGINCLOSEDFUNC;
507 } else {
508 unput(c);
509 r = '#';
511 goto leave;
513 else if (c == '$') {
514 c = input();
515 if (c == '\\') {
516 c = input();
517 switch (c) {
518 case 'n' : c = '\n'; break;
519 case 'r' : c = '\r'; break;
520 case 't' : c = '\t'; break;
521 case 'f' : c = '\f'; break;
522 case 'v' : c = '\v'; break;
525 r = processchar(c);
526 goto leave;
528 else if (c == ',') { r = c; goto leave; }
529 else if (c == '=') {
530 c = input();
531 if (strchr(binopchars, c)) goto binop;
532 else {
533 unput(c);
534 r = '=';
535 goto leave;
538 else if (strchr(binopchars, c)) goto binop;
539 else if(!(isprint(c) || isspace(c) || c == 0)) {
540 yylen = 0;
541 goto start;
543 else goto error1;
545 ident:
546 c = input();
548 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
549 || c == '_' || (c >= '0' && c <= '9')) goto ident;
550 else if (c == ':') {
551 yytext[yylen] = 0;
552 r = processkeywordbinop(yytext) ;
553 goto leave;
554 } else {
555 unput(c);
556 yytext[yylen] = 0;
557 r = processident(yytext) ;
558 goto leave;
561 symbol1:
562 c = input();
564 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto symbol2;
565 else if (c >= '0' && c <= '9') goto symbol4;
566 else {
567 unput(c);
568 yytext[yylen] = 0;
569 r = processsymbol(yytext) ;
570 goto leave;
573 symbol2:
574 c = input();
576 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
577 || c == '_' || (c >= '0' && c <= '9')) goto symbol2;
578 else {
579 unput(c);
580 yytext[yylen] = 0;
581 r = processsymbol(yytext) ;
582 goto leave;
585 symbol4:
586 c = input();
587 if (c >= '0' && c <= '9') goto symbol4;
588 else {
589 unput(c);
590 yytext[yylen] = 0;
591 r = processsymbol(yytext) ;
592 goto leave;
597 binop:
599 c = input();
601 if (c == 0) goto binop2;
602 if (strchr(binopchars, c)) goto binop;
603 else {
604 binop2:
605 unput(c);
606 yytext[yylen] = 0;
607 r = processbinop(yytext) ;
608 goto leave;
611 radix_digits_1:
613 c = input();
614 if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_1;
615 if (c >= 'a' && c <= 'a' + sc_min(36,radix) - 11) goto radix_digits_1;
616 if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_1;
617 if (c == '.') {
618 goto radix_digits_2;
620 unput(c);
621 yytext[yylen] = 0;
622 r = processintradix(yytext, yylen, radix);
623 goto leave;
625 radix_digits_2:
627 c = input();
628 if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_2;
629 if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_2;
630 // do not allow lower case after decimal point.
631 unput(c);
632 yytext[yylen] = 0;
633 r = processfloatradix(yytext, yylen, radix);
634 goto leave;
636 hexdigits:
638 c = input();
639 if (c >= '0' && c <= '9') goto hexdigits;
640 if (c >= 'a' && c <= 'f') goto hexdigits;
641 if (c >= 'A' && c <= 'F') goto hexdigits;
642 unput(c);
643 yytext[yylen] = 0;
644 r = processhex(yytext);
645 goto leave;
647 digits_1: /* number started with digits */
649 c = input();
651 if (c >= '0' && c <= '9') goto digits_1;
652 else if (c == 'r') {
653 radix = sc_strtoi(yytext, yylen-1, 10);
654 yylen = 0;
655 goto radix_digits_1;
657 else if (c == 'e' || c == 'E') goto expon_1;
658 else if (c == '.') {
659 c2 = input();
660 if (c2 >= '0' && c2 <= '9') goto digits_2;
661 else {
662 unput(c2);
663 unput(c);
664 yytext[yylen] = 0;
665 r = processint(yytext);
666 goto leave;
669 else if (c == 'b' || c == 's') {
670 d = input();
671 if (d >= '0' && d <= '9') goto accidental1;
672 if (d == c) goto accidental2;
673 goto accidental3;
674 accidental1:
675 d = input();
676 if (d >= '0' && d <= '9') goto accidental1;
677 unput(d);
678 yytext[yylen] = 0;
679 r = processaccidental1(yytext);
680 goto leave;
681 accidental2:
682 d = input();
683 if (d == c) goto accidental2;
684 accidental3:
685 unput(d);
686 yytext[yylen] = 0;
687 r = processaccidental2(yytext);
688 goto leave;
690 else if (c == 'x') {
691 yylen = 0;
692 goto hexdigits;
693 } else {
694 unput(c);
695 yytext[yylen] = 0;
696 r = processint(yytext);
697 goto leave;
700 digits_2:
702 c = input();
704 if (c >= '0' && c <= '9') goto digits_2;
705 else if (c == 'e' || c == 'E') goto expon_1;
706 // else if (c == 'π' || c == '∏') {
707 // --yylen;
708 // yytext[yylen] = 0;
709 // r = processfloat(yytext, 1);
710 // goto leave;
711 // }
712 else {
713 unput(c);
714 yytext[yylen] = 0;
715 r = processfloat(yytext, 0);
716 goto leave;
719 expon_1: /* e has been seen, need digits */
720 c = input();
722 if (c >= '0' && c <= '9') goto expon_3;
723 else if (c == '+' || c == '-') goto expon_2;
724 else goto error1;
726 expon_2: /* + or - seen but still need digits */
727 c = input();
729 if (c >= '0' && c <= '9') goto expon_3;
730 else goto error1;
732 expon_3:
733 c = input();
735 if (c >= '0' && c <= '9') goto expon_3;
736 // else if (c == 'π' || c == '∏') {
737 // --yylen;
738 // yytext[yylen] = 0;
739 // r = processfloat(yytext, 1);
740 // goto leave;
741 // }
742 else {
743 unput(c);
744 yytext[yylen] = 0;
745 r = processfloat(yytext, 0);
746 goto leave;
749 symbol3 : {
750 int startline, endchar;
751 startline = lineno;
752 endchar = '\'';
754 /*do {
755 c = input();
756 } while (c != endchar && c != 0);*/
757 for (;yylen<MAXYYLEN;) {
758 c = input();
759 if (c == '\n' || c == '\r') {
760 asRelativePath(curfilename,extPath);
761 post("Symbol open at end of line on line %d in file '%s'\n",
762 startline+errLineOffset, extPath);
763 yylen = 0;
764 r = 0;
765 goto leave;
767 if (c == '\\') {
768 yylen--;
769 c = input();
770 } else if (c == endchar) break;
771 if (c == 0) break;
773 if (c == 0) {
774 asRelativePath(curfilename,extPath);
775 post("Open ended symbol ... started on line %d in file '%s'\n",
776 startline+errLineOffset, extPath);
777 yylen = 0;
778 r = 0;
779 goto leave;
781 yytext[yylen] = 0;
782 yytext[yylen-1] = 0;
783 r = processsymbol(yytext);
784 goto leave;
787 string1 : {
788 int startline, endchar;
789 startline = lineno;
790 endchar = '"';
792 for (;yylen<MAXYYLEN;) {
793 c = input();
794 if (c == '\\') {
795 yylen--;
796 c = input();
797 switch (c) {
798 case 'n' : yytext[yylen-1] = '\n'; break;
799 case 'r' : yytext[yylen-1] = '\r'; break;
800 case 't' : yytext[yylen-1] = '\t'; break;
801 case 'f' : yytext[yylen-1] = '\f'; break;
802 case 'v' : yytext[yylen-1] = '\v'; break;
804 } else if (c == '\r') c = '\n';
805 else if (c == endchar) break;
806 if (c == 0) break;
808 if (c == 0) {
809 asRelativePath(curfilename,extPath);
810 post("Open ended string ... started on line %d in file '%s'\n",
811 startline+errLineOffset, extPath);
812 yylen = 0;
813 r = 0;
814 goto leave;
816 yylen--;
818 do {
819 c = input0();
820 } while (c && isspace(c));
822 if (c == '"') goto string1;
823 else if (c) unput0(c);
825 yytext[yylen] = 0;
826 r = processstring(yytext);
827 goto leave;
830 comment1: /* comment -- to end of line */
831 do {
832 c = input0();
833 } while (c != '\n' && c != '\r' && c != 0);
834 yylen = 0;
835 if (c == 0) { r = 0; goto leave; }
836 else goto start;
838 comment2 : {
839 int startline, clevel, prevc;
840 startline = lineno;
841 prevc = 0;
842 clevel = 1;
843 do {
844 c = input0();
845 if (c == '/' && prevc == '*') {
846 if (--clevel <= 0) break;
847 } else if (c == '*' && prevc == '/') clevel++;
848 prevc = c;
849 } while (c != 0);
850 yylen = 0;
851 if (c == 0) {
852 asRelativePath(curfilename,extPath);
853 post("Open ended comment ... started on line %d in file '%s'\n",
854 startline+errLineOffset, extPath);
855 r = 0;
856 goto leave;
858 goto start;
862 error1:
864 yytext[yylen] = 0;
866 asRelativePath(curfilename, extPath);
867 post("illegal input string '%s' \n at '%s' line %d char %d\n",
868 yytext, extPath, lineno+errLineOffset, charno);
869 post("code %d\n", c);
870 //postfl(" '%c' '%s'\n", c, binopchars);
871 //postfl("%d\n", strchr(binopchars, c));
873 error2:
874 asRelativePath(curfilename, extPath);
875 post(" in file '%s' line %d char %d\n", extPath, lineno+errLineOffset, charno);
876 r = BADTOKEN;
877 goto leave;
879 leave:
880 yytext[yylen] = 0;
882 #if DEBUGLEX
883 if (gDebugLexer) postfl("yylex: %d '%s'\n",r,yytext);
884 #endif
885 //if (lexCmdLine>0) postfl("yylex: %d '%s'\n",r,yytext);
886 return r;
889 int processbinop(char *token)
891 PyrSymbol *sym;
892 PyrSlot slot;
893 PyrSlotNode *node;
895 #if DEBUGLEX
896 if (gDebugLexer) postfl("processbinop: '%s'\n",token);
897 #endif
898 sym = getsym(token);
899 SetSymbol(&slot, sym);
900 node = newPyrSlotNode(&slot);
901 zzval = (long)node;
902 if (strcmp(token, "<-")==0) return LEFTARROW;
903 if (strcmp(token, "<>")==0) return READWRITEVAR;
904 if (strcmp(token, "|")==0) return '|';
905 if (strcmp(token, "<")==0) return '<';
906 if (strcmp(token, ">")==0) return '>';
907 if (strcmp(token, "-")==0) return '-';
908 if (strcmp(token, "*")==0) return '*';
909 if (strcmp(token, "+")==0) return '+';
910 return BINOP;
913 int processkeywordbinop(char *token)
915 PyrSymbol *sym;
916 PyrSlot slot;
917 PyrSlotNode *node;
919 //post("'%s' file '%s'\n", token, curfilename);
921 #if DEBUGLEX
922 if (gDebugLexer) postfl("processkeywordbinop: '%s'\n",token);
923 #endif
924 token[strlen(token)-1] = 0; // strip off colon
925 sym = getsym(token);
926 SetSymbol(&slot, sym);
927 node = newPyrSlotNode(&slot);
928 zzval = (long)node;
929 return KEYBINOP;
932 int processident(char *token)
934 char c;
935 PyrSymbol *sym;
937 PyrSlot slot;
938 PyrParseNode *node;
940 c = token[0];
941 zzval = -1;
943 #if DEBUGLEX
944 if (gDebugLexer) postfl("word: '%s'\n",token);
945 #endif
947 strcpy(uptoken, token);
948 for (str = uptoken; *str; ++str) {
949 if (*str >= 'a' && *str <= 'z') *str += 'A' - 'a';
952 if (token[0] == '_') {
953 if (token[1] == 0) {
954 node = newPyrCurryArgNode();
955 zzval = (long)node;
956 return CURRYARG;
957 } else {
958 sym = getsym(token);
959 SetSymbol(&slot, sym);
960 node = newPyrSlotNode(&slot);
961 zzval = (long)node;
962 return PRIMITIVENAME;
965 if (token[0] >= 'A' && token[0] <= 'Z') {
966 sym = getsym(token);
967 SetSymbol(&slot, sym);
968 node = newPyrSlotNode(&slot);
969 zzval = (long)node;
970 #if DEBUGLEX
971 if (gDebugLexer) postfl("CLASSNAME: '%s'\n",token);
972 #endif
973 return CLASSNAME;
975 if (strcmp("var",token) ==0) return VAR;
976 if (strcmp("arg",token) ==0) return ARG;
977 if (strcmp("classvar",token) ==0) return CLASSVAR;
978 if (strcmp("const",token) ==0) return SC_CONST;
980 if (strcmp("while",token) ==0) {
982 sym = getsym(token);
983 SetSymbol(&slot, sym);
984 node = newPyrSlotNode(&slot);
985 zzval = (long)node;
986 return WHILE;
988 if (strcmp("pi",token) ==0) {
989 SetFloat(&slot, pi);
990 node = newPyrSlotNode(&slot);
991 zzval = (long)node;
992 return PIE;
994 if (strcmp("true",token) ==0) {
995 SetTrue(&slot);
996 node = newPyrSlotNode(&slot);
997 zzval = (long)node;
998 return TRUEOBJ;
1000 if (strcmp("false",token) ==0) {
1001 SetFalse(&slot);
1002 node = newPyrSlotNode(&slot);
1003 zzval = (long)node;
1004 return FALSEOBJ;
1006 if (strcmp("nil",token) ==0) {
1007 SetNil(&slot);
1008 node = newPyrSlotNode(&slot);
1009 zzval = (long)node;
1010 return NILOBJ;
1012 if (strcmp("inf",token) ==0) {
1013 SetFloat(&slot, std::numeric_limits<double>::infinity());
1014 node = newPyrSlotNode(&slot);
1015 zzval = (long)node;
1016 return SC_FLOAT;
1019 sym = getsym(token);
1021 SetSymbol(&slot, sym);
1022 node = newPyrSlotNode(&slot);
1023 zzval = (long)node;
1024 return NAME;
1027 int processhex(char *s)
1029 PyrSlot slot;
1030 PyrSlotNode *node;
1031 char *c;
1032 int val;
1033 #if DEBUGLEX
1034 if (gDebugLexer) postfl("processhex: '%s'\n",s);
1035 #endif
1037 c = s;
1038 val = 0;
1039 while (*c) {
1040 if (*c >= '0' && *c <= '9') val = val*16 + *c - '0';
1041 else if (*c >= 'a' && *c <= 'z') val = val*16 + *c - 'a' + 10;
1042 else if (*c >= 'A' && *c <= 'Z') val = val*16 + *c - 'A' + 10;
1043 c++;
1046 SetInt(&slot, val);
1047 node = newPyrSlotNode(&slot);
1048 zzval = (long)node;
1049 return INTEGER;
1053 int processintradix(char *s, int n, int radix)
1055 PyrSlot slot;
1056 PyrSlotNode *node;
1057 #if DEBUGLEX
1058 if (gDebugLexer) postfl("processintradix: '%s'\n",s);
1059 #endif
1061 SetInt(&slot, sc_strtoi(s, n, radix));
1062 node = newPyrSlotNode(&slot);
1063 zzval = (long)node;
1064 return INTEGER;
1067 int processfloatradix(char *s, int n, int radix)
1069 PyrSlot slot;
1070 PyrSlotNode *node;
1071 #if DEBUGLEX
1072 if (gDebugLexer) postfl("processfloatradix: '%s'\n",s);
1073 #endif
1075 SetFloat(&slot, sc_strtof(s, n, radix));
1076 node = newPyrSlotNode(&slot);
1077 zzval = (long)node;
1078 return INTEGER;
1081 int processint(char *s)
1083 PyrSlot slot;
1084 PyrSlotNode *node;
1085 #if DEBUGLEX
1086 if (gDebugLexer) postfl("processint: '%s'\n",s);
1087 #endif
1089 SetInt(&slot, atoi(s));
1090 node = newPyrSlotNode(&slot);
1091 zzval = (long)node;
1092 return INTEGER;
1095 int processchar(int c)
1097 PyrSlot slot;
1098 PyrSlotNode *node;
1099 #if DEBUGLEX
1100 if (gDebugLexer) postfl("processhex: '%c'\n",c);
1101 #endif
1103 SetChar(&slot, c);
1104 node = newPyrSlotNode(&slot);
1105 zzval = (long)node;
1106 return ASCII;
1109 int processfloat(char *s, int sawpi)
1111 PyrSlot slot;
1112 PyrSlotNode *node;
1113 double z;
1114 #if DEBUGLEX
1115 if (gDebugLexer) postfl("processfloat: '%s'\n",s);
1116 #endif
1118 if (sawpi) { z = atof(s)*pi; SetFloat(&slot, z); }
1119 else { SetFloat(&slot, atof(s)); }
1120 node = newPyrSlotNode(&slot);
1121 zzval = (long)node;
1122 return SC_FLOAT;
1126 int processaccidental1(char *s)
1128 PyrSlot slot;
1129 PyrSlotNode *node;
1130 char *c;
1131 double degree=0.;
1132 double cents=0.;
1133 double centsdiv=1000.;
1134 #if 0
1135 printf("processaccidental1: '%s'\n",s);
1136 #endif
1138 c = s;
1139 while (*c) {
1140 if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0';
1141 else break;
1142 c++;
1145 if (*c == 'b') centsdiv = -1000.;
1146 else if (*c == 's') centsdiv = 1000.;
1147 c++;
1149 while (*c) {
1150 if (*c >= '0' && *c <= '9') {
1151 cents = cents*10. + *c - '0';
1153 else break;
1154 c++;
1157 if (cents > 499.) cents = 499.;
1159 SetFloat(&slot, degree + cents/centsdiv);
1160 node = newPyrSlotNode(&slot);
1161 zzval = (long)node;
1162 return ACCIDENTAL;
1165 int processaccidental2(char *s)
1167 PyrSlot slot;
1168 PyrSlotNode *node;
1169 char *c;
1170 double degree=0.;
1171 double semitones=0.;
1172 #if 0
1173 printf("processaccidental2: '%s'\n",s);
1174 #endif
1176 c = s;
1177 while (*c) {
1178 if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0';
1179 else break;
1180 c++;
1183 while (*c) {
1184 if (*c == 'b') semitones -= 1.;
1185 else if (*c == 's') semitones += 1.;
1186 c++;
1189 if (semitones > 4.) semitones = 4.;
1191 SetFloat(&slot, degree + semitones/10.);
1192 node = newPyrSlotNode(&slot);
1193 zzval = (long)node;
1194 return ACCIDENTAL;
1197 int processsymbol(char *s)
1199 PyrSlot slot;
1200 PyrSlotNode *node;
1201 PyrSymbol *sym;
1202 #if DEBUGLEX
1203 if (gDebugLexer) postfl("processsymbol: '%s'\n",s);
1204 #endif
1205 sym = getsym(s+1);
1207 SetSymbol(&slot, sym);
1208 node = newPyrSlotNode(&slot);
1209 zzval = (long)node;
1210 return SYMBOL;
1213 int processstring(char *s)
1215 PyrSlot slot;
1216 PyrSlotNode *node;
1217 PyrString *string;
1218 #if DEBUGLEX
1219 if (gDebugLexer) postfl("processstring: '%s'\n",s);
1220 #endif
1221 int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
1222 string = newPyrString(gMainVMGlobals->gc, s+1, flags, false);
1223 SetObject(&slot, string);
1224 node = newPyrSlotNode(&slot);
1225 zzval = (long)node;
1226 return STRING;
1229 void yyerror(const char *s)
1231 parseFailed = 1;
1232 yytext[yylen] = 0;
1233 error("%s\n",s);
1234 postErrorLine(lineno, linepos, charno);
1235 //Debugger();
1238 void fatal()
1240 parseFailed = 1;
1241 yytext[yylen] = 0;
1242 error("Parse error\n");
1243 postErrorLine(lineno, linepos, charno);
1244 //Debugger();
1247 #if 0
1248 void postErrorLine()
1250 int i, j, start, end;
1251 char str[256];
1253 parseFailed = true;
1254 for (i=textpos-1; i>=0; --i) {
1255 if (text[i] == '\r' || text[i] == '\n') break;
1257 start = i+1;
1258 for (i=textpos; i < textlen; ++i) {
1259 if (text[i] == '\r' || text[i] == '\n') break;
1261 end=i;
1262 for (i=start, j=0; i<end; ++i) {
1263 if (i == textpos) str[j++] = '¶';
1264 str[j++] = text[i];
1266 if (textpos == end) str[j++] = '¶';
1267 str[j] = 0;
1269 postfl("%s\n", str);
1271 #endif
1273 void postErrorLine(int linenum, int start, int charpos)
1275 int i, j, end, pos;
1276 char str[256];
1278 //post("start %d\n", start);
1279 //parseFailed = true;
1280 char extPath[MAXPATHLEN];
1281 asRelativePath(curfilename, extPath);
1282 post(" in file '%s'\n", extPath);
1283 post(" line %d char %d:\n\n", linenum+errLineOffset, charpos);
1284 // nice: postfl previous line for context
1286 //postfl("text '%s' %d\n", text, text);
1288 // postfl error line for context
1289 pos = start + charpos;
1290 for (i=pos; i < textlen; ++i) {
1291 if (text[i] == 0 || text[i] == '\r' || text[i] == '\n') break;
1293 end=i;
1294 for (i=start, j=0; i<end && j<255; ++i) {
1295 str[j++] = text[i];
1297 str[j] = 0;
1298 post(" %s\n ", str);
1299 for (i=0; i<charpos-yylen; i++) post(" ");
1300 for (i=0; i<yylen; i++) post("^");
1301 post("\n");
1303 i=end+1;
1304 if (i<textlen) {
1305 // postfl following line for context
1306 for (j=0; j<255 && i<textlen; ++i) {
1307 if (text[i] == 0 ||text[i] == '\r' || text[i] == '\n') break;
1308 str[j++] = text[i];
1310 str[j] = 0;
1311 post(" %s\n", str);
1313 post("-----------------------------------\n", str);
1317 void c2pstrcpy(unsigned char* dst, const char *src);
1318 void c2pstrcpy(unsigned char* dst, const char *src)
1320 int c;
1321 unsigned char *dstp = &dst[1];
1322 while ((c = *src++) != 0) *dstp++ = c;
1323 dst[0] = dstp - dst - 1;
1326 void p2cstrcpy(char *dst, const unsigned char* src);
1327 void p2cstrcpy(char *dst, const unsigned char* src)
1329 int n = *src++;
1330 for (int i=0; i<n; ++i) *dst++ = *src++;
1331 *dst++ = 0;
1335 void pstrncpy(unsigned char *s1, unsigned char *s2, int n);
1336 void pstrncpy(unsigned char *s1, unsigned char *s2, int n)
1338 int i, m;
1339 m = *s2++;
1340 n = (n < m) ? n : m;
1341 *s1 = n; s1++;
1342 for (i=0; i<n; ++i) { *s1 = *s2; s1++; s2++; }
1345 int pstrcmp(unsigned char *s1, unsigned char *s2);
1346 int pstrcmp(unsigned char *s1, unsigned char *s2)
1348 int i, len1, len2, len;
1349 len1 = *s1++;
1350 len2 = *s2++;
1351 len = sc_min(len1, len2);
1352 for (i=0; i<len; ++i) {
1353 if (s1[i] < s2[i]) return -1;
1354 if (s1[i] > s2[i]) return 1;
1356 if (len1 < len2) return -1;
1357 if (len1 > len2) return 1;
1358 return 0;
1361 bool scanForClosingBracket()
1363 int r, c, d, startLevel;
1364 bool res = true;
1365 // finite state machine to parse input stream into tokens
1367 #if DEBUGLEX
1368 if (gDebugLexer) postfl("->scanForClosingBracket\n");
1369 #endif
1370 startLevel = brackets.num;
1371 start:
1372 c = input0();
1374 if (c == 0) goto leave;
1375 else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') {
1376 goto start;
1378 else if (c == '\'') goto symbol3;
1379 else if (c == '"') goto string1;
1380 else if (c == '/') {
1381 c = input0();
1382 if (c == '/') goto comment1;
1383 else if (c == '*') goto comment2;
1384 else { unput(c); goto start; }
1386 else if (c == '$') {
1387 c = input0();
1388 if (c == '\\') {
1389 c = input0();
1390 switch (c) {
1391 case 'n' : c = '\n'; break;
1392 case 'r' : c = '\r'; break;
1393 case 't' : c = '\t'; break;
1394 case 'f' : c = '\f'; break;
1395 case 'v' : c = '\v'; break;
1398 goto start;
1400 else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
1401 pushls(&brackets, (int)c);
1402 r = c;
1403 goto start;
1405 else if (c == CLOSSQUAR) {
1406 if (!emptyls(&brackets)) {
1407 if ((d = popls(&brackets)) != OPENSQUAR) {
1408 fatal();
1409 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1410 goto error1;
1412 } else {
1413 fatal();
1414 post("unmatched '%c'\n",c);
1415 goto error1;
1417 r = c;
1418 if (brackets.num < startLevel) goto leave;
1419 else goto start;
1421 else if (c == CLOSPAREN) {
1422 if (!emptyls(&brackets)) {
1423 if ((d = popls(&brackets)) != OPENPAREN) {
1424 fatal();
1425 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1426 goto error1;
1428 } else {
1429 fatal();
1430 post("unmatched '%c'\n",c);
1431 goto error1;
1433 if (brackets.num < startLevel) goto leave;
1434 else goto start;
1436 else if (c == CLOSCURLY) {
1437 if (!emptyls(&brackets)) {
1438 if ((d = popls(&brackets)) != OPENCURLY) {
1439 fatal();
1440 post("opening bracket was a '%c', but found a '%c'\n",d,c);
1441 goto error1;
1443 } else {
1444 fatal();
1445 post("unmatched '%c'\n",c);
1446 goto error1;
1448 if (brackets.num < startLevel) goto leave;
1449 else goto start;
1450 } else {
1451 goto start;
1453 symbol3 : {
1454 int startline, endchar;
1455 startline = lineno;
1456 endchar = '\'';
1458 do {
1459 c = input0();
1460 if (c == '\\') {
1461 c = input0();
1463 } while (c != endchar && c != 0);
1464 if (c == 0) {
1465 char extPath[MAXPATHLEN];
1466 asRelativePath(curfilename, extPath);
1467 post("Open ended symbol ... started on line %d in file '%s'\n",
1468 startline, extPath);
1469 goto error2;
1471 goto start;
1474 string1 : {
1475 int startline, endchar;
1476 startline = lineno;
1477 endchar = '\"';
1479 do {
1480 c = input0();
1481 if (c == '\\') {
1482 c = input0();
1484 } while (c != endchar && c != 0);
1485 if (c == 0) {
1486 char extPath[MAXPATHLEN];
1487 asRelativePath(curfilename, extPath);
1488 post("Open ended string ... started on line %d in file '%s'\n",
1489 startline, extPath);
1490 goto error2;
1492 goto start;
1494 comment1: /* comment -- to end of line */
1495 do {
1496 c = input0();
1497 } while (c != '\n' && c != '\r' && c != 0);
1498 if (c == 0) { goto leave; }
1499 else goto start;
1501 comment2 : {
1502 int startline, clevel, prevc;
1503 startline = lineno;
1504 prevc = 0;
1505 clevel = 1;
1506 do {
1507 c = input0();
1508 if (c == '/' && prevc == '*') {
1509 if (--clevel <= 0) break;
1510 } else if (c == '*' && prevc == '/') clevel++;
1511 prevc = c;
1512 } while (c != 0);
1513 if (c == 0) {
1514 char extPath[MAXPATHLEN];
1515 asRelativePath(curfilename, extPath);
1516 post("Open ended comment ... started on line %d in file '%s'\n",
1517 startline, extPath);
1518 goto error2;
1520 goto start;
1523 error1:
1524 char extPath[MAXPATHLEN];
1525 asRelativePath(curfilename, extPath);
1526 post(" in file '%s' line %d char %d\n", extPath, lineno, charno);
1527 res = false;
1528 goto leave;
1530 error2:
1531 res = false;
1532 goto leave;
1534 leave:
1535 #if DEBUGLEX
1536 if (gDebugLexer) postfl("<-scanForClosingBracket\n");
1537 #endif
1538 return res;
1542 int numClassDeps;
1543 static ClassExtFile* sClassExtFiles;
1544 static ClassExtFile* eClassExtFiles;
1546 ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos);
1547 ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos)
1549 ClassExtFile* classext;
1550 classext = (ClassExtFile*)pyr_pool_compile->Alloc(sizeof(ClassExtFile));
1551 classext->fileSym = fileSym;
1552 classext->next = 0;
1553 classext->startPos = startPos;
1554 classext->endPos = endPos;
1555 if (!sClassExtFiles) sClassExtFiles = classext;
1556 else eClassExtFiles->next = classext;
1557 eClassExtFiles = classext;
1558 return classext;
1562 ClassDependancy* newClassDependancy(PyrSymbol *className, PyrSymbol *superClassName,
1563 PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
1565 ClassDependancy* classdep;
1567 //post("classdep '%s' '%s' '%s' %d %d\n", className->name, superClassName->name,
1568 // fileSym->name, className, superClassName);
1569 // pyrmalloc:
1570 // lifetime: kill after compile.
1571 numClassDeps++;
1572 if (className->classdep) {
1573 error("duplicate Class found: '%s' \n", className->name);
1574 post("%s\n",className->classdep->fileSym->name);
1575 postfl("%s\n\n",fileSym->name);
1576 return className->classdep;
1578 classdep = (ClassDependancy*)pyr_pool_compile->Alloc(sizeof(ClassDependancy));
1579 MEMFAIL(text);
1580 classdep->className = className;
1581 classdep->superClassName = superClassName;
1582 classdep->fileSym = fileSym;
1583 classdep->superClassDep = NULL;
1584 classdep->next = NULL;
1585 classdep->subclasses = NULL;
1587 classdep->startPos = startPos;
1588 classdep->endPos = endPos;
1589 classdep->lineOffset = lineOffset;
1591 className->classdep = classdep;
1592 return classdep;
1595 void buildDepTree()
1597 ClassDependancy *next;
1598 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1600 //postfl("->buildDepTree\n"); fflush(stdout);
1601 for (int i=0; i<symbolTable->TableSize(); ++i) {
1602 PyrSymbol *sym = symbolTable->Get(i);
1603 if (sym && (sym->flags & sym_Class)) {
1604 if (sym->classdep) {
1605 if (sym->classdep->superClassName->classdep) {
1606 next = sym->classdep->superClassName->classdep->subclasses;
1607 sym->classdep->superClassName->classdep->subclasses = sym->classdep;
1608 sym->classdep->next = next;
1609 } else if (sym->classdep->superClassName != s_none) {
1610 error("Superclass '%s' of class '%s' is not defined in any file.\n%s\n",
1611 sym->classdep->superClassName->name, sym->classdep->className->name,sym->classdep->fileSym->name);
1616 //postfl("<-buildDepTree\n"); fflush(stdout);
1619 extern PyrClass *gClassList;
1621 ClassDependancy **gClassCompileOrder;
1622 int gClassCompileOrderNum = 0;
1623 int gClassCompileOrderSize = 1000;
1625 void compileDepTree();
1627 void traverseFullDepTree()
1629 //postfl("->traverseFullDepTree\n"); fflush(stdout);
1630 gClassCompileOrderNum = 0;
1631 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Alloc(
1632 gClassCompileOrderSize * sizeof(ClassDependancy));
1633 MEMFAIL(gClassCompileOrder);
1635 // parse and compile all files
1636 initParser(); // sets compiler errors to 0
1637 gParserResult = -1;
1639 traverseDepTree(s_object->classdep, 0);
1640 compileDepTree(); // compiles backwards using the order defined in gClassCompileOrder
1641 compileClassExtensions();
1643 pyr_pool_compile->Free(gClassCompileOrder);
1645 finiParser();
1646 //postfl("<-traverseFullDepTree\n"); fflush(stdout);
1650 void traverseDepTree(ClassDependancy *classdep, int level)
1652 ClassDependancy *subclassdep;
1654 if (!classdep) return;
1656 subclassdep = classdep->subclasses;
1657 for (; subclassdep; subclassdep = subclassdep->next) {
1658 traverseDepTree(subclassdep, level+1);
1660 if (gClassCompileOrderNum > gClassCompileOrderSize) {
1661 gClassCompileOrderSize *= 2;
1662 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Realloc(gClassCompileOrder,
1663 gClassCompileOrderSize * sizeof(ClassDependancy));
1664 MEMFAIL(gClassCompileOrder);
1667 /* postfl("traverse level:%d, gClassCompileOrderNum:%d, '%s' '%s' '%s'\n", level, gClassCompileOrderNum, classdep->className->name, classdep->superClassName->name,
1668 classdep->fileSym->name); fflush(stdout);
1671 gClassCompileOrder[gClassCompileOrderNum++] = classdep;
1675 void compileClass(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset)
1677 //fprintf(stderr, "compileClass: %d\n", fileSym->u.index);
1679 gCompilingFileSym = fileSym;
1680 gCompilingVMGlobals = 0;
1681 gRootParseNode = NULL;
1682 initParserPool();
1683 if (startLexer(fileSym, startPos, endPos, lineOffset)) {
1684 //postfl("->Parsing %s\n", fileSym->name); fflush(stdout);
1685 parseFailed = yyparse();
1686 //postfl("<-Parsing %s %d\n", fileSym->name, parseFailed); fflush(stdout);
1687 //post("parseFailed %d\n", parseFailed); fflush(stdout);
1688 if (!parseFailed && gRootParseNode) {
1689 //postfl("Compiling nodes %p\n", gRootParseNode);fflush(stdout);
1690 compilingCmdLine = false;
1691 compileNodeList(gRootParseNode, true);
1692 //postfl("done compiling\n");fflush(stdout);
1693 } else {
1694 compileErrors++;
1695 char extPath[MAXPATHLEN];
1696 asRelativePath(fileSym->name, extPath);
1697 error("file '%s' parse failed\n", extPath);
1698 postfl("error parsing\n");
1700 finiLexer();
1701 } else {
1702 error("file '%s' open failed\n", fileSym->name);
1704 freeParserPool();
1707 void compileDepTree()
1709 ClassDependancy *classdep;
1710 int i;
1712 for (i=gClassCompileOrderNum-1; i>=0; --i) {
1713 classdep = gClassCompileOrder[i];
1714 /*postfl("compile %d '%s' '%s' '%s'...%d/%d/%d\n", i, classdep->className->name, classdep->superClassName->name,
1715 classdep->fileSym->name, classdep->startLine, classdep->endLine, classDep->lineOffset);*/
1716 compileClass(classdep->fileSym, classdep->startPos, classdep->endPos, classdep->lineOffset);
1718 //postfl("<compile\n");
1721 void compileClassExtensions()
1723 if (sClassExtFiles) {
1724 ClassExtFile *classext = sClassExtFiles;
1725 do {
1726 //postfl("compile class ext: %d/%d\n", classext->startPos, classext->endPos);
1727 compileClass(classext->fileSym, classext->startPos, classext->endPos, -1);
1728 classext = classext->next;
1729 } while (classext);
1733 void findDiscrepancy();
1735 void traverseFullDepTree2()
1738 // assign a class index to all classes
1739 if (!parseFailed && !compileErrors) {
1740 buildClassTree();
1741 gNumClasses = 0;
1743 // now I index them during pass one
1744 indexClassTree(class_object, 0);
1745 setSelectorFlags();
1746 if (2*numClassDeps != gNumClasses) {
1747 error("There is a discrepancy.\n");
1748 /* not always correct
1749 if(2*numClassDeps < gNumClasses) {
1750 post("Duplicate files may exist in the directory structure.\n");
1751 } else {
1752 post("Some class files may be missing.\n");
1755 post("numClassDeps %d gNumClasses %d\n", numClassDeps, gNumClasses);
1756 findDiscrepancy();
1757 compileErrors++;
1758 } else {
1759 double elapsed;
1760 buildBigMethodMatrix();
1761 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1762 post("\tNumber of Symbols %d\n", symbolTable->NumItems());
1763 post("\tByte Code Size %d\n", totalByteCodes);
1764 //elapsed = TickCount() - compileStartTime;
1765 //elapsed = 0;
1766 elapsed = elapsedTime() - compileStartTime;
1767 post("\tcompiled %d files in %.2f seconds\n",
1768 gNumCompiledFiles, elapsed );
1769 if(numOverwrites == 1){
1770 post("\nInfo: One method is currently overwritten by an extension. To see which, execute:\nMethodOverride.printAll\n\n");
1772 else if(numOverwrites > 1){
1773 post("\nInfo: %i methods are currently overwritten by extensions. To see which, execute:\nMethodOverride.printAll\n\n", numOverwrites);
1775 post("compile done\n");
1780 bool parseOneClass(PyrSymbol *fileSym)
1782 int token;
1783 PyrSymbol *className, *superClassName;
1784 ClassDependancy *classdep;
1785 bool res;
1787 int startPos, startLineOffset;
1789 res = true;
1791 startPos = textpos;
1792 startLineOffset = lineno - 1;
1794 token = yylex();
1795 if (token == CLASSNAME) {
1796 className = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1797 // I think this is wrong: zzval is space pool alloced
1798 //pyrfree((PyrSlot*)zzval);
1800 token = yylex();
1801 if (token == 0) return false;
1802 if (token == OPENSQUAR) {
1803 scanForClosingBracket(); // eat indexing spec
1804 token = yylex();
1805 if (token == 0) return false;
1807 if (token == ':') {
1808 token = yylex(); // get super class
1809 if (token == 0) return false;
1810 if (token == CLASSNAME) {
1811 superClassName = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1812 // I think this is wrong: zzval is space pool alloced
1813 //pyrfree((PyrSlot*)zzval);
1814 token = yylex();
1815 if (token == 0) return false;
1816 if (token == OPENCURLY) {
1817 scanForClosingBracket(); // eat class body
1818 classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1819 } else {
1820 compileErrors++;
1821 postfl("Expected %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1822 postErrorLine(lineno, linepos, charno);
1823 return false;
1825 } else {
1826 compileErrors++;
1827 post("Expected superclass name. got token: '%s' %d\n", yytext, token);
1828 postErrorLine(lineno, linepos, charno);
1829 return false;
1831 } else if (token == OPENCURLY) {
1832 if (className == s_object) superClassName = s_none;
1833 else superClassName = s_object;
1834 scanForClosingBracket(); // eat class body
1835 classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1836 } else {
1837 compileErrors++;
1838 post("Expected ':' or %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1839 postErrorLine(lineno, linepos, charno);
1840 return false;
1842 } else if (token == '+') {
1843 token = yylex();
1844 if (token == 0) return false;
1845 scanForClosingBracket();
1847 newClassExtFile(fileSym, startPos, textpos);
1848 return false;
1849 } else {
1850 if (token != 0) {
1851 compileErrors++;
1852 post("Expected class name. got token: '%s' %d\n", yytext, token);
1853 postErrorLine(lineno, linepos, charno);
1854 return false;
1855 } else {
1856 res = false;
1859 return res;
1862 //void ClearLibMenu();
1864 void aboutToFreeRuntime();
1865 void aboutToFreeRuntime()
1867 //ClearLibMenu();
1870 //void init_graph_compile();
1871 //void tellPlugInsAboutToCompile();
1872 void pyrmath_init_globs();
1874 void initPassOne()
1876 aboutToFreeRuntime();
1878 //dump_pool_histo(pyr_pool_runtime);
1879 pyr_pool_runtime->FreeAllInternal();
1880 //dump_pool_histo(pyr_pool_runtime);
1881 //gPermanentObjPool.Init(pyr_pool_runtime, PERMOBJCHUNK);
1882 sClassExtFiles = 0;
1884 void *ptr = pyr_pool_runtime->Alloc(sizeof(SymbolTable));
1885 gMainVMGlobals->symbolTable = new (ptr) SymbolTable(pyr_pool_runtime, 8192);
1887 //gFileSymbolTable = newSymbolTable(512);
1889 pyrmath_init_globs();
1891 initSymbols(); // initialize symbol globals
1892 //init_graph_compile();
1893 initSpecialSelectors();
1894 initSpecialClasses();
1895 initClasses();
1896 initParserPool();
1897 initParseNodes();
1898 initPrimitives();
1899 //tellPlugInsAboutToCompile();
1900 initLexer();
1901 compileErrors = 0;
1902 numClassDeps = 0;
1903 compiledOK = false;
1904 compiledDirectories.clear();
1905 sc_InitCompileDirectory();
1908 void finiPassOne()
1910 //postfl("->finiPassOne\n");
1911 freeParserPool();
1912 //postfl("<-finiPassOne\n");
1915 static bool passOne_ProcessDir(const char *dirname, int level)
1917 if (!sc_DirectoryExists(dirname))
1918 return true;
1920 if (compiledDirectories.find(std::string(dirname)) != compiledDirectories.end())
1921 // already compiled
1922 return true;
1924 bool success = true;
1926 if (gLibraryConfig && gLibraryConfig->pathIsExcluded(dirname)) {
1927 post("\texcluding dir: '%s'\n", dirname);
1928 return success;
1931 if (level == 0) post("\tcompiling dir: '%s'\n", dirname);
1933 SC_DirHandle *dir = sc_OpenDir(dirname);
1934 if (!dir) {
1935 error("open directory failed '%s'\n", dirname); fflush(stdout);
1936 return false;
1939 for (;;) {
1940 char diritem[MAXPATHLEN];
1941 bool skipItem = true;
1942 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
1943 if (!validItem) break;
1944 if (skipItem) continue;
1946 if (sc_DirectoryExists(diritem)) {
1947 success = passOne_ProcessDir(diritem, level + 1);
1948 } else {
1949 success = passOne_ProcessOneFile(diritem, level + 1);
1952 if (!success) break;
1955 compiledDirectories.insert(std::string(dirname));
1956 sc_CloseDir(dir);
1957 return success;
1960 bool passOne()
1962 initPassOne();
1964 if (sc_IsStandAlone()) {
1965 /// FIXME: this should be moved to the LibraryConfig file
1966 if (!passOne_ProcessDir(gCompileDir, 0))
1967 return false;
1968 } else
1969 if (!gLibraryConfig->forEachIncludedDirectory(passOne_ProcessDir))
1970 return false;
1972 finiPassOne();
1973 return true;
1976 // true if filename ends in ".sc"
1977 bool isValidSourceFileName(char *filename)
1979 int len = strlen(filename);
1980 bool validExtension = (len>3 && strncmp(filename+len-3, ".sc", 3) == 0)
1981 || (len>7 && strncmp(filename+len-7, ".sc.rtf", 7) == 0);
1982 if (!validExtension)
1983 return false;
1985 boost::filesystem::path pathname(filename);
1987 if (pathname.filename().c_str()[0] == '.') // hidden filename
1988 return false;
1990 return true;
1993 // sekhar's replacement
1994 bool passOne_ProcessOneFile(const char * filenamearg, int level)
1996 bool success = true;
1998 bool isAlias = false;
2000 char filename[MAXPATHLEN];
2001 int status = sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN);
2003 if (status<0) {
2004 printf("WARNING: skipping invalid symbolic link: %s\n", filenamearg);
2005 return success;
2008 if (gLibraryConfig && gLibraryConfig->pathIsExcluded(filename)) {
2009 post("\texcluding file: '%s'\n", filename);
2010 return success;
2013 if (isValidSourceFileName(filename)) {
2014 gNumCompiledFiles++;
2015 PyrSymbol * fileSym = getsym(filename);
2016 fileSym->u.source = NULL;
2017 if (startLexer(fileSym, -1, -1, -1)) {
2018 while (parseOneClass(fileSym)) { };
2019 finiLexer();
2020 } else {
2021 error("file '%s' open failed\n", filename);
2022 success = false;
2024 } else {
2025 if (sc_DirectoryExists(filename))
2026 success = passOne_ProcessDir(filename, level);
2028 return success;
2031 void schedRun();
2033 void compileSucceeded();
2034 void compileSucceeded()
2036 compiledOK = !(parseFailed || compileErrors);
2037 if (compiledOK) {
2038 compiledOK = true;
2040 compiledOK = initRuntime(gMainVMGlobals, 128*1024, pyr_pool_runtime);
2042 if (compiledOK) {
2043 VMGlobals *g = gMainVMGlobals;
2045 g->canCallOS = true;
2046 //++g->sp; SetObject(g->sp, g->process);
2047 //runInterpreter(g, s_hardwaresetup, 1);
2049 ++g->sp; SetObject(g->sp, g->process);
2050 runInterpreter(g, s_startup, 1);
2051 g->canCallOS = false;
2053 schedRun();
2055 flushPostBuf();
2059 void aboutToCompileLibrary();
2060 void aboutToCompileLibrary()
2062 //printf("->aboutToCompileLibrary\n");
2063 pthread_mutex_lock (&gLangMutex);
2064 if (compiledOK) {
2065 VMGlobals *g = gMainVMGlobals;
2067 g->canCallOS = true;
2069 ++g->sp;
2070 SetObject(g->sp, g->process);
2071 runInterpreter(g, s_shutdown, 1);
2073 g->canCallOS = false;
2075 pthread_mutex_unlock (&gLangMutex);
2076 //printf("<-aboutToCompileLibrary\n");
2079 void closeAllGUIScreens();
2080 void TempoClock_stopAll(void);
2081 void closeAllCustomPorts();
2083 void shutdownLibrary()
2085 closeAllGUIScreens();
2087 schedStop();
2089 aboutToCompileLibrary();
2091 TempoClock_stopAll();
2093 pthread_mutex_lock (&gLangMutex);
2095 closeAllCustomPorts();
2097 if (compiledOK) {
2098 VMGlobals *g = gMainVMGlobals;
2099 g->canCallOS = true;
2100 g->gc->RunAllFinalizers();
2101 g->canCallOS = false;
2104 pyr_pool_runtime->FreeAll();
2106 compiledOK = false;
2108 pthread_mutex_unlock (&gLangMutex);
2111 SC_DLLEXPORT_C bool compileLibrary()
2113 //printf("->compileLibrary\n");
2114 shutdownLibrary();
2116 pthread_mutex_lock (&gLangMutex);
2117 gNumCompiledFiles = 0;
2118 compiledOK = false;
2120 // FIXME: the library config should have been initialized earlier!
2121 if (!gLibraryConfig)
2122 SC_LanguageConfig::readDefaultLibraryConfig();
2124 compileStartTime = elapsedTime();
2126 totalByteCodes = 0;
2128 #ifdef NDEBUG
2129 postfl("compiling class library...\n");
2130 #else
2131 postfl("compiling class library (debug build)...\n");
2132 #endif
2134 bool res = passOne();
2135 if (res) {
2137 postfl("\tpass 1 done\n");
2139 if (!compileErrors) {
2140 buildDepTree();
2141 traverseFullDepTree();
2142 traverseFullDepTree2();
2143 flushPostBuf();
2145 if (!compileErrors && gShowWarnings) {
2146 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
2147 symbolTable->CheckSymbols();
2150 pyr_pool_compile->FreeAll();
2151 flushPostBuf();
2152 compileSucceeded();
2153 } else {
2154 compiledOK = false;
2157 pthread_mutex_unlock (&gLangMutex);
2158 //printf("<-compileLibrary\n");
2159 return compiledOK;
2162 void signal_init_globs();
2164 void dumpByteCodes(PyrBlock *theBlock);
2166 SC_DLLEXPORT_C void runLibrary(PyrSymbol* selector)
2168 VMGlobals *g = gMainVMGlobals;
2169 g->canCallOS = true;
2170 try {
2171 if (compiledOK) {
2172 ++g->sp; SetObject(g->sp, g->process);
2173 runInterpreter(g, selector, 1);
2174 } else {
2175 postfl("Library has not been compiled successfully.\n");
2177 } catch (std::exception &ex) {
2178 PyrMethod *meth = g->method;
2179 if (meth) {
2180 int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1;
2181 post("caught exception in runLibrary %s:%s %3d\n",
2182 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip
2184 dumpByteCodes(meth);
2185 } else {
2186 post("caught exception in runLibrary\n");
2188 error(ex.what());
2189 } catch (...) {
2190 postfl("DANGER: OUT of MEMORY. Operation failed.\n");
2192 g->canCallOS = false;
2195 void interpretCmdLine(const char *textbuf, int textlen, char *methodname)
2197 PyrString *string;
2199 if (compiledOK) {
2200 PyrSlot slot;
2202 string = newPyrStringN(gMainVMGlobals->gc, textlen, 0, false);
2203 memcpy(string->s, textbuf, textlen);
2204 SetObject(&slotRawInterpreter(&gMainVMGlobals->process->interpreter)->cmdLine, string);
2205 gMainVMGlobals->gc->GCWrite(slotRawObject(&gMainVMGlobals->process->interpreter), string);
2206 SetObject(&slot, gMainVMGlobals->process);
2207 //#if __profile__
2208 // ProfilerInit(collectSummary, microsecondsTimeBase, 500, 100);
2209 //#endif
2210 slotCopy((++gMainVMGlobals->sp), &slot);
2211 runInterpreter(gMainVMGlobals, getsym(methodname), 1);
2212 //#if __profile__
2213 // ProfilerDump("\pErase2.prof");
2214 // ProfilerTerm();
2215 //#endif
2216 } else {
2217 postfl("Library has not been compiled successfully.\n");
2221 void init_SuperCollider()