earlybrowserreborn - Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 roytam 1 /*
2  * Most of this code is Jon's fault.
3  *
4  * Basically, it's trying to be a real fast lexical analyzer.
5  *
6  */
7  
8  
9 #define TEST
10  
11  
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <assert.h>
15  
16 #include "ytabh"
17 #include "violakeywords.h"
18  
19 char getc_buf[BUFSIZ + 1];
20 static char *getc_ptr = getc_buf + 1;
21  
22 enum { FROMSTRING, FROMFILE };
23  
24 #define lexHandleError(s) fputs(s, stdout)
25  
26 extern int verbose;
27  
28 /*
29  * Here should be all the really viola-specific stuff about the lexer.
30  * General lex stuff should go later.
31  *
32  */
33  
34 #define TRUE 1
35 #define FALSE 0
36 #include "ast.h"
37 #include "math.h"
38  
39 #include "utils.h"
40 #include "hash.h"
41 #include "mystrings.h"
42 #include "ident.h"
43  
44 char scanComment();
45  
46 #define strdup saveString
47 #define io_getc() (*getc_ptr++)
48 #define io_ungetc(c) (--getc_ptr)
49  
50 #define input io_getc
51 #define unput io_ungetc
52  
53 int identStrID = STR_LAST_OF_THE_PREDEFINED;
54 int varStrID = 0;
55  
56 /*
57  * Stores identifier in hashtable
58  */
59 int storeIdent(identStr)
60         char *identStr;
61 {
62         HashEntry *entry;
63  
64         if (!(entry = symStr2ID->get(symStr2ID, (long)identStr))) {
65                 entry = symStr2ID->put(symStr2ID,(long)identStr,++identStrID);
66                 symID2Str->put(symID2Str, identStrID, (long)identStr);
67         }
68  
69         return entry->val;
70 }
71  
72 int getIdent(identStr)
73         char *identStr;
74 {
75         HashEntry *entry;
76  
77         if (entry = symStr2ID->get(symStr2ID, (long)identStr))
78           return entry->val;
79  
80         return NULL;
81 }
82  
83 int tokenize(identStr)
84         char *identStr;
85 {
86         HashEntry *entry;
87         char *cp;
88  
89         if (!(entry = symStr2ID->get(symStr2ID, (long)identStr))) {
90                 cp = saveString(identStr);
91                 entry = symStr2ID->put(symStr2ID, (long)cp, ++identStrID);
92                 symID2Str->put(symID2Str, identStrID, (long)cp);
93         }
94         return entry->val;
95 }
96  
97 /*
98  * Scan for integer, maximum of n digits.
99  * Return integer value.
100  */
101 int scanIntNDigits(n)
102         int n;
103 {
104         int i = 0;
105         char c;
106         char buf[BUFSIZ];
107  
108         while (isdigit(c = input()) && (n-- > 0)) buf[i++] = c;
109         unput(c);
110         buf[i] = '\0';
111         i = (int)atoi(buf);
112  
113         return i;
114 }
115  
116 /*
117  * Convert a "back-slash code" character representation to a character
118  * i.e. "a" or "\n" or "\253"
119  */
120 char convertEscChar()
121 {
122         char c;
123 /*      char escbuf[4];
124         int i;*/
125  
126         if (input() == '\\') {  /* deal with escape character */
127                 switch (c = input()) {
128                 case 'n':
129                         return '\n';    /* newline */
130                 case 't':
131                         return '\t';    /* horizontal tab */
132                 case 'v':
133                         return '\v';    /* vertal tab */
134                 case 'b':
135                         return '\b';    /* backspace */
136                 case 'r':
137                         return '\r';    /* carriage return */
138                 case 'f':
139                         return '\f';    /* form feed */
140                 case '\\':
141                         return '\\';    /* backslash */
142                 case '\'':
143                         return '\'';    /* single quote */
144                 case '\"':
145                         return '\"';    /* double quote */
146                 default:
147                         unput(c);       /* number after '\' is the ascii # */
148 /*
149                         i = 0;
150                         while (isdigit(c) && (i < 3)) {
151                             escbuf[i++] = c;
152                             c = input();
153                         }
154                         if (i < 3) unput(c);
155                         escbuf[i] = '\0';
156                         return atoi(escbuf);
157 */
158                         return (char)scanIntNDigits(3);
159                 }
160         }
161         return c;
162 }
163  
164 /*
165  * Scan a character string, enclosed in two delimeter chars, into yytext
166  * and return token and semantic value.
167  * Converts back-slash representations to char. ie. "\n" => '\n'
168  * NOTE: ascii codes must be three digits, unless it is at the end of
169  * the string, or the next character is anything other than a digit.
170  * example: "\65B" => "AB"   "\0652" => "A2"   "\65\66" => "AB"
171  */
172 char *scanStringBlock(delimeter)
173         char delimeter;
174 {
175         char c;
176         short i=0;
177         static char yytext[BUFSIZ];
178  
179 L:      if ((c = input()) == '\\') {
180                 unput(c);
181                 yytext[i++] = convertEscChar();
182                 goto L;
183         } else if (c == delimeter || c == '\0') {
184                 yytext[i] = '\0';
185                 return yytext;
186         } else {
187                 yytext[i++] = c;
188         }
189         goto L;
190 }
191  
192 /*
193  * Scan a character constant into yytext
194  * and return token and semantic value.
195  */
196 int scanChar()
197 {
198         char *s;
199  
200         s = scanStringBlock('\''); /* extract and convert the escape-char */
201         yylval.c = *s; /* representation */
202  
203         return CHARCONST;
204 }
205  
206 /*
207  * Scan a character string into yytext, store it in string table,
208  * and return token and semantic value.
209  */
210 int scanString()
211 {
212         char *s;
213  
214         s = scanStringBlock('\"');      /* process escape characters */
215         yylval.s = SaveString(s);       /* should use headp... */
216  
217         return STRINGCONST;
218 }
219  
220 /*
221  * Scan an identifier.
222  */
223 int scanIdentifier(sp)
224         char *sp;
225 {
226         HashEntry *entry;
227  
228         /* store in symbolic table */
229         yylval.i = storeIdent(SaveString(sp));
230         return IDENT;
231 }
232  
233 int dumpProximityErrorLine(buff, i)
234         char *buff;
235         int *i;
236 {
237         char c, j;
238  
239         for (j = 0; c = yyscript[(*i)++]; j++) {
240                 if (c == '\n') {
241                         buff[j] = '\0';
242                         return 1;
243                 }
244                 buff[j] = c;
245         }
246         buff[j] = '\0';
247         return 0;
248 }
249  
250 reportError()
251 {
252         int i = 0, ln = 0, hasmore = 1;
253         char c;
254  
255         if (yyscriptcontext == SCRIPT_ORIGIN_OBJ_SCRIPT) {
256                 fprintf(stderr,
257                         "error at line %d... (obj=%s, in script)\n",
258                         lineno, yyobjcontext);
259         } else if (yyscriptcontext == SCRIPT_ORIGIN_CLASS_SCRIPT) {
260                 fprintf(stderr,
261                         "error at line %d... (obj=%s, in classScript)\n",
262                         lineno, yyobjcontext);
263         } else {
264                 fprintf(stderr,
265                         "error at line %d... (obj=%s, in eval)\n",
266                         lineno, yyobjcontext);
267                 fprintf(stderr,
268                         "script = {%s}\n",
269                         yyscript);
270         }
271  
272         for (;;) {
273                 c = yyscript[i];
274                 if (c == '\0') return;
275                 if (c == '\n') {
276                         ln++;
277                         if (ln >= lineno - 2) break;
278                 }
279                 i++;
280         }
281  
282         hasmore = dumpProximityErrorLine(buff, &i);
283         printf(" %d:\t%s\n", ln++, buff);
284         if (!hasmore) return;
285         hasmore = dumpProximityErrorLine(buff, &i);
286         printf(" %d:\t%s\n", ln++, buff);
287         if (!hasmore) return;
288         hasmore = dumpProximityErrorLine(buff, &i);
289         printf("*%d:\t%s\n", ln++, buff);
290         if (!hasmore) return;
291         hasmore = dumpProximityErrorLine(buff, &i);
292         printf(" %d:\t%s\n", ln++, buff);
293         if (!hasmore) return;
294         hasmore = dumpProximityErrorLine(buff, &i);
295         printf(" %d:\t%s\n", ln++, buff);
296         if (!hasmore) return;
297  
298 }
299  
300  
301  
302 /*
303  *
304  * From here on should be mostly stuff that is generically lexical-
305  * analyzerish.
306  *
307  */
308  
309 char scratchbuf[BUFSIZ];
310 FILE *datastream;
311  
312 #ifdef TEST
313  
314 YYSTYPE yylval;
315 /*#define scanString grabstring*/
316  
317 #define make_strn alloc_stringn
318  
319 #endif /* TEST */
320  
321  
322 char *alloc_string(s)
323     char *s;
324 {
325         char *t = (char *)malloc(strlen(s) + 1);
326         assert (t != NULL);
327         strcpy(t, s);
328         return t;
329 }
330  
331 char *alloc_stringn(s, l)
332     char *s;
333     int l;
334 {
335         char *t = (char *)malloc(l + 1);
336         assert(t != NULL);
337         bcopy(s, t, l);
338         t[l] = '\0';
339         return t;
340 }
341  
342 char *realloc_strcat(s, t, l, m)
343     char *s;
344     char *t;
345     int l;
346     int m;
347 {
348         s = (char *)realloc(s, l + m + 1);
349         bcopy(t, s + l, m);
350         s[m + l] = '\0';
351         return s;
352 }
353  
354 int lineno;
355 int lexsource;
356 char *langstring;
357  
358 #ifdef ANSI
359 void clear_lexbuf(void);
360 void activate_symbol_intercept(void);
361  
362 static int grabident(char c);
363 static int grabstring();
364 static int grabop(char c);
365 static int grabint(char c);
366 static int iskeyword(char *name);
367 static int refresh_buf(void);
368 #endif /* ANSI */
369  
370  
371 static char *translate_token(token)
372     int token;
373 {
374         static char buf[80];
375         if (token == 0) {
376             sprintf(buf, "END-OF-INPUT");
377         } else
378         if (token < 256) {
379             sprintf(buf, "'%c'", token);
380         } else if (token == STRING) {
381             sprintf(buf, "a string");
382         } else
383         if (token == INTCONST) {
384             sprintf(buf, "the integer %d", yylval.i);
385         } else if (token == FLOATCONST) {
386             sprintf(buf, "the float %f", yylval.f);
387         } else sprintf(buf, "token %d", token);
388         return buf;
389 }
390  
391 #ifdef NOT
392 int yyerror(s)
393     char *s;
394 {
395 /*      extern int yychar;*/
396         char buf[BUFSIZ];
397         unsigned int chars;
398  
399         sprintf(buf, "Parse error near line %d, character %d.", lineno,
400                 chars);
401         lexHandleError(buf);
402  
403 /*      sprintf(buf, "Offending token: %d.", yychar);*/
404         lexHandleError(buf);
405  
406         return 1;
407 }
408 #endif /* NOT */
409  
410 #define TRIEMAX 128
411 typedef void **trielevel;   /* TRIEMANIA */
412  
413 trielevel trietop;
414  
415 /*
416  * We use element #0 of a level of the trie to store the value of the token
417  * that we can accept here, or NULL if no such.  This, of course, assumes
418  * that character #0 is never going to exist in one of our keywords.
419  *
420  */
421  
422 static unsigned int numtries = 0;
423 static trielevel newlevel() {
424     unsigned int i = 0;
425     trielevel l;
426  
427     l = (trielevel)malloc(sizeof(void *) * TRIEMAX);
428     while (i < TRIEMAX) l[i++] = NULL;
429     numtries++;
430     return l;
431 }
432  
433 int init_scanutils() {
434     unsigned int i;
435     void **tp, **tq;
436     char *s;
437     char c;
438  
439     /*
440      * Fill trie.
441      *
442      */
443  
444     trietop = newlevel();
445  
446     i = 0;
447     while (i < PRIMSYMS) {
448         s = primstuff[i].name;
449         tp = trietop;
450         while (*s) {
451             c = *s;
452             if (tp[c] != NULL) tq = (void **)(tp[c]);
453             else {
454                 tq = newlevel();
455                 tp[c] = tq;
456             }
457             if (islower(c)) tp[toupper(c)] = tp[c];
458             tp = tq;
459             s++;
460         }
461         tp[0] = (void *)(primstuff[i].token);
462         i++;
463     }
464     if (verbose) printf("Built trie with %d levels (%d bytes.)\n", numtries,numtries*128*4);
465  
466     return 1;
467 }
468  
469 void clear_lexbuf() {
470         lineno = 1;
471         refresh_buf();
472 }
473  
474 void skip_hashbang() {
475         if ((*(getc_ptr) == '#') && (*(getc_ptr + 1) == '!')) {
476             getc_ptr += 2;
477             while (*getc_ptr && (*getc_ptr != '\n')) getc_ptr++;
478         }
479 }
480  
4 roytam 481 /*static*/ int refresh_buf() {
1 roytam 482     switch(lexsource) {
483         case FROMFILE:
484             getc_buf[0] = *(getc_ptr - 1);
485  
486          /*
487           * This is still okay to do even if getc_ptr is at the beginning
488           * of a new buffer (i.e. it == getc_buf + 1) since we will then
489           * just copy the first byte of getc_buf[] into itself.  Since in
490           * this case it is erroneous to ever io_unget() a character anyway,
491           * not having read any yet, we don't care if this data is
492           * meaningless.
493           *
494           * Addendum: If we're reading from a string and it's empty
495           *           then (getc_buf - 1) will be a pointer into unknown
496           *           data and using that data would invoke havoc.  However,
497           *           we will never use this data since an empty line
498           *           can only be encountered between tokens and we will
499           *           never ungetc between tokens.  Utilities like purify
500           *           and saber (codecenter, bleah) will choke on this,
501           *           reporting it as an error, when really it does no
502           *           damage.  The way to fix this would be to copy all
503           *           of the memory-resident string that we're parsing
504           *           into another buffer that has an extra character
505           *           of space at the beginning, but this sort of garbage
506           *           is just what we moved away from lex in order to
507           *           avoid.
508           *
509           *  Addendum to addendum: NEVER MIND!  getc_buf is not used
510           *                        when we're reading from memory resident
511           *                        string any more, only from file, so
512           *                        the above "Addendum" paragraph is
513           *                        pointless.
514           *
515           * BTW, the whole point of character 0 of getc_buf is so that we
516           * can io_unget() with impunity across buffer boundaries.
517           *
518           */
519  
520             getc_ptr = getc_buf + 1;
521             if (fgets(getc_ptr, BUFSIZ - 1, datastream) == NULL) {
522                 getc_buf[0] = getc_buf[1] = '\0';
523                 return EOF;
524             }
525             break;
526         case FROMSTRING:
527             if (lineno > 1) return EOF;
528             lineno++;
529             if (*langstring == '\0') return EOF;
530             getc_ptr = langstring;
531             /*
532              * This is okay since we will never have a buffer boundary
533              * when reading from a language-contained string, since we
534              * already have the whole thing sequentially in memory.  So,
535              * we will therefore never have to io_unget() across a
536              * boundary.
537              *
538              */
539             break;
540         default:
541             assert (0);
542     }
543     return 0;
544 }
545  
546 int yylex() {
547         char c;
548 yypoint:
549         switch(c = io_getc()) {
550         case '\n':
551                 lineno++;
552         case ' ':
553         case '\t':
554         case '\r':
555         case '\f':
556         case '\b':
557                 goto yypoint;
558         case '\0':
559                 if (refresh_buf() != EOF) goto yypoint;
560         case EOF:
561                 return EOF;
562         case '.':
563         case ':':
564         case ',':
565         case '(':
566         case ')':
567         case '[':
568         case ']':
569         case '{':
570         case '}':
571         case ';':
572         case '\\':
573                 return c;
574         case '=':
575         case '!':
576         case '<':
577         case '>':
578         case '+':
579         case '-':
580         case '%':
581         case '*':
582         case '/':
583         case '&':
584         case '|':
585                 return grabop(c);
586         case '"':
587 /*              return grabstring();*/
588                 return scanString();
589         case '\'':
590                 return scanChar();
591         case '0':
592         case '1':
593         case '2':
594         case '3':
595         case '4':
596         case '5':
597         case '6':
598         case '7':
599         case '8':
600         case '9':
601                 return grabint(c);
602         case '_':
603         case 'a':
604         case 'b':
605         case 'c':
606         case 'd':
607         case 'e':
608         case 'f':
609         case 'g':
610         case 'h':
611         case 'i':
612         case 'j':
613         case 'k':
614         case 'l':
615         case 'm':
616         case 'n':
617         case 'o':
618         case 'p':
619         case 'q':
620         case 'r':
621         case 's':
622         case 't':
623         case 'u':
624         case 'v':
625         case 'w':
626         case 'x':
627         case 'y':
628         case 'z':
629         case 'A':
630         case 'B':
631         case 'C':
632         case 'D':
633         case 'E':
634         case 'F':
635         case 'G':
636         case 'H':
637         case 'I':
638         case 'J':
639         case 'K':
640         case 'L':
641         case 'M':
642         case 'N':
643         case 'O':
644         case 'P':
645         case 'Q':
646         case 'R':
647         case 'S':
648         case 'T':
649         case 'U':
650         case 'V':
651         case 'W':
652         case 'X':
653         case 'Y':
654         case 'Z':
655                 return grabtag(c);
656         default:
657                 return c;
658         }
659 }
660  
661 #ifdef ANSI
662 extern void *is_inlib(char *s);
663 #endif /* ANSI */
664  
4 roytam 665 /*static*/ int grabtag(c)
1 roytam 666     char c;
667 {
668         char buf[BUFSIZ];
669         int i = 0, j;
670         void *q;
671  
672         while (c && (i < BUFSIZ - 1)) {
673             if (isalnum(c) || (c == '_') || (c == '.')) {
674                 buf[i++] = c;
675                 c = io_getc();
676             } else break;
677         }
678  
679         io_ungetc(c);
680         buf[i] = '\0';
681  
682         switch (j = iskeyword(buf)) {
683             default:
684                 yylval.i = j;
685                 return j;
686             case SPECIAL_TRUE:
687                 yylval.i = 1;
688                 return INTCONST;
689             case SPECIAL_FALSE:
690                 yylval.i = 0;
691                 return INTCONST;
692             case 0:
693                 break;
694         }
695  
696     nospec:
697         return scanIdentifier(buf);
698 }
699  
700 #define BIGBUFSIZ 2*BUFSIZ
701 static int grabstring() {
702     char buf[BIGBUFSIZ];
703     static int have_allocated = 0;
704     char c;
705     int i = 0;
706     char *product;
707     int total_len = 0;
708  
709     while (1) {
710         while (i < BIGBUFSIZ - 1) {
711           strpt1:
712             switch(c = io_getc()) {
713                 case '\0':
714                     if (refresh_buf() == EOF) goto endstr; /* UNT STRING */
715                     goto strpt1;
716                 case '"':
717                     goto endstr;
718                 case '\n':
719                     lineno++;
720                   gross:
721                     c = io_getc();
722                     switch(c) {
723                         case '\0':
724                             if (refresh_buf() == EOF) goto endstr;
725                             goto gross;
726                         case ' ':
727                         case '\t':
728                             goto gross;
729                         default:
730                             io_ungetc(c);
731                             c = ' ';
732                             break;
733                     }
734                     break;
735                 case '\\':
736                   strpt2:
737                      switch(c = io_getc()) {
738                        case 'n':
739                          c = '\n';
740                          break;
741                        case 't':
742                          c = '\t';
743                          break;
744                        case '\0':
745                          if (refresh_buf() == EOF) {
746                              buf[i++] = '\\';
747                              goto endstr;
748                          }
749                          goto strpt2;
750                      }
751                 }
752                 buf[i++] = c;
753         }
754  
755     endstr:
756         if (i == 0) {
757                 if (total_len) {
758                     yylval.s = make_strn(product, total_len);
759                     free(product);
760                 } else yylval.s = strdup("");
761                 return STRING;
762  
763         }
764  
765         if ((total_len == 0) && (i < BIGBUFSIZ - 1)) {
766                 yylval.s = make_strn(buf, i);
767                 return STRING;
768         }
769  
770         if (total_len) product = realloc_strcat(product, buf, total_len, i);
771             else product = alloc_stringn(buf, i);
772  
773         total_len += i;
774         i = 0;
775     }
776 }
777  
778 static int snarf_comment2() {
779     int c;
780  
781     loophead:
782         c = io_getc();
783     loop2:
784         switch (c) {
785             case 0:
786                 if (refresh_buf() == EOF) goto loopdone;
787                 goto loophead;
788             case '\n':
789                 lineno++;
790                 goto loophead;
791             case '*':
792                 c = io_getc();
793                 if (c == '/') return yylex();
794                 goto loop2;
795         }
796     goto loophead;
797  
798   loopdone:
799     io_ungetc(c);
800     return yylex();
801 }
802  
4 roytam 803 /*static*/ int grabop(c)
1 roytam 804     char c;
805 {
806         int i;
807         trielevel tp;
808  
809         tp = trietop;
810         while (c) {
811             if (tp[c]) {
812 /*              printf("Take %c\n", c);*/
813                 tp = (void **)tp[c];
814             } else if (tp[0]) {         /* Illegal char, but accept */
815                 io_ungetc(c);
816 /*              printf("Accept %c\n", c);*/
817                 i = (unsigned long)tp[0];
818                 if (i == SPECIAL_COMMENT) return snarf_comment2();
819                 return (yylval.i = i);
820             } else {                    /* Illegal char, no accept */
821                 sprintf(scratchbuf, "Illegal operator character '%c'.\n", c);
822 /*              fprintf(stderr, "^^^^^^^^%s", scratchbuf);*/
823                 lexHandleError(scratchbuf);
824                 return (yylval.i = c);
825             }
826             c = io_getc();
827         }
828         return (yylval.i = (unsigned int)tp[0]);
829 }
830  
831 #define MAXNLEN 38
4 roytam 832 /*static*/ int grabint(c)
1 roytam 833     char c;
834 {
835     char intbuf[MAXNLEN + 2];
836     unsigned int floating_pointp = 0;
837     int ilen = 0;
838  
839     while (ilen < MAXNLEN) {
840         if (c == '.') goto readfloat;
841         intbuf[ilen++] = c;
842         c = io_getc();
843         if (!isdigit(c) && (c != '.')) goto donereading;
844     }
845  
846   readfloat:
847     floating_pointp = 1;
848     while (ilen < MAXNLEN) {
849         intbuf[ilen++] = c;
850         c = io_getc();
851         if (!isdigit(c)) goto donereading;
852     }
853  
854   donereading:
855     intbuf[ilen] = '\0';
856     if (ilen != MAXNLEN) io_ungetc(c);
857  
858     if (floating_pointp) {
859         yylval.f = atof(intbuf);
860         return FLOATCONST;
861     }
862     yylval.i = atoi(intbuf);
863     return INTCONST;
864 }
865  
4 roytam 866 /*static*/ int iskeyword(name)
1 roytam 867     char *name;
868 {
869         int index = 0;
870         trielevel tb = trietop;
871  
872         while (*name) {
873             if (tb[*name]) {
874                 tb = (trielevel)tb[*name];
875             } else return 0;
876             name++;
877         }
878         return (unsigned long)tb[0];
879 }
880  
881 void set_parsing_string(s)
882     char *s;
883 {
884     lexsource = FROMSTRING;
885     langstring = s;
886     clear_lexbuf();
887 }
888  
889 void parse_file(filename)
890     char *filename;
891 {
892   /*
893    * Do some file opening stuff
894    */
895     lexsource = FROMFILE;
896     datastream = fopen(filename, "r");
897     clear_lexbuf();
898     skip_hashbang();
899     yyparse();
900 }